]> git.tdb.fi Git - builder.git/commitdiff
Add profile templates
authorMikko Rasa <tdb@tdb.fi>
Thu, 29 Mar 2007 09:46:05 +0000 (09:46 +0000)
committerMikko Rasa <tdb@tdb.fi>
Thu, 29 Mar 2007 09:46:05 +0000 (09:46 +0000)
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

source/builder.cpp
source/builder.h
source/config.cpp
source/config.h
source/executable.cpp
source/package.cpp
source/package.h

index 31cdd1806aa62b5e921ed531d73631920a8baf3a..723930a315b3c6e16c9d30192e4847762c5b5a26 100644 (file)
@@ -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<string> parts=split(pt, '-');
+
+       for(vector<string>::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))
index 3e3388dbc4b41043ee0cb0278da362b227bc01d2..385468210fc2590b433d6d426075dadc73a98224 100644 (file)
@@ -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<std::string, Package *>   PackageMap;
        typedef std::map<std::string, Target *>    TargetMap;
        typedef std::map<std::string, StringMap>   ToolMap;
+       typedef std::map<std::string, StringMap>   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;
index 36a59638f104506a9bf6adaca70ab0d8b2ddd57f..afa60e87e45f10fe3a0e0c9780e2c52c9a607741 100644 (file)
@@ -2,11 +2,18 @@
 #include <msp/error.h>
 #include <msp/path/utils.h>
 #include <msp/time/utils.h>
+#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<<profile<<'\n';
+       if(!package.get_builder().get_dry_run())
+       {
+               ofstream out((package.get_source()/".profile.cache").str().c_str());
+               if(out)
+                       out<<profile<<'\n';
+       }
+
+       freeze_mtime=true;
+       package.get_builder().apply_profile_template(*this, profile);
+       freeze_mtime=false;
 
        load();
 }
@@ -82,28 +99,76 @@ to the current time.
 
 @return  Whether any option values were changed
 */
-bool Config::update(const RawOptionMap &opts)
+bool Config::update(const StringMap &opts)
 {
        bool changed=false;
-       for(RawOptionMap::const_iterator i=opts.begin(); i!=opts.end(); ++i)
+       for(StringMap::const_iterator i=opts.begin(); i!=opts.end(); ++i)
        {
                if(set_option(i->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)
 {
index 2767f8263a827a67693ee18376d605e842077530..e35743a3050e5ff1c4c979be8b5b9d5d2c57fcbf 100644 (file)
@@ -6,8 +6,9 @@
 #include <msp/parser/loader.h>
 #include <msp/path/path.h>
 #include <msp/time/timestamp.h>
+#include "misc.h"
 
-typedef std::map<std::string, std::string> RawOptionMap;
+class Package;
 
 /**
 Manages configuration for a package.  A configuration may have an arbitary
@@ -30,6 +31,7 @@ public:
        };
        typedef std::map<std::string, Option> 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();
index a5a944ed18e7131e856b7af5fbc3d13238fd4c67..db8bd11db0b3c832790d3cbdbef4d2f717ad80fd 100644 (file)
@@ -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();
 }
index 2e7932c1c57a93dbed709797eb14a05b5a9572ea..74dcbaa693a09e0e32969659b193bced835a95f2 100644 (file)
@@ -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<string> &info):
        builder(b),
        name(n),
        buildable(false),
+       config(*this),
        conf_done(false)
 {
        for(vector<string>::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);
 }
 
 /**
index 68e0c224c2116126d29ec620e44fe71a4bab5242..fdc5aa2f0bc27dd264edc464815507e51c8771a2 100644 (file)
@@ -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: