+#include <stdexcept>
+#include <vector>
+#include <msp/fs/dir.h>
+#include <msp/fs/utils.h>
+#include "builder.h"
+#include "component.h"
+#include "executable.h"
+#include "externaltask.h"
+#include "gnucxxcompiler.h"
+#include "gnulinker.h"
+#include "objectfile.h"
+#include "sharedlibrary.h"
+#include "sourcepackage.h"
+#include "staticlibrary.h"
+
+using namespace std;
+using namespace Msp;
+
+GnuLinker::GnuLinker(Builder &b):
+ Tool(b, "LINK")
+{
+ input_suffixes.push_back(".o");
+ input_suffixes.push_back(".a");
+}
+
+Target *GnuLinker::create_target(const list<Target *> &sources, const std::string &arg) const
+{
+ if(sources.empty())
+ throw invalid_argument("GnuLinker::create_target");
+ list<ObjectFile *> objs;
+ for(list<Target *>::const_iterator i=sources.begin(); i!=sources.end(); ++i)
+ {
+ if(ObjectFile *obj = dynamic_cast<ObjectFile *>(*i))
+ objs.push_back(obj);
+ else
+ throw invalid_argument("GnuLinker::create_target");
+ }
+
+ const Component &comp = objs.front()->get_component();
+ Binary *bin = 0;
+ if(arg=="shared")
+ bin = new SharedLibrary(builder, comp, objs);
+ else
+ bin = new Executable(builder, comp, objs);
+ bin->set_tool(*this);
+ return bin;
+}
+
+Task *GnuLinker::run(const Target &target) const
+{
+ const Binary &bin = dynamic_cast<const Binary &>(target);
+ const SharedLibrary *shlib = dynamic_cast<const SharedLibrary *>(&bin);
+
+ string command = "gcc";
+
+ const list<Target *> &depends = target.get_depends();
+ for(list<Target *>::const_iterator i=depends.begin(); i!=depends.end(); ++i)
+ if(ObjectFile *obj = dynamic_cast<ObjectFile *>(*i))
+ {
+ const Tool *tool = obj->get_tool();
+ if(dynamic_cast<const GnuCxxCompiler *>(tool))
+ command = "g++";
+ }
+
+ vector<string> argv;
+ argv.push_back(command);
+
+ const Component &comp = bin.get_component();
+
+ if(shlib)
+ {
+ argv.push_back("-shared");
+ if(!shlib->get_soname().empty())
+ argv.push_back("-Wl,-soname,"+shlib->get_soname());
+ }
+ else if(comp.get_package().get_library_mode()==ALL_STATIC)
+ argv.push_back("-static");
+
+ const BuildInfo &binfo = comp.get_build_info();
+ for(list<string>::const_iterator i=binfo.ldflags.begin(); i!=binfo.ldflags.end(); ++i)
+ argv.push_back(*i);
+ for(list<string>::const_iterator i=binfo.libpath.begin(); i!=binfo.libpath.end(); ++i)
+ argv.push_back("-L"+*i);
+
+ FS::Path work_dir = comp.get_package().get_source();
+
+ argv.push_back("-o");
+ argv.push_back(relative(bin.get_path(), work_dir).str());
+ for(TargetList::const_iterator i=depends.begin(); i!=depends.end(); ++i)
+ {
+ Target *tgt = (*i)->get_real_target();
+
+ if(ObjectFile *obj = dynamic_cast<ObjectFile *>(tgt))
+ argv.push_back(relative(obj->get_path(), work_dir).str());
+ else if(StaticLibrary *stlib = dynamic_cast<StaticLibrary *>(tgt))
+ argv.push_back(stlib->get_path().str());
+ else if(Library *lib = dynamic_cast<Library *>(tgt))
+ argv.push_back("-l"+lib->get_libname());
+ }
+
+ if(!builder.get_dry_run())
+ FS::mkpath(FS::dirname(bin.get_path()), 0755);
+
+ return new ExternalTask(argv, work_dir);
+}