#include "misc.h"
#include "objectfile.h"
#include "package.h"
+#include "pkgconfig.h"
#include "sharedlibrary.h"
#include "staticlibrary.h"
#include "systemlibrary.h"
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);
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'];
/**
Tries to locate a header included from a given location and with a given include
-path. Considers known targets as well as existing files.
+path. Considers known targets as well as existing files. If a matching target
+is not found but a file exists, a new SystemHeader target will be created and
+returned.
*/
Target *Builder::get_header(const string &include, const string &from, const list<string> &path)
{
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<string>::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<string>::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;
}
-Target *Builder::get_library(const string &lib, const list<string> &path)
+/**
+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<string> &path, unsigned mode)
{
string hash(8, 0);
for(list<string>::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<string>::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<string>::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()
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);
return 1;
}
- default_pkg->create_build_info();
+ if(conf_only)
+ return 0;
if(create_targets())
return 1;
" -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";
}
}
+/**
+Loads the given build file.
+
+@param fn Path to the file
+
+@return 0 on success, -1 if the file could not be opened
+*/
int Builder::load_build_file(const Path::Path &fn)
{
ifstream in(fn.str().c_str());
return 0;
}
+/**
+Creates targets for all packages and prepares them for building.
+
+@return 0 if everything went ok, -1 if something bad happened and a build
+ shouldn't be attempted
+*/
int Builder::create_targets()
{
Target *world=new VirtualTarget(*this, "world");
const ComponentList &components=i->second->get_components();
for(ComponentList::const_iterator j=components.begin(); j!=components.end(); ++j)
{
+ // Collect all files belonging to the component
PathList files;
const PathList &sources=j->get_sources();
for(PathList::const_iterator k=sources.begin(); k!=sources.end(); ++k)
{
string basename=(*k)[-1];
string ext=Path::splitext(basename).ext;
- if(ext==".cpp" || ext==".c")
+ if((ext==".cpp" || ext==".c") && build_exe)
{
- if(build_exe)
- {
- SourceFile *src=new SourceFile(*this, &*j, k->str());
- add_target(src);
-
- ObjectFile *obj=new ObjectFile(*this, *j, *src);
- add_target(obj);
- objs.push_back(obj);
- }
+ SourceFile *src=new SourceFile(*this, &*j, k->str());
+ add_target(src);
+
+ // Compile sources
+ ObjectFile *obj=new ObjectFile(*this, *j, *src);
+ add_target(obj);
+ objs.push_back(obj);
}
else if(ext==".h")
{
hdr=new Header(*this, &*j, k->str());
add_target(hdr);
}
+
+ // Install headers if requested
if(!j->get_install_headers().empty())
{
Path::Path inst_path=inst_base/"include"/j->get_install_headers()/basename;
}
}
}
+
+ if(i->second->get_install_flags()&(Package::LIB|Package::INCLUDE))
+ {
+ PkgConfig *pc=new PkgConfig(*this, *i->second);
+ add_target(pc);
+ Install *inst=new Install(*this, *i->second, *pc, (inst_base/"lib"/"pkgconfig"/Path::basename(pc->get_name())).str());
+ add_target(inst);
+ install->add_depend(inst);
+ }
}
+ // Find dependencies until no new targets are created
while(!new_tgts.empty())
{
Target *tgt=new_tgts.front();
new_tgts.push_back(tgt);
}
- for(list<string>::iterator i=what_if.begin(); i!=what_if.end(); ++i)
+ // Apply what-ifs
+ for(StringList::iterator i=what_if.begin(); i!=what_if.end(); ++i)
{
Target *tgt=get_target((cwd/ *i).str());
if(!tgt)
tgt->touch();
}
+ // Make the cmdline target depend on all targets mentioned on the command line
Target *cmdline=new VirtualTarget(*this, "cmdline");
add_target(cmdline);
world->add_depend(cmdline);
return 0;
}
-Target *Builder::check_header(const Msp::Path::Path &fn)
+/**
+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::get_header(const Msp::Path::Path &fn)
{
Target *tgt=get_target(fn.str());
if(tgt) return tgt;
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.
+*/
void Builder::add_target(Target *t)
{
targets.insert(TargetMap::value_type(t->get_name(), t));
new_tgts.push_back(t);
}
+/**
+Updates a hash with a string. This is used from get_header and get_library.
+*/
void Builder::update_hash(string &hash, const string &value)
{
for(unsigned i=0; i<value.size(); ++i)
return fail?-1:0;
}
+/**
+Prints out information about the default package.
+*/
void Builder::package_help()
{
const Config &config=default_pkg->get_config();