description "Mikkosoft Productions software builder";
require "mspcore";
+ require "mspstrings";
require "mspparser";
require "msppath";
- require "mspregex++";
- require "mspgetopt++";
require "sigc++-2.0";
program "builder"
#!/bin/sh
-REQUIRED="misc core parser path regex++ getopt++"
+REQUIRED="core parser path strings"
CFLAGS="-Iinclude `pkg-config --cflags sigc++-2.0`"
LIBS="`pkg-config --libs sigc++-2.0` -lpthread"
if [ -z "$LIBPATH" ]; then
#include <fstream>
#include <iostream>
-#include <msp/progress.h>
+#include <set>
#include <msp/core/error.h>
#include <msp/getopt++/getopt++.h>
#include <msp/parser/parser.h>
#include "sharedlibrary.h"
#include "staticlibrary.h"
#include "systemlibrary.h"
+#include "unlink.h"
#include "virtualtarget.h"
using namespace std;
Builder::Builder(int argc, char **argv):
analyzer(0),
- do_build(false),
+ build(false),
+ clean(0),
dry_run(false),
help(false),
verbose(1),
jobs(1),
conf_all(false),
conf_only(false),
- build_all(false)
+ build_all(false),
+ create_makefile(false)
{
string analyze_mode;
string work_dir;
bool full_paths=false;
unsigned max_depth=5;
-
+
GetOpt getopt;
getopt.add_option('a', "analyze", analyze_mode, GetOpt::REQUIRED_ARG);
- getopt.add_option('b', "build", do_build, GetOpt::NO_ARG);
-// getopt.add_option('c', "clean", clean, GetOpt::NO_ARG);
+ getopt.add_option('b', "build", build, GetOpt::NO_ARG);
+ getopt.add_option('c', "clean", clean, GetOpt::NO_ARG);
getopt.add_option('f', "file", build_file, GetOpt::REQUIRED_ARG);
getopt.add_option('h', "help", help, GetOpt::NO_ARG);
getopt.add_option('j', "jobs", jobs, GetOpt::REQUIRED_ARG);
getopt.add_option( "chrome", chrome, GetOpt::NO_ARG);
getopt.add_option( "conf-only", conf_only, GetOpt::NO_ARG);
getopt.add_option( "full-paths", full_paths, GetOpt::NO_ARG);
+ //getopt.add_option( "makefile", create_makefile, GetOpt::NO_ARG);
getopt.add_option( "max-depth", max_depth, GetOpt::REQUIRED_ARG);
getopt(argc, argv);
analyzer->set_max_depth(max_depth);
analyzer->set_full_paths(full_paths);
}
- else
- do_build=true;
+ else if(!clean && !create_makefile)
+ build=true;
const list<string> &args=getopt.get_args();
for(list<string>::const_iterator i=args.begin(); i!=args.end(); ++i)
cwd=Path::getcwd();
archs.insert(StringMap::value_type("native", ""));
- archs.insert(StringMap::value_type("arm", "arm-linux-gnu-"));
- archs.insert(StringMap::value_type("win32", "i586-mingw32msvc-"));
+ archs.insert(StringMap::value_type("arm", "arm-linux-gnu"));
+ archs.insert(StringMap::value_type("win32", "i586-mingw32msvc"));
StringMap &native_tools=tools.insert(ToolMap::value_type("native", StringMap())).first->second;
native_tools.insert(StringMap::value_type("CC", "gcc"));
{
if(i->first=="native")
continue;
-
+
StringMap &arch_profile=profile_tmpl.insert(ProfileTemplateMap::value_type(i->first, StringMap())).first->second;
arch_profile.insert(StringMap::value_type("arch", i->first));
arch_profile.insert(StringMap::value_type("prefix", "$HOME/local/$arch"));
+ arch_profile.insert(StringMap::value_type("outdir", "$profile"));
}
}
argv.push_back("--variable=source");
argv.push_back(n);
string srcdir=strip(run_command(argv));
-
+
PathList dirs;
if(!srcdir.empty())
dirs.push_back(srcdir);
is not found but a file exists, a new SystemHeader target will be created and
returned.
*/
-Target *Builder::get_header(const string &include, const string &from, const list<string> &path)
+Target *Builder::get_header(const string &include, const string &, const string &from, const list<string> &path)
{
string hash(8, 0);
update_hash(hash, from);
}
includes.insert(TargetMap::value_type(id, tgt));
-
+
return tgt;
}
@return Some kind of library target, if a match was found
*/
-Target *Builder::get_library(const string &lib, const list<string> &path, LibMode mode)
+Target *Builder::get_library(const string &lib, const string &arch, const list<string> &path, LibMode mode)
{
string hash(8, 0);
for(list<string>::const_iterator i=path.begin(); i!=path.end(); ++i)
if(i!=libraries.end())
return i->second;
- Target *tgt=0;
- if((tgt=get_library(lib, "/lib", mode)))
- ;
- else if((tgt=get_library(lib, "/usr/lib", mode)))
- ;
- else
+ StringList syspath;
+ if(arch=="native")
{
- for(list<string>::const_iterator j=path.begin(); (j!=path.end() && !tgt); ++j)
- tgt=get_library(lib, cwd/ *j, mode);
+ syspath.push_back("/lib");
+ syspath.push_back("/usr/lib");
}
+ else
+ syspath.push_back("/usr/"+get_arch_prefix(arch)+"/lib");
+
+ Target *tgt=0;
+ for(StringList::iterator j=syspath.begin(); (!tgt && j!=syspath.end()); ++j)
+ tgt=get_library(lib, arch, *j, mode);
+ for(StringList::const_iterator j=path.begin(); (!tgt && j!=path.end()); ++j)
+ tgt=get_library(lib, arch, cwd/ *j, mode);
libraries.insert(TargetMap::value_type(id, tgt));
if(j==i->second.end())
throw InvalidParameterValue("Unknown tool");
- return get_arch_prefix(arch)+j->second;
+ return get_arch_prefix(arch)+"-"+j->second;
}
void Builder::apply_profile_template(Config &config, const string &pt) const
if(analyzer)
analyzer->analyze();
- if(do_build)
- build();
+ //if(create_makefile
+
+ if(clean)
+ exit_code=do_clean();
+ else if(build)
+ exit_code=do_build();
return exit_code;
}
{
if(reason)
cerr<<reason<<'\n';
-
+
if(brief)
cerr<<"Usage: "<<argv0<<" [-a|--analyze MODE] [-b|--build] [-c|--clean] [-f|--file FILE] [-h|--help] [-j|--jobs NUM] [-n||--dry-run] [-v|--verbose] [-A|--conf-all] [-B|--build-all] [-C|--chdir DIRECTORY] [-W|--what-if FILE] [--chrome] [--conf-only] [--full-paths] [--max-depth NUM] [<target> ...]";
else
" --chrome Use extra chrome to print status.\n"
" --conf-only Stop after configuring packages.\n"
" --full-paths Output full paths in analysis.\n"
+ //" --makefile Create a makefile for this package.\n"
" --max-depth NUM Maximum depth to show in analysis.\n";
}
}
}
bool build_exe=j->get_type()!=Component::HEADERS;
-
+
list<ObjectFile *> objs;
for(PathList::iterator k=files.begin(); k!=files.end(); ++k)
{
}
else
exe=new Executable(*this, *j, objs);
-
+
add_target(exe);
if(i->second==default_pkg)
{
return 0;
}
-Target *Builder::get_library(const string &lib, const Path::Path &path, LibMode mode)
+Target *Builder::get_library(const string &lib, const string &arch, const Path::Path &path, LibMode mode)
{
- string full;
- if(mode!=DYNAMIC)
- {
- full=(path/("lib"+lib+".a")).str();
- Target *tgt=get_target(full);
- // Targets can only be associated with buildable packages (or no package at all)
- if(tgt && (tgt->get_package() || mode==ALL_STATIC)) return tgt;
- }
+ // Populate a list of candidate filenames
+ StringList candidates;
+
if(mode!=ALL_STATIC)
{
- full=(path/("lib"+lib+".so")).str();
- Target *tgt=get_target(full);
- if(tgt) return tgt;
+ if(arch=="win32")
+ candidates.push_back("lib"+lib+".dll");
+ else
+ candidates.push_back("lib"+lib+".so");
}
- if(Path::exists(full))
+ /* Static libraries are always considered, since sometimes shared versions
+ may not be available */
+ candidates.push_back("lib"+lib+".a");
+ if(arch=="win32")
+ candidates.push_back("lib"+lib+".dll.a");
+
+ for(StringList::iterator i=candidates.begin(); i!=candidates.end(); ++i)
{
- Target *tgt=new SystemLibrary(*this, full);
- add_target(tgt);
- return tgt;
+ string full=(path/ *i).str();
+ Target *tgt=get_target(full);
+
+ if(tgt)
+ {
+ Target *real_tgt=tgt;
+ if(dynamic_cast<Install *>(tgt))
+ real_tgt=real_tgt->get_depends().front();
+
+ /* Ignore dynamic libraries from local packages unless library mode is
+ DYNAMIC */
+ if(dynamic_cast<SharedLibrary *>(real_tgt) && mode!=DYNAMIC)
+ continue;
+ else if(tgt)
+ return tgt;
+ }
+ else if(Path::exists(full))
+ {
+ tgt=new SystemLibrary(*this, full);
+ add_target(tgt);
+ return tgt;
+ }
}
return 0;
This function supervises the build process, starting new actions when slots
become available.
*/
-int Builder::build()
+int Builder::do_build()
{
Target *cmdline=get_target("cmdline");
if(fail)
cout<<"Build failed\n";
- return fail?-1:0;
+ return fail?1:0;
+}
+
+/**
+Cleans buildable targets. If clean is 1, cleans only this package. If
+clean is 2 or greater, cleans all buildable packages.
+*/
+int Builder::do_clean()
+{
+ // Cleaning doesn't care about ordering, so a simpler method can be used
+
+ set<Target *> clean_tgts;
+ TargetList queue;
+ queue.push_back(get_target("cmdline"));
+
+ while(!queue.empty())
+ {
+ Target *tgt=queue.front();
+ queue.erase(queue.begin());
+
+ if(tgt->get_buildable() && (tgt->get_package()==default_pkg || clean>=2))
+ clean_tgts.insert(tgt);
+
+ const TargetList &deps=tgt->get_depends();
+ for(TargetList::const_iterator i=deps.begin(); i!=deps.end(); ++i)
+ if(!clean_tgts.count(*i))
+ queue.push_back(*i);
+ }
+
+ for(set<Target *>::iterator i=clean_tgts.begin(); i!=clean_tgts.end(); ++i)
+ {
+ Action *action=new Unlink(*this, **i);
+ while(action->check()<0);
+ delete action;
+ }
+
+ return 0;
}
/**
bool get_build_all() const { return build_all; }
Package *get_package(const std::string &);
Target *get_target(const std::string &);
- Target *get_header(const std::string &, const std::string &, const StringList &);
- Target *get_library(const std::string &, const StringList &, LibMode);
+ Target *get_header(const std::string &, const std::string &, const std::string &, const StringList &);
+ Target *get_library(const std::string &, const std::string &, const StringList &, LibMode);
const Msp::Path::Path &get_cwd() const { return cwd; }
const std::string &get_arch_prefix(const std::string &) const;
std::string get_tool(const std::string &, const std::string &);
private:
Builder &bld;
Msp::Path::Path src;
-
+
void package(const std::string &);
};
typedef std::map<std::string, Target *> TargetMap;
typedef std::map<std::string, StringMap> ToolMap;
typedef std::map<std::string, StringMap> ProfileTemplateMap;
-
+
StringList cmdline_targets;
StringMap cmdline_options;
Msp::Path::Path cwd;
-
+
PackageMap packages;
PackageList new_pkgs;
Package *default_pkg;
ToolMap tools; //< arch, tool name -> program name
StringMap archs; //< arch -> prefix
ProfileTemplateMap profile_tmpl;
-
+
Analyzer *analyzer;
- bool do_build;
+ bool build;
+ unsigned clean;
bool dry_run;
bool help;
unsigned verbose;
bool conf_all;
bool conf_only;
bool build_all;
+ bool create_makefile;
int load_build_file(const Msp::Path::Path &);
int create_targets();
Target *get_header(const Msp::Path::Path &);
- Target *get_library(const std::string &, const Msp::Path::Path &, LibMode);
+ Target *get_library(const std::string &, const std::string &, const Msp::Path::Path &, LibMode);
void add_target(Target *);
void update_hash(std::string &, const std::string &);
- int build();
+ int do_build();
+ int do_clean();
+ int do_create_makefile();
void package_help();
-
+
static Msp::Application::RegApp<Builder> reg;
};
-#include <msp/algo.h>
#include "buildinfo.h"
using namespace Msp;
{
StringList l2;
for(StringList::iterator i=l.begin(); i!=l.end(); ++i)
- if(!contains(l2, *i))
+ if(find(l2.begin(), l2.end(), *i)==l2.end())
l2.push_back(*i);
swap(l, l2);
}
-#include <msp/error.h>
+#include <msp/core/error.h>
#include "component.h"
#include "package.h"
using namespace std;
-#include <iostream>
-
Component::Component(Package &p, Type t, const string &n):
pkg(p),
type(t),
--- /dev/null
+#include <msp/strings/utils.h>
+#include "condition.h"
+#include "package.h"
+
+using namespace std;
+using namespace Msp;
+
+#include <iostream>
+
+Condition::Condition(Package &p, const string &expr):
+ pkg(p)
+{
+ vector<string> parts=split(expr);
+
+ for(vector<string>::iterator i=parts.begin(); i!=parts.end(); ++i)
+ {
+ if(*i=="and")
+ continue;
+
+ unsigned token=i->find_first_of("=!");
+ if(token==string::npos)
+ expression.insert(StringMap::value_type(*i, "!0"));
+ else if(token==0 && (*i)[0]=='!')
+ expression.insert(StringMap::value_type(*i, "=0"));
+ else
+ expression.insert(StringMap::value_type(i->substr(0, token), i->substr(token)));
+ }
+}
+
+void Condition::resolve_refs()
+{
+ for(PkgRefList::iterator i=requires.begin(); i!=requires.end(); ++i)
+ i->resolve();
+}
+
+bool Condition::eval()
+{
+ const Config &conf=pkg.get_config();
+
+ bool result=true;
+ for(StringMap::iterator i=expression.begin(); i!=expression.end(); ++i)
+ {
+ bool neg=(i->second[0]=='!');
+ unsigned start=1;
+ if(i->second[1]=='=')
+ ++start;
+
+ if((conf.get_option(i->first).value==i->second.substr(start))==neg)
+ result=false;
+ }
+
+ return result;
+}
+
+
+Condition::Loader::Loader(Condition &c):
+ cond(c)
+{
+ add("require", &Loader::require);
+ add("build_info", &Loader::build_info);
+}
+
+void Condition::Loader::require(const string &pkg)
+{
+ cond.requires.push_back(PackageRef(cond.pkg.get_builder(), pkg));
+}
+
+void Condition::Loader::build_info()
+{
+ load_sub(cond.build_info);
+}
--- /dev/null
+#ifndef CONDITION_H_
+#define CONDITION_H_
+
+#include <msp/parser/loader.h>
+#include "buildinfo.h"
+#include "misc.h"
+#include "packageref.h"
+
+class Config;
+
+class Condition
+{
+public:
+ class Loader: public Msp::Parser::Loader
+ {
+ public:
+ Loader(Condition &);
+ private:
+ Condition &cond;
+
+ void require(const std::string &);
+ void build_info();
+ };
+
+ Condition(Package &, const std::string &);
+ const PkgRefList &get_requires() const { return requires; }
+ const BuildInfo &get_build_info() const { return build_info; }
+ void resolve_refs();
+ bool eval();
+private:
+ Package &pkg;
+ StringMap expression;
+ PkgRefList requires;
+ BuildInfo build_info;
+};
+typedef std::list<Condition> ConditionList;
+
+#endif
#include <fstream>
-#include <msp/error.h>
+#include <msp/core/error.h>
#include <msp/path/utils.h>
#include <msp/time/utils.h>
#include "builder.h"
ofstream out(fn.str().c_str());
if(!out) return;
-
+
for(i=options.begin(); i!=options.end(); ++i)
out<<"option \""<<i->second.name<<"\" \""<<i->second.value<<"\";\n";
}
#include <iostream>
-#include <msp/algo.h>
#include "builder.h"
#include "component.h"
#include "executable.h"
void Executable::find_depends()
{
LibMode libmode=package->get_library_mode();
-
+
list<const Component *> queue;
list<Target *> dep_libs;
queue.push_back(&comp);
{
const Component *c=queue.front();
queue.erase(queue.begin());
-
+
+ const StringList &libpath=c->get_build_info().libpath;
+ const string &arch=c->get_package().get_arch();
+
const list<string> &libs=c->get_build_info().libs;
for(StringList::const_iterator i=libs.begin(); i!=libs.end(); ++i)
{
- Target *lib=builder.get_library(*i, c->get_build_info().libpath, libmode);
+ Target *lib=builder.get_library(*i, arch, libpath, libmode);
if(lib)
{
- if(contains(depends, lib))
- continue;
-
- dep_libs.push_front(lib);
+ dep_libs.push_back(lib);
if(dynamic_cast<Install *>(lib))
lib=lib->get_depends().front();
}
}
+ /* Add only the last occurrence of each library to the actual dependencies.
+ This ensures that static library ordering is correct. */
for(list<Target *>::iterator i=dep_libs.begin(); i!=dep_libs.end(); ++i)
- add_depend(*i);
+ {
+ bool last=true;
+ for(list<Target *>::iterator j=i; (last && j!=dep_libs.end()); ++j)
+ last=(j==i || *j!=*i);
+ if(last)
+ add_depend(*i);
+ }
deps_ready=true;
}
#include <sys/wait.h>
#include <iostream>
-#include <msp/iter.h>
#include "builder.h"
#include "externalaction.h"
signal_done.emit();
return 0;
}
-
+
if(!pid)
return exit_code;
}
cout<<'\n';
}
-
+
if(builder.get_dry_run())
pid=-1;
else
if(pid==0)
{
char *argv_[argv.size()+1];
- for(CountingIterator<string, StringList::iterator> i=argv.begin(); i!=argv.end(); ++i)
- argv_[i.count()]=strdup(i->c_str());
- argv_[argv.size()]=0;
+
+ unsigned j=0;
+ for(StringList::iterator i=argv.begin(); i!=argv.end(); ++i)
+ argv_[j++]=strdup(i->c_str());
+ argv_[j]=0;
+
execvp(argv_[0], argv_);
cout<<"Couldn't execute "<<argv.front()<<'\n';
exit(1);
--- /dev/null
+#ifndef FEATURE_H_
+#define FEATURE_H_
+
+struct Feature
+{
+ std::string name;
+ std::string descr;
+
+ Feature(const std::string &n, const std::string &d): name(n), descr(d) { }
+};
+typedef std::list<Feature> FeatureList;
+
+#endif
#include <iostream>
#include <sys/wait.h>
-#include <msp/iter.h>
#include "misc.h"
using namespace std;
if(pid==0)
{
char *argv_[argv.size()+1];
- for(CountingIterator<const string, StringList::const_iterator> i=argv.begin(); i!=argv.end(); ++i)
- argv_[i.count()]=strdup(i->c_str());
- argv_[argv.size()]=0;
+
+ unsigned j=0;
+ for(StringList::const_iterator i=argv.begin(); i!=argv.end(); ++i)
+ argv_[j++]=strdup(i->c_str());
+ argv_[j]=0;
+
close(pfd[0]);
dup2(pfd[1], 1);
dup2(pfd[1], 2);
+
execvp(argv_[0], argv_);
::exit(1);
}
result.append(buf, len);
}
}
-
+
return result;
}
-#include <msp/algo.h>
#include <msp/path/utils.h>
#include "builder.h"
#include "compile.h"
if(!src)
return;
+ const string &arch=comp.get_package().get_arch();
+ const StringList &incpath=comp.get_build_info().incpath;
+
const list<string> &includes=src->get_includes();
for(list<string>::const_iterator i=includes.begin(); i!=includes.end(); ++i)
{
- Target *hdr2=builder.get_header(*i, path, comp.get_build_info().incpath);
- if(hdr2 && !contains(depends, hdr2))
+ Target *hdr2=builder.get_header(*i, arch, path, incpath);
+ if(hdr2 && find(depends.begin(), depends.end(), hdr2)==depends.end())
add_depend(hdr2);
}
}
conf_done(false),
use_pkgconfig(true),
need_path(false)
-{ }
+{
+ if(builder.get_verbose()>=4)
+ cout<<"Created buildable package "<<n<<" at "<<s<<'\n';
+}
/**
Sets the path where the package files were installed. This is only useful for
Package *pkg=i->resolve();
if(pkg) all_reqs.push_back(pkg);
}
+
for(ComponentList::iterator i=components.begin(); i!=components.end(); ++i)
{
i->resolve_refs();
if(j->get_package())
all_reqs.push_back(j->get_package());
}
+
+ for(ConditionList::iterator i=conditions.begin(); i!=conditions.end(); ++i)
+ {
+ i->resolve_refs();
+ const PkgRefList &creqs=i->get_requires();
+ for(PkgRefList::const_iterator j=creqs.begin(); j!=creqs.end(); ++j)
+ if(j->get_package())
+ all_reqs.push_back(j->get_package());
+ }
}
/**
config.select_profile(prof->second);
else
config.select_last_profile();
-
+
if(flag && config.update(opts))
{
if(builder.get_verbose()>=2)
config.finish();
+ for(ConditionList::iterator i=conditions.begin(); i!=conditions.end(); ++i)
+ if(i->eval())
+ {
+ const PkgRefList &reqs=i->get_requires();
+ requires.insert(requires.end(), reqs.begin(), reqs.end());
+ build_info.add(i->get_build_info());
+ }
+
for(PackageList::iterator i=all_reqs.begin(); i!=all_reqs.end(); ++i)
{
if((*i)->get_need_path())
argv.push_back("--libs");
argv.push_back(name);
vector<string> info=split(run_command(argv));
-
+
bool need_path=false;
bool use_pkgconfig=true;
if(info.empty())
{
use_pkgconfig=false;
-
+
//XXX Put these in an external file
if(name=="opengl")
info.push_back("-lGL");
need_path=true;
else if(name=="devil")
info.push_back("-lIL");
+ else if(name=="Xlib")
+ info.push_back("-lX11");
else
return 0;
}
-
+
Package *pkg=new Package(b, name, info);
pkg->need_path=need_path;
pkg->use_pkgconfig=use_pkgconfig;
else if(!i->compare(0, 2, "-l"))
export_binfo.libs.push_back(i->substr(2));
}
+
+ if(builder.get_verbose()>=4)
+ {
+ cout<<"Created non-buildable package "<<name<<" with";
+ for(vector<string>::const_iterator i=info.begin(); i!=info.end(); ++i)
+ cout<<' '<<*i;
+ cout<<'\n';
+ }
}
/**
if(flags&DATA)
config.add_option("includedir", "$prefix/share", "Data installation directory");*/
- for(PkgRefList::iterator i=requires.begin(); i!=requires.end(); ++i)
- if(i->get_package() && i->get_package()->get_need_path())
- config.add_option(i->get_name()+"_path", "", "Path for "+i->get_name());
+ for(FeatureList::iterator i=features.begin(); i!=features.end(); ++i)
+ config.add_option("with_"+i->name, "0", i->descr);
+
+ for(PackageList::const_iterator i=all_reqs.begin(); i!=all_reqs.end(); ++i)
+ if((*i)->get_need_path())
+ config.add_option((*i)->get_name()+"_path", "", "Path for "+(*i)->get_name());
}
/**
Package *pkg=i->get_package();
if(!pkg)
continue;
- build_info.add(pkg->get_exported_binfo());
- //XXX We probably really only want to pass cflags and defines through
- export_binfo.add(pkg->get_exported_binfo());
+ const BuildInfo &ebi=pkg->get_exported_binfo();
+ build_info.add(ebi);
+
+ export_binfo.cflags.insert(export_binfo.cflags.end(), ebi.cflags.begin(), ebi.cflags.end());
+ export_binfo.incpath.insert(export_binfo.incpath.end(), ebi.incpath.begin(), ebi.incpath.end());
+ export_binfo.defines.insert(export_binfo.defines.end(), ebi.defines.begin(), ebi.defines.end());
}
-
+
build_info.cflags.push_back("-Wall");
build_info.cflags.push_back("-Wshadow");
build_info.cflags.push_back("-Wextra");
build_info.defines.push_back("DEBUG");
}
+ for(FeatureList::iterator i=features.begin(); i!=features.end(); ++i)
+ if(lexical_cast<bool>(config.get_option("with_"+i->name).value))
+ build_info.cflags.push_back("-DWITH_"+toupper(i->name));
+
build_info.unique();
for(list<Component>::iterator i=components.begin(); i!=components.end(); ++i)
add("version", &Package::version);
add("description", &Package::description);
add("require", &Loader::require);
+ add("feature", &Loader::feature);
+ add("if", &Loader::condition);
add("program", &Loader::program);
add("library", &Loader::library);
add("module", &Loader::module);
pkg.requires.push_back(PackageRef(pkg.builder, n));
}
+void Package::Loader::feature(const string &n, const string &d)
+{
+ pkg.features.push_back(Feature(n, d));
+}
+
+void Package::Loader::condition(const string &c)
+{
+ Condition cond(pkg, c);
+ load_sub(cond);
+ pkg.conditions.push_back(cond);
+}
+
void Package::Loader::program(const string &n)
{
Component prog(pkg, Component::PROGRAM, n);
#include <msp/parser/loader.h>
#include "buildinfo.h"
#include "component.h"
+#include "condition.h"
#include "config.h"
+#include "feature.h"
#include "packageref.h"
class Builder;
Package &pkg;
void require(const std::string &);
+ void feature(const std::string &, const std::string &);
+ void condition(const std::string &);
void program(const std::string &);
void library(const std::string &);
void module(const std::string &);
Msp::Path::Path source;
PkgRefList requires;
PackageList all_reqs;
+ FeatureList features;
BuildInfo build_info;
BuildInfo export_binfo;
+ ConditionList conditions;
ComponentList components;
Config config;
bool conf_done;
#include <fstream>
-#include <msp/regex++/regex++.h>
+#include <msp/strings/regex.h>
#include "builder.h"
#include "component.h"
+#include "package.h"
#include "sourcefile.h"
using namespace std;
using namespace Msp;
-#include <iostream>
-
SourceFile::SourceFile(Builder &b, const Component *c, const string &n):
Target(b, c?&c->get_package():0, n),
comp(c)
string line;
while(getline(in, line))
if(RegMatch match=r_include.match(line))
- includes.push_back(match[1].str());
+ includes.push_back(match[1].str);
+
+ const StringList &incpath=comp->get_build_info().incpath;
+ const string &arch=comp->get_package().get_arch();
string path=name.substr(0, name.rfind('/'));
for(list<string>::iterator i=includes.begin(); i!=includes.end(); ++i)
{
- Target *hdr=builder.get_header(*i, path, comp->get_build_info().incpath);
+ Target *hdr=builder.get_header(*i, arch, path, incpath);
if(hdr)
add_depend(hdr);
}
public:
const std::string &get_name() const { return name; }
Target *get_buildable_target();
+ bool get_buildable() const { return buildable; }
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; }
void add_depend(Target *);
virtual void find_depends() { deps_ready=true; }
virtual void prepare();
-
+
/**
Creates and returns an Action suitable for building this target.
*/
virtual Action *build()=0;
-
+
void reset_count() { counted=false; }
virtual unsigned count_rebuild();
void touch();
--- /dev/null
+#include <msp/path/utils.h>
+#include "package.h"
+#include "target.h"
+#include "unlink.h"
+
+Unlink::Unlink(Builder &b, const Target &t):
+ Action(b)
+{
+ const Package &pkg=*t.get_package();
+
+ announce(pkg.get_name(), "RM", relative(t.get_name(), pkg.get_source()).str());
+
+ unlink(t.get_name().c_str());
+}
+
+int Unlink::check()
+{
+ signal_done.emit();
+ return 0;
+}
--- /dev/null
+#ifndef UNLINK_H_
+#define UNLINK_H_
+
+#include "action.h"
+
+class Target;
+
+class Unlink: public Action
+{
+public:
+ Unlink(Builder &, const Target &);
+ int check();
+};
+
+#endif