X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=plugins%2Fgnu%2Fgnulinker.cpp;fp=plugins%2Fgnu%2Fgnulinker.cpp;h=710c44b9b3f0bfaf722be1372691775d66b8a718;hb=c8e829c219c65ff8e93b6c7b66212ff0876441c5;hp=0000000000000000000000000000000000000000;hpb=e2c9c3fffcc61a0c102ccf6a7924e2de709092ad;p=builder.git diff --git a/plugins/gnu/gnulinker.cpp b/plugins/gnu/gnulinker.cpp new file mode 100644 index 0000000..710c44b --- /dev/null +++ b/plugins/gnu/gnulinker.cpp @@ -0,0 +1,325 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gnucompiler.h" +#include "gnulinker.h" + +using namespace std; +using namespace Msp; + +GnuLinker::GnuLinker(Builder &b, const Architecture &a): + Tool(b, &a, "LINK") +{ + input_suffixes.push_back(".o"); + input_suffixes.push_back(".a"); + + processing_unit = COMPONENT; + + set_command("gcc", true); + set_run_external(_run); +} + +Target *GnuLinker::create_target(const vector &sources, const string &arg) +{ + if(sources.empty()) + throw invalid_argument("GnuLinker::create_target"); + vector objs; + objs.reserve(sources.size()); + for(Target *s: sources) + objs.push_back(&dynamic_cast(*s)); + + const Component &comp = *objs.front()->get_component(); + Binary *bin = 0; + if(arg=="shared") + { + SharedLibrary *shlib = new SharedLibrary(builder, comp, objs); + if(architecture->get_system()=="windows") + { + Tool &dlltool = builder.get_toolchain().get_tool("DLL"); + dlltool.create_target(*shlib); + } + bin = shlib; + } + else + bin = new Executable(builder, comp, objs); + bin->set_tool(*this); + return bin; +} + +Target *GnuLinker::create_install(Target &target) const +{ + if(SharedLibrary *shlib = dynamic_cast(&target)) + { + Tool © = builder.get_toolchain().get_tool("CP"); + InstalledFile *inst_tgt = dynamic_cast(copy.create_target(target)); + if(architecture->get_system()=="windows") + builder.get_build_graph().add_installed_target(*shlib->get_import_library()); + else + { + string link_name = architecture->create_filename(shlib->get_libname()); + if(link_name!=FS::basename(inst_tgt->get_path())) + inst_tgt->set_symlink(link_name); + } + return inst_tgt; + } + else + return 0; +} + +string GnuLinker::create_build_signature(const BuildInfo &binfo) const +{ + string result = Tool::create_build_signature(binfo); + result += ','; + if(binfo.libmode<=BuildInfo::STATIC) + result += 't'; + else + result += 'd'; + if(binfo.strip) + result += 's'; + if(!binfo.libs.empty()) + { + result += ",l"; + result += join(binfo.libs.begin(), binfo.libs.end(), ",l"); + } + return result; +} + +void GnuLinker::do_prepare(ToolData &tool) const +{ + bool path_found = false; + const FS::Path &sysroot = tool.build_info.sysroot; + const std::string &tool_tag = static_cast(tool).get_tag(); + + const FileTarget *exe = static_cast(tool).get_executable(); + if(exe) + { + ExternalTask::Arguments argv; + argv.push_back(exe->get_path().str()); + argv.push_back("-v"); + argv.push_back("-Wl,--verbose"); + argv.push_back("-nostdlib"); + if(!sysroot.empty()) + argv.push_back("--sysroot="+sysroot.str()); + + builder.get_logger().log("auxcommands", "Running %s", join(argv.begin(), argv.end())); + try + { + string output = ExternalTask::run_and_capture_output(argv, FS::Path(), true); + + string::size_type lib_path = output.find("LIBRARY_PATH="); + if(lib_path!=string::npos) + { + string::size_type newline = output.find('\n', lib_path); + for(const string &p: split(output.substr(lib_path+13, newline-lib_path-13), ':')) + { + FS::Path path = strip(p); + if(!any_equals(tool.system_path, path)) + { + builder.get_logger().log("tools", "Got %s frontend system path: %s", tool_tag, path); + tool.system_path.push_back(path); + } + path_found = true; + } + } + + string::size_type start = 0; + while(startis_native()) + { + tool.system_path.push_back("/lib"); + tool.system_path.push_back("/usr/lib"); + if(architecture->match_name("pc-32-linux")) + { + tool.system_path.push_back("/lib/i386-linux-gnu"); + tool.system_path.push_back("/usr/lib/i386-linux-gnu"); + } + else if(architecture->match_name("pc-64-linux")) + { + tool.system_path.push_back("/lib/x86_64-linux-gnu"); + tool.system_path.push_back("/usr/lib/x86_64-linux-gnu"); + } + } + else + tool.system_path.push_back(format("/usr/%s/lib", architecture->get_cross_prefix())); + } +} + +ExternalTask::Arguments GnuLinker::_run(const Binary &bin, FS::Path &work_dir) +{ + const Tool &tool = *bin.get_tool(); + const Builder &builder = tool.get_builder(); + const Architecture &arch = *tool.get_architecture(); + + ExternalTask::Arguments argv; + argv.push_back(tool.get_executable()->get_path().str()); + + if(const SharedLibrary *shlib = dynamic_cast(&bin)) + { + argv.push_back("-shared"); + argv.push_back("-fPIC"); + if(arch.get_system()!="windows" && !shlib->get_soname().empty()) + { + if(arch.get_system()=="darwin") + { + argv.push_back("-install_name"); + argv.push_back(shlib->get_soname()); + + const string &ver = shlib->get_package()->get_version(); + const string &if_ver = shlib->get_package()->get_interface_version(); + if(!ver.empty() && !if_ver.empty()) + { + argv.push_back("-current_version"); + argv.push_back(ver); + argv.push_back("-compatibility_version"); + argv.push_back(if_ver); + } + } + else + argv.push_back("-Wl,-soname,"+shlib->get_soname()); + } + } + + BuildInfo binfo; + bin.collect_build_info(binfo); + + const FS::Path &sysroot = binfo.sysroot; + if(!sysroot.empty()) + argv.push_back("--sysroot="+sysroot.str()); + + FS::Path lib_dir = builder.get_prefix()/"lib"; + if(binfo.rpath_mode==BuildInfo::ABSOLUTE) + argv.push_back("-Wl,-rpath,"+lib_dir.str()); + else + { + if(binfo.rpath_mode==BuildInfo::RELATIVE) + argv.push_back("-Wl,-rpath,$ORIGIN/../lib"); + argv.push_back("-Wl,-rpath-link,"+lib_dir.str()); + } + + for(const FS::Path &p: binfo.libpath) + argv.push_back("-L"+p.str()); + if(binfo.strip) + argv.push_back("-s"); + if(binfo.threads && arch.get_system()!="windows" && arch.get_system()!="darwin") + argv.push_back("-pthread"); + + const Architecture &native_arch = builder.get_native_arch(); + if(arch.is_native() && arch.get_bits()!=native_arch.get_bits()) + argv.push_back(format("-m%d", arch.get_bits())); + + argv.push_back("-o"); + argv.push_back(relative(bin.get_path(), work_dir).str()); + + for(const string &s: binfo.keep_symbols) + argv.push_back("-u"+s); + + bool static_link_ok = (binfo.libmode<=BuildInfo::STATIC); + + bool has_cplusplus = false; + for(Target *d: bin.get_dependencies()) + { + FileTarget *file = dynamic_cast(d); + Target *tgt = d->get_real_target(); + + if(ObjectFile *obj = dynamic_cast(tgt)) + { + argv.push_back(relative(obj->get_path(), work_dir).str()); + if(obj->get_tool()->get_tag()=="CXX") + has_cplusplus = true; + } + else if(StaticLibrary *stlib = dynamic_cast(tgt)) + argv.push_back((file?file:stlib)->get_path().str()); + else if(SharedLibrary *shlib = dynamic_cast(tgt)) + { + argv.push_back("-l"+shlib->get_libname()); + static_link_ok = false; + } + else if(ImportLibrary *imp = dynamic_cast(tgt)) + { + shlib = imp->get_shared_library(); + if(shlib) + argv.push_back("-l"+shlib->get_libname()); + else + argv.push_back((file?file:imp)->get_path().str()); + static_link_ok = false; + } + } + + for(const string &l: binfo.libs) + if(l.size()>10 && !l.compare(l.size()-10, 10, ".framework")) + { + argv.push_back("-framework"); + argv.push_back(l.substr(0, l.size()-10)); + } + + if(static_link_ok) + argv.push_back("-static"); + else + { + if(has_cplusplus) + { + auto i = binfo.libmodes.find("stdc++"); + if(i!=binfo.libmodes.end() && i->second<=BuildInfo::STATIC) + argv.push_back("-static-libstdc++"); + } + + if(arch.get_system()=="windows") + argv.push_back("-Wl,--enable-auto-import"); + } + + return argv; +}