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

Test #3848 + #3850 #3858

Closed
wants to merge 10 commits into from
4 changes: 4 additions & 0 deletions .azure-pipelines/1-posix-setup.yml
Original file line number Diff line number Diff line change
@@ -63,6 +63,10 @@ steps:
fi
mkdir llvm
tar -xf llvm.tar.xz --strip 1 -C llvm
# Non-Mac: make lld the default linker
if [ "$CI_OS" != "osx" ]; then
sudo ln -sf "$PWD/llvm/bin/ld.lld" /usr/bin/ld
fi
# Set PARALLEL_JOBS env variable and persist it for future steps
if [ "$CI_OS" = "osx" ]; then
PARALLEL_JOBS=$(sysctl -n hw.logicalcpu)
6 changes: 3 additions & 3 deletions .azure-pipelines/4a-mac_x64.yml
Original file line number Diff line number Diff line change
@@ -38,9 +38,9 @@ steps:
CMAKE_OSX_DEPLOYMENT_TARGET=$IOS_DEPLOYMENT_TARGET \
BUILD_LTO_LIBS=ON
mkdir installed/lib-{arm64,ios-arm64,ios-x86_64}
cp -a build-libs-arm64/lib/*.{a,dylib} installed/lib-arm64
cp -a build-libs-ios-arm64/lib/*.{a,dylib} installed/lib-ios-arm64
cp -a build-libs-ios-x86_64/lib/*.{a,dylib} installed/lib-ios-x86_64
cp -a build-libs-arm64/lib/*.{a,dylib,o} installed/lib-arm64
cp -a build-libs-ios-arm64/lib/*.{a,dylib,o} installed/lib-ios-arm64
cp -a build-libs-ios-x86_64/lib/*.{a,dylib,o} installed/lib-ios-x86_64
sections="
\"arm64-apple-macos\":
{
8 changes: 4 additions & 4 deletions .github/workflows/supported_llvm_versions.yml
Original file line number Diff line number Diff line change
@@ -16,22 +16,22 @@ jobs:
os: ubuntu-18.04
host_dc: ldc-beta
llvm_version: "11.1.0"
cmake_opts: "-DRT_SUPPORT_SANITIZERS=ON"
cmake_opts: "-DBUILD_SHARED_LIBS=ON -DRT_SUPPORT_SANITIZERS=ON"
- job_name: Ubuntu 18.04, LLVM 9, latest LDC beta
os: ubuntu-18.04
host_dc: ldc-beta
llvm_version: "9.0.1"
cmake_opts: "-DBUILD_SHARED_LIBS=ON -DRT_SUPPORT_SANITIZERS=ON"
cmake_opts: "-DBUILD_SHARED_LIBS=OFF -DRT_SUPPORT_SANITIZERS=ON"
- job_name: Ubuntu 18.04, LLVM 8, latest LDC beta
os: ubuntu-18.04
host_dc: ldc-beta
llvm_version: "8.0.0"
cmake_opts: "-DBUILD_SHARED_LIBS=OFF"
cmake_opts: "-DLIB_SUFFIX=64"
- job_name: Ubuntu 18.04, LLVM 6, latest DMD beta
os: ubuntu-18.04
host_dc: dmd-beta
llvm_version: "6.0.1"
cmake_opts: "-DLIB_SUFFIX=64 -DLDC_LINK_MANUALLY=ON"
cmake_opts: "-DLDC_LINK_MANUALLY=ON"
- job_name: Latest macOS, LLVM 10, latest DMD beta
os: macos-latest
host_dc: dmd-beta
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -134,9 +134,9 @@ script:
- installed/bin/ldc2 hello.d -of=hello -link-defaultlib-shared
- ./hello
# Run hello-world integration test with LTO
- installed/bin/ldc2 hello.d -of=hello_thin -flto=thin -defaultlib=phobos2-ldc-lto,druntime-ldc-lto
- installed/bin/ldc2 hello.d -of=hello_thin -linker=gold -flto=thin -defaultlib=phobos2-ldc-lto,druntime-ldc-lto
- ./hello_thin
- installed/bin/ldc2 hello.d -of=hello_full -flto=full -defaultlib=phobos2-ldc-lto,druntime-ldc-lto
- installed/bin/ldc2 hello.d -of=hello_full -linker=gold -flto=full -defaultlib=phobos2-ldc-lto,druntime-ldc-lto
- ./hello_full
# Run dynamic-compile integration test
# FIXME: disabled since LLVM 12, needs https://github.com/ldc-developers/ldc/pull/3184
5 changes: 3 additions & 2 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
@@ -63,14 +63,15 @@ jobs:
variables:
CI_OS: linux
ARCH: x86_64
# To improve portability of the generated binaries, link the C++ standard library statically.
BOOTSTRAP_CMAKE_FLAGS: -DBUILD_LTO_LIBS=ON
# To improve portability of the generated binaries, link the C++ standard library statically.
# FIXME: need to use ld.gold for LTOing LDC itself for now, fixed in frontend v2.099
EXTRA_CMAKE_FLAGS: >
-DMULTILIB=ON
-DBUILD_LTO_LIBS=ON
-DCMAKE_EXE_LINKER_FLAGS=-static-libstdc++
-DJITRT_EXTRA_LDFLAGS=-static-libstdc++
-DD_COMPILER_FLAGS="-O -flto=full -defaultlib=phobos2-ldc-lto,druntime-ldc-lto"
-DD_COMPILER_FLAGS="-O -flto=full -linker=gold -defaultlib=phobos2-ldc-lto,druntime-ldc-lto"
-DEXTRA_CXXFLAGS=-flto=full
steps:
- template: .azure-pipelines/1-posix-setup.yml
30 changes: 14 additions & 16 deletions driver/linker-gcc.cpp
Original file line number Diff line number Diff line change
@@ -489,6 +489,14 @@ void ArgsBuilder::build(llvm::StringRef outputPath,
args.push_back(objfile);
}

// add precompiled rt.dso object file (in lib directory) when linking
// against shared druntime
const auto &libDirs = ConfigFile::instance.libDirs();
if (!defaultLibNames.empty() && linkAgainstSharedDefaultLibs() &&
!libDirs.empty()) {
args.push_back((llvm::Twine(libDirs[0]) + "/ldc_rt.dso.o").str());
}

// Link with profile-rt library when generating an instrumented binary.
if (opts::isInstrumentingForPGO()) {
addProfileRuntimeLinkFlags(*global.params.targetTriple);
@@ -533,7 +541,7 @@ void ArgsBuilder::build(llvm::StringRef outputPath,
addUserSwitches();

// lib dirs
for (const char *dir_c : ConfigFile::instance.libDirs()) {
for (const char *dir_c : libDirs) {
const llvm::StringRef dir(dir_c);
if (!dir.empty())
args.push_back(("-L" + dir).str());
@@ -587,22 +595,12 @@ void ArgsBuilder::build(llvm::StringRef outputPath,
void ArgsBuilder::addLinker() {
llvm::StringRef linker = opts::linker;

// We have a default linker preference for Linux targets. It can be disabled
// via `-linker=` (explicitly empty).
if (global.params.targetTriple->isOSLinux() &&
// Default to ld.bfd for Android (placing .tdata and .tbss sections adjacent
// to each other as required by druntime's rt.sections_android, contrary to
// gold and lld as of Android NDK r21d).
if (global.params.targetTriple->getEnvironment() == llvm::Triple::Android &&
opts::linker.getNumOccurrences() == 0) {
// Default to ld.bfd for Android (placing .tdata and .tbss sections adjacent
// to each other as required by druntime's rt.sections_android, contrary to
// gold and lld as of Android NDK r21d).
if (global.params.targetTriple->getEnvironment() == llvm::Triple::Android) {
linker = "bfd";
}
// Otherwise default to ld.gold for Linux due to ld.bfd issues with ThinLTO
// (see #2278) and older bfd versions stripping llvm.used symbols (e.g.,
// ModuleInfo refs) with --gc-sections (see #2870).
else {
linker = "gold";
}
linker = "bfd";
}

if (!linker.empty())
12 changes: 6 additions & 6 deletions driver/linker-msvc.cpp
Original file line number Diff line number Diff line change
@@ -148,10 +148,12 @@ int linkObjToBinaryMSVC(llvm::StringRef outputPath,
args.push_back(objfile);
}

// add precompiled rt.dso_windows object file (in lib directory) when linking
// add precompiled rt.dso object file (in lib directory) when linking
// against shared druntime
if (!defaultLibNames.empty() && linkAgainstSharedDefaultLibs()) {
args.push_back("dso_windows.obj");
const auto &libDirs = ConfigFile::instance.libDirs();
if (!defaultLibNames.empty() && linkAgainstSharedDefaultLibs() &&
!libDirs.empty()) {
args.push_back((llvm::Twine(libDirs[0]) + "/ldc_rt.dso.obj").str());
}

// .res/.def files
@@ -197,16 +199,14 @@ int linkObjToBinaryMSVC(llvm::StringRef outputPath,
}

// lib dirs
const auto &libDirs = ConfigFile::instance.libDirs();
for (const char *dir_c : libDirs) {
const llvm::StringRef dir(dir_c);
if (!dir.empty())
args.push_back(("/LIBPATH:" + dir).str());
}

if (useInternalToolchain && !libDirs.empty()) {
args.push_back(
(llvm::Twine("/LIBPATH:") + *libDirs.begin() + "/mingw").str());
args.push_back((llvm::Twine("/LIBPATH:") + libDirs[0] + "/mingw").str());
}

// default libs
226 changes: 25 additions & 201 deletions gen/modules.cpp
Original file line number Diff line number Diff line change
@@ -83,73 +83,31 @@ void Module::checkAndAddOutputFile(const FileName &file) {
}

namespace {
/// Ways the druntime module registry system can be implemented.
/// Ways the druntime ModuleInfo registry system can be implemented.
enum class RegistryStyle {
/// Modules are inserted into a linked list starting at the _Dmodule_ref
/// global.
/// ModuleInfo refs are inserted into a linked list starting at the
/// _Dmodule_ref global.
legacyLinkedList,

/// Module references are emitted into the .minfo/__minfo section.
sectionSimple,

/// Module references are emitted into the __minfo section. Global
/// constructors/destructors make sure _d_dso_registry is invoked once per ELF
/// object.
sectionELF,

/// Module references are emitted into the .minfo section. Global
/// constructors/destructors make sure _d_dso_registry is invoked once per
/// shared object. A "TLS anchor" function to identify the TLS range
/// corresponding to this image is also passed to druntime.
sectionDarwin
/// Pointers to defined ModuleInfos are emitted into the special .minfo /
/// __minfo section. A linked binary then contains pointers to all ModuleInfos
/// of linked object files in that section.
section,
};

/// Returns the module registry style to use for the current target triple.
/// Returns the ModuleInfo registry style to use for the current target triple.
RegistryStyle getModuleRegistryStyle() {
const auto &t = *global.params.targetTriple;

if (t.isOSWindows() || t.getEnvironment() == llvm::Triple::Android ||
t.isOSBinFormatWasm()) {
return RegistryStyle::sectionSimple;
}

if (t.isOSDarwin()) {
return RegistryStyle::sectionDarwin;
}

if (t.isOSLinux() || t.isOSFreeBSD() || t.isOSNetBSD() || t.isOSOpenBSD() ||
t.isOSBinFormatWasm() || t.isOSDarwin() || t.isOSLinux() ||
t.isOSFreeBSD() || t.isOSNetBSD() || t.isOSOpenBSD() ||
t.isOSDragonFly()) {
return RegistryStyle::sectionELF;
return RegistryStyle::section;
}

return RegistryStyle::legacyLinkedList;
}

LLGlobalVariable *declareDSOGlobal(llvm::StringRef mangledName, LLType *type,
bool isThreadLocal = false) {
auto global = declareGlobal(Loc(), gIR->module, type, mangledName, false,
isThreadLocal, false);
global->setVisibility(LLGlobalValue::HiddenVisibility);
return global;
}

LLGlobalVariable *defineDSOGlobal(llvm::StringRef mangledName, LLConstant *init,
bool isThreadLocal = false) {
auto global =
defineGlobal(Loc(), gIR->module, mangledName, init,
LLGlobalValue::LinkOnceODRLinkage, false, isThreadLocal);
global->setVisibility(LLGlobalValue::HiddenVisibility);
return global;
}

LLFunction *createDSOFunction(llvm::StringRef mangledName,
LLFunctionType *type) {
auto fn = LLFunction::Create(type, LLGlobalValue::LinkOnceODRLinkage,
mangledName, &gIR->module);
fn->setVisibility(LLGlobalValue::HiddenVisibility);
return fn;
}

/// Build ModuleReference and register function, to register the module info in
/// the global linked list.
///
@@ -222,160 +180,26 @@ LLFunction *build_module_reference_and_ctor(const char *moduleMangle,
return ctor;
}

/// Builds a void*() function with hidden visibility that returns the address of
/// a dummy TLS global (also with hidden visibility).
///
/// The global is non-zero-initialised and aligned to 16 bytes.
llvm::Function *buildGetTLSAnchor() {
// Create a dummmy TLS global private to this module.
const auto one = llvm::ConstantInt::get(LLType::getInt8Ty(gIR->context()), 1);
const auto anchor =
defineDSOGlobal("ldc.tls_anchor", one, /*isThreadLocal=*/true);
anchor->setAlignment(LLMaybeAlign(16));

