diff --git a/driver/linker-gcc.cpp b/driver/linker-gcc.cpp index 20c69aabb0..1b364fb7e6 100644 --- a/driver/linker-gcc.cpp +++ b/driver/linker-gcc.cpp @@ -556,7 +556,14 @@ void ArgsBuilder::build(llvm::StringRef outputPath, } } - addDefaultPlatformLibs(); + const auto explicitPlatformLibs = getExplicitPlatformLibs(); + if (explicitPlatformLibs.hasValue()) { + for (const auto &name : explicitPlatformLibs.getValue()) { + args.push_back("-l" + name); + } + } else { + addDefaultPlatformLibs(); + } addTargetFlags(); } diff --git a/driver/linker-msvc.cpp b/driver/linker-msvc.cpp index c76cd90aef..db2eb24844 100644 --- a/driver/linker-msvc.cpp +++ b/driver/linker-msvc.cpp @@ -206,32 +206,23 @@ int linkObjToBinaryMSVC(llvm::StringRef outputPath, addSwitch(ls); } - llvm::Optional> platformLibNames = - getExplicitPlatformLibs(); - - if (platformLibNames.hasValue()) { - args.insert( - args.end(), - std::make_move_iterator(platformLibNames.getValue().begin()), - std::make_move_iterator(platformLibNames.getValue().end())); + auto explicitPlatformLibs = getExplicitPlatformLibs(); + if (explicitPlatformLibs.hasValue()) { + for (auto &lib : explicitPlatformLibs.getValue()) { + args.push_back(llvm::sys::path::has_extension(lib) ? std::move(lib) + : lib + ".lib"); + } } else { // default platform libs // TODO check which libaries are necessary - args.push_back("kernel32.lib"); - args.push_back("user32.lib"); - args.push_back("gdi32.lib"); - args.push_back("winspool.lib"); - args.push_back("shell32.lib"); // required for dmain2.d - args.push_back("ole32.lib"); - args.push_back("oleaut32.lib"); - args.push_back("uuid.lib"); - args.push_back("comdlg32.lib"); - args.push_back("advapi32.lib"); - - // these get pulled in by druntime (rt/msvc.c); include explicitly for - // -betterC convenience (issue #3035) - args.push_back("oldnames.lib"); - args.push_back("legacy_stdio_definitions.lib"); + args.insert(args.end(), + {"kernel32.lib", "user32.lib", "gdi32.lib", "winspool.lib", + "shell32.lib", // required for dmain2.d + "ole32.lib", "oleaut32.lib", "uuid.lib", "comdlg32.lib", + "advapi32.lib", + // these get pulled in by druntime (rt/msvc.c); include + // explicitly for -betterC convenience (issue #3035) + "oldnames.lib", "legacy_stdio_definitions.lib"}); } Logger::println("Linking with: "); diff --git a/driver/linker.cpp b/driver/linker.cpp index bc926e61f0..3fc08ca9d7 100644 --- a/driver/linker.cpp +++ b/driver/linker.cpp @@ -32,6 +32,11 @@ static cl::opt linkInternally("link-internally", cl::ZeroOrMore, constexpr bool linkInternally = false; #endif +static cl::opt platformLib( + "platformlib", cl::ZeroOrMore, cl::value_desc("lib1,lib2,..."), + cl::desc("Platform libraries to link with (overrides previous)"), + cl::cat(opts::linkingCategory)); + static cl::opt noDefaultLib( "nodefaultlib", cl::ZeroOrMore, cl::Hidden, cl::desc("Don't add a default library for linking implicitly")); @@ -41,11 +46,6 @@ static cl::opt cl::desc("Default libraries to link with (overrides previous)"), cl::cat(opts::linkingCategory)); -static cl::opt platformLib( - "platformlib", cl::ZeroOrMore, cl::value_desc("lib1,lib2,..."), - cl::desc("Platform libraries to link with (overrides previous)"), - cl::cat(opts::linkingCategory)); - static cl::opt debugLib( "debuglib", cl::ZeroOrMore, cl::Hidden, cl::value_desc("lib1,lib2,..."), cl::desc("Debug versions of default libraries (overrides previous). If the " @@ -141,23 +141,19 @@ static std::string getOutputName() { ////////////////////////////////////////////////////////////////////////////// -static std::vector getLibNames(const cl::opt& opt, - const bool addDebugSuffix, - const bool addSharedSuffix) { +static std::vector +parseLibNames(llvm::StringRef commaSeparatedList, llvm::StringRef suffix = {}) { std::vector result; - std::stringstream libNames(opt); - while (libNames.good()) { + std::stringstream list(commaSeparatedList); + while (list.good()) { std::string lib; - std::getline(libNames, lib, ','); + std::getline(list, lib, ','); if (lib.empty()) { continue; } - result.emplace_back(( - llvm::Twine(lib) + - (addDebugSuffix ? "-debug" : "") + - (addSharedSuffix ? "-shared" : "")).str()); + result.push_back(suffix.empty() ? std::move(lib) : (lib + suffix).str()); } return result; @@ -173,14 +169,20 @@ static std::vector getDefaultLibNames() { "overrides the existing list instead of appending to " "it. Please use the latter instead."); } else if (!global.params.betterC) { - const bool addDebugSuffix = - (linkDefaultLibDebug && debugLib.getNumOccurrences() == 0); - const bool addSharedSuffix = linkAgainstSharedDefaultLibs(); + llvm::StringRef list = defaultLib; + std::string suffix; - result = getLibNames( - linkDefaultLibDebug && !addDebugSuffix ? debugLib : defaultLib, - addDebugSuffix, - addSharedSuffix); + if (linkDefaultLibDebug) { + if (debugLib.getNumOccurrences() == 0) + suffix = "-debug"; + else + list = debugLib; + } + if (linkAgainstSharedDefaultLibs()) { + suffix += "-shared"; + } + + result = parseLibNames(list, suffix); } return result; @@ -189,13 +191,9 @@ static std::vector getDefaultLibNames() { ////////////////////////////////////////////////////////////////////////////// llvm::Optional> getExplicitPlatformLibs() { - llvm::Optional> result; - - if (platformLib.getNumOccurrences() > 0) { - result = getLibNames(platformLib, false, false); - } - - return result; + if (platformLib.getNumOccurrences() > 0) + return parseLibNames(platformLib); + return llvm::None; } ////////////////////////////////////////////////////////////////////////////// diff --git a/driver/linker.h b/driver/linker.h index f2f37f7fd3..f9be0ad848 100644 --- a/driver/linker.h +++ b/driver/linker.h @@ -40,7 +40,7 @@ llvm::cl::boolOrDefault linkFullyStatic(); bool linkAgainstSharedDefaultLibs(); /** - * Returns the value of -platformlib. + * Returns the -platformlib library names, if specified. */ llvm::Optional> getExplicitPlatformLibs(); diff --git a/tests/linking/platformlib.d b/tests/linking/platformlib.d index 2c31e69790..9ccf664286 100644 --- a/tests/linking/platformlib.d +++ b/tests/linking/platformlib.d @@ -1,21 +1,27 @@ -/* Make sure -platformlib overrides the default platform libraries list. - * We only care about the platform libs in the linker command line; - * make sure linking fails in all cases (no main()) as linking would - * fail without the platform libraries anyway. Finally this option is - * relevant only for windows targets so make sure we target Windows with - * -mtriple=x86_64-unknown-windows-coff. - */ +// Make sure -platformlib overrides the default platform libraries list. -// RUN: not %ldc -v -mtriple=x86_64-unknown-windows-coff -platformlib= %s | FileCheck %s -// CHECK-NOT: kernel32.lib -// CHECK-NOT: user32 -// CHECK-NOT: gdi32 -// CHECK-NOT: winspool -// CHECK-NOT: shell32 -// CHECK-NOT: ole32 -// CHECK-NOT: oleaut32 -// CHECK-NOT: uuid -// CHECK-NOT: comdlg32 -// CHECK-NOT: advapi32 -// CHECK-NOT: oldnames -// CHECK-NOT: legacy_stdio_definitions + +// RUN: %ldc %s -platformlib= -gcc=echo -linker=echo | FileCheck --check-prefix=EMPTY %s + +// EMPTY-NOT: -lrt +// EMPTY-NOT: -ldl +// EMPTY-NOT: -lpthread +// EMPTY-NOT: -lm + +// EMPTY-NOT: kernel32 +// EMPTY-NOT: user32 +// EMPTY-NOT: gdi32 +// EMPTY-NOT: winspool +// EMPTY-NOT: shell32 +// EMPTY-NOT: ole32 +// EMPTY-NOT: oleaut32 +// EMPTY-NOT: uuid +// EMPTY-NOT: comdlg32 +// EMPTY-NOT: advapi32 +// EMPTY-NOT: oldnames +// EMPTY-NOT: legacy_stdio_definitions + + +// RUN: %ldc %s -platformlib=myPlatformLib1,myPlatformLib2 -gcc=echo -linker=echo | FileCheck --check-prefix=CUSTOM %s + +// CUSTOM: {{(-lmyPlatformLib1 -lmyPlatformLib2)|(myPlatformLib1.lib myPlatformLib2.lib)}}