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

LDC: Apply dflags affecting symbol visibility to all deps #2660

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ jobs:
# FIXME: DMD fails a few tests on Windows; remove them for now
if [[ '${{ matrix.dc }}' = dmd* ]]; then
# DLL support is lacking
rm -rf test/{1-dynLib-simple,2-dynLib-dep,2-dynLib-with-staticLib-dep}
rm -rf test/{1-dynLib-simple,2-dynLib-dep,2-dynLib-with-staticLib-dep,dynLib-monolith}
# Unicode in paths too
rm -rf test/issue130-unicode-СНА*
# ImportC probably requires set-up MSVC environment variables
Expand Down
20 changes: 20 additions & 0 deletions changelog/ldc_visibility.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
LDC: Apply dflags affecting symbol visibility to all deps

The `-fvisibility` (and, on Windows, `-dllimport` and `-link-defaultlib-shared`)
flags in effect for some root project are now passed down to all (direct and indirect)
dependencies of that root project - when using LDC. This is mainly important on
Windows, for executables linked against shared druntime/Phobos, as well as DLLs.

For Windows executables to be linked against the druntime/Phobos DLLs via
`-link-defaultlib-shared`, this means that all its static-library dub dependencies
are now automatically compiled with `-link-defaultlib-shared` too, thus defaulting to
`-dllimport=defaultLibsOnly`, which is a (Windows-specific) requirement for this
scenario.

With LDC, code ending up in a Windows DLL is compiled with `-fvisibility=public
-dllimport=all` by default (implicit flags added by dub). This can now be overridden
via e.g. `-fvisibility=hidden -dllimport=defaultLibsOnly` to generate a DLL exporting
only select symbols with explicit `export` visibility and linking all dub deps
statically (but druntime/Phobos dynamically). If you want to additionally link druntime
and Phobos statically into the DLL, use `-link-defaultlib-shared=false
-fvisibility=hidden -dllimport=none` instead.
33 changes: 33 additions & 0 deletions source/dub/generators/generator.d
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,39 @@ class ProjectGenerator
configureDependents(*roottarget, targets);
visited.clear();

// LDC: need to pass down dflags affecting symbol visibility, especially on Windows
if (genSettings.platform.compiler == "ldc")
{
const isWindows = genSettings.platform.isWindows();
bool passDownDFlag(string flag)
{
if (flag.startsWith("--"))
flag = flag[1 .. $];
return flag.startsWith("-fvisibility=") || (isWindows &&
(flag.startsWith("-link-defaultlib-shared") ||
flag.startsWith("-dllimport=")));
}

// all dflags from dependencies have already been added to the root project
auto rootDFlagsToPassDown = roottarget.buildSettings.dflags.filter!passDownDFlag.array;

if (rootDFlagsToPassDown.length)
{
foreach (name, ref ti; targets)
{
if (&ti != roottarget && ti.buildSettings.targetType != TargetType.dynamicLibrary)
{
import std.range : chain;
ti.buildSettings.dflags = ti.buildSettings.dflags
// remove all existing visibility flags first to reduce duplicates
.filter!(f => !passDownDFlag(f))
.chain(rootDFlagsToPassDown)
.array;
}
}
}
}

// 4. As an extension to configureDependents we need to copy any injectSourceFiles
// in our dependencies (ignoring targetType)
void configureDependentsFinalImages(ref TargetInfo ti, TargetInfo[string] targets, ref TargetInfo finalBinaryTarget, size_t level = 0)
Expand Down
39 changes: 39 additions & 0 deletions test/dynLib-monolith.script.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/+ dub.json: {
"name": "dynlib-monolith-script"
} +/
module dynlib_monolith_script;

import std.algorithm, std.path, std.process, std.stdio;

int main()
{
const dc = environment.get("DC", "dmd");
if (!dc.startsWith("ldc"))
{
writeln("Skipping test, needs LDC");
return 0;
}

// enforce a full build (2 static libs, 1 dynamic one) and collect -v output
enum projDir = dirName(__FILE_FULL_PATH__).buildPath("dynLib-monolith");
const res = execute([environment.get("DUB", "dub"), "build", "-f", "-v", "--root", projDir]);

int errorOut(string msg)
{
writeln("Error: " ~ msg);
writeln("===========================================================");
writeln(res.output);
writeln("===========================================================");
return 1;
}

if (res.status != 0)
return errorOut("The dub invocation failed:");

version (Windows) enum needle = " -fvisibility=hidden -dllimport=defaultLibsOnly";
else enum needle = " -fvisibility=hidden";
if (res.output.count(needle) != 3)
return errorOut("Cannot find exactly 3 occurrences of '" ~ needle ~ "' in the verbose dub output:");

return 0;
}
Empty file added test/dynLib-monolith/.no_run
Empty file.
Empty file added test/dynLib-monolith/.no_test
Empty file.
17 changes: 17 additions & 0 deletions test/dynLib-monolith/dub.sdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name "dynlib-monolith"
description "A 'monolithic' dynamic library, linking all dependencies statically (except for shared druntime/Phobos) and exporting only select symbols explicitly via 'export'"
targetType "dynamicLibrary"
dependency "inner_dep" path="inner_dep"

# With LDC, `-fvisibility=hidden` is passed down for compiling all dependencies.
dflags "-fvisibility=hidden" platform="ldc"
dflags "-fvisibility=hidden" platform="gdc"
# not supported by DMD

# With LDC on Windows, code ending up in a DLL is compiled with
# `-fvisibility=public -dllimport=all` by default. So we additionally need to
# override `-dllimport` to dllimport from the shared druntime/Phobos DLLs only
# (used by default for dynamic libraries; with static druntime/Phobos via
# `-link-defaultlib-shared=false`, use `-dllimport=none`).
# This flag is also passed down to all deps.
dflags "-dllimport=defaultLibsOnly" platform="windows-ldc"
4 changes: 4 additions & 0 deletions test/dynLib-monolith/inner_dep/dub.sdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
name "inner_dep"
description "A static library depending on another static library"
targetType "staticLibrary"
dependency "staticlib-simple" path="../../1-staticLib-simple"
7 changes: 7 additions & 0 deletions test/dynLib-monolith/inner_dep/source/inner_dep/mod.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module inner_dep.mod;

void innerDepFunction()
{
import staticlib.app;
entry();
}
7 changes: 7 additions & 0 deletions test/dynLib-monolith/source/library.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module library;

export void foo()
{
import inner_dep.mod;
innerDepFunction();
}
Empty file.
11 changes: 11 additions & 0 deletions test/exe-shared-defaultlib/dub.sdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name "exe-shared-defaultlib"
description "An executable with a statically linked dep, linked against *shared* druntime/Phobos"
targetType "executable"
dependency "staticlib-simple" path="../1-staticLib-simple/"

# With LDC on Windows, `-link-defaultlib-shared` is passed down for compiling
# all dependencies (for an implicit `-dllimport=defaultLibsOnly`).
dflags "-link-defaultlib-shared" platform="ldc"

# no libphobos2.dll/dylib with DMD on Windows/Mac
dflags "-defaultlib=libphobos2.so" platform="linux-dmd"
7 changes: 7 additions & 0 deletions test/exe-shared-defaultlib/source/app.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module app;
import staticlib.app;

void main()
{
entry();
}
Loading