From: Mikko Rasa Date: Sun, 27 Aug 2006 21:09:00 +0000 (+0000) Subject: Builder can build itself now. X-Git-Tag: 0.9~70 X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=59ac0a44d6edf179c01604c6ced744873213f855;p=builder.git Builder can build itself now. --- diff --git a/Build b/Build index 4db65e6..16e9982 100644 --- a/Build +++ b/Build @@ -3,10 +3,11 @@ package "builder" version "0.1"; description "Mikkosoft Productions software builder"; - require "mspframework"; + require "mspcore"; require "mspparser"; require "msppath"; require "mspregex++"; + require "sigc++-2.0"; program "builder" { diff --git a/source/action.cpp b/source/action.cpp new file mode 100644 index 0000000..7ed0da1 --- /dev/null +++ b/source/action.cpp @@ -0,0 +1,16 @@ +#include +#include +#include +#include "action.h" + +using namespace std; + +void Action::announce(const string &pkg, const string &tool, const string &tgt) +{ + ostringstream line; + line< +#include + +class Builder; + +class Action +{ +public: + sigc::signal signal_done; + + virtual int check()=0; + virtual ~Action() { } +protected: + Builder &builder; + + Action(Builder &b): builder(b) { } + void announce(const std::string &, const std::string &, const std::string &); +}; + +#endif diff --git a/source/builder.cpp b/source/builder.cpp index 3f93a67..05ecf87 100644 --- a/source/builder.cpp +++ b/source/builder.cpp @@ -2,6 +2,8 @@ #include #include #include +#include +#include "action.h" #include "builder.h" #include "executable.h" #include "header.h" @@ -18,7 +20,15 @@ Builder::Builder(int argc, char **argv): cwd(Path::getcwd()) { for(int i=1; i dirs; if(!srcdir.empty()) - load_build_file(srcdir/"Build"); + dirs.push_back(srcdir); - return 0; + string dirname=n; + 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) + if(!load_build_file(*j/"Build")) + { + i=packages.find(n); + if(i!=packages.end()) + return i->second; + return 0; + } + + Package *pkg=Package::create(*this, n); + packages.insert(PackageMap::value_type(n, pkg)); + new_pkgs.push_back(pkg); + + return pkg; } Target *Builder::get_target(const string &n) @@ -100,6 +119,27 @@ int Builder::main() pkg->resolve_refs(); } + std::list missing; + for(PackageMap::iterator i=packages.begin(); i!=packages.end(); ++i) + { + const list &requires=i->second->get_requires(); + for(list::const_iterator j=requires.begin(); j!=requires.end(); ++j) + if(!j->get_package()) + missing.push_back(j->get_name()); + } + + if(!missing.empty()) + { + missing.sort(); + missing.unique(); + cerr<<"The following packages were not found on the system:\n"; + for(list::iterator i=missing.begin(); i!=missing.end(); ++i) + cerr<<" "<<*i<<'\n'; + cerr<<"Please install them and try again.\n"; + } + + default_pkg->create_build_info(); + cout<<"Active packages:"; for(PackageMap::iterator i=packages.begin(); i!=packages.end(); ++i) { @@ -109,14 +149,17 @@ int Builder::main() } cout<<'\n'; - create_targets(); + if(create_targets()) + return 1; for(TargetMap::iterator i=targets.begin(); i!=targets.end(); ++i) - cout<second->get_name()<<' '<second->get_type()<<'\n'; + cout<second->get_name()<<' '<second->get_type()<<' '<second->get_rebuild()<<' '<second->get_rebuild_reason()<<'\n'; cout<<"Active targets: "<add_depend(def_tgt); for(PackageMap::iterator i=packages.begin(); i!=packages.end(); ++i) { - cout<second->get_source()<<'\n'; + 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(); - cout< files=list_files(base); list objs; for(list::iterator k=files.begin(); k!=files.end(); ++k) { Path::Path fn=base/ *k; - //cout<<*k<<'\n'; string ext=Path::splitext(*k).ext; if(ext==".cpp" || ext==".c") { @@ -172,6 +217,8 @@ void Builder::create_targets() add_target(exe); if(i->second==default_pkg) def_tgt->add_depend(exe); + else + world->add_depend(exe); } } @@ -181,6 +228,26 @@ void Builder::create_targets() new_tgts.erase(new_tgts.begin()); tgt->find_depends(); } + + Target *cmdline=new VirtualTarget(*this, "cmdline"); + add_target(cmdline); + world->add_depend(cmdline); + for(list::iterator i=cmdline_targets.begin(); i!=cmdline_targets.end(); ++i) + { + Target *tgt=get_target(*i); + if(!tgt) + tgt=get_target((cwd/ *i).str()); + if(!tgt) + { + cerr<<"I don't know anything about "<<*i<<'\n'; + return 1; + } + cmdline->add_depend(tgt); + } + + world->prepare(); + + return 0; } Target *Builder::check_header(const Msp::Path::Path &fn) @@ -202,6 +269,44 @@ void Builder::add_target(Target *t) new_tgts.push_back(t); } +int Builder::build() +{ + Target *cmdline=get_target("cmdline"); + list actions; + bool fail=false; + + while(cmdline->get_rebuild() && !fail) + { + if(actions.empty() && !fail) + { + Target *tgt=cmdline->get_buildable_target(); + if(tgt) + { + cout<<"Build "<get_name()<<'\n'; + Action *action=tgt->build(); + if(action) + actions.push_back(action); + } + } + else + sleep(10*Time::msec); + + for(list::iterator i=actions.begin(); i!=actions.end();) + { + int status=(*i)->check(); + if(status>=0) + { + delete *i; + i=actions.erase(i); + if(status>0) + fail=true; + } + } + } + + return 0; +} + Application::RegApp Builder::reg; Builder::Loader::Loader(Builder &b, const Path::Path &s): diff --git a/source/builder.h b/source/builder.h index f66b310..bdc5e2f 100644 --- a/source/builder.h +++ b/source/builder.h @@ -4,9 +4,10 @@ #include #include #include -#include +#include #include #include +#include "config.h" class Package; class Target; @@ -32,10 +33,12 @@ private: void package(const std::string &); }; - typedef std::map PackageMap; - typedef std::map TargetMap; + typedef std::map PackageMap; + typedef std::map TargetMap; + typedef std::map ToolMap; std::list cmdline_targets; + RawOptionMap cmdline_options; TargetMap targets; PackageMap packages; unsigned verbose; @@ -44,11 +47,13 @@ private: std::list new_pkgs; TargetMap includes; std::list new_tgts; + ToolMap tools; int load_build_file(const Msp::Path::Path &); - void create_targets(); + int create_targets(); Target *check_header(const Msp::Path::Path &); void add_target(Target *); + int build(); static Msp::Application::RegApp reg; }; diff --git a/source/buildinfo.cpp b/source/buildinfo.cpp new file mode 100644 index 0000000..7669546 --- /dev/null +++ b/source/buildinfo.cpp @@ -0,0 +1,33 @@ +#include +#include "buildinfo.h" + +using namespace Msp; + +void BuildInfo::add(const BuildInfo &bi) +{ + cflags.insert(cflags.end(), bi.cflags.begin(), bi.cflags.end()); + defines.insert(defines.end(), bi.defines.begin(), bi.defines.end()); + incpath.insert(incpath.end(), bi.incpath.begin(), bi.incpath.end()); + ldflags.insert(ldflags.end(), bi.ldflags.begin(), bi.ldflags.end()); + libpath.insert(libpath.end(), bi.libpath.begin(), bi.libpath.end()); + libs.insert(libs.end(), bi.libs.begin(), bi.libs.end()); +} + +void BuildInfo::unique() +{ + unique(cflags); + unique(defines); + unique(incpath); + unique(ldflags); + unique(libpath); + unique(libs); +} + +void BuildInfo::unique(InfoList &l) +{ + InfoList l2; + for(InfoList::iterator i=l.begin(); i!=l.end(); ++i) + if(!contains(l2, *i)) + l2.push_back(*i); + swap(l, l2); +} diff --git a/source/buildinfo.h b/source/buildinfo.h index 02549ea..a4035b1 100644 --- a/source/buildinfo.h +++ b/source/buildinfo.h @@ -18,6 +18,8 @@ public: void add(const BuildInfo &); void unique(); +private: + void unique(InfoList &); }; #endif diff --git a/source/compile.cpp b/source/compile.cpp new file mode 100644 index 0000000..15aaee9 --- /dev/null +++ b/source/compile.cpp @@ -0,0 +1,47 @@ +#include +#include "buildinfo.h" +#include "compile.h" +#include "component.h" +#include "package.h" + +using namespace std; +using namespace Msp; + +Compile::Compile(Builder &b, const Path::Path &s, const Path::Path &o, const Component &c): + ExternalAction(b), + source(s), + object(o), + comp(c) +{ + string ext=Path::splitext(source.str()).ext; + const char *tool=0; + if(ext==".cpp" || ext==".cc") + { + tool="CXX"; + argv.push_back("g++"); + } + else + { + tool="CC"; + argv.push_back("gcc"); + } + argv.push_back("-c"); + + const BuildInfo &binfo=comp.get_build_info(); + for(list::const_iterator i=binfo.cflags.begin(); i!=binfo.cflags.end(); ++i) + argv.push_back(*i); + for(list::const_iterator i=binfo.incpath.begin(); i!=binfo.incpath.end(); ++i) + argv.push_back("-I"+*i); + for(list::const_iterator i=binfo.defines.begin(); i!=binfo.defines.end(); ++i) + argv.push_back("-D"+*i); + + argv.push_back("-o"); + argv.push_back(object.str()); + argv.push_back(source.str()); + + Path::mkpath(object.subpath(0, object.size()-1), 0755); + + announce(comp.get_package().get_name(), tool, relative(object.str(), comp.get_package().get_source()).str()); + + launch(); +} diff --git a/source/compile.h b/source/compile.h new file mode 100644 index 0000000..42ae95c --- /dev/null +++ b/source/compile.h @@ -0,0 +1,19 @@ +#ifndef COMPILE_H_ +#define COMPILE_H_ + +#include +#include "externalaction.h" + +class Component; + +class Compile: public ExternalAction +{ +public: + Compile(Builder &, const Msp::Path::Path &, const Msp::Path::Path &, const Component &); +private: + Msp::Path::Path source; + Msp::Path::Path object; + const Component ∁ +}; + +#endif diff --git a/source/component.cpp b/source/component.cpp index bab7ba1..a94a566 100644 --- a/source/component.cpp +++ b/source/component.cpp @@ -9,6 +9,12 @@ Component::Component(Package &p, Type t, const string &n): name(n) { } +void Component::create_build_info() +{ + build_info=pkg.get_build_info(); + build_info.unique(); +} + Component::Loader::Loader(Component &c): comp(c) { diff --git a/source/component.h b/source/component.h index c5e1d0c..a27ddca 100644 --- a/source/component.h +++ b/source/component.h @@ -26,15 +26,19 @@ public: { PROGRAM, LIBRARY, - MODULE + MODULE, + HEADERS }; Component(Package &, Type, const std::string &); - 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 BuildInfo &get_build_info() const { return build_info; } + 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 BuildInfo &get_build_info() const { return build_info; } + bool get_install() const { return install; } + const std::string &get_install_headers() const { return install_headers; } + void create_build_info(); protected: Package &pkg; Type type; diff --git a/source/config.cpp b/source/config.cpp new file mode 100644 index 0000000..50e0de9 --- /dev/null +++ b/source/config.cpp @@ -0,0 +1,48 @@ +#include +#include "config.h" + +using namespace std; +using namespace Msp; + +void Config::add_option(const string &n, const string &v, const string &d) +{ + options.insert(OptionMap::value_type(n, Option(n, v, d))); +} + +const Config::Option &Config::get_option(const string &name) const +{ + OptionMap::const_iterator i=options.find(name); + if(i==options.end()) + throw Exception("Tried to access nonexistent option "+name); + + return i->second; +} + +bool Config::is_option(const string &name) const +{ + return options.count(name); +} + +bool Config::process(const RawOptionMap &opts) +{ + bool changed=false; + for(RawOptionMap::const_iterator i=opts.begin(); i!=opts.end(); ++i) + { + OptionMap::iterator j=options.find(i->first); + if(j!=options.end()) + { + if(i->second!=j->second.value) + changed=true; + j->second.value=i->second; + } + } + + return changed; +} + +Config::Option::Option(const string &n, const string &v, const string &d): + name(n), + defv(v), + descr(d), + value(v) +{ } diff --git a/source/config.h b/source/config.h new file mode 100644 index 0000000..1b78e3a --- /dev/null +++ b/source/config.h @@ -0,0 +1,33 @@ +#ifndef CONFIG_H_ +#define CONFIG_H_ + +#include +#include +#include "option.h" + +typedef std::map RawOptionMap; + +class Config +{ +public: + struct Option + { + std::string name; + std::string defv; + std::string descr; + std::string value; + + Option(const std::string &, const std::string &, const std::string &); + }; + typedef std::map OptionMap; + + void add_option(const std::string &, const std::string &, const std::string &); + const Option &get_option(const std::string &) const; + bool is_option(const std::string &) const; + bool process(const RawOptionMap &); + void load(const std::string &); +private: + OptionMap options; +}; + +#endif diff --git a/source/executable.cpp b/source/executable.cpp index 2dfeee8..1568233 100644 --- a/source/executable.cpp +++ b/source/executable.cpp @@ -1,5 +1,6 @@ #include "component.h" #include "executable.h" +#include "link.h" #include "objectfile.h" #include "package.h" @@ -9,10 +10,16 @@ Executable::Executable(Builder &b, const Component &c, const list Target(b, &c.get_package(), generate_target_name(c)), comp(c) { + buildable=true; for(list::const_iterator i=objs.begin(); i!=objs.end(); ++i) add_depend(*i); } +Action *Executable::build() +{ + return Target::build(new Link(builder, *this, comp));; +} + string Executable::generate_target_name(const Component &comp) { string prefix; diff --git a/source/executable.h b/source/executable.h index 3e34851..52b0cee 100644 --- a/source/executable.h +++ b/source/executable.h @@ -12,6 +12,7 @@ public: Executable(Builder &, const Component &, const std::list &); const char *get_type() const { return "Executable"; } void find_depends() { } + Action *build(); private: const Component ∁ diff --git a/source/externalaction.cpp b/source/externalaction.cpp new file mode 100644 index 0000000..d4a48d7 --- /dev/null +++ b/source/externalaction.cpp @@ -0,0 +1,52 @@ +#include +#include +#include "builder.h" +#include "externalaction.h" + +using namespace std; +using namespace Msp; + +int ExternalAction::check() +{ + if(!pid) + return 255; + + int status; + if(waitpid(pid, &status, WNOHANG)==pid) + { + signal_done.emit(); + if(WIFEXITED(status)) + return WEXITSTATUS(status); + else + return 254; + } + else + return -1; +} + +void ExternalAction::launch() +{ + if(builder.get_verbose()>=1) + { + for(list::const_iterator i=argv.begin(); i!=argv.end(); ++i) + { + if(i!=argv.begin()) + cout<<' '; + cout<<*i; + } + cout<<'\n'; + } + + pid=fork(); + if(pid==0) + { + char *argv_[argv.size()+1]; + for(CountingIterator::iterator> i=argv.begin(); i!=argv.end(); ++i) + argv_[i.count()]=strdup(i->c_str()); + argv_[argv.size()]=0; + execvp(argv_[0], argv_); + exit(1); + } + else if(pid<0) + pid=0; +} diff --git a/source/externalaction.h b/source/externalaction.h new file mode 100644 index 0000000..52eed37 --- /dev/null +++ b/source/externalaction.h @@ -0,0 +1,20 @@ +#ifndef EXTERNALACTION_H_ +#define EXTERNALACTION_H_ + +#include +#include +#include "action.h" + +class ExternalAction: public Action +{ +public: + int check(); +protected: + std::list argv; + int pid; + + ExternalAction(Builder &b): Action(b) { } + void launch(); +}; + +#endif diff --git a/source/install.h b/source/install.h new file mode 100644 index 0000000..3c179c6 --- /dev/null +++ b/source/install.h @@ -0,0 +1,29 @@ +#ifndef INSTALL_H_ +#define INSTALL_H_ + +#include +#include +#include "action.h" + +class Install: public Action +{ +public: + Install(const Msp::Path::Path &, const Msp::Path::Path &); +private: + class Worker: public Msp::Thread + { + public: + Worker(Install &i): install(i), done(false) { launch(); } + private: + Install &install; + bool done; + + void main(); + }; + + Msp::Path::Path src; + Msp::Path::Path dest; + Worker worker; +}; + +#endif diff --git a/source/link.cpp b/source/link.cpp new file mode 100644 index 0000000..242c966 --- /dev/null +++ b/source/link.cpp @@ -0,0 +1,35 @@ +#include +#include "component.h" +#include "executable.h" +#include "link.h" +#include "package.h" + +using namespace std; +using namespace Msp; + +Link::Link(Builder &b, const Executable &exe, const Component &comp): + ExternalAction(b) +{ + argv.push_back("g++"); + + const BuildInfo &binfo=comp.get_build_info(); + for(list::const_iterator i=binfo.ldflags.begin(); i!=binfo.ldflags.end(); ++i) + argv.push_back(*i); + for(list::const_iterator i=binfo.libpath.begin(); i!=binfo.libpath.end(); ++i) + argv.push_back("-L"+*i); + for(list::const_iterator i=binfo.libs.begin(); i!=binfo.libs.end(); ++i) + argv.push_back("-l"+*i); + + argv.push_back("-o"); + argv.push_back(exe.get_name()); + const list &deps=exe.get_depends(); + for(list::const_iterator i=deps.begin(); i!=deps.end(); ++i) + argv.push_back((*i)->get_name()); + + Path::Path epath=exe.get_name(); + Path::mkpath(epath.subpath(0, epath.size()-1), 0755); + + announce(comp.get_package().get_name(), "LINK", relative(epath, comp.get_package().get_source()).str()); + + launch(); +} diff --git a/source/link.h b/source/link.h new file mode 100644 index 0000000..eecbcbd --- /dev/null +++ b/source/link.h @@ -0,0 +1,15 @@ +#ifndef LINK_H_ +#define LINK_H_ + +#include "externalaction.h" + +class Component; +class Executable; + +class Link: public ExternalAction +{ +public: + Link(Builder &, const Executable &, const Component &); +}; + +#endif diff --git a/source/objectfile.cpp b/source/objectfile.cpp index b308c2b..d29cd11 100644 --- a/source/objectfile.cpp +++ b/source/objectfile.cpp @@ -1,5 +1,6 @@ #include #include "builder.h" +#include "compile.h" #include "component.h" #include "objectfile.h" #include "package.h" @@ -12,9 +13,15 @@ ObjectFile::ObjectFile(Builder &b, const Component &c, SourceFile &src): Target(b, &c.get_package(), generate_target_name(c, src.get_name())), comp(c) { + buildable=true; add_depend(&src); } +Action *ObjectFile::build() +{ + return Target::build(new Compile(builder, depends.front()->get_name(), name, comp)); +} + 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 d270529..9fa4979 100644 --- a/source/objectfile.h +++ b/source/objectfile.h @@ -12,6 +12,7 @@ public: ObjectFile(Builder &, const Component &, SourceFile &); const char *get_type() const { return "ObjectFile"; } void find_depends() { } + Action *build(); private: const Component ∁ diff --git a/source/option.cpp b/source/option.cpp new file mode 100644 index 0000000..8f1a6e9 --- /dev/null +++ b/source/option.cpp @@ -0,0 +1,10 @@ +#include "option.h" + +using namespace std; + +Option::Option(const string &n, const string &v, const string &d): + name(n), + defv(v), + descr(d), + value(v) +{ } diff --git a/source/option.h b/source/option.h new file mode 100644 index 0000000..cbf1769 --- /dev/null +++ b/source/option.h @@ -0,0 +1,22 @@ +#ifndef OPTION_H_ +#define OPTION_H_ + +#include + +class Option +{ +public: + Option(const std::string &, const std::string &, const std::string &); + void set_value(const std::string &v) { value=v; } + const std::string &get_value() const { return value; } + const std::string &get_name() const { return name; } + const std::string &get_default_value() const { return defv; } + const std::string &get_description() const { return descr; } +private: + std::string name; + std::string defv; + std::string descr; + std::string value; +}; + +#endif diff --git a/source/package.cpp b/source/package.cpp index 5cf7e07..fcbe9f7 100644 --- a/source/package.cpp +++ b/source/package.cpp @@ -1,4 +1,6 @@ +#include #include "builder.h" +#include "misc.h" #include "package.h" using namespace std; @@ -10,7 +12,7 @@ PackageRef::PackageRef(Builder &b, const string &n): package(0) { } -Package *PackageRef::get_package() +Package *PackageRef::resolve() { if(!package) package=builder.get_package(name); @@ -21,14 +23,135 @@ Package::Package(Builder &b, const string &n, const Path::Path &s): builder(b), name(n), source(s), - buildable(false) + buildable(true), + build_info_ready(false) +{ } + +Package::Package(Builder &b, const string &n, const vector &info): + builder(b), + name(n), + buildable(false), + build_info_ready(true) { + for(vector::const_iterator i=info.begin(); i!=info.end(); ++i) + { + if(!i->compare(0, 2, "-I")) + export_binfo.incpath.push_back(i->substr(2)); + else if(!i->compare(0, 2, "-D")) + export_binfo.defines.push_back(i->substr(2)); + else if(!i->compare(0, 2, "-L")) + export_binfo.libpath.push_back(i->substr(2)); + else if(!i->compare(0, 2, "-l")) + export_binfo.libs.push_back(i->substr(2)); + } } void Package::resolve_refs() { for(list::iterator i=requires.begin(); i!=requires.end(); ++i) - i->get_package(); + i->resolve(); +} + +void Package::create_build_info() +{ + if(build_info_ready) + return; + + for(list::iterator i=requires.begin(); i!=requires.end(); ++i) + { + if(!i->get_package()) + continue; + i->get_package()->create_build_info(); + build_info.add(i->get_package()->get_exported_binfo()); + } + + build_info.cflags.push_back("-Wall"); + build_info.cflags.push_back("-Wshadow"); + build_info.cflags.push_back("-Wextra"); + build_info.cflags.push_back("-Wpointer-arith"); + build_info.cflags.push_back("-Wconversion"); + build_info.cflags.push_back("-Werror"); + + unsigned flags=get_install_flags(); + + if(flags&INCLUDE) + export_binfo.incpath.push_back((Path::Path(config.get_option("prefix").value)/"include").str()); + if(flags&LIB) + export_binfo.libpath.push_back((Path::Path(config.get_option("prefix").value)/"lib").str()); + + build_info.unique(); + export_binfo.unique(); + + for(list::iterator i=components.begin(); i!=components.end(); ++i) + { + i->create_build_info(); + if(i->get_type()==Component::LIBRARY) + export_binfo.libs.push_back(i->get_name()); + } + + build_info_ready=true; +} + +void Package::process_options(const RawOptionMap &opts) +{ + config.process(opts); +} + +Package *Package::create(Builder &b, const string &name) +{ + list argv; + argv.push_back("pkg-config"); + argv.push_back("--cflags"); + argv.push_back("--libs"); + argv.push_back(name); + vector info=split(run_command(argv)); + + if(info.empty()) + return 0; + + Package *pkg=new Package(b, name, info); + return pkg; +} + +void Package::init_buildable() +{ + buildable=true; + + config.add_option("tempdir", "temp", "Directory for storing temporary files"); + config.add_option("optimize", "0", "Apply compiler optimizations"); + config.add_option("debug", "0", "Produce debugging symbols"); + + const char *home=getenv("HOME"); + unsigned flags=get_install_flags(); + if(flags) + config.add_option("prefix", string(home)+"/local"/*"/usr"*/, "Installation prefix"); + /*if(flags&INCLUDE) + config.add_option("includedir", "$prefix/include", "Header installation directory"); + if(flags&BIN) + config.add_option("includedir", "$prefix/bin", "Binary installation directory"); + if(flags&LIB) + config.add_option("includedir", "$prefix/lib", "Library installation directory"); + if(flags&DATA) + config.add_option("includedir", "$prefix/share", "Data installation directory");*/ +} + +unsigned Package::get_install_flags() +{ + unsigned flags=0; + for(ComponentList::iterator i=components.begin(); i!=components.end(); ++i) + { + if(i->get_install()) + { + if(i->get_type()==Component::PROGRAM) + flags|=BIN; + else if(i->get_type()==Component::LIBRARY || i->get_type()==Component::MODULE) + flags|=LIB; + } + if(!i->get_install_headers().empty()) + flags|=INCLUDE; + } + + return flags; } Package::Loader::Loader(Package &p): @@ -43,7 +166,7 @@ Package::Loader::Loader(Package &p): Package::Loader::~Loader() { - pkg.buildable=true; + pkg.init_buildable(); } void Package::Loader::require(const string &n) diff --git a/source/package.h b/source/package.h index 42c453a..aafec0f 100644 --- a/source/package.h +++ b/source/package.h @@ -6,6 +6,7 @@ #include #include "buildinfo.h" #include "component.h" +#include "config.h" class Builder; class Package; @@ -14,7 +15,9 @@ class PackageRef { public: PackageRef(Builder &, const std::string &); - Package *get_package(); + const std::string &get_name() const { return name; } + Package *get_package() const { return package; } + Package *resolve(); private: Builder &builder; std::string name; @@ -39,15 +42,29 @@ public: }; Package(Builder &, const std::string &, const Msp::Path::Path &); - Package(Builder &, const std::string &, const std::list &); - const std::string &get_name() const { return name; } - const Msp::Path::Path &get_source() const { return source; } + Package(Builder &, const std::string &, const std::vector &); + const std::string &get_name() const { return name; } + const Msp::Path::Path &get_source() const { return source; } const ComponentList &get_components() const { return components; } - bool get_buildable() const { return buildable; } - void resolve_refs(); + bool get_buildable() const { return buildable; } + const Config &get_config() const { return config; } + const std::list &get_requires() const { return requires; } + const BuildInfo &get_build_info() const { return build_info; } + const BuildInfo &get_exported_binfo() const { return export_binfo; } + void resolve_refs(); + void create_build_info(); + void process_options(const RawOptionMap &); static Package *create(Builder &, const std::string &); private: + enum InstallFlags + { + INCLUDE=1, + BIN=2, + LIB=4, + DATA=8 + }; + Builder &builder; std::string name; std::string version; @@ -58,6 +75,11 @@ private: Msp::Path::Path source; bool buildable; ComponentList components; + Config config; + bool build_info_ready; + + void init_buildable(); + unsigned get_install_flags(); }; #endif diff --git a/source/sourcefile.cpp b/source/sourcefile.cpp index 55910a6..4214253 100644 --- a/source/sourcefile.cpp +++ b/source/sourcefile.cpp @@ -32,3 +32,9 @@ 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 962c575..af25fe9 100644 --- a/source/sourcefile.h +++ b/source/sourcefile.h @@ -9,11 +9,14 @@ class SourceFile: public Target { public: SourceFile(Builder &, const Component *, const std::string &); - void find_depends(); 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/target.cpp b/source/target.cpp index 481d2f4..8ba3cc3 100644 --- a/source/target.cpp +++ b/source/target.cpp @@ -1,27 +1,26 @@ +#include +#include "action.h" #include "builder.h" #include "target.h" using namespace std; - -Target *TargetRef::get_target() -{ - if(!target) - target=builder.get_target(name); - return target; -} +using namespace Msp; Target *Target::get_buildable_target() { - if(rebuild && ready_for_build && !building) - return this; - + bool self_ok=true; for(list::iterator i=depends.begin(); i!=depends.end(); ++i) { Target *tgt=(*i)->get_buildable_target(); if(tgt) return tgt; + else if((*i)->get_rebuild()) + self_ok=false; } + if(self_ok && rebuild && !building) + return this; + return 0; } @@ -31,17 +30,68 @@ void Target::add_depend(Target *dep) dep->rdepends.push_back(this); } +void Target::prepare() +{ + if(prepared) + return; + + for(list::iterator i=depends.begin(); i!=depends.end(); ++i) + (*i)->prepare(); + + check_rebuild(); +} + Target::Target(Builder &b, const Package *p, const string &n): builder(b), package(p), name(n), building(false), rebuild(false), - ready_for_build(false) -{ } + prepared(false), + buildable(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) { rebuild=true; rebuild_reason=reason; } + +void Target::check_rebuild() +{ + if(!buildable) + return; + + if(!mtime) + mark_rebuild("Does not exist"); + else + { + for(list::iterator i=depends.begin(); (i!=depends.end() && !rebuild); ++i) + { + if((*i)->get_virtual_mtime()>mtime) + mark_rebuild((*i)->get_name()+" has changed"); + else if((*i)->get_rebuild()) + mark_rebuild((*i)->get_name()+" needs rebuilding"); + } + } +} + +Action *Target::build(Action *action) +{ + building=true; + action->signal_done.connect(sigc::mem_fun(this, &Target::build_done)); + return action; +} + +void Target::build_done() +{ + building=false; + rebuild=false; +} diff --git a/source/target.h b/source/target.h index 21135b0..371445b 100644 --- a/source/target.h +++ b/source/target.h @@ -5,20 +5,9 @@ #include #include +class Action; class Builder; class Package; -class Target; - -class TargetRef -{ -public: - TargetRef(Builder &b, const std::string &n): builder(b), name(n) { } - Target *get_target(); -private: - Builder &builder; - std::string name; - Target *target; -}; class Target { @@ -27,9 +16,14 @@ public: Target *get_buildable_target(); bool get_rebuild() const { return rebuild; } const std::string &get_rebuild_reason() const { return rebuild_reason; } - virtual void find_depends()=0; - void add_depend(Target *); + const Msp::Time::TimeStamp &get_mtime() const { return mtime; } + const Msp::Time::TimeStamp &get_virtual_mtime() const { return vmtime; } 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; virtual ~Target() { } protected: Builder &builder; @@ -39,12 +33,17 @@ protected: bool rebuild; std::string rebuild_reason; Msp::Time::TimeStamp mtime; + Msp::Time::TimeStamp vmtime; std::list depends; std::list rdepends; - bool ready_for_build; + bool prepared; + bool buildable; Target(Builder &, const Package *, const std::string &); void mark_rebuild(const std::string &); + virtual void check_rebuild(); + Action *build(Action *); + virtual void build_done(); }; #endif diff --git a/source/virtualtarget.cpp b/source/virtualtarget.cpp new file mode 100644 index 0000000..5c1e4c7 --- /dev/null +++ b/source/virtualtarget.cpp @@ -0,0 +1,10 @@ +#include "virtualtarget.h" + +using namespace std; + +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"); +} diff --git a/source/virtualtarget.h b/source/virtualtarget.h index e388061..83ac8f9 100644 --- a/source/virtualtarget.h +++ b/source/virtualtarget.h @@ -9,6 +9,9 @@ public: VirtualTarget(Builder &b, const std::string &n): Target(b,0,n) { } const char *get_type() const { return "VirtualTarget"; } void find_depends() { } + Action *build() { rebuild=false; return 0; } +private: + void check_rebuild(); }; #endif