Skip to content

Commit

Permalink
Make all static library exports contribute to dlls on Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
rikkimax committed Mar 5, 2023
1 parent ab037ce commit c8291b0
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 1 deletion.
8 changes: 8 additions & 0 deletions changelog/static_libraries_exported_dll.dd
@@ -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
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
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
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
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
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

0 comments on commit c8291b0

Please sign in to comment.