Skip to content

Commit 076022c

Browse files
rikkimaxdlang-bot
authored andcommitted
Make all static library exports contribute to dlls on Windows
1 parent ab037ce commit 076022c

File tree

6 files changed

+65
-1
lines changed

6 files changed

+65
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Static libraries now contribute towards DLL exports on Windows
2+
3+
Previously if you did not explicitly pull in an object file within a static library, it was elided by the linker automatically.
4+
This pulls them in automatically for linkers compatible with Microsoft's linker via the ``/WHOLEARCHIVE:file`` flag. Supports LLD.
5+
6+
It does not affect executables, although DLL's being built as dependencies by DUB will include it.
7+
8+
If you have previously used a linker script (.def) or ``/WHOLEARCHIVE`` you may be able to remove them from your builds.

source/dub/compilers/compiler.d

+3
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,9 @@ interface Compiler {
217217

218218
return build_platform;
219219
}
220+
221+
/// Given a platform specification, determine if a compiler is on Windows and PE-COFF with MSVC link compatible linker.
222+
bool isWindowsCOFF(in BuildPlatform platform);
220223
}
221224

222225
private {

source/dub/compilers/dmd.d

+6
Original file line numberDiff line numberDiff line change
@@ -434,4 +434,10 @@ config /etc/dmd.conf
434434
|| arg.startsWith("-defaultlib=");
435435
}
436436
}
437+
438+
bool isWindowsCOFF(in BuildPlatform platform)
439+
{
440+
// x86_omf and x86_mscoff shouldn't be something you have to worry about here, but just in case something leaks
441+
return platform.isWindows && platform.architecture.canFind("x86", "x86_64", "x86_mscoff") && !platform.architecture.canFind("x86_omf");
442+
}
437443
}

source/dub/compilers/gdc.d

+5
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,11 @@ class GDCCompiler : Compiler {
259259

260260
return dflags;
261261
}
262+
263+
bool isWindowsCOFF(in BuildPlatform platform)
264+
{
265+
return false;
266+
}
262267
}
263268

264269
private string extractTarget(const string[] args) { auto i = args.countUntil("-o"); return i >= 0 ? args[i+1] : null; }

source/dub/compilers/ldc.d

+6
Original file line numberDiff line numberDiff line change
@@ -322,4 +322,10 @@ config /etc/ldc2.conf (x86_64-pc-linux-gnu)
322322
|| arg.startsWith("-mtriple=");
323323
}
324324
}
325+
326+
bool isWindowsCOFF(in BuildPlatform platform)
327+
{
328+
// What will happen on ARM Windows? Who knows. Once LDC ships for ARM, lets find out!
329+
return platform.isWindows();
330+
}
325331
}

source/dub/generators/build.d

+37-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,32 @@ class BuildGenerator : ProjectGenerator {
9797
const copyDynamicLibDepsLinkerFiles = rootTT == TargetType.dynamicLibrary || rootTT == TargetType.none;
9898
const copyDynamicLibDepsRuntimeFiles = copyDynamicLibDepsLinkerFiles || rootTT == TargetType.executable;
9999

100-
bool[string] visited;
100+
// Check to see if given a compiler and platform target
101+
// are Windows and linking using a MSVC link compatible linker.
102+
const isWindowsCOFF = settings.compiler.isWindowsCOFF(settings.platform);
103+
104+
bool[string] visited, visitedStaticInDll;
105+
106+
void visitStaticLibsInDll(ref BuildSettings bs, string target) {
107+
if (target in visitedStaticInDll) return;
108+
visitedStaticInDll[target] = true;
109+
110+
auto ti = targets[target];
111+
if (ti.buildSettings.targetType != TargetType.staticLibrary)
112+
return;
113+
114+
const ldepPath = target_paths[target].toNativeString();
115+
116+
// Add the MSVC link /WHOLEARCHIVE flag with static library path passed in
117+
// the purpose of this is to allow all exports from a static library to contribute
118+
// towards the dll's exports.
119+
bs.addLFlags("/WHOLEARCHIVE:" ~ ldepPath);
120+
121+
foreach (ldep; ti.linkDependencies) {
122+
visitStaticLibsInDll(bs, ldep);
123+
}
124+
}
125+
101126
void buildTargetRec(string target)
102127
{
103128
if (target in visited) return;
@@ -111,6 +136,17 @@ class BuildGenerator : ProjectGenerator {
111136
NativePath[] additional_dep_files;
112137
auto bs = ti.buildSettings.dup;
113138
const tt = bs.targetType;
139+
140+
// Windows only behavior for DLL's with static library dependencies
141+
if (tt == TargetType.dynamicLibrary && isWindowsCOFF) {
142+
// discover all static libraries that are going into our DLL
143+
visitedStaticInDll = null;
144+
145+
foreach (ldep; ti.linkDependencies) {
146+
visitStaticLibsInDll(bs, ldep);
147+
}
148+
}
149+
114150
foreach (ldep; ti.linkDependencies) {
115151
const ldepPath = target_paths[ldep].toNativeString();
116152
const doLink = tt != TargetType.staticLibrary && !(bs.options & BuildOption.syntaxOnly);

0 commit comments

Comments
 (0)