Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make all static library exports contribute to dlls on Windows #2614

Merged
merged 1 commit into from
Mar 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions changelog/static_libraries_exported_dll.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Static libraries now contribute towards DLL exports on Windows

Previously if you did not explicitly pull in an object file within a static library, it was elided by the linker automatically.
This pulls them in automatically for linkers compatible with Microsoft's linker via the ``/WHOLEARCHIVE:file`` flag. Supports LLD.

It does not affect executables, although DLL's being built as dependencies by DUB will include it.

If you have previously used a linker script (.def) or ``/WHOLEARCHIVE`` you may be able to remove them from your builds.
3 changes: 3 additions & 0 deletions source/dub/compilers/compiler.d
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,9 @@ interface Compiler {

return build_platform;
}

/// Given a platform specification, determine if a compiler is on Windows and PE-COFF with MSVC link compatible linker.
bool isWindowsCOFF(in BuildPlatform platform);
}

private {
Expand Down
6 changes: 6 additions & 0 deletions source/dub/compilers/dmd.d
Original file line number Diff line number Diff line change
Expand Up @@ -434,4 +434,10 @@ config /etc/dmd.conf
|| arg.startsWith("-defaultlib=");
}
}

bool isWindowsCOFF(in BuildPlatform platform)
{
// x86_omf and x86_mscoff shouldn't be something you have to worry about here, but just in case something leaks
return platform.isWindows && platform.architecture.canFind("x86", "x86_64", "x86_mscoff") && !platform.architecture.canFind("x86_omf");
}
}
5 changes: 5 additions & 0 deletions source/dub/compilers/gdc.d
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,11 @@ class GDCCompiler : Compiler {

return dflags;
}

bool isWindowsCOFF(in BuildPlatform platform)
{
return false;
}
}

private string extractTarget(const string[] args) { auto i = args.countUntil("-o"); return i >= 0 ? args[i+1] : null; }
Expand Down
6 changes: 6 additions & 0 deletions source/dub/compilers/ldc.d
Original file line number Diff line number Diff line change
Expand Up @@ -322,4 +322,10 @@ config /etc/ldc2.conf (x86_64-pc-linux-gnu)
|| arg.startsWith("-mtriple=");
}
}

bool isWindowsCOFF(in BuildPlatform platform)
{
// What will happen on ARM Windows? Who knows. Once LDC ships for ARM, lets find out!
return platform.isWindows();
}
}
38 changes: 37 additions & 1 deletion source/dub/generators/build.d
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,32 @@ class BuildGenerator : ProjectGenerator {
const copyDynamicLibDepsLinkerFiles = rootTT == TargetType.dynamicLibrary || rootTT == TargetType.none;
const copyDynamicLibDepsRuntimeFiles = copyDynamicLibDepsLinkerFiles || rootTT == TargetType.executable;

bool[string] visited;
// Check to see if given a compiler and platform target
// are Windows and linking using a MSVC link compatible linker.
const isWindowsCOFF = settings.compiler.isWindowsCOFF(settings.platform);

bool[string] visited, visitedStaticInDll;

void visitStaticLibsInDll(ref BuildSettings bs, string target) {
if (target in visitedStaticInDll) return;
visitedStaticInDll[target] = true;

auto ti = targets[target];
if (ti.buildSettings.targetType != TargetType.staticLibrary)
return;

const ldepPath = target_paths[target].toNativeString();

// Add the MSVC link /WHOLEARCHIVE flag with static library path passed in
// the purpose of this is to allow all exports from a static library to contribute
// towards the dll's exports.
bs.addLFlags("/WHOLEARCHIVE:" ~ ldepPath);

foreach (ldep; ti.linkDependencies) {
visitStaticLibsInDll(bs, ldep);
}
}

void buildTargetRec(string target)
{
if (target in visited) return;
Expand All @@ -111,6 +136,17 @@ class BuildGenerator : ProjectGenerator {
NativePath[] additional_dep_files;
auto bs = ti.buildSettings.dup;
const tt = bs.targetType;

// Windows only behavior for DLL's with static library dependencies
if (tt == TargetType.dynamicLibrary && isWindowsCOFF) {
// discover all static libraries that are going into our DLL
visitedStaticInDll = null;

foreach (ldep; ti.linkDependencies) {
visitStaticLibsInDll(bs, ldep);
}
}

foreach (ldep; ti.linkDependencies) {
const ldepPath = target_paths[ldep].toNativeString();
const doLink = tt != TargetType.staticLibrary && !(bs.options & BuildOption.syntaxOnly);
Expand Down