From: Mikko Rasa Date: Thu, 29 Mar 2007 09:46:05 +0000 (+0000) Subject: Add profile templates X-Git-Tag: 0.9~37 X-Git-Url: http://git.tdb.fi/?p=builder.git;a=commitdiff_plain;h=b6dcf65b5e1b99f6c65454358c7610f3e9c8af2b Add profile templates Use .exe and .dll suffixes on win32 Add support for variable references in config options Don't save current profile if --dry-run was specified --- diff --git a/source/builder.cpp b/source/builder.cpp index 31cdd18..723930a 100644 --- a/source/builder.cpp +++ b/source/builder.cpp @@ -89,7 +89,7 @@ Builder::Builder(int argc, char **argv): { unsigned equal=i->find('='); if(equal!=string::npos) - cmdline_options.insert(RawOptionMap::value_type(i->substr(0, equal), i->substr(equal+1))); + cmdline_options.insert(StringMap::value_type(i->substr(0, equal), i->substr(equal+1))); else cmdline_targets.push_back(*i); } @@ -112,6 +112,24 @@ Builder::Builder(int argc, char **argv): native_tools.insert(StringMap::value_type("LD", "gcc")); native_tools.insert(StringMap::value_type("LDXX", "g++")); native_tools.insert(StringMap::value_type("AR", "ar")); + + StringMap &release_profile=profile_tmpl.insert(ProfileTemplateMap::value_type("release", StringMap())).first->second; + release_profile.insert(StringMap::value_type("optimize", "3")); + release_profile.insert(StringMap::value_type("outdir", "$profile")); + + StringMap &debug_profile=profile_tmpl.insert(ProfileTemplateMap::value_type("debug", StringMap())).first->second; + debug_profile.insert(StringMap::value_type("debug", "1")); + debug_profile.insert(StringMap::value_type("outdir", "$profile")); + + for(StringMap::iterator i=archs.begin(); i!=archs.end(); ++i) + { + 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")); + } } /** @@ -280,6 +298,20 @@ string Builder::get_tool(const std::string &tool, const std::string &arch) return get_arch_prefix(arch)+j->second; } +void Builder::apply_profile_template(Config &config, const string &pt) const +{ + vector parts=split(pt, '-'); + + for(vector::iterator i=parts.begin(); i!=parts.end(); ++i) + { + ProfileTemplateMap::const_iterator j=profile_tmpl.find(*i); + if(j==profile_tmpl.end()) + continue; + + config.update(j->second); + } +} + int Builder::main() { if(load_build_file(cwd/build_file)) diff --git a/source/builder.h b/source/builder.h index 3e3388d..3854682 100644 --- a/source/builder.h +++ b/source/builder.h @@ -12,6 +12,7 @@ #include "target.h" class Analyzer; +class Config; class Package; /** @@ -31,6 +32,7 @@ public: 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 &); + void apply_profile_template(Config &, const std::string &) const; int main(); ~Builder(); @@ -51,9 +53,10 @@ private: typedef std::map PackageMap; typedef std::map TargetMap; typedef std::map ToolMap; + typedef std::map ProfileTemplateMap; StringList cmdline_targets; - RawOptionMap cmdline_options; + StringMap cmdline_options; Msp::Path::Path cwd; PackageMap packages; @@ -65,8 +68,9 @@ private: TargetMap includes; TargetMap libraries; - ToolMap tools; /// Not used yet + ToolMap tools; //< arch, tool name -> program name StringMap archs; //< arch -> prefix + ProfileTemplateMap profile_tmpl; Analyzer *analyzer; bool do_build; diff --git a/source/config.cpp b/source/config.cpp index 36a5963..afa60e8 100644 --- a/source/config.cpp +++ b/source/config.cpp @@ -2,11 +2,18 @@ #include #include #include +#include "builder.h" #include "config.h" +#include "package.h" using namespace std; using namespace Msp; +Config::Config(Package &p): + package(p), + freeze_mtime(false) +{ } + /** Adds a configuration option. @@ -46,29 +53,39 @@ default profile is assumed. */ void Config::select_last_profile() { - ifstream in((source/".profile.cache").str().c_str()); + ifstream in((package.get_source()/".profile.cache").str().c_str()); if(in) { string profile; - in>>profile; + getline(in, profile); set_option("profile", profile); } - else - set_option("profile", "default"); + + freeze_mtime=true; + package.get_builder().apply_profile_template(*this, get_option("profile").value); + freeze_mtime=false; load(); } /** -Selects the given profile. The profile cache file is updated as well. +Selects the given profile. The profile cache file is updated as well, unless +--dry-run was given. */ void Config::select_profile(const string &profile) { set_option("profile", profile); - ofstream out((source/".profile.cache").str().c_str()); - if(out) - out<first, i->second) && i->first!="profile") changed=true; } - if(changed) + if(changed && !freeze_mtime) mtime=Time::now(); return changed; } +/** +Expands any variable references in options. +*/ +void Config::finish() +{ + for(unsigned n=0; n<20; ++n) + { + bool changed=false; + for(OptionMap::iterator i=options.begin(); i!=options.end(); ++i) + { + Option &opt=i->second; + unsigned dollar=0; + while((dollar=opt.value.find('$', dollar))!=string::npos) + { + unsigned end; + string var; + if(opt.value[dollar+1]=='{') + { + end=opt.value.find('}', dollar+2); + if(end==string::npos) + throw Exception("Unterminated variable reference"); + var=opt.value.substr(dollar+2, end-dollar-2); + ++end; + } + else + { + for(end=dollar+1; (isalnum(opt.value[end]) && opt.value[end]!='_'); ++end); + var=opt.value.substr(dollar+1, end-dollar-1); + } + + string value; + if(is_option(var)) + value=get_option(var).value; + else + value=getenv(var.c_str()); + + opt.value.replace(dollar, end-dollar, value); + + dollar+=value.size(); + changed=true; + } + } + + if(!changed) + break; + } +} + void Config::save() const { - Path::Path fn=source/".options.cache"; + Path::Path fn=package.get_source()/".options.cache"; OptionMap::const_iterator i=options.find("profile"); if(i!=options.end()) - fn=source/(".options."+i->second.value+".cache"); + fn=package.get_source()/(".options."+i->second.value+".cache"); ofstream out(fn.str().c_str()); if(!out) return; @@ -129,11 +194,11 @@ bool Config::set_option(const string &opt, const string &val) void Config::load() { - Path::Path fn=source/".options.cache"; + Path::Path fn=package.get_source()/".options.cache"; OptionMap::iterator i=options.find("profile"); if(i!=options.end()) - fn=source/(".options."+i->second.value+".cache"); + fn=package.get_source()/(".options."+i->second.value+".cache"); ifstream in(fn.str().c_str()); if(!in) return; @@ -147,6 +212,7 @@ void Config::load() loader.load(parser); } + Config::Option::Option(const string &n, const string &v, const string &d): name(n), defv(v), @@ -154,6 +220,7 @@ Config::Option::Option(const string &n, const string &v, const string &d): value(v) { } + Config::Loader::Loader(Config &c): conf(c) { diff --git a/source/config.h b/source/config.h index 2767f82..e35743a 100644 --- a/source/config.h +++ b/source/config.h @@ -6,8 +6,9 @@ #include #include #include +#include "misc.h" -typedef std::map RawOptionMap; +class Package; /** Manages configuration for a package. A configuration may have an arbitary @@ -30,6 +31,7 @@ public: }; typedef std::map OptionMap; + Config(Package &); void add_option(const std::string &, const std::string &, const std::string &); const Option &get_option(const std::string &) const; const OptionMap &get_options() const { return options; } @@ -37,8 +39,8 @@ public: bool is_option(const std::string &) const; void select_last_profile(); void select_profile(const std::string &); - bool update(const RawOptionMap &); - void set_source(const Msp::Path::Path &s) { source=s; } + bool update(const StringMap &); + void finish(); void save() const; private: class Loader: public Msp::Parser::Loader @@ -50,10 +52,11 @@ private: void option(const std::string &, const std::string &); }; - - Msp::Path::Path source; + + Package &package; OptionMap options; Msp::Time::TimeStamp mtime; + bool freeze_mtime; bool set_option(const std::string &, const std::string &); void load(); diff --git a/source/executable.cpp b/source/executable.cpp index a5a944e..db8bd11 100644 --- a/source/executable.cpp +++ b/source/executable.cpp @@ -76,14 +76,23 @@ we need to pass the value to the Target c'tor. string Executable::generate_target_name(const Component &c) { string prefix,suffix; + const string &arch=c.get_package().get_arch(); if(c.get_type()==Component::LIBRARY) { prefix="lib"; - suffix=".so"; + if(arch=="win32") + suffix=".dll"; + else + suffix=".so"; } else if(c.get_type()==Component::MODULE) suffix=".m"; + else if(c.get_type()==Component::PROGRAM) + { + if(arch=="win32") + suffix=".exe"; + } return (c.get_package().get_out_dir()/(prefix+c.get_name()+suffix)).str(); } diff --git a/source/package.cpp b/source/package.cpp index 2e7932c..74dcbaa 100644 --- a/source/package.cpp +++ b/source/package.cpp @@ -17,6 +17,7 @@ Package::Package(Builder &b, const string &n, const Path::Path &s): name(n), buildable(true), source(s), + config(*this), conf_done(false), use_pkgconfig(true), need_path(false) @@ -102,7 +103,7 @@ void Package::resolve_refs() Processes configuration options that were most likely obtained from the command line. */ -void Package::configure(const RawOptionMap &opts, unsigned flag) +void Package::configure(const StringMap &opts, unsigned flag) { if(conf_done) return; @@ -114,8 +115,8 @@ void Package::configure(const RawOptionMap &opts, unsigned flag) { init_config(); - RawOptionMap::const_iterator prof=opts.find("profile"); - if(prof!=opts.end()) + StringMap::const_iterator prof=opts.find("profile"); + if(prof!=opts.end() && flag) config.select_profile(prof->second); else config.select_last_profile(); @@ -128,6 +129,8 @@ void Package::configure(const RawOptionMap &opts, unsigned flag) config.save(); } + config.finish(); + for(PackageList::iterator i=all_reqs.begin(); i!=all_reqs.end(); ++i) { if((*i)->get_need_path()) @@ -189,6 +192,7 @@ Package::Package(Builder &b, const string &n, const vector &info): builder(b), name(n), buildable(false), + config(*this), conf_done(false) { for(vector::const_iterator i=info.begin(); i!=info.end(); ++i) @@ -218,10 +222,9 @@ void Package::init_config() config.add_option("arch", "native", "Architecture for cross-compiling"); config.add_option("staticlibs", "local", "Use static libraries"); - const char *home=getenv("HOME"); unsigned flags=get_install_flags(); if(flags) - config.add_option("prefix", string(home)+"/local"/*"/usr"*/, "Installation prefix"); + config.add_option("prefix", "$HOME/local", "Installation prefix"); /*if(flags&INCLUDE) config.add_option("includedir", "$prefix/include", "Header installation directory"); if(flags&BIN) @@ -234,8 +237,6 @@ void Package::init_config() 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()); - - config.set_source(source); } /** diff --git a/source/package.h b/source/package.h index 68e0c22..fdc5aa2 100644 --- a/source/package.h +++ b/source/package.h @@ -70,7 +70,7 @@ public: const std::string &get_arch() const { return config.get_option("arch").value; } LibMode get_library_mode() const; void resolve_refs(); - void configure(const RawOptionMap &, unsigned); + void configure(const StringMap &, unsigned); static Package *create(Builder &, const std::string &); private: