]> git.tdb.fi Git - builder.git/blobdiff - source/builder.cpp
Bump version to 1.0
[builder.git] / source / builder.cpp
index b06b8ffb2fd0b1de4c7b288989cd8704ce295919..ce82ba33351f191f1055eae0a053c915247a2053 100644 (file)
@@ -6,6 +6,7 @@ Distributed under the LGPL
 */
 
 #include <set>
+#include <cstdlib>
 #include <sys/utsname.h>
 #include <msp/core/except.h>
 #include <msp/core/getopt.h>
@@ -123,7 +124,7 @@ Builder::Builder(int argc, char **argv):
        const vector<string> &args=getopt.get_args();
        for(vector<string>::const_iterator i=args.begin(); i!=args.end(); ++i)
        {
-               unsigned equal=i->find('=');
+               string::size_type equal=i->find('=');
                if(equal!=string::npos)
                        cmdline_options.insert(StringMap::value_type(i->substr(0, equal), i->substr(equal+1)));
                else
@@ -151,7 +152,7 @@ Builder::Builder(int argc, char **argv):
        native_arch->set_tool("AR",  "ar");
 
        load_build_file((FS::get_sys_data_dir(argv[0], "builder")/"builderrc").str());
-       load_build_file((FS::get_home_dir()/".builderrc").str());
+       load_build_file((FS::get_user_data_dir("builder")/"rc").str());
 
        if(arch.empty())
                current_arch=native_arch;
@@ -194,6 +195,25 @@ Builder::~Builder()
 
 int Builder::main()
 {
+       if(prefix.str()!="/usr")
+       {
+               FS::Path pcdir=prefix/"lib"/"pkgconfig";
+               if(const char *pcp=getenv("PKG_CONFIG_PATH"))
+               {
+                       vector<string> path=split(pcp, ':');
+                       bool found=false;
+                       for(vector<string>::const_iterator i=path.begin(); (!found && i!=path.end()); ++i)
+                               found=(*i==pcdir.str());
+                       if(!found)
+                       {
+                               path.push_back(pcdir.str());
+                               setenv("PKG_CONFIG_PATH", join(path.begin(), path.end(), ":").c_str(), true);
+                       }
+               }
+               else
+                       setenv("PKG_CONFIG_PATH", pcdir.str().c_str(), true);
+       }
+
        if(load_build_file(cwd/build_file))
        {
                if(help)
@@ -238,19 +258,19 @@ int Builder::main()
                        if(dynamic_cast<SourcePackage *>(*i))
                                IO::print("*");
                        unsigned count=0;
-                       unsigned ood_count=0;
+                       unsigned to_be_built=0;
                        for(TargetMap::iterator j=targets.begin(); j!=targets.end(); ++j)
                                if(j->second->get_package()==*i)
                                {
                                        ++count;
                                        if(j->second->get_rebuild())
-                                               ++ood_count;
+                                               ++to_be_built;
                                }
                        if(count)
                        {
                                IO::print(" (%d targets", count);
-                               if(ood_count)
-                                       IO::print(", %d out-of-date", ood_count);
+                               if(to_be_built)
+                                       IO::print(", %d to be built", to_be_built);
                                IO::print(")");
                        }
                        IO::print("\n");
@@ -265,12 +285,11 @@ int Builder::main()
                IO::print(IO::cerr, "The following problems were detected:\n");
                for(ProblemList::iterator i=problems.begin(); i!=problems.end(); ++i)
                        IO::print(IO::cerr, "  %s: %s\n", i->package, i->descr);
-               IO::print(IO::cerr, "Please fix them and try again.\n");
+               if(!analyzer)
+                       IO::print(IO::cerr, "Please fix them and try again.\n");
                return 1;
        }
 
-       //if(create_makefile
-
        if(clean)
                exit_code=do_clean();
        else if(build)
@@ -279,6 +298,32 @@ int Builder::main()
        return exit_code;
 }
 
+string Builder::run_pkgconfig(const string &pkg, const string &what)
+{
+       list<string> argv;
+       argv.push_back("pkg-config");
+       if(what=="cflags" || what=="libs")
+               argv.push_back("--"+what);
+       else if(what=="flags")
+       {
+               argv.push_back("--cflags");
+               argv.push_back("--libs");
+       }
+       else
+               argv.push_back("--variable="+what);
+       argv.push_back(pkg);
+
+       if(verbose>=4)
+               IO::print("Running %s\n", join(argv.begin(), argv.end()));
+
+       int status;
+       string res=run_command(argv, &status);
+       if(status)
+               throw Exception(format("pkg-config for package %s failed", pkg));
+
+       return res;
+}
+
 Package *Builder::get_package(const string &name)
 {
        PackageMap::iterator i=packages.find(format("%s/%s", name, current_arch->get_name()));
@@ -295,14 +340,19 @@ Package *Builder::get_package(const string &name)
                        return i->second;
        }
 
-       // Package source not found - create a binary package
-       Package *pkg=BinaryPackage::from_pkgconfig(*this, name);
+       Package *pkg=0;
+       try
+       {
+               // Package source not found - create a binary package
+               pkg=BinaryPackage::from_pkgconfig(*this, name);
+       }
+       catch(...)
+       {
+               problem(name, "not found");
+       }
 
        packages.insert(PackageMap::value_type(name, pkg));
 
-       if(!pkg)
-               problem(name, "not found");
-
        return pkg;
 }
 
