]> git.tdb.fi Git - builder.git/commitdiff
Better encapsulation of config inside Package
authorMikko Rasa <tdb@tdb.fi>
Fri, 19 Jan 2007 13:42:50 +0000 (13:42 +0000)
committerMikko Rasa <tdb@tdb.fi>
Fri, 19 Jan 2007 13:42:50 +0000 (13:42 +0000)
Support for cross-compiling
Support for multiple configuration profiles per package
Give a clear indication of build failure
Report problems with packages in a more generic manner

16 files changed:
source/archive.cpp
source/builder.cpp
source/builder.h
source/compile.cpp
source/config.cpp
source/config.h
source/executable.cpp
source/externalaction.cpp
source/link.cpp
source/misc.h
source/objectfile.cpp
source/package.cpp
source/package.h
source/pkgconfigaction.cpp
source/staticlibrary.cpp
source/target.cpp

index 11c633c39da54539d2fdd827cb831a8556aea2b3..7da7250f1d47c0beba22051221d93ffc9d1744cb 100644 (file)
@@ -14,7 +14,9 @@ Archive::Archive(Builder &b, const StaticLibrary &lib):
 {
        const Component &comp=lib.get_component();
 
-       argv.push_back("ar");
+       const string &prefix=b.get_arch_prefix(lib.get_package()->get_arch());
+
+       argv.push_back(prefix+"ar");
        argv.push_back("rc");
 
        argv.push_back(lib.get_name());
index 8cb836abed682b9b49bf5541bc11f83f8f2b9ec3..7825a20c85dbd091a845e232ac3a1a7764e6c08f 100644 (file)
@@ -97,6 +97,10 @@ Builder::Builder(int argc, char **argv):
                chdir(work_dir.c_str());
 
        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-"));
 }
 
 /**
@@ -205,12 +209,11 @@ a new SystemLibrary target will be created and returned.
 
 @param   lib   Name of the library to get (without "lib" prefix or extension)
 @param   path  List of paths to search for the library
-@param   mode  Shared / shared mode - 0: always shared, 1: static for buildable
-               packages, otherwise shared, 2: always static
+@param   mode  Shared / static mode
 
 @return  Some kind of library target, if a match was found
 */
-Target *Builder::get_library(const string &lib, const list<string> &path, unsigned mode)
+Target *Builder::get_library(const string &lib, const list<string> &path, LibMode mode)
 {
        string hash(8, 0);
        for(list<string>::const_iterator i=path.begin(); i!=path.end(); ++i)
@@ -238,6 +241,15 @@ Target *Builder::get_library(const string &lib, const list<string> &path, unsign
        return tgt;
 }
 
+const string &Builder::get_arch_prefix(const string &arch) const
+{
+       StringMap::const_iterator i=archs.find(arch);
+       if(i==archs.end())
+               throw InvalidParameterValue("Unknown architecture");
+
+       return i->second;
+}
+
 int Builder::main()
 {
        if(load_build_file(cwd/build_file))
@@ -265,18 +277,24 @@ int Builder::main()
                return 0;
        }
 
-       StringList missing;
+       StringMap problems;
        for(PackageMap::iterator i=packages.begin(); i!=packages.end(); ++i)
+       {
+               string prob;
                if(!i->second)
-                       missing.push_back(i->first);
+                       prob="missing";
+               else if(i->second->get_buildable() && i->second->get_arch()!=default_pkg->get_arch())
+                       prob="wrong architecture ("+i->second->get_arch()+")";
+               if(!prob.empty())
+                       problems.insert(StringMap::value_type(i->first, prob));
+       }
 
-       if(!missing.empty())
+       if(!problems.empty())
        {
-               missing.sort();
-               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";
+               cerr<<"The following problems were detected:\n";
+               for(StringMap::iterator i=problems.begin(); i!=problems.end(); ++i)
+                       cerr<<"  "<<i->first<<": "<<i->second<<'\n';
+               cerr<<"Please fix them and try again.\n";
                return 1;
        }
 
@@ -411,8 +429,8 @@ int Builder::create_targets()
                        continue;
 
                Path::Path inst_base;
-               if(i->second->get_config().is_option("prefix"))
-                       inst_base=i->second->get_config().get_option("prefix").value;
+               if(i->second->get_buildable())
+                       inst_base=i->second->get_prefix();
 
                const ComponentList &components=i->second->get_components();
                for(ComponentList::const_iterator j=components.begin(); j!=components.end(); ++j)
@@ -591,17 +609,17 @@ Target *Builder::get_header(const Msp::Path::Path &fn)
        return 0;
 }
 
-Target *Builder::get_library(const string &lib, const Path::Path &path, unsigned mode)
+Target *Builder::get_library(const string &lib, const Path::Path &path, LibMode mode)
 {
        string full;
-       if(mode>=1)
+       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==2)) return tgt;
+               if(tgt && (tgt->get_package() || mode==ALL_STATIC)) return tgt;
        }
-       if(mode<=1)
+       if(mode!=ALL_STATIC)
        {
                full=(path/("lib"+lib+".so")).str();
                Target *tgt=get_target(full);
@@ -707,6 +725,9 @@ int Builder::build()
                }
        }
 
+       if(fail)
+               cout<<"Build failed\n";
+
        return fail?-1:0;
 }
 
index 830d356b28959c1d35e22c5eedbc1959256f7d5f..98e541da348ba5264ef5cac7d861ed7bf0d4def7 100644 (file)
@@ -27,8 +27,9 @@ public:
        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 &, unsigned);
+       Target   *get_library(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;
        int      main();
        ~Builder();
 
@@ -64,6 +65,7 @@ private:
        TargetMap    libraries;
 
        ToolMap      tools;    /// Not used yet
+       StringMap    archs;    /// arch -> prefix
        
        Analyzer        *analyzer;
        bool            do_build;
@@ -81,7 +83,7 @@ private:
        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 &, unsigned);
+       Target *get_library(const std::string &, const Msp::Path::Path &, LibMode);
        void   add_target(Target *);
        void   update_hash(std::string &, const std::string &);
        int    build();
index fd802bbb54e76d2a960ae140e40003a174aa03a4..02ae493ea1892a4002c320a88d4ab9997ade1634 100644 (file)
@@ -17,17 +17,19 @@ Compile::Compile(Builder &b, const ObjectFile &obj):
        const TargetList &deps=obj.get_depends();
        Path::Path spath=deps.front()->get_name();
 
+       const string &prefix=b.get_arch_prefix(obj.get_package()->get_arch());
+
        string ext=Path::splitext(spath.str()).ext;
        const char *tool=0;
        if(ext==".cpp" || ext==".cc")
        {
                tool="CXX";
-               argv.push_back("g++");
+               argv.push_back(prefix+"g++");
        }
        else
        {
                tool="CC";
-               argv.push_back("gcc");
+               argv.push_back(prefix+"gcc");
        }
        argv.push_back("-c");
        
index 99e5981503eb35ab9780711a092cea30a3701776..36a59638f104506a9bf6adaca70ab0d8b2ddd57f 100644 (file)
@@ -40,6 +40,39 @@ bool Config::is_option(const string &name) const
        return options.count(name);
 }
 
+/**
+Selects the last profile used.  If the profile cache file is not present, the
+default profile is assumed.
+*/
+void Config::select_last_profile()
+{
+       ifstream in((source/".profile.cache").str().c_str());
+       if(in)
+       {
+               string profile;
+               in>>profile;
+               set_option("profile", profile);
+       }
+       else
+               set_option("profile", "default");
+
+       load();
+}
+
+/**
+Selects the given profile.  The profile cache file is updated as well.
+*/
+void Config::select_profile(const string &profile)
+{
+       set_option("profile", profile);
+
+       ofstream out((source/".profile.cache").str().c_str());
+       if(out)
+               out<<profile<<'\n';
+
+       load();
+}
+
 /**
 Processes options from the given raw option map.  Nonexistent options are
 ignored.  If any options were changed, the mtime of the configuration is updated
@@ -49,18 +82,13 @@ to the current time.
 
 @return  Whether any option values were changed
 */
-bool Config::process(const RawOptionMap &opts)
+bool Config::update(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;
-               }
+               if(set_option(i->first, i->second) && i->first!="profile")
+                       changed=true;
        }
 
        if(changed)
@@ -69,11 +97,44 @@ bool Config::process(const RawOptionMap &opts)
        return changed;
 }
 
-/**
-Loads configuration from a file, if it exists.
-*/
-void Config::load(const Path::Path &fn)
+void Config::save() const
+{
+       Path::Path fn=source/".options.cache";
+
+       OptionMap::const_iterator i=options.find("profile");
+       if(i!=options.end())
+               fn=source/(".options."+i->second.value+".cache");
+
+       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";
+}
+
+bool Config::set_option(const string &opt, const string &val)
 {
+       bool result=false;
+
+       OptionMap::iterator i=options.find(opt);
+       if(i!=options.end())
+       {
+               if(i->second.value!=val)
+                       result=true;
+               i->second.value=val;
+       }
+
+       return result;
+}
+
+void Config::load()
+{
+       Path::Path fn=source/".options.cache";
+
+       OptionMap::iterator i=options.find("profile");
+       if(i!=options.end())
+               fn=source/(".options."+i->second.value+".cache");
+
        ifstream in(fn.str().c_str());
        if(!in) return;
 
@@ -86,15 +147,6 @@ void Config::load(const Path::Path &fn)
        loader.load(parser);
 }
 
-void Config::save(const Path::Path &fn) const
-{
-       ofstream out(fn.str().c_str());
-       if(!out) return;
-       
-       for(OptionMap::const_iterator i=options.begin(); i!=options.end(); ++i)
-               out<<"option \""<<i->second.name<<"\" \""<<i->second.value<<"\";\n";
-}
-
 Config::Option::Option(const string &n, const string &v, const string &d):
        name(n),
        defv(v),
@@ -110,7 +162,5 @@ Config::Loader::Loader(Config &c):
 
 void Config::Loader::option(const string &n, const string &v)
 {
-       OptionMap::iterator i=conf.options.find(n);
-       if(i!=conf.options.end())
-               i->second.value=v;
+       conf.set_option(n, v);
 }
index 355108fb2c35bcd26f5c012c107dc4d587703212..2767f8263a827a67693ee18376d605e842077530 100644 (file)
@@ -35,9 +35,11 @@ public:
        const OptionMap &get_options() const          { return options; }
        const Msp::Time::TimeStamp &get_mtime() const { return mtime; }
        bool is_option(const std::string &) const;
-       bool process(const RawOptionMap &);
-       void load(const Msp::Path::Path &); 
-       void save(const Msp::Path::Path &) 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; }
+       void save() const;
 private:
        class Loader: public Msp::Parser::Loader
        {
@@ -49,8 +51,12 @@ private:
                void option(const std::string &, const std::string &);
        };
        
-       OptionMap options;
+       Msp::Path::Path source;
+       OptionMap       options;
        Msp::Time::TimeStamp mtime;
+
+       bool set_option(const std::string &, const std::string &);
+       void load();
 };
 
 #endif
index cd8ceaff2040dc006cf446bc0b7ef80f9a0cd10a..1f23990da93ca569af5476a7032a468d597549d4 100644 (file)
@@ -26,12 +26,7 @@ Finds and adds any required libraries to the dependencies.
 */
 void Executable::find_depends()
 {
-       const string &staticlibs=package->get_config().get_option("staticlibs").value;
-       unsigned libmode=0;
-       if(staticlibs=="all")
-               libmode=2;
-       else if(staticlibs=="local")
-               libmode=1;
+       LibMode libmode=package->get_library_mode();
        
        //XXX Duplicate libraries?
        list<const Component *> queue;
@@ -84,5 +79,5 @@ string Executable::generate_target_name(const Component &c)
                suffix=".so";
        }
 
-       return (c.get_package().get_source()/(prefix+c.get_name()+suffix)).str();
+       return (c.get_package().get_out_dir()/(prefix+c.get_name()+suffix)).str();
 }
index 0ae68ff05f30bd297b314de7a77ac3e471192cb0..97f6c619f426cb16e50cef20aa170e2008b86ea7 100644 (file)
@@ -61,6 +61,7 @@ void ExternalAction::launch()
                                argv_[i.count()]=strdup(i->c_str());
                        argv_[argv.size()]=0;
                        execvp(argv_[0], argv_);
