From: Mikko Rasa Date: Thu, 31 Aug 2006 14:03:51 +0000 (+0000) Subject: Add command line options (not all of them work yet) X-Git-Tag: 0.9~68 X-Git-Url: http://git.tdb.fi/?p=builder.git;a=commitdiff_plain;h=0d80cabf649b931b26e7055385156c75a7385d35 Add command line options (not all of them work yet) Make object files depend on all included headers Support multiple source directories per component Support installing files Make executables depend on all required libraries Add analyzer Enhance and clean up normal output Support parallel builds Add component type headers Add bootstrap.sh for initial build Add Readme.txt --- diff --git a/Build b/Build index 16e9982..8c59e73 100644 --- a/Build +++ b/Build @@ -7,6 +7,7 @@ package "builder" require "mspparser"; require "msppath"; require "mspregex++"; + require "mspgetopt++"; require "sigc++-2.0"; program "builder" diff --git a/Readme.txt b/Readme.txt new file mode 100644 index 0000000..c0004ad --- /dev/null +++ b/Readme.txt @@ -0,0 +1,27 @@ +Builder +Copyright © 2006 Mikko Rasa, Mikkosoft Productions +Version 0.1 + + +Builder is a program for building other programs, similar to make, scons and +others. It is specifically designed to suit my needs, with the goal of +minimizing the amount of per-package configuration. + + +* Building Builder + +Builder is normally built using itself. However, if you just downloaded the +source and don't yet have a Builder binary, how is that possible? To resolve +this problem, there's a script called bootstrap.sh in the Builder main +directory. Before running it, make sure you have the following libraries +available: + +MSP libraries: misc core parser path regex++ getopt++ + +Others: sigc++-2.0 + +Since the MSP libraries are also normally built with Builder, the script will +need to have their sources available. By default, it will look at ../libs. +You can change this by setting the LIBPATH evironment variable for the script. +If everything goes well, you should have a builder-stage1 binary that you can +use to build a normal version of Builder. diff --git a/bootstrap.sh b/bootstrap.sh new file mode 100755 index 0000000..2f74909 --- /dev/null +++ b/bootstrap.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +REQUIRED="misc core parser path regex++ getopt++" +CFLAGS="-Iinclude `pkg-config --cflags sigc++-2.0`" +LIBS="`pkg-config --libs sigc++-2.0` -lpthread" +if [ -z "$LIBPATH" ]; then + LIBPATH=`pwd`/../libs +fi + +mkdir -p include/msp + +sources=source/*.cpp + +for i in $REQUIRED; do + path=$LIBPATH/$i + if [ ! -e $path ]; then + echo $i missing + exit 1 + fi + if [ $i == "core" ]; then + ln -sf $path/source/core include/msp/core + ln -sf $path/source/time include/msp/time + elif [ $i == "misc" ]; then + ln -sf $path/source/*.h include/msp + else + ln -sf $path/source include/msp/$i + fi + sources="$sources `find $path/source -name '*.cpp'`" +done + +g++ $sources -o builder-stage1 $CFLAGS $LIBS diff --git a/source/analyzer.cpp b/source/analyzer.cpp new file mode 100644 index 0000000..a4780fd --- /dev/null +++ b/source/analyzer.cpp @@ -0,0 +1,110 @@ +#include +#include +#include +#include +#include "analyzer.h" +#include "builder.h" +#include "install.h" +#include "objectfile.h" +#include "package.h" +#include "target.h" + +using namespace std; +using namespace Msp; + +Analyzer::Analyzer(Builder &b): + builder(b), + max_depth(0), + full_paths(false) +{ } + +void Analyzer::analyze() +{ + TableRow row; + row.push_back("Name"); + row.push_back("Package"); + row.push_back("Type"); + row.push_back("Rebuild"); + table.push_back(row); + + build_depend_table(*builder.get_target("cmdline"), 0); + + print_table(); +} + +void Analyzer::build_depend_table(Target &tgt, unsigned depth) +{ + if(mode!=REBUILD) + { + if(dynamic_cast(&tgt)) + return build_depend_table(*tgt.get_depends().front(), depth); + else if(dynamic_cast(&tgt)) + return build_depend_table(*tgt.get_depends().front(), depth); + } + else if(!tgt.get_rebuild()) + return; + + TableRow row; + + string fn; + if(full_paths) + fn=tgt.get_name(); + else + fn=Path::Path(tgt.get_name())[-1]; + row.push_back(string(depth*2, ' ')+fn); + + const Package *pkg=tgt.get_package(); + if(pkg) + row.push_back(pkg->get_name()); + else + row.push_back(""); + + row.push_back(tgt.get_type()); + + if(tgt.get_rebuild()) + { + if(tgt.get_rebuild_reason().empty()) + row.push_back("Yes (no reason)"); + else + row.push_back(tgt.get_rebuild_reason()); + } + + table.push_back(row); + + if(!max_depth || depth &depends=tgt.get_depends(); + //depends.sort(target_order); + for(list::const_iterator i=depends.begin(); i!=depends.end(); ++i) + build_depend_table(**i, depth+1); + } +} + +void Analyzer::print_table() const +{ + vector col_width; + + for(Table::const_iterator i=table.begin(); i!=table.end(); ++i) + { + if(col_width.size()size()) + col_width.resize(i->size(), 0); + for(unsigned j=0; jsize(); ++j) + col_width[j]=max(col_width[j], (*i)[j].size()); + } + + for(Table::const_iterator i=table.begin(); i!=table.end(); ++i) + { + ostringstream ss; + ss<size(); ++j) + { + if(j>0) + ss<<" "; + ss<get_name()get_name(); } diff --git a/source/analyzer.h b/source/analyzer.h new file mode 100644 index 0000000..6c7b9dc --- /dev/null +++ b/source/analyzer.h @@ -0,0 +1,43 @@ +#ifndef ANALYZER_H_ +#define ANALYZER_H_ + +#include +#include +#include + +class Builder; +class Target; + +class Analyzer +{ +public: + enum Mode + { + DEPS, + ALLDEPS, + REBUILD, + RDEPS + }; + + Analyzer(Builder &); + void set_mode(Mode m) { mode=m; } + void set_max_depth(unsigned m) { max_depth=m; } + void set_full_paths(bool f) { full_paths=f; } + void analyze(); +private: + typedef std::vector TableRow; + typedef std::list Table; + + Builder &builder; + Mode mode; + Table table; + unsigned max_depth; + bool full_paths; + + void build_depend_table(Target &, unsigned); + void print_table() const; + + static bool target_order(Target *, Target *); +}; + +#endif diff --git a/source/builder.cpp b/source/builder.cpp index c900837..cb8ddf6 100644 --- a/source/builder.cpp +++ b/source/builder.cpp @@ -1,15 +1,23 @@ #include +#include +#include #include +#include +#include #include #include #include +#include #include "action.h" +#include "analyzer.h" #include "builder.h" #include "executable.h" #include "header.h" +#include "install.h" #include "misc.h" #include "objectfile.h" #include "package.h" +#include "systemlibrary.h" #include "virtualtarget.h" using namespace std; @@ -17,9 +25,60 @@ using namespace Msp; Builder::Builder(int argc, char **argv): verbose(1), - cwd(Path::getcwd()) + cwd(Path::getcwd()), + analyzer(0), + jobs(1), + chrome(false) { - for(int i=1; iset_mode(Analyzer::DEPS); + else if(mode=="alldeps") + analyzer->set_mode(Analyzer::ALLDEPS); + else if(mode=="rebuild") + analyzer->set_mode(Analyzer::REBUILD); + else if(mode=="rdeps") + analyzer->set_mode(Analyzer::RDEPS); + else + throw UsageError("Invalid analysis mode"); + + if(getopt["max-depth"]) + analyzer->set_max_depth(strtol(getopt["max-depth"].arg())); + analyzer->set_full_paths(getopt["full-paths"]); + } + + if(getopt['j']) + jobs=max(strtol(getopt['j'].arg()), 1L); + + if(getopt["chrome"]) + chrome=true; + + if(getopt['C']) + chdir(getopt['C'].arg().c_str()); + + for(int i=index; i dirs; + PathList dirs; if(!srcdir.empty()) dirs.push_back(srcdir); string dirname=n; - if(dirname.compare(0, 3, "msp")) + if(!dirname.compare(0, 3, "msp")) dirname.erase(0, 3); dirs.push_back(cwd/dirname); dirs.push_back(cwd/".."/dirname); - for(list::iterator j=dirs.begin(); j!=dirs.end(); ++j) + for(PathList::iterator j=dirs.begin(); j!=dirs.end(); ++j) if(!load_build_file(*j/"Build")) { i=packages.find(n); if(i!=packages.end()) return i->second; - return 0; + break; } Package *pkg=Package::create(*this, n); @@ -81,6 +147,7 @@ Target *Builder::get_target(const string &n) Target *Builder::get_header(const string &include, const string &from, const list &path) { + //XXX Should really hash the include path here string id=from+":"+include; TargetMap::iterator i=includes.find(id); if(i!=includes.end()) @@ -101,9 +168,33 @@ Target *Builder::get_header(const string &include, const string &from, const lis return 0; } +Target *Builder::get_library(const string &lib, const list &path) +{ + string hash(8, 0); + for(list::const_iterator i=path.begin(); i!=path.end(); ++i) + for(unsigned j=0; jsize(); ++j) + hash[j%8]^=(*i)[j]; + + string basename="lib"+lib+".so"; + for(list::const_iterator i=path.begin(); i!=path.end(); ++i) + { + string full=(Path::Path(*i)/basename).str(); + Target *tgt=get_target(full); + if(tgt) return tgt; + + if(Path::exists(full)) + { + add_target(tgt=new SystemLibrary(*this, full)); + return tgt; + } + } + + return 0; +} + int Builder::main() { - if(load_build_file("Build")) + if(load_build_file(cwd/"Build")) { cerr<<"No build info here.\n"; return 1; @@ -137,32 +228,58 @@ int Builder::main() for(list::iterator i=missing.begin(); i!=missing.end(); ++i) cerr<<" "<<*i<<'\n'; cerr<<"Please install them and try again.\n"; + return 1; } default_pkg->create_build_info(); - cout<<"Active packages:"; + /*cout<<"Active packages:"; for(PackageMap::iterator i=packages.begin(); i!=packages.end(); ++i) { cout<<' '<second->get_name(); if(i->second->get_buildable()) cout<<'*'; } - cout<<'\n'; + cout<<'\n';*/ if(create_targets()) return 1; - /*for(TargetMap::iterator i=targets.begin(); i!=targets.end(); ++i) - cout<second->get_name()<<' '<second->get_type()<<' '<second->get_rebuild()<<' '<second->get_rebuild_reason()<<'\n';*/ + cout<=2) + { + for(PackageMap::iterator i=packages.begin(); i!=packages.end(); ++i) + { + cout<<' '<second->get_name(); + if(i->second->get_buildable()) + cout<<'*'; + unsigned count=0; + for(TargetMap::iterator j=targets.begin(); j!=targets.end(); ++j) + if(j->second->get_package()==i->second) + ++count; + cout<<" ("<analyze(); build(); return exit_code; } +Builder::~Builder() +{ + for(PackageMap::iterator i=packages.begin(); i!=packages.end(); ++i) + delete i->second; + for(TargetMap::iterator i=targets.begin(); i!=targets.end(); ++i) + delete i->second; + delete analyzer; +} + int Builder::load_build_file(const Path::Path &fn) { ifstream in(fn.str().c_str()); @@ -170,7 +287,7 @@ int Builder::load_build_file(const Path::Path &fn) return -1; Parser::Parser parser(in, fn.str()); - Loader loader(*this, cwd/fn.subpath(0, fn.size()-1)); + Loader loader(*this, fn.subpath(0, fn.size()-1)); loader.load(parser); return 0; @@ -185,41 +302,92 @@ int Builder::create_targets() add_target(def_tgt); world->add_depend(def_tgt); + Target *install=new VirtualTarget(*this, "install"); + add_target(install); + world->add_depend(install); + for(PackageMap::iterator i=packages.begin(); i!=packages.end(); ++i) { + if(!i->second) + continue; if(!i->second->get_buildable()) continue; const ComponentList &components=i->second->get_components(); for(ComponentList::const_iterator j=components.begin(); j!=components.end(); ++j) { - Path::Path base=i->second->get_source()/j->get_source(); - list files=list_files(base); + PathList files; + const PathList &sources=j->get_sources(); + for(PathList::const_iterator k=sources.begin(); k!=sources.end(); ++k) + { + list sfiles=list_files(*k); + for(list::iterator l=sfiles.begin(); l!=sfiles.end(); ++l) + files.push_back(*k / *l); + } + + Path::Path inst_base=i->second->get_config().get_option("prefix").value; + bool build_exe=j->get_type()!=Component::HEADERS; + list objs; - for(list::iterator k=files.begin(); k!=files.end(); ++k) + for(PathList::iterator k=files.begin(); k!=files.end(); ++k) { - Path::Path fn=base/ *k; - string ext=Path::splitext(*k).ext; + string basename=(*k)[-1]; + string ext=Path::splitext(basename).ext; if(ext==".cpp" || ext==".c") { - SourceFile *src=new SourceFile(*this, &*j, fn.str()); - add_target(src); - - ObjectFile *obj=new ObjectFile(*this, *j, *src); - add_target(obj); - objs.push_back(obj); + if(build_exe) + { + SourceFile *src=new SourceFile(*this, &*j, k->str()); + add_target(src); + + ObjectFile *obj=new ObjectFile(*this, *j, *src); + add_target(obj); + objs.push_back(obj); + } } else if(ext==".h") - add_target(new Header(*this, &*j, fn.str())); + { + Target *hdr=get_target(k->str()); + if(!hdr) + { + hdr=new Header(*this, &*j, k->str()); + add_target(hdr); + } + if(!j->get_install_headers().empty()) + { + Path::Path inst_path=inst_base/"include"/j->get_install_headers()/basename; + Install *inst=new Install(*this, *i->second, *hdr, inst_path.str()); + add_target(inst); + install->add_depend(inst); + } + } } - Executable *exe=new Executable(*this, *j, objs); - add_target(exe); - if(i->second==default_pkg) - def_tgt->add_depend(exe); - else - world->add_depend(exe); + if(build_exe) + { + Executable *exe=new Executable(*this, *j, objs); + add_target(exe); + if(i->second==default_pkg) + def_tgt->add_depend(exe); + else + world->add_depend(exe); + + if(j->get_install()) + { + string inst_dir; + if(j->get_type()==Component::PROGRAM) + inst_dir="bin"; + else if(j->get_type()==Component::LIBRARY) + inst_dir="lib"; + if(!inst_dir.empty()) + { + Install *inst=new Install(*this, *i->second, *exe, (inst_base/inst_dir/Path::basename(exe->get_name())).str()); + add_target(inst); + install->add_depend(inst); + } + } + } } } @@ -241,7 +409,7 @@ int Builder::create_targets() if(!tgt) { cerr<<"I don't know anything about "<<*i<<'\n'; - return 1; + return -1; } cmdline->add_depend(tgt); } @@ -273,44 +441,81 @@ void Builder::add_target(Target *t) int Builder::build() { Target *cmdline=get_target("cmdline"); - list actions; - bool fail=false; - if(!cmdline->get_rebuild()) + unsigned total=cmdline->count_rebuild(); + if(!total) + { cout<<"Already up to date\n"; + return 0; + } + cout<<"Will build "< actions; + + //ProgressBar *progress=0; + if(chrome) + { + //progress=new ProgressBar(cout, total); + cout<<"0 targets built\n"; + } + unsigned count=0; - while(cmdline->get_rebuild() && !fail) + bool fail=false; + bool finish=false; + + while(!finish) { - if(actions.empty() && !fail) + if(actions.size()get_buildable_target(); if(tgt) { - //cout<<"Build "<get_name()<<'\n'; + /*if(chrome) + { + cout<<"\e["<set(count); + cout<<"\e["<build(); if(action) actions.push_back(action); } + else if(actions.empty()) + finish=true; } else - sleep(10*Time::msec); + Time::sleep(10*Time::msec); - for(list::iterator i=actions.begin(); i!=actions.end();) + for(unsigned i=0; icheck(); + int status=actions[i]->check(); if(status>=0) { - delete *i; - i=actions.erase(i); + ++count; + if(chrome) + { + cout<<"\e["<0) - fail=true; + finish=fail=true; } else ++i; } } - return 0; + //delete progress; + + return fail?-1:0; } Application::RegApp Builder::reg; @@ -328,6 +533,5 @@ void Builder::Loader::package(const string &n) load_sub(*pkg); bld.packages.insert(PackageMap::value_type(n, pkg)); bld.new_pkgs.push_back(pkg); - //cout<<"loaded "<get_name()<<'\n'; } diff --git a/source/builder.h b/source/builder.h index bdc5e2f..34afb92 100644 --- a/source/builder.h +++ b/source/builder.h @@ -9,6 +9,7 @@ #include #include "config.h" +class Analyzer; class Package; class Target; @@ -20,7 +21,9 @@ public: Package *get_package(const std::string &); Target *get_target(const std::string &); Target *get_header(const std::string &, const std::string &, const std::list &); + Target *get_library(const std::string &, const std::list &); int main(); + ~Builder(); private: class Loader: public Msp::Parser::Loader { @@ -39,15 +42,23 @@ private: std::list cmdline_targets; RawOptionMap cmdline_options; - TargetMap targets; - PackageMap packages; - unsigned verbose; - Package *default_pkg; - Msp::Path::Path cwd; + + PackageMap packages; std::list new_pkgs; - TargetMap includes; + Package *default_pkg; + + TargetMap targets; std::list new_tgts; - ToolMap tools; + TargetMap includes; + TargetMap libraries; + + ToolMap tools; + unsigned verbose; + Msp::Path::Path cwd; + Analyzer *analyzer; + unsigned jobs; + std::list what_if; + bool chrome; int load_build_file(const Msp::Path::Path &); int create_targets(); diff --git a/source/component.cpp b/source/component.cpp index a94a566..38f4d6b 100644 --- a/source/component.cpp +++ b/source/component.cpp @@ -25,5 +25,5 @@ Component::Loader::Loader(Component &c): void Component::Loader::source(const string &s) { - comp.source=comp.pkg.get_source()/s; + comp.sources.push_back(comp.pkg.get_source()/s); } diff --git a/source/component.h b/source/component.h index a27ddca..af2fc2f 100644 --- a/source/component.h +++ b/source/component.h @@ -5,6 +5,7 @@ #include #include #include "buildinfo.h" +#include "misc.h" class Package; @@ -34,7 +35,7 @@ public: const Package &get_package() const { return pkg; } Type get_type() const { return type; } const std::string &get_name() const { return name; } - const Msp::Path::Path &get_source() const { return source; } + const PathList &get_sources() const { return sources; } const BuildInfo &get_build_info() const { return build_info; } bool get_install() const { return install; } const std::string &get_install_headers() const { return install_headers; } @@ -43,7 +44,7 @@ protected: Package &pkg; Type type; std::string name; - Msp::Path::Path source; + PathList sources; bool install; std::string install_headers; BuildInfo build_info; diff --git a/source/copy.cpp b/source/copy.cpp new file mode 100644 index 0000000..23cd6f1 --- /dev/null +++ b/source/copy.cpp @@ -0,0 +1,48 @@ +#include +#include +#include "copy.h" +#include "package.h" + +using namespace std; +using namespace Msp; + +Copy::Copy(Builder &b, const Package &pkg, const Path::Path &s, const Path::Path &d): + Action(b), + src(s), + dest(d), + worker(*this) +{ + announce(pkg.get_name(), "INST", dest[-1]); +} + +int Copy::check() +{ + if(worker.get_done()) + { + signal_done.emit(); + worker.join(); + return 0; + } + return -1; +} + +void Copy::Worker::main() +{ + Path::mkpath(copy.src.subpath(0, copy.src.size()-1), 0755); + unlink(copy.dest.str().c_str()); + ifstream in(copy.src.str().c_str()); + ofstream out(copy.dest.str().c_str()); + + char buf[16384]; + while(!in.eof()) + { + in.read(buf, sizeof(buf)); + out.write(buf, in.gcount()); + } + + struct stat st; + Path::stat(copy.src, st); + chmod(copy.dest.str().c_str(), st.st_mode&0777); + + done=true; +} diff --git a/source/copy.h b/source/copy.h index e39be16..a6d5c51 100644 --- a/source/copy.h +++ b/source/copy.h @@ -5,10 +5,12 @@ #include #include "action.h" +class Package; + class Copy: public Action { public: - Copy(Builder &, const Msp::Path::Path &, const Msp::Path::Path &); + Copy(Builder &, const Package &, const Msp::Path::Path &, const Msp::Path::Path &); int check(); private: class Worker: public Msp::Thread diff --git a/source/executable.cpp b/source/executable.cpp index 1568233..4e7b1f4 100644 --- a/source/executable.cpp +++ b/source/executable.cpp @@ -1,3 +1,4 @@ +#include "builder.h" #include "component.h" #include "executable.h" #include "link.h" @@ -15,6 +16,17 @@ Executable::Executable(Builder &b, const Component &c, const list add_depend(*i); } +void Executable::find_depends() +{ + const list &libs=comp.get_build_info().libs; + for(list::const_iterator i=libs.begin(); i!=libs.end(); ++i) + { + Target *lib=builder.get_library(*i, comp.get_build_info().libpath); + if(lib) + add_depend(lib); + } +} + Action *Executable::build() { return Target::build(new Link(builder, *this, comp));; diff --git a/source/executable.h b/source/executable.h index 52b0cee..f118b87 100644 --- a/source/executable.h +++ b/source/executable.h @@ -11,7 +11,7 @@ class Executable: public Target public: Executable(Builder &, const Component &, const std::list &); const char *get_type() const { return "Executable"; } - void find_depends() { } + void find_depends(); Action *build(); private: const Component ∁ diff --git a/source/install.cpp b/source/install.cpp new file mode 100644 index 0000000..1ade8b2 --- /dev/null +++ b/source/install.cpp @@ -0,0 +1,33 @@ +#include "builder.h" +#include "copy.h" +#include "header.h" +#include "install.h" +#include "package.h" + +using namespace std; + +Install::Install(Builder &b, const Package &p, Target &tgt, const string &n): + Target(b, &p, n) +{ + buildable=true; + add_depend(&tgt); +} + +void Install::check_rebuild() +{ + if(!mtime) + mark_rebuild("Does not exist"); + else + { + Target *dep=depends.front(); + if(dep->get_mtime()>mtime) + mark_rebuild(dep->get_name()+" has changed"); + else if(dep->get_rebuild()) + mark_rebuild(dep->get_name()+" needs rebuilding"); + } +} + +Action *Install::build() +{ + return Target::build(new Copy(builder, *package, depends.front()->get_name(), name)); +} diff --git a/source/install.h b/source/install.h new file mode 100644 index 0000000..b81ac9b --- /dev/null +++ b/source/install.h @@ -0,0 +1,17 @@ +#ifndef INSTALL_H_ +#define INSTALL_H_ + +#include "target.h" + +class Install: public Target +{ +public: + Install(Builder &, const Package &, Target &, const std::string &); + const char *get_type() const { return "Install"; } + void find_depends() { } + void check_rebuild(); + Action *build(); +private: +}; + +#endif diff --git a/source/link.cpp b/source/link.cpp index 242c966..e2c0f12 100644 --- a/source/link.cpp +++ b/source/link.cpp @@ -12,6 +12,9 @@ Link::Link(Builder &b, const Executable &exe, const Component &comp): { argv.push_back("g++"); + if(comp.get_type()==Component::LIBRARY) + argv.push_back("-shared"); + const BuildInfo &binfo=comp.get_build_info(); for(list::const_iterator i=binfo.ldflags.begin(); i!=binfo.ldflags.end(); ++i) argv.push_back(*i); diff --git a/source/misc.h b/source/misc.h index ae2ff69..a35c0ed 100644 --- a/source/misc.h +++ b/source/misc.h @@ -3,6 +3,9 @@ #include #include +#include + +typedef std::list PathList; std::string run_command(const std::list &); diff --git a/source/objectfile.cpp b/source/objectfile.cpp index d29cd11..3e531f7 100644 --- a/source/objectfile.cpp +++ b/source/objectfile.cpp @@ -2,6 +2,7 @@ #include "builder.h" #include "compile.h" #include "component.h" +#include "install.h" #include "objectfile.h" #include "package.h" #include "sourcefile.h" @@ -17,11 +18,40 @@ ObjectFile::ObjectFile(Builder &b, const Component &c, SourceFile &src): add_depend(&src); } +void ObjectFile::find_depends() +{ + find_depends(depends.front()); +} + Action *ObjectFile::build() { return Target::build(new Compile(builder, depends.front()->get_name(), name, comp)); } +void ObjectFile::find_depends(Target *tgt) +{ + SourceFile *src=dynamic_cast(tgt); + if(!src) + { + Install *inst=dynamic_cast(tgt); + if(inst) + src=dynamic_cast(inst->get_depends().front()); + } + if(!src) + return; + + const string &sname=src->get_name(); + string path=sname.substr(0, sname.rfind('/')); + + const list &includes=src->get_includes(); + for(list::const_iterator i=includes.begin(); i!=includes.end(); ++i) + { + Target *hdr2=builder.get_header(*i, path, package->get_build_info().incpath); + if(hdr2) + add_depend(hdr2); + } +} + string ObjectFile::generate_target_name(const Component &comp, const string &src) { return (comp.get_package().get_source()/"temp"/comp.get_name()/(Path::splitext(src.substr(src.rfind('/')+1)).base+".o")).str(); diff --git a/source/objectfile.h b/source/objectfile.h index 9fa4979..962151c 100644 --- a/source/objectfile.h +++ b/source/objectfile.h @@ -11,11 +11,13 @@ class ObjectFile: public Target public: ObjectFile(Builder &, const Component &, SourceFile &); const char *get_type() const { return "ObjectFile"; } - void find_depends() { } + void find_depends(); Action *build(); private: const Component ∁ + void find_depends(Target *); + static std::string generate_target_name(const Component &, const std::string &); }; diff --git a/source/package.cpp b/source/package.cpp index e6e3b50..3072fd6 100644 --- a/source/package.cpp +++ b/source/package.cpp @@ -114,13 +114,21 @@ Package *Package::create(Builder &b, const string &name) { list argv; argv.push_back("pkg-config"); + argv.push_back("--silence-errors"); argv.push_back("--cflags"); argv.push_back("--libs"); argv.push_back(name); vector info=split(run_command(argv)); if(info.empty()) - return 0; + { + if(name=="opengl") + info.push_back("-lGL"); + else if(name=="pthread") + info.push_back("-lpthread"); + else + return 0; + } Package *pkg=new Package(b, name, info); return pkg; @@ -177,6 +185,7 @@ Package::Loader::Loader(Package &p): add("require", &Loader::require); add("program", &Loader::program); add("library", &Loader::library); + add("headers", &Loader::headers); } Package::Loader::~Loader() @@ -189,16 +198,23 @@ void Package::Loader::require(const string &n) pkg.requires.push_back(PackageRef(pkg.builder, n)); } -void Package::Loader::program(const std::string &n) +void Package::Loader::program(const string &n) { Component prog(pkg, Component::PROGRAM, n); load_sub(prog); pkg.components.push_back(prog); } -void Package::Loader::library(const std::string &n) +void Package::Loader::library(const string &n) { Component prog(pkg, Component::LIBRARY, n); load_sub(prog); pkg.components.push_back(prog); } + +void Package::Loader::headers(const string &n) +{ + Component prog(pkg, Component::HEADERS, n); + load_sub(prog); + pkg.components.push_back(prog); +} diff --git a/source/package.h b/source/package.h index aafec0f..06a68ba 100644 --- a/source/package.h +++ b/source/package.h @@ -39,6 +39,7 @@ public: void require(const std::string &); void program(const std::string &); void library(const std::string &); + void headers(const std::string &); }; Package(Builder &, const std::string &, const Msp::Path::Path &); diff --git a/source/sourcefile.cpp b/source/sourcefile.cpp index 4214253..ea76efd 100644 --- a/source/sourcefile.cpp +++ b/source/sourcefile.cpp @@ -7,6 +7,8 @@ using namespace std; using namespace Msp; +#include + SourceFile::SourceFile(Builder &b, const Component *c, const string &n): Target(b, c?&c->get_package():0, n), comp(c) @@ -32,9 +34,3 @@ void SourceFile::find_depends() add_depend(hdr); } } - -void SourceFile::check_rebuild() -{ - for(list::iterator i=depends.begin(); i!=depends.end(); ++i) - vmtime=max(vmtime, (*i)->get_virtual_mtime()); -} diff --git a/source/sourcefile.h b/source/sourcefile.h index af25fe9..b1ec829 100644 --- a/source/sourcefile.h +++ b/source/sourcefile.h @@ -9,14 +9,13 @@ class SourceFile: public Target { public: SourceFile(Builder &, const Component *, const std::string &); + const std::list &get_includes() const { return includes; } const char *get_type() const { return "SourceFile"; } void find_depends(); Action *build() { rebuild=false; return 0; } private: const Component *comp; std::list includes; - - void check_rebuild(); }; #endif diff --git a/source/systemlibrary.h b/source/systemlibrary.h new file mode 100644 index 0000000..9751270 --- /dev/null +++ b/source/systemlibrary.h @@ -0,0 +1,15 @@ +#ifndef SYSTEMLIBRARY_H_ +#define SYSTEMLIBRARY_H_ + +#include "target.h" + +class SystemLibrary: public Target +{ +public: + SystemLibrary(Builder &b, const std::string &n): Target(b,0,n) { } + const char *get_type() const { return "SystemLibrary"; } + void find_depends() { } + Action *build() { return 0; } +}; + +#endif diff --git a/source/target.cpp b/source/target.cpp index b3dc509..d4c2431 100644 --- a/source/target.cpp +++ b/source/target.cpp @@ -1,4 +1,5 @@ #include +#include #include "action.h" #include "builder.h" #include "package.h" @@ -42,6 +43,23 @@ void Target::prepare() check_rebuild(); } +unsigned Target::count_rebuild() +{ + if(counted) + return 0; + + counted=true; + unsigned count=rebuild; + for(list::iterator i=depends.begin(); i!=depends.end(); ++i) + count+=(*i)->count_rebuild(); + return count; +} + +void Target::touch() +{ + mtime=Time::now(); +} + Target::Target(Builder &b, const Package *p, const string &n): builder(b), package(p), @@ -49,14 +67,12 @@ Target::Target(Builder &b, const Package *p, const string &n): building(false), rebuild(false), prepared(false), - buildable(false) + buildable(false), + counted(false) { struct stat st; if(!Path::stat(name, st)) - { mtime=Time::TimeStamp::from_unixtime(st.st_mtime); - vmtime=mtime; - } } void Target::mark_rebuild(const std::string &reason) @@ -76,10 +92,10 @@ void Target::check_rebuild() { for(list::iterator i=depends.begin(); (i!=depends.end() && !rebuild); ++i) { - if((*i)->get_virtual_mtime()>mtime) - mark_rebuild((*i)->get_name()+" has changed"); + if((*i)->get_mtime()>mtime) + mark_rebuild(Path::basename((*i)->get_name())+" has changed"); else if((*i)->get_rebuild()) - mark_rebuild((*i)->get_name()+" needs rebuilding"); + mark_rebuild(Path::basename((*i)->get_name())+" needs rebuilding"); } } if(!rebuild && package && package->get_config().get_mtime()>mtime) diff --git a/source/target.h b/source/target.h index 371445b..f0ec0f2 100644 --- a/source/target.h +++ b/source/target.h @@ -12,18 +12,21 @@ class Package; class Target { public: - const std::string &get_name() const { return name; } - Target *get_buildable_target(); - bool get_rebuild() const { return rebuild; } - const std::string &get_rebuild_reason() const { return rebuild_reason; } - const Msp::Time::TimeStamp &get_mtime() const { return mtime; } - const Msp::Time::TimeStamp &get_virtual_mtime() const { return vmtime; } + const std::string &get_name() const { return name; } + Target *get_buildable_target(); + bool get_rebuild() const { return rebuild; } + const std::string &get_rebuild_reason() const { return rebuild_reason; } + const Msp::Time::TimeStamp &get_mtime() const { return mtime; } virtual const char *get_type() const=0; const std::list &get_depends() const { return depends; } - void add_depend(Target *); - virtual void find_depends()=0; - virtual void prepare(); - virtual Action *build()=0; + const Package *get_package() const { return package; } + void add_depend(Target *); + virtual void find_depends()=0; + virtual void prepare(); + virtual Action *build()=0; + void reset_count() { counted=false; } + unsigned count_rebuild(); + void touch(); virtual ~Target() { } protected: Builder &builder; @@ -33,11 +36,11 @@ protected: bool rebuild; std::string rebuild_reason; Msp::Time::TimeStamp mtime; - Msp::Time::TimeStamp vmtime; std::list depends; std::list rdepends; bool prepared; bool buildable; + bool counted; Target(Builder &, const Package *, const std::string &); void mark_rebuild(const std::string &); diff --git a/source/virtualtarget.cpp b/source/virtualtarget.cpp index 5c1e4c7..d3f80df 100644 --- a/source/virtualtarget.cpp +++ b/source/virtualtarget.cpp @@ -1,3 +1,4 @@ +#include #include "virtualtarget.h" using namespace std; @@ -6,5 +7,5 @@ void VirtualTarget::check_rebuild() { for(list::iterator i=depends.begin(); (i!=depends.end() && !rebuild); ++i) if((*i)->get_rebuild()) - mark_rebuild((*i)->get_name()+" needs rebuilding"); + mark_rebuild(Msp::Path::basename((*i)->get_name())+" needs rebuilding"); }