@@ -334,16 +384,21 @@ Target *Builder::get_header(const string &include, const FS::Path &from, const l
                StringList argv;
                argv.push_back(current_arch->get_tool("CXX"));
                argv.push_back("--version");
-               cxx_ver=Regex("[0-9]\\.[0-9.]+").match(run_command(argv))[0].str;
-               while(!cxx_ver.empty() && !FS::is_dir(FS::Path("/usr/include/c++")/cxx_ver))
+               if(RegMatch m=Regex("[0-9]\\.[0-9.]+").match(run_command(argv)))
                {
-                       unsigned dot=cxx_ver.rfind('.');
-                       if(dot==string::npos)
-                               break;
-                       cxx_ver.erase(dot);
+                       cxx_ver=m[0].str;
+                       while(!cxx_ver.empty() && !FS::is_dir(FS::Path("/usr/include/c++")/cxx_ver))
+                       {
+                               string::size_type dot=cxx_ver.rfind('.');
+                               if(dot==string::npos)
+                                       break;
+                               cxx_ver.erase(dot);
+                       }
+                       if(verbose>=5)
+                               IO::print("C++ version is %s\n", cxx_ver);
                }
-               if(verbose>=5)
-                       IO::print("C++ version is %s\n", cxx_ver);
+               else
+                       cxx_ver="-";
        }
 
        string fn=include.substr(1);
@@ -355,7 +410,8 @@ Target *Builder::get_header(const string &include, const FS::Path &from, const l
                syspath.push_back("/usr/include");
        else
                syspath.push_back("/usr/"+current_arch->get_prefix()+"/include");
-       syspath.push_back((FS::Path("/usr/include/c++/")/cxx_ver).str());
+       if(cxx_ver!="-")
+               syspath.push_back((FS::Path("/usr/include/c++/")/cxx_ver).str());
 
        Target *tgt=0;
        if(include[0]=='\"')
@@ -447,6 +503,7 @@ void Builder::usage(const char *reason, const char *argv0, bool brief)
                IO::print(IO::cerr, "Usage: %s\n", usagemsg);
        else
        {
+               IO::print(IO::cerr, "Builder 1.0\n\n");
                IO::print(IO::cerr, "Usage: %s [options] [<target> ...]\n\n", argv0);
                IO::print(IO::cerr, "Options:\n");
                IO::print(IO::cerr, helpmsg);
@@ -458,16 +515,15 @@ FS::Path Builder::get_package_location(const string &name)
        if(verbose>=3)
                IO::print("Looking for package %s\n", name);
 
-       // Try to get source directory with pkgconfig
-       list<string> argv;
-       argv.push_back("pkg-config");
-       argv.push_back("--variable=source");
-       argv.push_back(name);
-       if(verbose>=4)
-               IO::print("Running %s\n", join(argv.begin(), argv.end()));
-       string srcdir=strip(run_command(argv));
-       if(!srcdir.empty())
-               return srcdir;
+       try
+       {
+               // Try to get source directory with pkgconfig
+               string srcdir=strip(run_pkgconfig(name, "source"));
+               if(!srcdir.empty())
+                       return srcdir;
+       }
+       catch(...)
+       { }
 
        if(pkg_dirs.empty())
        {
@@ -592,18 +648,7 @@ int Builder::create_targets()
                cmdline->add_depend(tgt);
        }
 
-       /* If world is to be built, prepare cmdline.  If not, add cmdline to world
-       and prepare world.  I don't really like this, but it keeps the graph
-       acyclic.
-       
-       XXX Could we skip preparing targets we are not interested in? */
-       if(build_world)
-               cmdline->prepare();
-       else
-       {
-               world->add_depend(cmdline);
-               world->prepare();
-       }
+       cmdline->prepare();
 
        for(PackageMap::iterator i=packages.begin(); i!=packages.end(); ++i)
                if(SourcePackage *spkg=dynamic_cast<SourcePackage *>(i->second))
@@ -612,7 +657,7 @@ int Builder::create_targets()
        return 0;
 }
 
-Target *Builder::get_header(const Msp::FS::Path &fn)
+Target *Builder::get_header(const FS::Path &fn)
 {
        Target *tgt=get_target(fn.str());
        if(tgt) return tgt;
@@ -679,7 +724,11 @@ int Builder::do_build()
 {
        Target *cmdline=get_target("cmdline");
 
-       unsigned total=cmdline->count_rebuild();
+       unsigned total=0;
+       for(map<string, Target *>::const_iterator i=targets.begin(); i!=targets.end(); ++i)
+               if(i->second->is_buildable() && i->second->get_rebuild())
+                       ++total;
+
        if(!total)
        {
                IO::print("Already up to date\n");
@@ -757,7 +806,7 @@ int Builder::do_clean()
                Target *tgt=queue.front();
                queue.erase(queue.begin());
 
-               if(tgt->get_buildable() && (tgt->get_package()==main_pkg || clean>=2))
+               if(tgt->is_buildable() && (tgt->get_package()==main_pkg || clean>=2))
                        clean_tgts.insert(tgt);
 
                const TargetList &deps=tgt->get_depends();