const auto getAnchor = createDSOFunction(
"ldc.get_tls_anchor", LLFunctionType::get(getVoidPtrType(), false));

IRBuilder<> builder(llvm::BasicBlock::Create(gIR->context(), "", getAnchor));
builder.CreateRet(anchor);

return getAnchor;
}

/// Builds the ldc.register_dso function, which is called by the global
/// {c, d}tors to invoke _d_dso_registry.
///
/// Pseudocode:
/// void ldc.register_dso() {
/// auto record = {1, dsoSlot, minfoBeg, minfoEnd[, getTlsAnchor]};
/// _d_dso_registry(cast(CompilerDSOData*)&record);
/// }
///
/// On Darwin platforms, the record contains an extra pointer to a function
/// which returns the address of a TLS global.
llvm::Function *buildRegisterDSO(RegistryStyle style, llvm::Value *dsoSlot,
llvm::Value *minfoBeg, llvm::Value *minfoEnd) {
const auto fn = createDSOFunction(
"ldc.register_dso",
LLFunctionType::get(LLType::getVoidTy(gIR->context()), false));

const auto dsoRegistry =
getRuntimeFunction(Loc(), gIR->module, "_d_dso_registry");
const auto recordPtrTy = dsoRegistry->getFunctionType()->getContainedType(1);

llvm::Function *getTlsAnchorPtr = nullptr;
if (style == RegistryStyle::sectionDarwin) {
getTlsAnchorPtr = buildGetTLSAnchor();
}

{
const auto bb = llvm::BasicBlock::Create(gIR->context(), "", fn);
IRBuilder<> b(bb);

llvm::Constant *version = DtoConstSize_t(1);
llvm::SmallVector<llvm::Type *, 6> memberTypes;
memberTypes.push_back(version->getType());
memberTypes.push_back(dsoSlot->getType());
memberTypes.push_back(minfoBeg->getType());
memberTypes.push_back(minfoEnd->getType());
if (style == RegistryStyle::sectionDarwin) {
memberTypes.push_back(getTlsAnchorPtr->getType());
}
llvm::StructType *stype =
llvm::StructType::get(gIR->context(), memberTypes, false);
llvm::Value *record = b.CreateAlloca(stype);

unsigned i = 0;
b.CreateStore(version, b.CreateStructGEP(stype, record, i++));
b.CreateStore(dsoSlot, b.CreateStructGEP(stype, record, i++));
b.CreateStore(minfoBeg, b.CreateStructGEP(stype, record, i++));
b.CreateStore(minfoEnd, b.CreateStructGEP(stype, record, i++));
if (style == RegistryStyle::sectionDarwin) {
b.CreateStore(getTlsAnchorPtr, b.CreateStructGEP(stype, record, i++));
}

b.CreateCall(dsoRegistry, b.CreateBitCast(record, recordPtrTy));
b.CreateRetVoid();
}

return fn;
}

void emitModuleRefToSection(RegistryStyle style, std::string moduleMangle,
// Emits a pointer to the specified ModuleInfo into the special
// .minfo (COFF & MachO) / __minfo section.
void emitModuleRefToSection(std::string moduleMangle,
llvm::Constant *thisModuleInfo) {
assert(style == RegistryStyle::sectionSimple ||
style == RegistryStyle::sectionELF ||
style == RegistryStyle::sectionDarwin);
// Only for the first D module to be emitted into this llvm::Module we need to
// create the global ctors/dtors. The magic linker symbols used to get the
// start and end of the .minfo section also only need to be emitted for the
// first D module.
// For all subsequent ones, we just need to emit an additional reference into
// the .minfo section.
const bool isFirst = !gIR->module.getGlobalVariable("ldc.dso_slot");

const auto moduleInfoPtrTy = DtoPtrToType(getModuleInfoType());
const auto moduleInfoRefsSectionName =
global.params.targetTriple->isWindowsMSVCEnvironment()

const auto &triple = *global.params.targetTriple;
const auto sectionName =
triple.isOSBinFormatCOFF()
? ".minfo"
: style == RegistryStyle::sectionDarwin ? "__DATA,.minfo" : "__minfo";
: triple.isOSBinFormatMachO() ? "__DATA,.minfo" : "__minfo";

const auto thismrefIRMangle =
getIRMangledModuleRefSymbolName(moduleMangle.c_str());
auto thismref = defineDSOGlobal(thismrefIRMangle,
DtoBitCast(thisModuleInfo, moduleInfoPtrTy));
thismref->setSection(moduleInfoRefsSectionName);
auto thismref = defineGlobal(Loc(), gIR->module, thismrefIRMangle,
DtoBitCast(thisModuleInfo, moduleInfoPtrTy),
LLGlobalValue::LinkOnceODRLinkage, false, false);
thismref->setVisibility(LLGlobalValue::HiddenVisibility);
thismref->setSection(sectionName);
gIR->usedArray.push_back(thismref);

if (!isFirst || style == RegistryStyle::sectionSimple) {
// Nothing left to do.
return;
}

// Use magic linker symbol names to obtain the begin and end of the .minfo
// section.
const auto magicBeginSymbolName = (style == RegistryStyle::sectionDarwin)
? "\1section$start$__DATA$.minfo"
: "__start___minfo";
const auto magicEndSymbolName = (style == RegistryStyle::sectionDarwin)
? "\1section$end$__DATA$.minfo"
: "__stop___minfo";
auto minfoBeg = declareDSOGlobal(magicBeginSymbolName, moduleInfoPtrTy);
auto minfoEnd = declareDSOGlobal(magicEndSymbolName, moduleInfoPtrTy);

// We want to have one global constructor and destructor per object (i.e.
// executable/shared library) that calls _d_dso_registry with the respective
// DSO record.
// To enable safe direct linking of D objects (e.g., "g++ dcode.o cppcode.o"),
// we emit a pair of global {c,d}tors into each object file, both pointing to
// a common ldc.register_dso() function.
// These per-object-file pairs will be folded to a single one when linking the
// DSO, together with the ldc.dso_slot globals and associated
// ldc.register_dso() functions.

// This is the DSO slot for use by the druntime implementation.
const auto dsoSlot =
defineDSOGlobal("ldc.dso_slot", getNullPtr(getVoidPtrType()));

const auto registerDSO = buildRegisterDSO(style, dsoSlot, minfoBeg, minfoEnd);

// We need to discard the {c,d}tor refs if this IR module's ldc.register_dso()
// function is discarded to prevent duplicate refs.
// Unfortunately, this doesn't work for macOS (v10.12, Xcode v9.2, LLVM
// v7.0.0).
if (style == RegistryStyle::sectionELF) {
llvm::appendToGlobalCtors(gIR->module, registerDSO, 65535, registerDSO);
llvm::appendToGlobalDtors(gIR->module, registerDSO, 65535, registerDSO);
return;
}

// macOS: emit the {c,d}tor refs manually
const auto dsoCtor = defineDSOGlobal("ldc.dso_ctor", registerDSO);
const auto dsoDtor = defineDSOGlobal("ldc.dso_dtor", registerDSO);
gIR->usedArray.push_back(dsoCtor);
gIR->usedArray.push_back(dsoDtor);
dsoCtor->setSection("__DATA,__mod_init_func,mod_init_funcs");
dsoDtor->setSection("__DATA,__mod_term_func,mod_term_funcs");
}

// Add module-private variables and functions for coverage analysis.
@@ -569,7 +393,7 @@ void registerModuleInfo(Module *m) {
const auto miCtor = build_module_reference_and_ctor(mangle, moduleInfoSym);
AppendFunctionToLLVMGlobalCtorsDtors(miCtor, 65535, true);
} else {
emitModuleRefToSection(style, mangle, moduleInfoSym);
emitModuleRefToSection(mangle, moduleInfoSym);
}
}
}
62 changes: 26 additions & 36 deletions runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -424,7 +424,7 @@ macro(dc src_files src_basedir d_flags output_basedir emit_bc all_at_once single
set(renameCommand "")
if(${emit_bc})
# rename generated *.bc to *.bc.o[bj]
set(renameCommand mv ${output_basedir}/${output_root}.bc ${output_bc})
set(renameCommand ${CMAKE_COMMAND} -E rename ${output_basedir}/${output_root}.bc ${output_bc})
list(APPEND outfiles ${output_bc})
endif()

@@ -461,7 +461,7 @@ macro(dc src_files src_basedir d_flags output_basedir emit_bc all_at_once single
string(REGEX REPLACE "${CMAKE_C_OUTPUT_EXTENSION}$" "" src_bc "${dst_bc}")
add_custom_command(
OUTPUT ${new_o} ${new_bc} APPEND
COMMAND mv ${src_bc} ${dst_bc}
COMMAND ${CMAKE_COMMAND} -E rename ${src_bc} ${dst_bc}
)
endforeach()
endif()
@@ -506,29 +506,6 @@ macro(compile_druntime d_flags lib_suffix path_suffix emit_bc all_at_once single
)
endmacro()

set(dso_windows_o "")
if("${TARGET_SYSTEM}" MATCHES "Windows")
# Windows: precompile rt.dso_windows object file & install to lib dir.
# The existing object file isn't reused to prevent *exported* symbols (only
# -link-defaultlib-shared for dllimport, no -fvisibility=public).
# This allows to create executables with -link-defaultlib-shared without
# any exports (and according extra linker files such as the import .lib).
set(dso_windows_bc "")
dc("${RUNTIME_DIR}/src/rt/dso_windows.d"
"${RUNTIME_DIR}/src"
"-conf=;${D_FLAGS};${D_FLAGS_RELEASE};-link-defaultlib-shared;${DRUNTIME_EXTRA_FLAGS};-I${RUNTIME_DIR}/src"
"${CMAKE_BINARY_DIR}/lib${LIB_SUFFIX}"
"OFF" # emit_bc
"ON" # all_at_once
"dso_windows" # single_obj_name
dso_windows_o
dso_windows_bc
)

add_custom_target(dso_windows DEPENDS ${dso_windows_o})
install(FILES ${dso_windows_o} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX})
endif()

# Sets up the targets for building the Phobos D object files, appending the
# names of the (bitcode) files to link into the library to outlist_o (outlist_bc).
macro(compile_phobos2 d_flags lib_suffix path_suffix emit_bc all_at_once single_obj outlist_o outlist_bc)
@@ -763,6 +740,8 @@ macro(build_runtime_variant d_flags c_flags ld_flags lib_suffix path_suffix emit
"${lib_suffix}${SHARED_LIB_SUFFIX}" "${path_suffix}"
"OFF" "${all_d_files_at_once}" "OFF" druntime_o druntime_bc)

set(rt_dso_o "${PROJECT_BINARY_DIR}/objects${target_suffix}/rt/dso${CMAKE_C_OUTPUT_EXTENSION}")

# compile Phobos with public visibility (and preferably to a single object file)
if(phobos2_common STREQUAL "")
set(phobos2_o "")
@@ -772,19 +751,30 @@ macro(build_runtime_variant d_flags c_flags ld_flags lib_suffix path_suffix emit
"OFF" "${all_d_files_at_once}" "${all_d_files_at_once}" phobos2_o phobos2_bc)
endif()

if("${TARGET_SYSTEM}" MATCHES "Windows")
# also link-in special rt.dso_windows druntime module
list(APPEND phobos2_o ${dso_windows_o})
endif()
# also link-in special rt.dso druntime module
list(APPEND phobos2_o ${rt_dso_o})

build_runtime_libs("${druntime_o}" "${druntime_bc}" "${phobos2_o}" "${phobos2_bc}"
"${c_flags}" "${ld_flags}" "${lib_suffix}${SHARED_LIB_SUFFIX}" "${path_suffix}"
"ON" "OFF" ${outlist_targets})

if(NOT phobos2_common STREQUAL "")
add_dependencies(phobos2-ldc${target_suffix} ${phobos2_common})
elseif("${TARGET_SYSTEM}" MATCHES "Windows")
add_dependencies(phobos2-ldc${target_suffix} dso_windows)
endif()

if("${lib_suffix}" STREQUAL "") # non-debug & non-unittest
# copy rt.dso to `ldc_rt.dso.o[bj]` in lib dir
add_custom_command(
TARGET druntime-ldc${target_suffix}
POST_BUILD COMMAND
${CMAKE_COMMAND} -E copy ${rt_dso_o} ${CMAKE_BINARY_DIR}/lib${path_suffix}/ldc_rt.dso${CMAKE_C_OUTPUT_EXTENSION}
)
# and install it too
install(
FILES ${rt_dso_o}
DESTINATION ${CMAKE_INSTALL_PREFIX}/lib${path_suffix}
RENAME ldc_rt.dso${CMAKE_C_OUTPUT_EXTENSION}
)
endif()
endif()
endmacro()
@@ -1030,9 +1020,9 @@ macro(compile_testrunner d_flags is_shared target_suffix extra_dir_suffix)
test_runner_bc
)