+                       cout<<"Couldn't execute "<<argv.front()<<'\n';
                        exit(1);
                }
                else if(pid<0)
index 0d94e5ab62251c14c4a49ffea687cfb3ab3d3077..2ff5a97e85060545194ab58b4832e219617bb542 100644 (file)
@@ -18,12 +18,14 @@ Link::Link(Builder &b, const Executable &exe):
 {
        const Component &comp=exe.get_component();
 
+       const string &prefix=b.get_arch_prefix(exe.get_package()->get_arch());
+
        //XXX Determine whether to use g++ or gcc
-       argv.push_back("g++");
+       argv.push_back(prefix+"g++");
        
        if(comp.get_type()==Component::LIBRARY)
                argv.push_back("-shared");
-       else if(comp.get_package().get_config().get_option("staticlibs").value=="all")
+       else if(comp.get_package().get_library_mode()==ALL_STATIC)
                argv.push_back("-static");
 
        const BuildInfo &binfo=comp.get_build_info();
index 1e1b16cdf9149cccb4279e1f1e048c9b4835c9d1..0fc0e32dd4c642e0fac0e59f2b2d7ec82ed194c6 100644 (file)
@@ -2,11 +2,20 @@
 #define MISC_H_
 
 #include <list>
+#include <map>
 #include <string>
 #include <msp/path/path.h>
 
+enum LibMode
+{
+       ALL_STATIC,
+       LOCAL_STATIC,
+       DYNAMIC
+};
+
 typedef std::list<std::string>     StringList;
 typedef std::list<Msp::Path::Path> PathList;
+typedef std::map<std::string, std::string> StringMap;
 
 std::string run_command(const StringList &);
 
index 2aab39b430906eec4f2bde29ed1a0357c1af7dab..3f4ba2019f32a835449d72ce336f0f08076573d7 100644 (file)
@@ -85,5 +85,5 @@ void ObjectFile::add_depend(Target *tgt)
 
 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();
+       return (comp.get_package().get_temp_dir()/comp.get_name()/(Path::splitext(src.substr(src.rfind('/')+1)).base+".o")).str();
 }
index c5e0ffc3428b6629645c7ae3698f000c8a0560f4..0bea2a96b03048c4d476815b56a799d7270526f2 100644 (file)
@@ -31,6 +31,16 @@ void Package::set_path(const Msp::Path::Path &p)
        path=builder.get_cwd()/p;
 }
 
+Msp::Path::Path Package::get_temp_dir() const
+{
+       return source/config.get_option("tempdir").value/config.get_option("profile").value;
+}
+
+Msp::Path::Path Package::get_out_dir() const
+{
+       return source/config.get_option("outdir").value;
+}
+
 /**
 Checks which kinds of things the components of this package install.
 
@@ -55,6 +65,19 @@ unsigned Package::get_install_flags()
        return flags;
 }
 
+LibMode Package::get_library_mode() const
+{
+       const string &mode=config.get_option("staticlibs").value;
+       if(mode=="all")
+               return ALL_STATIC;
+       else if(mode=="local")
+               return LOCAL_STATIC;
+       else if(mode=="none")
+               return DYNAMIC;
+       else
+               throw Exception("Unknown library mode");
+}
+
 /**
 Tries to resolve all references to dependency packages.
 */
@@ -91,11 +114,18 @@ void Package::configure(const RawOptionMap &opts, unsigned flag)
        {
                init_config();
 
-               if(flag && config.process(opts) && !builder.get_dry_run())
+               RawOptionMap::const_iterator prof=opts.find("profile");
+               if(prof!=opts.end())
+                       config.select_profile(prof->second);
+               else
+                       config.select_last_profile();
+                       
+               if(flag && config.update(opts))
                {
                        if(builder.get_verbose()>=2)
                                cout<<"Configuration of "<<name<<" changed\n";
-                       config.save(source/".options.cache");
+                       if(!builder.get_dry_run())
+                               config.save();
                }
 
                for(PackageList::iterator i=all_reqs.begin(); i!=all_reqs.end(); ++i)
@@ -141,6 +171,8 @@ Package *Package::create(Builder &b, const string &name)
                        info.push_back("-lgmpxx");
                else if(name=="fmod4")
                        need_path=true;
+               else if(name=="devil")
+                       info.push_back("-lIL");
                else
                        return 0;
        }
@@ -176,12 +208,14 @@ Initializes configuration options and loads cached values.
 */
 void Package::init_config()
 {
-       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");
-       config.add_option("cpu",        "auto",   "CPU type to optimize for");
-       config.add_option("arch",       "native", "Architecture for cross-compiling");
-       config.add_option("staticlibs", "local",  "Use static libraries");
+       config.add_option("profile",    "default", "Configuration profile");
+       config.add_option("tempdir",    "temp",    "Directory for storing temporary files");
+       config.add_option("outdir",     ".",       "Directory to put build results in");
+       config.add_option("optimize",   "0",       "Apply compiler optimizations");
+       config.add_option("debug",      "0",       "Produce debugging symbols");
+       config.add_option("cpu",        "auto",    "CPU type to optimize for");
+       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();
@@ -200,7 +234,7 @@ void Package::init_config()
                if(i->get_package() && i->get_package()->get_need_path())
                        config.add_option(i->get_name()+"_path", "", "Path for "+i->get_name());
 
-       config.load(source/".options.cache");
+       config.set_source(source);
 }
 
 /**
index 52338ccb501d2c38db1d4141bdcca65a53b10bc5..96fb6760beefe1cec0dabca79c5d2ac5c5ce378a 100644 (file)
@@ -53,6 +53,9 @@ public:
        const std::string   &get_version() const        { return version; }
        const std::string   &get_description() const    { return description; }
        const Msp::Path::Path &get_source() const       { return source; }
+       Msp::Path::Path     get_temp_dir() const;
+       Msp::Path::Path     get_out_dir() const;
+       Msp::Path::Path     get_prefix() const          { return config.get_option("prefix").value; }
        const ComponentList &get_components() const     { return components; }
        bool                get_buildable() const       { return buildable; }
        const Config        &get_config() const         { return config; }
@@ -63,6 +66,8 @@ public:
        bool                get_need_path() const       { return need_path; }
        unsigned            get_install_flags();
        bool                get_use_pkgconfig() const   { return use_pkgconfig; }
+       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);
 
index 65b0c948041bb4a88006b5d90ca34a34c33e044d..9c565f6ddcf5b1dc86588f8eb691b26beae19abe 100644 (file)
@@ -18,7 +18,7 @@ PkgConfigAction::PkgConfigAction(Builder &b, const PkgConfig &p):
        if(out)
        {
                // Prefix is already included in the various paths
-               //out<<"prefix="<<pkg.get_config().get_option("prefix").value<<"\n\n";
+               //out<<"prefix="<<pkg.get_prefix()<<"\n\n";
                out<<"source="<<pkg.get_source()<<"\n\n";
                
                out<<"Name: "<<pkg.get_name()<<'\n';
index df0cc7cb5811e9b2386f7fa398d9356a91ab1906..529aacc193aea8bb30acd58125d99ece41faa32f 100644 (file)
@@ -22,5 +22,5 @@ Action *StaticLibrary::build()
 
 string StaticLibrary::generate_target_name(const Component &c)
 {
-       return (c.get_package().get_source()/("lib"+c.get_name()+".a")).str();
+       return (c.get_package().get_out_dir()/("lib"+c.get_name()+".a")).str();
 }
index 1f4ace9d92c1d7b79122129a99b9781814e0f0d5..e8ed647477fcf82823f06195cfa8a7e43edf7441 100644 (file)
@@ -15,7 +15,10 @@ ready to be built (maybe because they are being built right now), returns 0.
 */
 Target *Target::get_buildable_target()
 {
-       bool self_ok=true;
+       if(!rebuild)
+               return 0;
+
+       bool self_ok=!building;
        for(TargetList::iterator i=depends.begin(); i!=depends.end(); ++i)
        {
                Target *tgt=(*i)->get_buildable_target();
@@ -25,7 +28,7 @@ Target *Target::get_buildable_target()
                        self_ok=false;
        }
 
-       if(self_ok && rebuild && !building)
+       if(self_ok)
                return this;
 
        return 0;