int linkObjToBinaryGcc(llvm::StringRef outputPath, bool useInternalLinker, llvm::cl::boolOrDefault fullyStaticFlag) { // find gcc for linking const std::string tool = getGcc(); // build arguments ArgsBuilder argsBuilder; argsBuilder.build(outputPath, fullyStaticFlag); Logger::println("Linking with: "); Stream logstr = Logger::cout(); for (const auto &arg : argsBuilder.args) { if (!arg.empty()) { logstr << "'" << arg << "' "; } } logstr << "\n"; // FIXME where's flush ? // try to call linker return executeToolAndWait(tool, argsBuilder.args, global.params.verbose); }
int linkObjToBinary(bool sharedLib) { Logger::println("*** Linking executable ***"); // error string std::string errstr; // find gcc for linking llvm::sys::Path gcc = getGcc(); // get a string version for argv[0] const char* gccStr = gcc.c_str(); // build arguments std::vector<const char*> args; // first the program name ?? args.push_back(gccStr); // object files for (unsigned i = 0; i < global.params.objfiles->dim; i++) { char *p = (char *)global.params.objfiles->data[i]; args.push_back(p); } // output filename std::string output; if (!sharedLib && global.params.exefile) { // explicit output = global.params.exefile; } else if (sharedLib && global.params.objname) { // explicit output = global.params.objname; } else { // inferred // try root module name if (Module::rootModule) output = Module::rootModule->toChars(); else if (global.params.objfiles->dim) output = FileName::removeExt((char*)global.params.objfiles->data[0]); else output = "a.out"; if (sharedLib) { std::string libExt = std::string(".") + global.dll_ext; if (!endsWith(output, libExt)) { if (global.params.os != OSWindows) output = "lib" + output + libExt; else output.append(libExt); } args.push_back("-shared"); } else if (global.params.os == OSWindows && !endsWith(output, ".exe")) { output.append(".exe"); } } args.push_back("-o"); args.push_back(output.c_str()); // set the global gExePath gExePath.set(output); assert(gExePath.isValid()); // create path to exe llvm::sys::Path exedir(llvm::sys::path::parent_path(gExePath.str())); if (!exedir.empty() && !llvm::sys::fs::exists(exedir.str())) { exedir.createDirectoryOnDisk(true, &errstr); if (!errstr.empty()) { error("failed to create path to linking output: %s\n%s", exedir.c_str(), errstr.c_str()); fatal(); } } // additional linker switches for (unsigned i = 0; i < global.params.linkswitches->dim; i++) { char *p = (char *)global.params.linkswitches->data[i]; args.push_back("-Xlinker"); args.push_back(p); } // user libs for (unsigned i = 0; i < global.params.libfiles->dim; i++) { char *p = (char *)global.params.libfiles->data[i]; args.push_back(p); } // default libs bool addSoname = false; switch(global.params.os) { case OSLinux: addSoname = true; args.push_back("-lrt"); // fallthrough case OSMacOSX: args.push_back("-ldl"); // fallthrough case OSFreeBSD: addSoname = true; args.push_back("-lpthread"); args.push_back("-lm"); break; case OSSolaris: args.push_back("-lm"); args.push_back("-lumem"); // solaris TODO break; case OSWindows: // FIXME: I'd assume kernel32 etc break; } //FIXME: enforce 64 bit if (global.params.is64bit) args.push_back("-m64"); else // Assume 32-bit? args.push_back("-m32"); OutBuffer buf; if (opts::createSharedLib && addSoname) { std::string soname = opts::soname.getNumOccurrences() == 0 ? output : opts::soname; if (!soname.empty()) { buf.writestring("-Wl,-soname,"); buf.writestring(soname.c_str()); args.push_back(buf.toChars()); } } // print link command? if (!quiet || global.params.verbose) { // Print it for (int i = 0; i < args.size(); i++) printf("%s ", args[i]); printf("\n"); fflush(stdout); } Logger::println("Linking with: "); std::vector<const char*>::const_iterator I = args.begin(), E = args.end(); Stream logstr = Logger::cout(); for (; I != E; ++I) if (*I) logstr << "'" << *I << "'" << " "; logstr << "\n"; // FIXME where's flush ? // terminate args list args.push_back(NULL); // try to call linker if (int status = llvm::sys::Program::ExecuteAndWait(gcc, &args[0], NULL, NULL, 0,0, &errstr)) { error("linking failed:\nstatus: %d", status); if (!errstr.empty()) error("message: %s", errstr.c_str()); return status; } return 0; }
static int linkObjToBinaryGcc(bool sharedLib) { Logger::println("*** Linking executable ***"); // find gcc for linking std::string gcc(getGcc()); // build arguments std::vector<std::string> args; // object files for (unsigned i = 0; i < global.params.objfiles->dim; i++) { const char *p = static_cast<const char *>(global.params.objfiles->data[i]); args.push_back(p); } // user libs for (unsigned i = 0; i < global.params.libfiles->dim; i++) { const char *p = static_cast<const char *>(global.params.libfiles->data[i]); args.push_back(p); } // output filename std::string output = getOutputName(sharedLib); if (sharedLib) args.push_back("-shared"); args.push_back("-o"); args.push_back(output); // set the global gExePath gExePath = output; //assert(gExePath.isValid()); // create path to exe CreateDirectoryOnDisk(gExePath); #if LDC_LLVM_VER >= 303 // Pass sanitizer arguments to linker. Requires clang. if (opts::sanitize == opts::AddressSanitizer) { args.push_back("-fsanitize=address"); } if (opts::sanitize == opts::MemorySanitizer) { args.push_back("-fsanitize=memory"); } if (opts::sanitize == opts::ThreadSanitizer) { args.push_back("-fsanitize=thread"); } #endif // additional linker switches for (unsigned i = 0; i < global.params.linkswitches->dim; i++) { const char *p = static_cast<const char *>(global.params.linkswitches->data[i]); // Don't push -l and -L switches using -Xlinker, but pass them indirectly // via GCC. This makes sure user-defined paths take precedence over // GCC's builtin LIBRARY_PATHs. if (!p[0] || !(p[0] == '-' && (p[1] == 'l' || p[1] == 'L'))) args.push_back("-Xlinker"); args.push_back(p); } // default libs bool addSoname = false; switch (global.params.targetTriple.getOS()) { case llvm::Triple::Linux: addSoname = true; args.push_back("-lrt"); if (!opts::disableLinkerStripDead) { args.push_back("-Wl,--gc-sections"); } // fallthrough case llvm::Triple::Darwin: case llvm::Triple::MacOSX: args.push_back("-ldl"); // fallthrough case llvm::Triple::FreeBSD: addSoname = true; args.push_back("-lpthread"); args.push_back("-lm"); break; case llvm::Triple::Solaris: args.push_back("-lm"); args.push_back("-lumem"); // solaris TODO break; #if LDC_LLVM_VER < 305 case llvm::Triple::MinGW32: // This is really more of a kludge, as linking in the Winsock functions // should be handled by the pragma(lib, ...) in std.socket, but it // makes LDC behave as expected for now. args.push_back("-lws2_32"); break; #endif default: // OS not yet handled, will probably lead to linker errors. // FIXME: Win32. break; } #if LDC_LLVM_VER >= 305 if (global.params.targetTriple.isWindowsGNUEnvironment()) { // This is really more of a kludge, as linking in the Winsock functions // should be handled by the pragma(lib, ...) in std.socket, but it // makes LDC behave as expected for now. args.push_back("-lws2_32"); } #endif // Only specify -m32/-m64 for architectures where the two variants actually // exist (as e.g. the GCC ARM toolchain doesn't recognize the switches). // MIPS does not have -m32/-m64 but requires -mabi=. if (global.params.targetTriple.get64BitArchVariant().getArch() != llvm::Triple::UnknownArch && global.params.targetTriple.get32BitArchVariant().getArch() != llvm::Triple::UnknownArch) { if (global.params.targetTriple.get64BitArchVariant().getArch() == llvm::Triple::mips64 || global.params.targetTriple.get64BitArchVariant().getArch() == llvm::Triple::mips64el) { switch (getMipsABI()) { case MipsABI::EABI: args.push_back("-mabi=eabi"); break; case MipsABI::O32: args.push_back("-mabi=32"); break; case MipsABI::N32: args.push_back("-mabi=n32"); break; case MipsABI::N64: args.push_back("-mabi=64"); break; case MipsABI::Unknown: break; } } else { if (global.params.is64bit) args.push_back("-m64"); else args.push_back("-m32"); } } if (opts::createSharedLib && addSoname) { std::string soname = opts::soname; if (!soname.empty()) { args.push_back("-Wl,-soname," + soname); } } Logger::println("Linking with: "); std::vector<std::string>::const_iterator I = args.begin(), E = args.end(); Stream logstr = Logger::cout(); for (; I != E; ++I) if (!(*I).empty()) logstr << "'" << *I << "'" << " "; logstr << "\n"; // FIXME where's flush ? // try to call linker return executeToolAndWait(gcc, args, global.params.verbose); }
static int linkObjToBinaryGcc(bool sharedLib) { Logger::println("*** Linking executable ***"); // find gcc for linking const std::string tool = getGcc(); // build arguments std::vector<std::string> args; appendObjectFiles(args); // Link with profile-rt library when generating an instrumented binary. // profile-rt uses Phobos (MD5 hashing) and therefore must be passed on the // commandline before Phobos. if (global.params.genInstrProf) { #if LDC_LLVM_VER >= 308 if (global.params.targetTriple->isOSLinux()) { // For Linux, explicitly define __llvm_profile_runtime as undefined // symbol, so that the initialization part of profile-rt is linked in. args.push_back( ("-Wl,-u," + llvm::getInstrProfRuntimeHookVarName()).str()); } #endif args.push_back("-lldc-profile-rt"); } // user libs for (unsigned i = 0; i < global.params.libfiles->dim; i++) args.push_back((*global.params.libfiles)[i]); // output filename std::string output = getOutputName(sharedLib); if (sharedLib) { args.push_back("-shared"); } if (staticFlag) { args.push_back("-static"); } args.push_back("-o"); args.push_back(output); // set the global gExePath gExePath = output; // assert(gExePath.isValid()); // create path to exe CreateDirectoryOnDisk(gExePath); // Pass sanitizer arguments to linker. Requires clang. if (opts::sanitize == opts::AddressSanitizer) { args.push_back("-fsanitize=address"); } if (opts::sanitize == opts::MemorySanitizer) { args.push_back("-fsanitize=memory"); } if (opts::sanitize == opts::ThreadSanitizer) { args.push_back("-fsanitize=thread"); } // Add LTO link flags before adding the user link switches, such that the user // can pass additional options to the LTO plugin. if (opts::isUsingLTO()) addLTOLinkFlags(args); // additional linker and cc switches (preserve order across both lists) for (unsigned ilink = 0, icc = 0;;) { unsigned linkpos = ilink < opts::linkerSwitches.size() ? opts::linkerSwitches.getPosition(ilink) : std::numeric_limits<unsigned>::max(); unsigned ccpos = icc < opts::ccSwitches.size() ? opts::ccSwitches.getPosition(icc) : std::numeric_limits<unsigned>::max(); if (linkpos < ccpos) { const std::string& p = opts::linkerSwitches[ilink++]; // Don't push -l and -L switches using -Xlinker, but pass them indirectly // via GCC. This makes sure user-defined paths take precedence over // GCC's builtin LIBRARY_PATHs. // Options starting with `-Wl,`, -shared or -static are not handled by // the linker and must be passed to the driver. auto str = llvm::StringRef(p); if (!(str.startswith("-l") || str.startswith("-L") || str.startswith("-Wl,") || str.startswith("-shared") || str.startswith("-static"))) { args.push_back("-Xlinker"); } args.push_back(p); } else if (ccpos < linkpos) { args.push_back(opts::ccSwitches[icc++]); } else { break; } } // libs added via pragma(lib, libname) for (unsigned i = 0; i < global.params.linkswitches->dim; i++) { args.push_back((*global.params.linkswitches)[i]); } // default libs bool addSoname = false; switch (global.params.targetTriple->getOS()) { case llvm::Triple::Linux: addSoname = true; // Make sure we don't do --gc-sections when generating a profile- // instrumented binary. The runtime relies on magic sections, which // would be stripped by gc-section on older version of ld, see bug: // https://sourceware.org/bugzilla/show_bug.cgi?id=19161 if (!opts::disableLinkerStripDead && !global.params.genInstrProf) { args.push_back("-Wl,--gc-sections"); } if (global.params.targetTriple->getEnvironment() == llvm::Triple::Android) { args.push_back("-ldl"); args.push_back("-lm"); break; } args.push_back("-lrt"); // fallthrough case llvm::Triple::Darwin: case llvm::Triple::MacOSX: args.push_back("-ldl"); // fallthrough case llvm::Triple::FreeBSD: case llvm::Triple::NetBSD: case llvm::Triple::OpenBSD: case llvm::Triple::DragonFly: addSoname = true; args.push_back("-lpthread"); args.push_back("-lm"); break; case llvm::Triple::Solaris: args.push_back("-lm"); args.push_back("-lumem"); args.push_back("-lsocket"); args.push_back("-lnsl"); break; default: // OS not yet handled, will probably lead to linker errors. // FIXME: Win32. break; } if (global.params.targetTriple->isWindowsGNUEnvironment()) { // This is really more of a kludge, as linking in the Winsock functions // should be handled by the pragma(lib, ...) in std.socket, but it // makes LDC behave as expected for now. args.push_back("-lws2_32"); } // Only specify -m32/-m64 for architectures where the two variants actually // exist (as e.g. the GCC ARM toolchain doesn't recognize the switches). // MIPS does not have -m32/-m64 but requires -mabi=. if (global.params.targetTriple->get64BitArchVariant().getArch() != llvm::Triple::UnknownArch && global.params.targetTriple->get32BitArchVariant().getArch() != llvm::Triple::UnknownArch) { if (global.params.targetTriple->get64BitArchVariant().getArch() == llvm::Triple::mips64 || global.params.targetTriple->get64BitArchVariant().getArch() == llvm::Triple::mips64el) { switch (getMipsABI()) { case MipsABI::EABI: args.push_back("-mabi=eabi"); break; case MipsABI::O32: args.push_back("-mabi=32"); break; case MipsABI::N32: args.push_back("-mabi=n32"); break; case MipsABI::N64: args.push_back("-mabi=64"); break; case MipsABI::Unknown: break; } } else { switch (global.params.targetTriple->getArch()) { case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::aarch64: case llvm::Triple::aarch64_be: #if LDC_LLVM_VER == 305 case llvm::Triple::arm64: case llvm::Triple::arm64_be: #endif break; default: if (global.params.is64bit) { args.push_back("-m64"); } else { args.push_back("-m32"); } } } } if (global.params.dll && addSoname) { std::string soname = opts::soname; if (!soname.empty()) { args.push_back("-Wl,-soname," + soname); } } Logger::println("Linking with: "); Stream logstr = Logger::cout(); for (const auto &arg : args) { if (!arg.empty()) { logstr << "'" << arg << "'" << " "; } } logstr << "\n"; // FIXME where's flush ? // try to call linker return executeToolAndWait(tool, args, global.params.verbose); }
int linkObjToBinaryGcc(bool sharedLib) { Logger::println("*** Linking executable ***"); // find gcc for linking llvm::sys::Path gcc = getGcc(); // build arguments std::vector<std::string> args; // object files for (unsigned i = 0; i < global.params.objfiles->dim; i++) { char *p = static_cast<char *>(global.params.objfiles->data[i]); args.push_back(p); } // user libs for (unsigned i = 0; i < global.params.libfiles->dim; i++) { char *p = static_cast<char *>(global.params.libfiles->data[i]); args.push_back(p); } // output filename std::string output; if (!sharedLib && global.params.exefile) { // explicit output = global.params.exefile; } else if (sharedLib && global.params.objname) { // explicit output = global.params.objname; } else { // inferred // try root module name if (Module::rootModule) output = Module::rootModule->toChars(); else if (global.params.objfiles->dim) output = FileName::removeExt(static_cast<char*>(global.params.objfiles->data[0])); else output = "a.out"; if (sharedLib) { std::string libExt = std::string(".") + global.dll_ext; if (!endsWith(output, libExt)) { if (global.params.os != OSWindows) output = "lib" + output + libExt; else output.append(libExt); } } else if (global.params.os == OSWindows && !endsWith(output, ".exe")) { output.append(".exe"); } } if (sharedLib) args.push_back("-shared"); args.push_back("-o"); args.push_back(output); // set the global gExePath gExePath.set(output); assert(gExePath.isValid()); // create path to exe CreateDirectoryOnDisk(gExePath.str()); // additional linker switches for (unsigned i = 0; i < global.params.linkswitches->dim; i++) { char *p = static_cast<char *>(global.params.linkswitches->data[i]); args.push_back("-Xlinker"); args.push_back(p); } // default libs bool addSoname = false; switch(global.params.os) { case OSLinux: addSoname = true; args.push_back("-lrt"); // fallthrough case OSMacOSX: args.push_back("-ldl"); // fallthrough case OSFreeBSD: addSoname = true; args.push_back("-lpthread"); args.push_back("-lm"); break; case OSSolaris: args.push_back("-lm"); args.push_back("-lumem"); // solaris TODO break; case OSWindows: // FIXME: I'd assume kernel32 etc break; } //FIXME: enforce 64 bit if (global.params.is64bit) args.push_back("-m64"); else // Assume 32-bit? args.push_back("-m32"); if (opts::createSharedLib && addSoname) { std::string soname = opts::soname; if (!soname.empty()) { args.push_back("-Wl,-soname," + soname); } } Logger::println("Linking with: "); std::vector<std::string>::const_iterator I = args.begin(), E = args.end(); Stream logstr = Logger::cout(); for (; I != E; ++I) if (!(*I).empty()) logstr << "'" << *I << "'" << " "; logstr << "\n"; // FIXME where's flush ? // try to call linker return ExecuteToolAndWait(gcc, args, !quiet || global.params.verbose); }
int linkObjToExecutable(const char* argv0) { Logger::println("*** Linking executable ***"); // error string std::string errstr; // find gcc for linking llvm::sys::Path gcc = getGcc(); // get a string version for argv[0] const char* gccStr = gcc.c_str(); // build arguments std::vector<const char*> args; // first the program name ?? args.push_back(gccStr); // object files for (int i = 0; i < global.params.objfiles->dim; i++) { char *p = (char *)global.params.objfiles->data[i]; args.push_back(p); } // output filename std::string exestr; if (global.params.exefile) { // explicit exestr = global.params.exefile; } else { // inferred // try root module name if (Module::rootModule) exestr = Module::rootModule->toChars(); else if (global.params.objfiles->dim) exestr = FileName::removeExt((char*)global.params.objfiles->data[0]); else exestr = "a.out"; } if (global.params.os == OSWindows && !(exestr.rfind(".exe") == exestr.length()-4)) exestr.append(".exe"); args.push_back("-o"); args.push_back(exestr.c_str()); // set the global gExePath gExePath.set(exestr); assert(gExePath.isValid()); // create path to exe llvm::sys::Path exedir(gExePath); exedir.set(gExePath.getDirname()); if (!exedir.exists()) { exedir.createDirectoryOnDisk(true, &errstr); if (!errstr.empty()) { error("failed to create path to linking output: %s\n%s", exedir.c_str(), errstr.c_str()); fatal(); } } // additional linker switches for (int i = 0; i < global.params.linkswitches->dim; i++) { char *p = (char *)global.params.linkswitches->data[i]; args.push_back(p); } // user libs for (int i = 0; i < global.params.libfiles->dim; i++) { char *p = (char *)global.params.libfiles->data[i]; args.push_back(p); } // default libs switch(global.params.os) { case OSLinux: args.push_back("-lrt"); // fallthrough case OSMacOSX: args.push_back("-ldl"); // fallthrough case OSFreeBSD: args.push_back("-lpthread"); args.push_back("-lm"); break; case OSSolaris: args.push_back("-lm"); args.push_back("-lumem"); // solaris TODO break; case OSWindows: // FIXME: I'd assume kernel32 etc break; } //FIXME: enforce 64 bit if (global.params.is64bit) args.push_back("-m64"); else // Assume 32-bit? args.push_back("-m32"); // print link command? if (!quiet || global.params.verbose) { // Print it for (int i = 0; i < args.size(); i++) printf("%s ", args[i]); printf("\n"); fflush(stdout); } Logger::println("Linking with: "); std::vector<const char*>::const_iterator I = args.begin(), E = args.end(); Stream logstr = Logger::cout(); for (; I != E; ++I) if (*I) logstr << "'" << *I << "'" << " "; logstr << "\n"; // FIXME where's flush ? // terminate args list args.push_back(NULL); // try to call linker if (int status = llvm::sys::Program::ExecuteAndWait(gcc, &args[0], NULL, NULL, 0,0, &errstr)) { error("linking failed:\nstatus: %d", status); if (!errstr.empty()) error("message: %s", errstr.c_str()); return status; } return 0; }