]> git.tdb.fi Git - builder.git/blobdiff - source/builder.cpp
Move class PackageRef to its own files
[builder.git] / source / builder.cpp
index 7ba6be89a55fd03ccc5d570f4a325ff2c0b29300..1917cd42288223796c123ae23797a04734b5e6e4 100644 (file)
@@ -26,6 +26,8 @@ using namespace Msp;
 Builder::Builder(int argc, char **argv):
        verbose(1),
        cwd(Path::getcwd()),
+       build_file("Build"),
+       do_build(true),
        analyzer(0),
        jobs(1),
        chrome(false)
@@ -39,9 +41,10 @@ Builder::Builder(int argc, char **argv):
        getopt.add_option(GetOpt::Option('W', "what-if", GetOpt::REQUIRED));
        getopt.add_option(GetOpt::Option('B', "build-all", GetOpt::NONE));
        getopt.add_option(GetOpt::Option('C', "chdir", GetOpt::REQUIRED));
-       getopt.add_option(GetOpt::Option('j', "jobs", GetOpt::REQUIRED));
+       getopt.add_option(GetOpt::Option('j', "jobs", GetOpt::REQUIRED, "1"));
        getopt.add_option(GetOpt::Option('h', "help", GetOpt::NONE));
        getopt.add_option(GetOpt::Option('c', "clean", GetOpt::NONE));
+       getopt.add_option(GetOpt::Option('f', "file", GetOpt::REQUIRED, "Build"));
        getopt.add_option(GetOpt::Option("chrome", GetOpt::NONE));
        getopt.add_option(GetOpt::Option("full-paths", GetOpt::NONE));
        int index=getopt(argc, argv);
@@ -67,17 +70,22 @@ Builder::Builder(int argc, char **argv):
                if(getopt["max-depth"])
                        analyzer->set_max_depth(strtol(getopt["max-depth"].arg()));
                analyzer->set_full_paths(getopt["full-paths"]);
+
+               if(!getopt['b'])
+                       do_build=false;
        }
 
-       if(getopt['j'])
-               jobs=max(strtol(getopt['j'].arg()), 1L);
+       dry_run=getopt['n'];
+
+       jobs=max(strtol(getopt['j'].arg()), 1L);
 
-       if(getopt["chrome"])
-               chrome=true;
+       chrome=getopt["chrome"];
 
        if(getopt['C'])
                chdir(getopt['C'].arg().c_str());
 
