From 57bdb055acb0453c75b22cb64f35cc0e817a2827 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 19 Jan 2007 13:42:50 +0000 Subject: [PATCH] Better encapsulation of config inside Package 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 --- source/archive.cpp | 4 +- source/builder.cpp | 55 ++++++++++++++------- source/builder.h | 6 ++- source/compile.cpp | 6 ++- source/config.cpp | 98 ++++++++++++++++++++++++++++---------- source/config.h | 14 ++++-- source/executable.cpp | 9 +--- source/externalaction.cpp | 1 + source/link.cpp | 6 ++- source/misc.h | 9 ++++ source/objectfile.cpp | 2 +- source/package.cpp | 52 ++++++++++++++++---- source/package.h | 5 ++ source/pkgconfigaction.cpp | 2 +- source/staticlibrary.cpp | 2 +- source/target.cpp | 7 ++- 16 files changed, 205 insertions(+), 73 deletions(-) diff --git a/source/archive.cpp b/source/archive.cpp index 11c633c..7da7250 100644 --- a/source/archive.cpp +++ b/source/archive.cpp @@ -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()); diff --git a/source/builder.cpp b/source/builder.cpp index 8cb836a..7825a20 100644 --- a/source/builder.cpp +++ b/source/builder.cpp @@ -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 &path, unsigned mode) +Target *Builder::get_library(const string &lib, const list &path, LibMode mode) { string hash(8, 0); for(list::const_iterator i=path.begin(); i!=path.end(); ++i) @@ -238,6 +241,15 @@ Target *Builder::get_library(const string &lib, const list &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::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<<" "<first<<": "<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; } diff --git a/source/builder.h b/source/builder.h index 830d356..98e541d 100644 --- a/source/builder.h +++ b/source/builder.h @@ -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(); diff --git a/source/compile.cpp b/source/compile.cpp index fd802bb..02ae493 100644 --- a/source/compile.cpp +++ b/source/compile.cpp @@ -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"); diff --git a/source/config.cpp b/source/config.cpp index 99e5981..36a5963 100644 --- a/source/config.cpp +++ b/source/config.cpp @@ -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<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 \""<second.name<<"\" \""<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 \""<second.name<<"\" \""<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); } diff --git a/source/config.h b/source/config.h index 355108f..2767f82 100644 --- a/source/config.h +++ b/source/config.h @@ -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 diff --git a/source/executable.cpp b/source/executable.cpp index cd8ceaf..1f23990 100644 --- a/source/executable.cpp +++ b/source/executable.cpp @@ -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 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(); } diff --git a/source/externalaction.cpp b/source/externalaction.cpp index 0ae68ff..97f6c61 100644 --- a/source/externalaction.cpp +++ b/source/externalaction.cpp @@ -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 "<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(); diff --git a/source/misc.h b/source/misc.h index 1e1b16c..0fc0e32 100644 --- a/source/misc.h +++ b/source/misc.h @@ -2,11 +2,20 @@ #define MISC_H_ #include +#include #include #include +enum LibMode +{ + ALL_STATIC, + LOCAL_STATIC, + DYNAMIC +}; + typedef std::list StringList; typedef std::list PathList; +typedef std::map StringMap; std::string run_command(const StringList &); diff --git a/source/objectfile.cpp b/source/objectfile.cpp index 2aab39b..3f4ba20 100644 --- a/source/objectfile.cpp +++ b/source/objectfile.cpp @@ -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(); } diff --git a/source/package.cpp b/source/package.cpp index c5e0ffc..0bea2a9 100644 --- a/source/package.cpp +++ b/source/package.cpp @@ -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 "<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); } /** diff --git a/source/package.h b/source/package.h index 52338cc..96fb676 100644 --- a/source/package.h +++ b/source/package.h @@ -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); diff --git a/source/pkgconfigaction.cpp b/source/pkgconfigaction.cpp index 65b0c94..9c565f6 100644 --- a/source/pkgconfigaction.cpp +++ b/source/pkgconfigaction.cpp @@ -18,7 +18,7 @@ PkgConfigAction::PkgConfigAction(Builder &b, const PkgConfig &p): if(out) { // Prefix is already included in the various paths - //out<<"prefix="<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; -- 2.45.2