if("${is_shared}" STREQUAL "ON" AND "${TARGET_SYSTEM}" MATCHES "Windows")
# also link-in special rt.dso_windows druntime module
list(APPEND test_runner_o ${dso_windows_o})
if("${is_shared}" STREQUAL "ON")
# also link-in special rt.dso druntime module
list(APPEND test_runner_o ${PROJECT_BINARY_DIR}/objects-unittest${target_suffix}/rt/dso${CMAKE_C_OUTPUT_EXTENSION})
endif()
endmacro()

@@ -1167,8 +1157,8 @@ endmacro()

function(add_tests d_files runner target_suffix)
foreach(file ${d_files})
# skip rt.dso_* (no ModuleInfo)
if(NOT "${file}" MATCHES "druntime/src/rt/dso_")
# skip rt.dso (no ModuleInfo)
if(NOT "${file}" MATCHES "druntime/src/rt/dso.d")
file_to_module_name(${file} module)
add_test(NAME "${module}${target_suffix}"
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}"
2 changes: 1 addition & 1 deletion runtime/druntime
6 changes: 5 additions & 1 deletion tests/codegen/ctor_initarray_gh2883.d
Original file line number Diff line number Diff line change
@@ -8,4 +8,8 @@
// CHECK: .section .init_array
// CHECK: .section .fini_array

// No code needed to generate asm for a module.
pragma(crt_constructor)
void ctor() {}

pragma(crt_destructor)
void dtor() {}
4 changes: 2 additions & 2 deletions tests/codegen/llvm_used_1.d
Original file line number Diff line number Diff line change
@@ -8,9 +8,9 @@
// RUN: %ldc -O3 %S/inputs/module_ctor.d -run %s | FileCheck --check-prefix=EXECUTE %s

// There was a bug where llvm.used was emitted more than once, whose symptom was that suffixed versions would appear: e.g. `@llvm.used.3`.
// Expect 4 llvm.used entries - 2 ModuleInfos refs + ldc.dso_{c,d}tor refs.
// Expect 2 llvm.used entries, for both ModuleInfo refs.
// LLVM-NOT: @llvm.used.
// LLVM: @llvm.used = appending global [4 x i8*]
// LLVM: @llvm.used = appending global [2 x i8*]
// LLVM-NOT: @llvm.used.

// EXECUTE: ctor