Skip to content

Commit

Permalink
Windows: Make -fvisibility=public export all defined symbols
Browse files Browse the repository at this point in the history
To pave the way for simple DLL generation (end goal:
druntime-ldc-shared.dll).

The dllexport storage class for functions definitions is enough; the
automatically generated import .lib seems to resolve the regular symbol
name to the actual symbol (__imp_*), so dllimport for declarations seems
superfluous.

For global variables, things are apparently different unfortunately.
  • Loading branch information
kinke committed Apr 23, 2021
1 parent e6deb6c commit f5050bc
Show file tree
Hide file tree
Showing 9 changed files with 61 additions and 37 deletions.
15 changes: 9 additions & 6 deletions driver/cl_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,15 @@ static cl::opt<bool, true>
createSharedLib("shared", cl::desc("Create shared library (DLL)"),
cl::ZeroOrMore, cl::location(global.params.dll));

cl::opt<unsigned char> defaultToHiddenVisibility(
"fvisibility", cl::ZeroOrMore,
cl::desc("Default visibility of symbols (not relevant for Windows)"),
cl::values(clEnumValN(0, "default", "Export all symbols"),
clEnumValN(1, "hidden",
"Only export symbols marked with 'export'")));
cl::opt<SymbolVisibility> symbolVisibility(
"fvisibility", cl::ZeroOrMore, cl::desc("Default visibility of symbols"),
cl::init(SymbolVisibility::default_),
cl::values(clEnumValN(SymbolVisibility::default_, "default",
"Hidden for Windows targets, otherwise public"),
clEnumValN(SymbolVisibility::hidden, "hidden",
"Only export symbols marked with 'export'"),
clEnumValN(SymbolVisibility::public_, "public",
"Export all symbols")));

static cl::opt<bool, true> verbose("v", cl::desc("Verbose"), cl::ZeroOrMore,
cl::location(global.params.verbose));
Expand Down
3 changes: 2 additions & 1 deletion driver/cl_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ extern cl::opt<std::string> mTargetTriple;
extern cl::opt<std::string> mABI;
extern FloatABI::Type floatABI;
extern cl::opt<bool> disableLinkerStripDead;
extern cl::opt<unsigned char> defaultToHiddenVisibility;
enum class SymbolVisibility { default_, hidden, public_ };
extern cl::opt<SymbolVisibility> symbolVisibility;
extern cl::opt<bool> noPLT;
extern cl::opt<bool> useDIP25;

Expand Down
12 changes: 1 addition & 11 deletions gen/functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -659,12 +659,6 @@ void DtoDeclareFunction(FuncDeclaration *fdecl, const bool willDefine) {

func->setCallingConv(gABI->callingConv(link, f, fdecl));

if (global.params.targetTriple->isOSWindows() && fdecl->isExport()) {
func->setDLLStorageClass(fdecl->isImportedSymbol()
? LLGlobalValue::DLLImportStorageClass
: LLGlobalValue::DLLExportStorageClass);
}

IF_LOG Logger::cout() << "func = " << *func << std::endl;

// add func to IRFunc
Expand Down Expand Up @@ -1143,9 +1137,7 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
return;
}

if (opts::defaultToHiddenVisibility && !fd->isExport()) {
func->setVisibility(LLGlobalValue::HiddenVisibility);
}
setVisibility(fd, func);

// if this function is naked, we take over right away! no standard processing!
if (fd->naked) {
Expand Down Expand Up @@ -1185,8 +1177,6 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
setLinkage(lwc, func);
}

assert(!func->hasDLLImportStorageClass());

// function attributes
if (gABI->needsUnwindTables()) {
func->addFnAttr(LLAttribute::UWTable);
Expand Down
6 changes: 4 additions & 2 deletions gen/naked.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "dmd/mangle.h"
#include "dmd/statement.h"
#include "dmd/template.h"
#include "driver/cl_options.h"
#include "gen/dvalue.h"
#include "gen/funcgenstate.h"
#include "gen/irstate.h"
Expand Down Expand Up @@ -240,8 +241,9 @@ void DtoDefineNakedFunction(FuncDeclaration *fd) {
gIR->module.appendModuleInlineAsm(asmstr.str());
asmstr.str("");

if (global.params.targetTriple->isWindowsMSVCEnvironment() &&
fd->isExport()) {
if (global.params.targetTriple->isOSWindows() &&
(opts::symbolVisibility == opts::SymbolVisibility::public_ ||
fd->isExport())) {
// Embed a linker switch telling the MS linker to export the naked function.
// This mimics the effect of the dllexport attribute for regular functions.
const auto linkerSwitch = std::string("/EXPORT:") + mangle;
Expand Down
13 changes: 11 additions & 2 deletions gen/tollvm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,17 @@ void setLinkageAndVisibility(Dsymbol *sym, llvm::GlobalObject *obj) {
}

void setVisibility(Dsymbol *sym, llvm::GlobalObject *obj) {
if (opts::defaultToHiddenVisibility && !sym->isExport())
obj->setVisibility(LLGlobalValue::HiddenVisibility);
if (global.params.targetTriple->isOSWindows()) {
if (opts::symbolVisibility == opts::SymbolVisibility::public_ ||
sym->isExport()) {
obj->setDLLStorageClass(LLGlobalValue::DLLExportStorageClass);
}
} else {
if (opts::symbolVisibility == opts::SymbolVisibility::hidden &&
!sym->isExport()) {
obj->setVisibility(LLGlobalValue::HiddenVisibility);
}
}
}

////////////////////////////////////////////////////////////////////////////////
Expand Down
11 changes: 0 additions & 11 deletions ir/irvar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,6 @@ void IrGlobal::declare() {
// as well).
gvar->setAlignment(LLMaybeAlign(DtoAlignment(V)));

// Windows: initialize DLL storage class with `dllimport` for `export`ed
// symbols
if (global.params.targetTriple->isOSWindows() && V->isExport()) {
gvar->setDLLStorageClass(LLGlobalValue::DLLImportStorageClass);
}

applyVarDeclUDAs(V, gvar);

if (dynamicCompileConst)
Expand All @@ -128,11 +122,6 @@ void IrGlobal::define() {
auto gvar = llvm::cast<LLGlobalVariable>(value);
value = gIR->setGlobalVarInitializer(gvar, initVal, V);

// Finalize DLL storage class.
if (gvar->hasDLLImportStorageClass()) {
gvar->setDLLStorageClass(LLGlobalValue::DLLExportStorageClass);
}

// If this global is used from a naked function, we need to create an
// artificial "use" for it, or it could be removed by the optimizer if
// the only reference to it is in inline asm.
Expand Down
11 changes: 7 additions & 4 deletions tests/codegen/export.d
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,19 @@

export
{
// CHECK-DAG: @{{.*}}exportedGlobal{{.*}} = dllexport
// CHECK: @{{.*}}exportedGlobal{{.*}} = dllexport
extern(C) __gshared void* exportedGlobal;

// CHECK-DAG: @{{.*}}importedGlobal{{.*}} = external dllimport
// CHECK: @{{.*}}importedGlobal{{.*}} = external
// CHECK-NOT: dllimport
extern(C) extern __gshared void* importedGlobal;

// CHECK-DAG: define dllexport {{.*}}_D6export11exportedFooFZv
// CHECK: define dllexport {{.*}}_D6export11exportedFooFZv
void exportedFoo() {}

// CHECK-DAG: declare dllimport {{.*}}_D6export11importedFooFZv
// CHECK: declare
// CHECK-NOT: dllimport
// CHECK-SAME: _D6export11importedFooFZv
void importedFoo();
}

Expand Down
21 changes: 21 additions & 0 deletions tests/codegen/fvisibility_dll.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Tests that -fvisibility=public for Windows targets exports defined symbols
// (dllexport) without explicit `export` visibility, and that linking an app
// against such a DLL via import library works as expected.

// REQUIRES: Windows

// generate DLL and import lib
// RUN: %ldc %S/inputs/fvisibility_dll_lib.d -betterC -shared -fvisibility=public -of=%t_lib.dll

// compile, link and run the app
// RUN: %ldc %s -I%S/inputs -betterC %t_lib.lib -of=%t.exe
// RUN: %t.exe

import fvisibility_dll_lib;

extern(C) void main()
{
//assert(dllGlobal == 123);
const x = dllSum(1, 2);
assert(x == 3);
}
6 changes: 6 additions & 0 deletions tests/codegen/inputs/fvisibility_dll_lib.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
__gshared int dllGlobal = 123;

double dllSum(double a, double b)
{
return a + b;
}

0 comments on commit f5050bc

Please sign in to comment.