+       build_file=getopt['f'].arg();
+
        for(int i=index; i<argc; ++i)
        {
                string v(argv[i]);
@@ -90,6 +98,9 @@ Builder::Builder(int argc, char **argv):
 
        if(cmdline_targets.empty())
                cmdline_targets.push_back("default");
+
+       if(getopt['W'])
+               what_if.push_back(getopt['W'].arg());
 }
 
 /**
@@ -105,6 +116,7 @@ Package *Builder::get_package(const string &n)
        if(i!=packages.end())
                return i->second;
 
+       // Try to get source directory with pkgconfig
        list<string> argv;
        argv.push_back("pkg-config");
        argv.push_back("--variable=source");
@@ -115,12 +127,14 @@ Package *Builder::get_package(const string &n)
        if(!srcdir.empty())
                dirs.push_back(srcdir);
 
+       // Make some other guesses about the source directory
        string dirname=n;
        if(!dirname.compare(0, 3, "msp"))
                dirname.erase(0, 3);
        dirs.push_back(cwd/dirname);
        dirs.push_back(cwd/".."/dirname);
 
+       // Go through the candidate directories and look for a Build file
        for(PathList::iterator j=dirs.begin(); j!=dirs.end(); ++j)
                if(!load_build_file(*j/"Build"))
                {
@@ -129,7 +143,8 @@ Package *Builder::get_package(const string &n)
                                return i->second;
                        break;
                }
-       
+
+       // Package source not found - create a binary package
        Package *pkg=Package::create(*this, n);
        packages.insert(PackageMap::value_type(n, pkg));
        if(pkg)
@@ -149,10 +164,18 @@ Target *Builder::get_target(const string &n)
        return 0;
 }
 
+/**
+Tries to locate a header included from a given location and with a given include
+path.  Considers known targets as well as existing files.
+*/
 Target *Builder::get_header(const string &include, const string &from, const list<string> &path)
 {
-       //XXX Should really hash the include path here
-       string id=from+":"+include;
+       string hash(8, 0);
+       update_hash(hash, from);
+       for(list<string>::const_iterator i=path.begin(); i!=path.end(); ++i)
+               update_hash(hash, *i);
+
+       string id=hash+include;
        TargetMap::iterator i=includes.find(id);
        if(i!=includes.end())
                return i->second;
@@ -163,6 +186,7 @@ Target *Builder::get_header(const string &include, const string &from, const lis
                return tgt;
        if((tgt=check_header(Path::Path("/usr/include")/fn)))
                return tgt;
+       //XXX Determine the C++ header location dynamically
        if((tgt=check_header(Path::Path("/usr/include/c++/4.1.2")/fn)))
                return tgt;
        for(list<string>::const_iterator j=path.begin(); j!=path.end(); ++j)
@@ -176,13 +200,17 @@ Target *Builder::get_library(const string &lib, const list<string> &path)
 {
        string hash(8, 0);
        for(list<string>::const_iterator i=path.begin(); i!=path.end(); ++i)
-               for(unsigned j=0; j<i->size(); ++j)
-                       hash[j%8]^=(*i)[j];
+               update_hash(hash, *i);
+
+       string id=hash+lib;
+       TargetMap::iterator i=libraries.find(id);
+       if(i!=libraries.end())
+               return i->second;
 
        string basename="lib"+lib+".so";
-       for(list<string>::const_iterator i=path.begin(); i!=path.end(); ++i)
+       for(list<string>::const_iterator j=path.begin(); j!=path.end(); ++j)
        {
-               string full=(Path::Path(*i)/basename).str();
+               string full=(Path::Path(*j)/basename).str();
                Target *tgt=get_target(full);
                if(tgt) return tgt;
                
@@ -198,7 +226,7 @@ Target *Builder::get_library(const string &lib, const list<string> &path)
 
 int Builder::main()
 {
-       if(load_build_file(cwd/"Build"))
+       if(load_build_file(cwd/build_file))
        {
                cerr<<"No build info here.\n";
                return 1;
@@ -206,10 +234,11 @@ int Builder::main()
 
        default_pkg=packages.begin()->second;
 
+       bool conf_all=cmdline_options.count("conf_all");
        while(!new_pkgs.empty())
        {
                Package *pkg=new_pkgs.front();
-               if(pkg==default_pkg)
+               if(pkg==default_pkg || conf_all)
                        pkg->process_options(cmdline_options);
                new_pkgs.erase(new_pkgs.begin());
                pkg->resolve_refs();
@@ -254,7 +283,8 @@ int Builder::main()
        if(analyzer)
                analyzer->analyze();
 
-       build();
+       if(do_build)
+               build();
 
        return exit_code;
 }
@@ -397,6 +427,17 @@ int Builder::create_targets()
                        new_tgts.push_back(tgt);
        }
 
+       for(list<string>::iterator i=what_if.begin(); i!=what_if.end(); ++i)
+       {
+               Target *tgt=get_target((cwd/ *i).str());
+               if(!tgt)
+               {
+                       cerr<<"Unknown what-if target "<<*i<<'\n';
+                       return -1;
+               }
+               tgt->touch();
+       }
+
        Target *cmdline=new VirtualTarget(*this, "cmdline");
        add_target(cmdline);
        world->add_depend(cmdline);
@@ -437,6 +478,16 @@ void Builder::add_target(Target *t)
        new_tgts.push_back(t);
 }
 
+void Builder::update_hash(string &hash, const string &value)
+{
+       for(unsigned i=0; i<value.size(); ++i)
+               hash[i%hash.size()]^=value[i];
+}
+
+/**
+This function supervises the build process, starting new actions when slots
+become available.
+*/
 int Builder::build()
 {
        Target *cmdline=get_target("cmdline");