From 4f78d9f016482ce1ac7d726852e33e07c090df1b Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 16 Nov 2006 19:58:57 +0000 Subject: [PATCH] Refactor package configuration Add --conf-only Only add xxx_path options for packages that need a path Add support for using static libraries Look for library target in the standard paths Actually put stuff into the include and library caches Some more comments and cleanup --- source/builder.cpp | 96 +++++++++++++------ source/builder.h | 6 +- source/component.cpp | 2 +- source/component.h | 1 + source/executable.cpp | 43 ++++++++- source/link.cpp | 22 ++++- source/package.cpp | 201 +++++++++++++++++++++------------------ source/package.h | 13 ++- source/sharedlibrary.cpp | 3 +- source/sharedlibrary.h | 5 +- source/systemlibrary.cpp | 13 +++ source/systemlibrary.h | 9 +- 12 files changed, 276 insertions(+), 138 deletions(-) create mode 100644 source/systemlibrary.cpp diff --git a/source/builder.cpp b/source/builder.cpp index c271c2b..38fbc17 100644 --- a/source/builder.cpp +++ b/source/builder.cpp @@ -48,6 +48,7 @@ Builder::Builder(int argc, char **argv): getopt.add_option(GetOpt::Option('C', "chdir", GetOpt::REQUIRED)); getopt.add_option(GetOpt::Option('W', "what-if", GetOpt::REQUIRED)); getopt.add_option(GetOpt::Option("chrome", GetOpt::NONE)); + getopt.add_option(GetOpt::Option("conf-only", GetOpt::NONE)); getopt.add_option(GetOpt::Option("full-paths", GetOpt::NONE)); getopt.add_option(GetOpt::Option("max-depth", GetOpt::REQUIRED)); int index=getopt(argc, argv); @@ -82,6 +83,7 @@ Builder::Builder(int argc, char **argv): jobs=max(strtol(getopt['j'].arg()), 1L); chrome=getopt["chrome"]; conf_all=getopt['A']; + conf_only=getopt["conf-only"]; build_file=getopt['f'].arg(); build_all=getopt['B']; help=getopt['h']; @@ -189,51 +191,62 @@ Target *Builder::get_header(const string &include, const string &from, const lis string fn=include.substr(1); Target *tgt=0; - if(include[0]=='"' && (tgt=check_header(Path::Path(from)/fn))) - return tgt; - if((tgt=check_header(Path::Path("/usr/include")/fn))) - return tgt; + if(include[0]=='"' && (tgt=get_header(Path::Path(from)/fn))) + ; + else if((tgt=get_header(Path::Path("/usr/include")/fn))) + ; //XXX Determine the C++ header location dynamically - if((tgt=check_header(Path::Path("/usr/include/c++/4.1.2")/fn))) - return tgt; - for(list::const_iterator j=path.begin(); j!=path.end(); ++j) - if((tgt=check_header(cwd/ *j/fn))) - return tgt; + else if((tgt=get_header(Path::Path("/usr/include/c++/4.1.2")/fn))) + ; + else + { + for(list::const_iterator j=path.begin(); (j!=path.end() && !tgt); ++j) + tgt=get_header(cwd/ *j/fn); + } + + includes.insert(TargetMap::value_type(id, tgt)); - return 0; + return tgt; } /** Tries to locate a library with the given library path. Considers known targets as well as existing files. If a matching target is not found but a file exists, 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 + +@return Some kind of library target, if a match was found */ -Target *Builder::get_library(const string &lib, const list &path) +Target *Builder::get_library(const string &lib, const list &path, unsigned mode) { string hash(8, 0); for(list::const_iterator i=path.begin(); i!=path.end(); ++i) update_hash(hash, *i); + //XXX Incorporate mode into id string id=hash+lib; TargetMap::iterator i=libraries.find(id); if(i!=libraries.end()) return i->second; - string basename="lib"+lib+".so"; - for(list::const_iterator j=path.begin(); j!=path.end(); ++j) + Target *tgt=0; + if((tgt=get_library(lib, "/lib", mode))) + ; + else if((tgt=get_library(lib, "/usr/lib", mode))) + ; + else { - string full=(cwd/ *j/basename).str(); - Target *tgt=get_target(full); - if(tgt) return tgt; - - if(Path::exists(full)) - { - add_target(tgt=new SystemLibrary(*this, full)); - return tgt; - } + for(list::const_iterator j=path.begin(); (j!=path.end() && !tgt); ++j) + tgt=get_library(lib, cwd/ *j, mode); } - return 0; + libraries.insert(TargetMap::value_type(id, tgt)); + + return tgt; } int Builder::main() @@ -249,12 +262,12 @@ int Builder::main() while(!new_pkgs.empty()) { Package *pkg=new_pkgs.front(); - if(pkg==default_pkg || conf_all) - pkg->process_options(cmdline_options); new_pkgs.erase(new_pkgs.begin()); pkg->resolve_refs(); } + default_pkg->configure(cmdline_options, conf_all?2:1); + if(help) { usage("builder", false); @@ -278,7 +291,8 @@ int Builder::main() return 1; } - default_pkg->create_build_info(); + if(conf_only) + return 0; if(create_targets()) return 1; @@ -352,6 +366,7 @@ void Builder::usage(const char *argv0, bool brief) " -C, --chdir DIR Change to DIR before doing anything else.\n" " -W, --what-if FILE Pretend that FILE has changed.\n" " --chrome Use extra chrome to print status.\n" + " --conf-only Stop after configuring packages.\n" " --full-paths Output full paths in analysis.\n" " --max-depth NUM Maximum depth to show in analysis.\n"; } @@ -562,7 +577,7 @@ int Builder::create_targets() Check if a header exists, either as a target or a file. Either an existing target or a new SystemHeader target will be returned. */ -Target *Builder::check_header(const Msp::Path::Path &fn) +Target *Builder::get_header(const Msp::Path::Path &fn) { Target *tgt=get_target(fn.str()); if(tgt) return tgt; @@ -575,6 +590,33 @@ Target *Builder::check_header(const Msp::Path::Path &fn) return 0; } +Target *Builder::get_library(const string &lib, const Path::Path &path, unsigned mode) +{ + string full; + if(mode>=1) + { + 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(mode<=1) + { + full=(path/("lib"+lib+".so")).str(); + Target *tgt=get_target(full); + if(tgt) return tgt; + } + + if(Path::exists(full)) + { + Target *tgt=new SystemLibrary(*this, full); + add_target(tgt); + return tgt; + } + + return 0; +} + /** Adds a target to both the target map and the new target queue. */ diff --git a/source/builder.h b/source/builder.h index 1016498..00bb2ad 100644 --- a/source/builder.h +++ b/source/builder.h @@ -27,7 +27,7 @@ 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 &); + Target *get_library(const std::string &, const StringList &, unsigned); const Msp::Path::Path &get_cwd() const { return cwd; } int main(); ~Builder(); @@ -75,11 +75,13 @@ private: unsigned jobs; StringList what_if; bool conf_all; + bool conf_only; bool build_all; int load_build_file(const Msp::Path::Path &); int create_targets(); - Target *check_header(const Msp::Path::Path &); + Target *get_header(const Msp::Path::Path &); + Target *get_library(const std::string &, const Msp::Path::Path &, unsigned); void add_target(Target *); void update_hash(std::string &, const std::string &); int build(); diff --git a/source/component.cpp b/source/component.cpp index 97fdacd..22392f0 100644 --- a/source/component.cpp +++ b/source/component.cpp @@ -30,7 +30,7 @@ void Component::create_build_info() { if(!i->get_package()) continue; - i->get_package()->create_build_info(); + //i->get_package()->create_build_info(); build_info.add(i->get_package()->get_exported_binfo()); } diff --git a/source/component.h b/source/component.h index 663132a..82b32e4 100644 --- a/source/component.h +++ b/source/component.h @@ -49,6 +49,7 @@ public: const BuildInfo &get_build_info() const { return build_info; } bool get_install() const { return install; } const std::string &get_install_headers() const { return install_headers; } + const PkgRefList &get_requires() const { return requires; } void resolve_refs(); void create_build_info(); protected: diff --git a/source/executable.cpp b/source/executable.cpp index 8f8c9a2..cd8ceaf 100644 --- a/source/executable.cpp +++ b/source/executable.cpp @@ -1,11 +1,16 @@ +#include +#include #include "builder.h" #include "component.h" #include "executable.h" +#include "install.h" #include "link.h" #include "objectfile.h" #include "package.h" +#include "staticlibrary.h" using namespace std; +using namespace Msp; Executable::Executable(Builder &b, const Component &c, const list &objs): Target(b, &c.get_package(), generate_target_name(c)), @@ -21,12 +26,40 @@ Finds and adds any required libraries to the dependencies. */ void Executable::find_depends() { - const list &libs=comp.get_build_info().libs; - for(list::const_iterator i=libs.begin(); i!=libs.end(); ++i) + const string &staticlibs=package->get_config().get_option("staticlibs").value; + unsigned libmode=0; + if(staticlibs=="all") + libmode=2; + else if(staticlibs=="local") + libmode=1; + + //XXX Duplicate libraries? + list queue; + queue.push_back(&comp); + while(!queue.empty()) { - Target *lib=builder.get_library(*i, comp.get_build_info().libpath); - if(lib) - add_depend(lib); + const Component *c=queue.front(); + queue.erase(queue.begin()); + + const list &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); + if(lib) + { + if(contains(depends, lib)) + continue; + add_depend(lib); + + if(dynamic_cast(lib)) + lib=lib->get_depends().front(); + if(StaticLibrary *stlib=dynamic_cast(lib)) + queue.push_back(&stlib->get_component()); + } + else + cout<<"Couldn't find library "<<*i<<" for "<::const_iterator i=binfo.ldflags.begin(); i!=binfo.ldflags.end(); ++i) argv.push_back(*i); for(list::const_iterator i=binfo.libpath.begin(); i!=binfo.libpath.end(); ++i) argv.push_back("-L"+*i); - for(list::const_iterator i=binfo.libs.begin(); i!=binfo.libs.end(); ++i) - argv.push_back("-l"+*i); argv.push_back("-o"); argv.push_back(exe.get_name()); const TargetList &deps=exe.get_depends(); for(TargetList::const_iterator i=deps.begin(); i!=deps.end(); ++i) - if(dynamic_cast(*i)) + { + Target *tgt=*i; + if(dynamic_cast(tgt)) + tgt=tgt->get_depends().front(); + + if(dynamic_cast(tgt)) + argv.push_back((*i)->get_name()); + else if(SharedLibrary *shlib=dynamic_cast(tgt)) + argv.push_back("-l"+shlib->get_libname()); + else if(dynamic_cast(tgt)) argv.push_back((*i)->get_name()); + else if(SystemLibrary *syslib=dynamic_cast(tgt)) + argv.push_back("-l"+syslib->get_libname()); + } Path::Path epath=exe.get_name(); if(!builder.get_dry_run()) diff --git a/source/package.cpp b/source/package.cpp index 14ae5f7..587ce80 100644 --- a/source/package.cpp +++ b/source/package.cpp @@ -17,7 +17,8 @@ Package::Package(Builder &b, const string &n, const Path::Path &s): name(n), buildable(true), source(s), - build_info_ready(false) + conf_done(false), + need_path(false) { } /** @@ -35,93 +36,51 @@ Tries to resolve all references to dependency packages. void Package::resolve_refs() { for(PkgRefList::iterator i=requires.begin(); i!=requires.end(); ++i) - i->resolve(); + { + Package *pkg=i->resolve(); + if(pkg) all_reqs.push_back(pkg); + } for(ComponentList::iterator i=components.begin(); i!=components.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()); + } } /** -Fills in build info based on configuration. +Processes configuration options that were most likely obtained from the command +line. */ -void Package::create_build_info() +void Package::configure(const RawOptionMap &opts, unsigned flag) { - if(build_info_ready) + if(conf_done || !buildable) return; - if(buildable) - { - for(PkgRefList::iterator i=requires.begin(); i!=requires.end(); ++i) - { - Package *pkg=i->get_package(); - if(!pkg) - continue; - if(pkg->get_need_path()) - pkg->set_path(config.get_option(pkg->get_name()+"_path").value); - pkg->create_build_info(); - build_info.add(pkg->get_exported_binfo()); - export_binfo.add(pkg->get_exported_binfo()); - } + if(builder.get_verbose()>=3) + cout<<"Configuring "<::iterator i=components.begin(); i!=components.end(); ++i) - { - i->create_build_info(); - if(i->get_type()==Component::LIBRARY) - export_binfo.libs.push_back(i->get_name()); - } + if(flag && config.process(opts) && !builder.get_dry_run()) + { + if(builder.get_verbose()>=2) + cout<<"Configuration of "<configure(opts, flag&2); + if((*i)->get_need_path()) + (*i)->set_path(config.get_option((*i)->get_name()+"_path").value); } - export_binfo.unique(); - - build_info_ready=true; -} + + create_build_info(); -/** -Processes configuration options that were most likely obtained from the command -line. -*/ -void Package::process_options(const RawOptionMap &opts) -{ - if(config.process(opts)) - config.save(source/".options.cache"); + conf_done=true; } /** @@ -165,8 +124,7 @@ Package *Package::create(Builder &b, const string &name) Package::Package(Builder &b, const string &n, const vector &info): builder(b), name(n), - buildable(false), - build_info_ready(false) + buildable(false) { for(vector::const_iterator i=info.begin(); i!=info.end(); ++i) { @@ -182,17 +140,16 @@ Package::Package(Builder &b, const string &n, const vector &info): } /** -Initializes a buildable package. Mostly adds configuration options. +Initializes configuration options and loads cached values. */ -void Package::init_buildable() +void Package::init_config() { - buildable=true; - - 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("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"); const char *home=getenv("HOME"); unsigned flags=get_install_flags(); @@ -208,11 +165,80 @@ void Package::init_buildable() config.add_option("includedir", "$prefix/share", "Data installation directory");*/ for(PkgRefList::iterator i=requires.begin(); i!=requires.end(); ++i) - config.add_option(i->get_name()+"_path", "", "Path for "+i->get_name()); + 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"); } +/** +Fills in build info based on configuration. All required packages must be +configured when this is called. +*/ +void Package::create_build_info() +{ + if(buildable) + { + for(PkgRefList::iterator i=requires.begin(); i!=requires.end(); ++i) + { + 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()); + } + + build_info.cflags.push_back("-Wall"); + build_info.cflags.push_back("-Wshadow"); + build_info.cflags.push_back("-Wextra"); + build_info.cflags.push_back("-Wpointer-arith"); + build_info.cflags.push_back("-Wconversion"); + build_info.cflags.push_back("-Werror"); + + unsigned flags=get_install_flags(); + + if(flags&INCLUDE) + export_binfo.incpath.push_back((Path::Path(config.get_option("prefix").value)/"include").str()); + if(flags&LIB) + export_binfo.libpath.push_back((Path::Path(config.get_option("prefix").value)/"lib").str()); + + string optimize=config.get_option("optimize").value; + if(strtol(optimize)) + { + build_info.cflags.push_back("-O"+optimize); + string cpu=config.get_option("cpu").value; + if(cpu!="auto") + build_info.cflags.push_back("-march="+cpu); + } + + if(strtobool(config.get_option("debug").value)) + { + build_info.cflags.push_back("-ggdb"); + build_info.defines.push_back("DEBUG"); + } + + build_info.unique(); + + for(list::iterator i=components.begin(); i!=components.end(); ++i) + { + i->create_build_info(); + if(i->get_type()==Component::LIBRARY) + export_binfo.libs.push_back(i->get_name()); + } + } + else if(name=="fmod4") + { + export_binfo.libs.push_back("fmodex"); + if(!path.empty()) + { + export_binfo.libpath.push_back((path/"api"/"lib").str()); + export_binfo.incpath.push_back((path/"api"/"inc").str()); + } + } + export_binfo.unique(); +} + /** Checks which kinds of things the components of this package install. @@ -249,11 +275,6 @@ Package::Loader::Loader(Package &p): add("build_info", &Loader::build_info); } -Package::Loader::~Loader() -{ - pkg.init_buildable(); -} - void Package::Loader::require(const string &n) { pkg.requires.push_back(PackageRef(pkg.builder, n)); diff --git a/source/package.h b/source/package.h index 3d980f2..b9807e3 100644 --- a/source/package.h +++ b/source/package.h @@ -10,6 +10,9 @@ #include "packageref.h" class Builder; +class Package; + +typedef std::list PackageList; /** A package is a distributable piece of software. They consist of one or more @@ -26,7 +29,6 @@ public: public: Loader(Package &); Package &get_object() { return pkg; } - ~Loader(); private: Package &pkg; @@ -50,8 +52,7 @@ public: Builder &get_builder() const { return builder; } bool get_need_path() const { return need_path; } void resolve_refs(); - void create_build_info(); - void process_options(const RawOptionMap &); + void configure(const RawOptionMap &, unsigned); static Package *create(Builder &, const std::string &); private: @@ -72,17 +73,19 @@ private: bool buildable; Msp::Path::Path source; PkgRefList requires; + PackageList all_reqs; BuildInfo build_info; BuildInfo export_binfo; ComponentList components; Config config; - bool build_info_ready; + bool conf_done; bool need_path; Msp::Path::Path path; Package(Builder &, const std::string &, const std::vector &); - void init_buildable(); + void init_config(); + void create_build_info(); unsigned get_install_flags(); }; diff --git a/source/sharedlibrary.cpp b/source/sharedlibrary.cpp index 557f7fe..0431f27 100644 --- a/source/sharedlibrary.cpp +++ b/source/sharedlibrary.cpp @@ -5,6 +5,7 @@ using namespace std; SharedLibrary::SharedLibrary(Builder &b, const Component &c, const list &objs): - Executable(b, c, objs) + Executable(b, c, objs), + libname(c.get_name()) { } diff --git a/source/sharedlibrary.h b/source/sharedlibrary.h index 639592d..79d4192 100644 --- a/source/sharedlibrary.h +++ b/source/sharedlibrary.h @@ -11,7 +11,10 @@ class SharedLibrary: public Executable { public: SharedLibrary(Builder &, const Component &, const std::list &); - const char *get_type() const { return "SharedLibrary"; } + const char *get_type() const { return "SharedLibrary"; } + const std::string &get_libname() const { return libname; } +private: + std::string libname; }; #endif diff --git a/source/systemlibrary.cpp b/source/systemlibrary.cpp new file mode 100644 index 0000000..00cbddc --- /dev/null +++ b/source/systemlibrary.cpp @@ -0,0 +1,13 @@ +#include +#include "systemlibrary.h" + +using namespace std; +using namespace Msp; + +SystemLibrary::SystemLibrary(Builder &b, const string &n): + Target(b, 0, n) +{ + libname=Path::splitext(Path::basename(n)).base; + if(!libname.compare(0, 3, "lib")) + libname.erase(0, 3); +} diff --git a/source/systemlibrary.h b/source/systemlibrary.h index babd494..edd50a2 100644 --- a/source/systemlibrary.h +++ b/source/systemlibrary.h @@ -9,9 +9,12 @@ A library that doesn't belong to any known package. class SystemLibrary: public Target { public: - SystemLibrary(Builder &b, const std::string &n): Target(b,0,n) { } - const char *get_type() const { return "SystemLibrary"; } - Action *build() { return 0; } + SystemLibrary(Builder &, const std::string &); + const char *get_type() const { return "SystemLibrary"; } + const std::string &get_libname() const { return libname; } + Action *build() { return 0; } +private: + std::string libname; }; #endif -- 2.45.2