version "0.1";
description "Mikkosoft Productions software builder";
- require "mspframework";
+ require "mspcore";
require "mspparser";
require "msppath";
require "mspregex++";
+ require "sigc++-2.0";
program "builder"
{
--- /dev/null
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+#include "action.h"
+
+using namespace std;
+
+void Action::announce(const string &pkg, const string &tool, const string &tgt)
+{
+ ostringstream line;
+ line<<left;
+ line<<'['<<setw(10)<<pkg<<"] ";
+ line<<'['<<setw(4)<<tool<<"] ";
+ line<<tgt;
+ cout<<line.str()<<'\n';
+}
--- /dev/null
+#ifndef ACTION_H_
+#define ACTION_H_
+
+#include <string>
+#include <sigc++/sigc++.h>
+
+class Builder;
+
+class Action
+{
+public:
+ sigc::signal<void> 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
#include <msp/strutils.h>
#include <msp/parser/parser.h>
#include <msp/path/utils.h>
+#include <msp/time/units.h>
+#include "action.h"
#include "builder.h"
#include "executable.h"
#include "header.h"
cwd(Path::getcwd())
{
for(int i=1; i<argc; ++i)
- cmdline_targets.push_back(argv[i]);
+ {
+ string v(argv[i]);
+ unsigned equal=v.find('=');
+ if(equal!=string::npos)
+ cmdline_options.insert(RawOptionMap::value_type(v.substr(0, equal), v.substr(equal+1)));
+ else
+ cmdline_targets.push_back(argv[i]);
+ }
+
if(cmdline_targets.empty())
cmdline_targets.push_back("default");
}
argv.push_back("pkg-config");
argv.push_back("--variable=source");
argv.push_back(n);
- Path::Path srcdir=run_command(argv);
- if(srcdir.empty())
- {
- string dirname=n;
- if(dirname.compare(0, 3, "msp"))
- dirname.erase(0, 3);
- if(Path::exists(cwd/dirname))
- srcdir=cwd/dirname;
- else if(Path::exists(cwd/".."/dirname))
- srcdir=cwd/".."/dirname;
- }
- else
- srcdir=strip(srcdir.str());
+ string srcdir=strip(run_command(argv));
+ cout<<srcdir;
+ list<Path::Path> 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<Path::Path>::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)
pkg->resolve_refs();
}
+ std::list<std::string> missing;
+ for(PackageMap::iterator i=packages.begin(); i!=packages.end(); ++i)
+ {
+ const list<PackageRef> &requires=i->second->get_requires();
+ for(list<PackageRef>::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<string>::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)
{
}
cout<<'\n';
- create_targets();
+ if(create_targets())
+ return 1;
for(TargetMap::iterator i=targets.begin(); i!=targets.end(); ++i)
- cout<<i->second->get_name()<<' '<<i->second->get_type()<<'\n';
+ cout<<i->second->get_name()<<' '<<i->second->get_type()<<' '<<i->second->get_rebuild()<<' '<<i->second->get_rebuild_reason()<<'\n';
cout<<"Active targets: "<<targets.size()<<'\n';
- return 0;
+ build();
+
+ return exit_code;
}
int Builder::load_build_file(const Path::Path &fn)
return 0;
}
-void Builder::create_targets()
+int Builder::create_targets()
{
Target *world=new VirtualTarget(*this, "world");
add_target(world);
+
Target *def_tgt=new VirtualTarget(*this, "default");
add_target(def_tgt);
+ world->add_depend(def_tgt);
for(PackageMap::iterator i=packages.begin(); i!=packages.end(); ++i)
{
- cout<<i->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<<base<<'\n';
list<string> files=list_files(base);
list<ObjectFile *> objs;
for(list<string>::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")
{
add_target(exe);
if(i->second==default_pkg)
def_tgt->add_depend(exe);
+ else
+ world->add_depend(exe);
}
}
new_tgts.erase(new_tgts.begin());
tgt->find_depends();
}
+
+ Target *cmdline=new VirtualTarget(*this, "cmdline");
+ add_target(cmdline);
+ world->add_depend(cmdline);
+ for(list<string>::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)
new_tgts.push_back(t);
}
+int Builder::build()
+{
+ Target *cmdline=get_target("cmdline");
+ list<Action *> actions;
+ bool fail=false;
+
+ while(cmdline->get_rebuild() && !fail)
+ {
+ if(actions.empty() && !fail)
+ {
+ Target *tgt=cmdline->get_buildable_target();
+ if(tgt)
+ {
+ cout<<"Build "<<tgt->get_name()<<'\n';
+ Action *action=tgt->build();
+ if(action)
+ actions.push_back(action);
+ }
+ }
+ else
+ sleep(10*Time::msec);
+
+ for(list<Action *>::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> Builder::reg;
Builder::Loader::Loader(Builder &b, const Path::Path &s):
#include <list>
#include <map>
#include <string>
-#include <msp/framework/application.h>
+#include <msp/core/application.h>
#include <msp/parser/loader.h>
#include <msp/path/path.h>
+#include "config.h"
class Package;
class Target;
void package(const std::string &);
};
- typedef std::map<std::string, Package *> PackageMap;
- typedef std::map<std::string, Target *> TargetMap;
+ typedef std::map<std::string, Package *> PackageMap;
+ typedef std::map<std::string, Target *> TargetMap;
+ typedef std::map<std::string, std::string> ToolMap;
std::list<std::string> cmdline_targets;
+ RawOptionMap cmdline_options;
TargetMap targets;
PackageMap packages;
unsigned verbose;
std::list<Package *> new_pkgs;
TargetMap includes;
std::list<Target *> 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<Builder> reg;
};
--- /dev/null
+#include <msp/algo.h>
+#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);
+}
void add(const BuildInfo &);
void unique();
+private:
+ void unique(InfoList &);
};
#endif
--- /dev/null
+#include <msp/path/utils.h>
+#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<string>::const_iterator i=binfo.cflags.begin(); i!=binfo.cflags.end(); ++i)
+ argv.push_back(*i);
+ for(list<string>::const_iterator i=binfo.incpath.begin(); i!=binfo.incpath.end(); ++i)
+ argv.push_back("-I"+*i);
+ for(list<string>::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();
+}
--- /dev/null
+#ifndef COMPILE_H_
+#define COMPILE_H_
+
+#include <msp/path/path.h>
+#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
name(n)
{ }
+void Component::create_build_info()
+{
+ build_info=pkg.get_build_info();
+ build_info.unique();
+}
+
Component::Loader::Loader(Component &c):
comp(c)
{
{
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;
--- /dev/null
+#include <msp/error.h>
+#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)
+{ }
--- /dev/null
+#ifndef CONFIG_H_
+#define CONFIG_H_
+
+#include <map>
+#include <string>
+#include "option.h"
+
+typedef std::map<std::string, std::string> 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<std::string, Option> 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
#include "component.h"
#include "executable.h"
+#include "link.h"
#include "objectfile.h"
#include "package.h"
Target(b, &c.get_package(), generate_target_name(c)),
comp(c)
{
+ buildable=true;
for(list<ObjectFile *>::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;
Executable(Builder &, const Component &, const std::list<ObjectFile *> &);
const char *get_type() const { return "Executable"; }
void find_depends() { }
+ Action *build();
private:
const Component ∁
--- /dev/null
+#include <sys/wait.h>
+#include <msp/iter.h>
+#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<string>::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<string, list<string>::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;
+}
--- /dev/null
+#ifndef EXTERNALACTION_H_
+#define EXTERNALACTION_H_
+
+#include <list>
+#include <string>
+#include "action.h"
+
+class ExternalAction: public Action
+{
+public:
+ int check();
+protected:
+ std::list<std::string> argv;
+ int pid;
+
+ ExternalAction(Builder &b): Action(b) { }
+ void launch();
+};
+
+#endif
--- /dev/null
+#ifndef INSTALL_H_
+#define INSTALL_H_
+
+#include <msp/core/thread.h>
+#include <msp/path/path.h>
+#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
--- /dev/null
+#include <msp/path/utils.h>
+#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<string>::const_iterator i=binfo.ldflags.begin(); i!=binfo.ldflags.end(); ++i)
+ argv.push_back(*i);
+ for(list<string>::const_iterator i=binfo.libpath.begin(); i!=binfo.libpath.end(); ++i)
+ argv.push_back("-L"+*i);
+ for(list<string>::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<Target *> &deps=exe.get_depends();
+ for(list<Target *>::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();
+}
--- /dev/null
+#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
#include <msp/path/utils.h>
#include "builder.h"
+#include "compile.h"
#include "component.h"
#include "objectfile.h"
#include "package.h"
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();
ObjectFile(Builder &, const Component &, SourceFile &);
const char *get_type() const { return "ObjectFile"; }
void find_depends() { }
+ Action *build();
private:
const Component ∁
--- /dev/null
+#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)
+{ }
--- /dev/null
+#ifndef OPTION_H_
+#define OPTION_H_
+
+#include <string>
+
+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
+#include <msp/strutils.h>
#include "builder.h"
+#include "misc.h"
#include "package.h"
using namespace std;
package(0)
{ }
-Package *PackageRef::get_package()
+Package *PackageRef::resolve()
{
if(!package)
package=builder.get_package(name);
builder(b),
name(n),
source(s),
- buildable(false)
+ buildable(true),
+ build_info_ready(false)
+{ }
+
+Package::Package(Builder &b, const string &n, const vector<string> &info):
+ builder(b),
+ name(n),
+ buildable(false),
+ build_info_ready(true)
{
+ for(vector<string>::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<PackageRef>::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<PackageRef>::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<Component>::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<string> argv;
+ argv.push_back("pkg-config");
+ argv.push_back("--cflags");
+ argv.push_back("--libs");
+ argv.push_back(name);
+ vector<string> 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):
Package::Loader::~Loader()
{
- pkg.buildable=true;
+ pkg.init_buildable();
}
void Package::Loader::require(const string &n)
#include <msp/parser/loader.h>
#include "buildinfo.h"
#include "component.h"
+#include "config.h"
class Builder;
class Package;
{
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;
};
Package(Builder &, const std::string &, const Msp::Path::Path &);
- Package(Builder &, const std::string &, const std::list<std::string> &);
- 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<std::string> &);
+ 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<PackageRef> &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;
Msp::Path::Path source;
bool buildable;
ComponentList components;
+ Config config;
+ bool build_info_ready;
+
+ void init_buildable();
+ unsigned get_install_flags();
};
#endif
add_depend(hdr);
}
}
+
+void SourceFile::check_rebuild()
+{
+ for(list<Target *>::iterator i=depends.begin(); i!=depends.end(); ++i)
+ vmtime=max(vmtime, (*i)->get_virtual_mtime());
+}
{
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<std::string> includes;
+
+ void check_rebuild();
};
#endif
+#include <msp/path/utils.h>
+#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<Target *>::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;
}
dep->rdepends.push_back(this);
}
+void Target::prepare()
+{
+ if(prepared)
+ return;
+
+ for(list<Target *>::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<Target *>::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;
+}
#include <string>
#include <msp/time/timestamp.h>
+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
{
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<Target *> &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;
bool rebuild;
std::string rebuild_reason;
Msp::Time::TimeStamp mtime;
+ Msp::Time::TimeStamp vmtime;
std::list<Target *> depends;
std::list<Target *> 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
--- /dev/null
+#include "virtualtarget.h"
+
+using namespace std;
+
+void VirtualTarget::check_rebuild()
+{
+ for(list<Target *>::iterator i=depends.begin(); (i!=depends.end() && !rebuild); ++i)
+ if((*i)->get_rebuild())
+ mark_rebuild((*i)->get_name()+" needs rebuilding");
+}
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