mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-04 00:55:49 +03:00
Windows: Make implicit dllimport more selective
* Newly require `-link-defaultlib-shared` for implicit dllimport. E.g., this enables to compile druntime DLL with `-fvisibility=public` for pure exports and no (local) imports (such as builtin TypeInfos). * `-link-defaultlib-shared` alone now only implicitly imports symbols from druntime/Phobos. This simplifies building complex DLLs linked against a bunch of static libs (dub only supports static lib dependencies!); the static libs don't need to be compiled with `-fvisibility=public` anymore (if the DLL itself isn't either), `-link-defaultlib-shared` is sufficient. This is mainly useful for existing DLLs with explicit exports, to make them link against *shared* druntime/Phobos and so end up with a single druntime/Phobos for the whole process.
This commit is contained in:
parent
2f0ece3274
commit
9865e459d1
15 changed files with 73 additions and 23 deletions
|
@ -109,6 +109,14 @@ enum FeatureState : byte
|
||||||
enabled = 1 /// Specified as `-preview=`
|
enabled = 1 /// Specified as `-preview=`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
version (IN_LLVM)
|
||||||
|
enum DLLImport : byte
|
||||||
|
{
|
||||||
|
none,
|
||||||
|
defaultLibsOnly, // only symbols from druntime/Phobos
|
||||||
|
all
|
||||||
|
}
|
||||||
|
|
||||||
// Put command line switches in here
|
// Put command line switches in here
|
||||||
extern (C++) struct Param
|
extern (C++) struct Param
|
||||||
{
|
{
|
||||||
|
@ -304,8 +312,8 @@ version (IN_LLVM)
|
||||||
bool linkonceTemplates; // -linkonce-templates
|
bool linkonceTemplates; // -linkonce-templates
|
||||||
|
|
||||||
// Windows-specific:
|
// Windows-specific:
|
||||||
bool dllexport; // dllexport ~all defined symbols?
|
bool dllexport; // dllexport ~all defined symbols?
|
||||||
bool dllimport; // dllimport data symbols not defined in any root module?
|
DLLImport dllimport; // dllimport data symbols not defined in any root module?
|
||||||
} // IN_LLVM
|
} // IN_LLVM
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,6 +98,15 @@ enum class FeatureState : signed char
|
||||||
enabled = 1 /// Specified as `-preview=`
|
enabled = 1 /// Specified as `-preview=`
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if IN_LLVM
|
||||||
|
enum class DLLImport : char
|
||||||
|
{
|
||||||
|
none,
|
||||||
|
defaultLibsOnly, // only symbols from druntime/Phobos
|
||||||
|
all
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
// Put command line switches in here
|
// Put command line switches in here
|
||||||
struct Param
|
struct Param
|
||||||
{
|
{
|
||||||
|
@ -279,8 +288,8 @@ struct Param
|
||||||
bool linkonceTemplates; // -linkonce-templates
|
bool linkonceTemplates; // -linkonce-templates
|
||||||
|
|
||||||
// Windows-specific:
|
// Windows-specific:
|
||||||
bool dllexport; // dllexport ~all defined symbols?
|
bool dllexport; // dllexport ~all defined symbols?
|
||||||
bool dllimport; // dllimport data symbols not defined in any root module?
|
DLLImport dllimport; // dllimport data symbols not defined in any root module?
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
3
dmd/id.h
3
dmd/id.h
|
@ -44,6 +44,9 @@ struct Id
|
||||||
static Identifier *dcompute;
|
static Identifier *dcompute;
|
||||||
static Identifier *dcPointer;
|
static Identifier *dcPointer;
|
||||||
static Identifier *object;
|
static Identifier *object;
|
||||||
|
static Identifier *core;
|
||||||
|
static Identifier *etc;
|
||||||
|
static Identifier *std;
|
||||||
static Identifier *ensure;
|
static Identifier *ensure;
|
||||||
static Identifier *require;
|
static Identifier *require;
|
||||||
static Identifier *xopEquals;
|
static Identifier *xopEquals;
|
||||||
|
|
|
@ -1090,10 +1090,10 @@ int cppmain() {
|
||||||
v == opts::SymbolVisibility::public_ ||
|
v == opts::SymbolVisibility::public_ ||
|
||||||
// default with -shared
|
// default with -shared
|
||||||
(v == opts::SymbolVisibility::default_ && global.params.dll);
|
(v == opts::SymbolVisibility::default_ && global.params.dll);
|
||||||
global.params.dllimport =
|
global.params.dllimport = !linkAgainstSharedDefaultLibs() ? DLLImport::none
|
||||||
v == opts::SymbolVisibility::public_ ||
|
: v == opts::SymbolVisibility::public_
|
||||||
// enforced when linking against shared default libs
|
? DLLImport::all
|
||||||
linkAgainstSharedDefaultLibs();
|
: DLLImport::defaultLibsOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
// allocate the target abi
|
// allocate the target abi
|
||||||
|
|
|
@ -1670,6 +1670,22 @@ std::string llvmTypeToString(llvm::Type *type) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isDefaultLibSymbol(Dsymbol *sym) {
|
||||||
|
auto mod = sym->getModule();
|
||||||
|
if (!mod)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto md = mod->md;
|
||||||
|
if (!md)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (md->packages.length == 0)
|
||||||
|
return md->id == Id::object;
|
||||||
|
|
||||||
|
auto p = md->packages.ptr[0];
|
||||||
|
return p == Id::core || p == Id::std || p == Id::etc || p == Id::ldc;
|
||||||
|
}
|
||||||
|
|
||||||
llvm::GlobalVariable *declareGlobal(const Loc &loc, llvm::Module &module,
|
llvm::GlobalVariable *declareGlobal(const Loc &loc, llvm::Module &module,
|
||||||
llvm::Type *type,
|
llvm::Type *type,
|
||||||
llvm::StringRef mangledName,
|
llvm::StringRef mangledName,
|
||||||
|
|
|
@ -245,6 +245,9 @@ LLConstant *toConstantArray(LLType *ct, LLArrayType *at, T *str, size_t len,
|
||||||
|
|
||||||
llvm::Constant *buildStringLiteralConstant(StringExp *se, bool zeroTerm);
|
llvm::Constant *buildStringLiteralConstant(StringExp *se, bool zeroTerm);
|
||||||
|
|
||||||
|
/// Is the specified symbol part of druntime/Phobos?
|
||||||
|
bool isDefaultLibSymbol(Dsymbol *sym);
|
||||||
|
|
||||||
/// Tries to declare an LLVM global. If a variable with the same mangled name
|
/// Tries to declare an LLVM global. If a variable with the same mangled name
|
||||||
/// already exists, checks if the types match and returns it instead.
|
/// already exists, checks if the types match and returns it instead.
|
||||||
///
|
///
|
||||||
|
|
|
@ -190,8 +190,9 @@ LLFunction *build_module_reference_and_ctor(const char *moduleMangle,
|
||||||
LLConstant *mref = gIR->module.getNamedGlobal(mrefIRMangle);
|
LLConstant *mref = gIR->module.getNamedGlobal(mrefIRMangle);
|
||||||
LLType *modulerefPtrTy = getPtrToType(modulerefTy);
|
LLType *modulerefPtrTy = getPtrToType(modulerefTy);
|
||||||
if (!mref) {
|
if (!mref) {
|
||||||
mref = declareGlobal(Loc(), gIR->module, modulerefPtrTy, mrefIRMangle,
|
mref =
|
||||||
false, false, global.params.dllimport);
|
declareGlobal(Loc(), gIR->module, modulerefPtrTy, mrefIRMangle, false,
|
||||||
|
false, global.params.dllimport != DLLImport::none);
|
||||||
}
|
}
|
||||||
mref = DtoBitCast(mref, getPtrToType(modulerefPtrTy));
|
mref = DtoBitCast(mref, getPtrToType(modulerefPtrTy));
|
||||||
|
|
||||||
|
|
|
@ -423,7 +423,7 @@ bool ldc_optimize_module(llvm::Module *M) {
|
||||||
|
|
||||||
addOptimizationPasses(mpm, fpm, optLevel(), sizeLevel());
|
addOptimizationPasses(mpm, fpm, optLevel(), sizeLevel());
|
||||||
|
|
||||||
if (global.params.dllimport) {
|
if (global.params.dllimport != DLLImport::none) {
|
||||||
mpm.add(createDLLImportRelocationPass());
|
mpm.add(createDLLImportRelocationPass());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -439,8 +439,7 @@ void buildTypeInfo(TypeInfoDeclaration *decl) {
|
||||||
// immutable on the D side, and e.g. synchronized() can be used on the
|
// immutable on the D side, and e.g. synchronized() can be used on the
|
||||||
// implicit monitor.
|
// implicit monitor.
|
||||||
const bool isConstant = false;
|
const bool isConstant = false;
|
||||||
// TODO: no dllimport when compiling druntime itself
|
bool useDLLImport = isBuiltin && global.params.dllimport != DLLImport::none;
|
||||||
const bool useDLLImport = isBuiltin && global.params.dllimport;
|
|
||||||
gvar = declareGlobal(decl->loc, gIR->module, type, irMangle, isConstant,
|
gvar = declareGlobal(decl->loc, gIR->module, type, irMangle, isConstant,
|
||||||
false, useDLLImport);
|
false, useDLLImport);
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,9 @@ bool IrAggr::useDLLImport() const {
|
||||||
if (!global.params.targetTriple->isOSWindows())
|
if (!global.params.targetTriple->isOSWindows())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (global.params.dllimport || aggrdecl->isExport()) {
|
if (aggrdecl->isExport() || global.params.dllimport == DLLImport::all ||
|
||||||
|
(global.params.dllimport == DLLImport::defaultLibsOnly &&
|
||||||
|
isDefaultLibSymbol(aggrdecl))) {
|
||||||
// dllimport, unless defined in a root module (=> no extra indirection for
|
// dllimport, unless defined in a root module (=> no extra indirection for
|
||||||
// other root modules, assuming *all* root modules will be linked together
|
// other root modules, assuming *all* root modules will be linked together
|
||||||
// to one or more binaries).
|
// to one or more binaries).
|
||||||
|
|
|
@ -27,7 +27,11 @@ llvm::GlobalVariable *IrModule::moduleInfoSymbol() {
|
||||||
|
|
||||||
const auto irMangle = getIRMangledModuleInfoSymbolName(M);
|
const auto irMangle = getIRMangledModuleInfoSymbolName(M);
|
||||||
|
|
||||||
const bool useDLLImport = global.params.dllimport && !M->isRoot();
|
bool useDLLImport = false;
|
||||||
|
if (global.params.dllimport == DLLImport::all)
|
||||||
|
useDLLImport = !M->isRoot();
|
||||||
|
else if (global.params.dllimport == DLLImport::defaultLibsOnly)
|
||||||
|
useDLLImport = !M->isRoot() && isDefaultLibSymbol(M);
|
||||||
|
|
||||||
moduleInfoVar = declareGlobal(Loc(), gIR->module,
|
moduleInfoVar = declareGlobal(Loc(), gIR->module,
|
||||||
llvm::StructType::create(gIR->context()),
|
llvm::StructType::create(gIR->context()),
|
||||||
|
|
|
@ -85,9 +85,13 @@ void IrGlobal::declare() {
|
||||||
if (global.params.targetTriple->isOSWindows()) {
|
if (global.params.targetTriple->isOSWindows()) {
|
||||||
// dllimport isn't supported for thread-local globals (MSVC++ neither)
|
// dllimport isn't supported for thread-local globals (MSVC++ neither)
|
||||||
if (!V->isThreadlocal()) {
|
if (!V->isThreadlocal()) {
|
||||||
// with -fvisibility=public / -link-defaultlib-shared, also include all
|
// with -fvisibility=public / -link-defaultlib-shared, also include
|
||||||
// extern(D) globals
|
// extern(D) globals
|
||||||
if (V->isExport() || (global.params.dllimport && V->linkage == LINK::d)) {
|
if (V->isExport() ||
|
||||||
|
(V->linkage == LINK::d &&
|
||||||
|
(global.params.dllimport == DLLImport::all ||
|
||||||
|
(global.params.dllimport == DLLImport::defaultLibsOnly &&
|
||||||
|
isDefaultLibSymbol(V))))) {
|
||||||
const bool isDefinedInRootModule =
|
const bool isDefinedInRootModule =
|
||||||
!(V->storage_class & STCextern) && !V->inNonRoot();
|
!(V->storage_class & STCextern) && !V->inNonRoot();
|
||||||
if (!isDefinedInRootModule)
|
if (!isDefinedInRootModule)
|
||||||
|
|
|
@ -708,7 +708,7 @@ macro(build_runtime_variant d_flags c_flags ld_flags lib_suffix path_suffix emit
|
||||||
AND NOT ${all_d_files_at_once})
|
AND NOT ${all_d_files_at_once})
|
||||||
set(phobos2_o "")
|
set(phobos2_o "")
|
||||||
set(phobos2_bc "")
|
set(phobos2_bc "")
|
||||||
compile_phobos2("${phobos2_d_flags};-relocation-model=pic;-fvisibility=public"
|
compile_phobos2("${phobos2_d_flags};-relocation-model=pic;-fvisibility=public;-link-defaultlib-shared"
|
||||||
"${lib_suffix}${SHARED_LIB_SUFFIX}" "${path_suffix}"
|
"${lib_suffix}${SHARED_LIB_SUFFIX}" "${path_suffix}"
|
||||||
"${emit_bc}" "${all_d_files_at_once}" "OFF" phobos2_o phobos2_bc)
|
"${emit_bc}" "${all_d_files_at_once}" "OFF" phobos2_o phobos2_bc)
|
||||||
|
|
||||||
|
@ -761,7 +761,7 @@ macro(build_runtime_variant d_flags c_flags ld_flags lib_suffix path_suffix emit
|
||||||
if(phobos2_common STREQUAL "")
|
if(phobos2_common STREQUAL "")
|
||||||
set(phobos2_o "")
|
set(phobos2_o "")
|
||||||
set(phobos2_bc "")
|
set(phobos2_bc "")
|
||||||
compile_phobos2("${phobos2_d_flags};-relocation-model=pic;-fvisibility=public"
|
compile_phobos2("${phobos2_d_flags};-relocation-model=pic;-fvisibility=public;-link-defaultlib-shared"
|
||||||
"${lib_suffix}${SHARED_LIB_SUFFIX}" "${path_suffix}"
|
"${lib_suffix}${SHARED_LIB_SUFFIX}" "${path_suffix}"
|
||||||
"OFF" "${all_d_files_at_once}" "${all_d_files_at_once}" phobos2_o phobos2_bc)
|
"OFF" "${all_d_files_at_once}" "${all_d_files_at_once}" phobos2_o phobos2_bc)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 65a26b5756fd1b4f693b013e1838ac11ac2e19d4
|
Subproject commit c424142bbab8def67d362ac18d534c2be165d39b
|
|
@ -4,11 +4,12 @@
|
||||||
|
|
||||||
// REQUIRES: Windows
|
// REQUIRES: Windows
|
||||||
|
|
||||||
// generate DLL and import lib
|
// generate DLL and import lib (public visibility by default)
|
||||||
// RUN: %ldc %S/inputs/fvisibility_dll_lib.d -betterC -shared -of=%t_lib.dll
|
// RUN: %ldc %S/inputs/fvisibility_dll_lib.d -betterC -shared -of=%t_lib.dll
|
||||||
|
|
||||||
// compile, link and run the app; -link-defaultlib-shared for importing data symbols as dllimport
|
// compile, link and run the app;
|
||||||
// RUN: %ldc %s -I%S/inputs -betterC -link-defaultlib-shared %t_lib.lib -of=%t.exe
|
// `-link-defaultlib-shared -fvisibility=public` for dllimporting data symbols
|
||||||
|
// RUN: %ldc %s -I%S/inputs -betterC -link-defaultlib-shared -fvisibility=public %t_lib.lib -of=%t.exe
|
||||||
// RUN: %t.exe
|
// RUN: %t.exe
|
||||||
|
|
||||||
import fvisibility_dll_lib;
|
import fvisibility_dll_lib;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue