diff --git a/.cirrus.yml b/.cirrus.yml index e8b695b7243..9613301ab6a 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -65,12 +65,17 @@ packaging_steps_template: &PACKAGING_STEPS_TEMPLATE cd build ninja install > /dev/null cd .. - perl -pi -e s?$PWD/install/?%%ldcbinarypath%%/../?g install/etc/ldc2.conf + perl -pi -e s?$PWD/install/?%%ldcbinarypath%%/../?g install/etc/ldc2.conf/* if [[ "$CI_OS" == "freebsd" ]]; then - perl -pi -e "s?,druntime-ldc\",?,druntime-ldc\", \"-gcc=$CC\",?" install/etc/ldc2.conf + cat > install/etc/ldc2.conf/35-ldc-default-CC.conf < D:/a/1/install absInstallDir=$(cygpath --mixed "$absInstallDir") fi - perl -pi -e "s|$absInstallDir/|%%ldcbinarypath%%/../|g" install/etc/ldc2.conf - cat install/etc/ldc2.conf + confs=( install/etc/ldc2.conf/* ) + perl -pi -e "s|$absInstallDir/|%%ldcbinarypath%%/../|g" "${confs[@]}" + cat "${confs[@]}" - name: Rename the installation dir to test portability shell: bash diff --git a/.github/actions/5a-ios/action.yml b/.github/actions/5a-ios/action.yml index b9fd835e666..5105e64e573 100644 --- a/.github/actions/5a-ios/action.yml +++ b/.github/actions/5a-ios/action.yml @@ -32,8 +32,7 @@ runs: CMAKE_OSX_DEPLOYMENT_TARGET="$deployment_target" \ BUILD_LTO_LIBS=ON - section=" - \"$arch-apple-ios\": + section="\"$arch-apple-ios\": { switches ~= [ \"-Xcc=-isysroot\", @@ -44,5 +43,5 @@ runs: ]; rpath = \"%%ldcbinarypath%%/../lib-ios-$arch\"; };" - echo "$section" >> installed/etc/ldc2.conf - cat installed/etc/ldc2.conf + echo "$section" >> installed/etc/ldc2.conf/31-ldc-runtime-lib-ios-$arch.conf + cat installed/etc/ldc2.conf/* diff --git a/.github/actions/merge-macos/action.yml b/.github/actions/merge-macos/action.yml index 0ea64343996..5865608d9c0 100644 --- a/.github/actions/merge-macos/action.yml +++ b/.github/actions/merge-macos/action.yml @@ -39,77 +39,26 @@ runs: rm lib-{x86_64,arm64}/libLTO.dylib # ldc2.conf: - # 1) make a backup copy - cp etc/ldc2.conf /tmp/ldc2.conf.bak - # 2) strip to the header comments (remove all existing sections, only keep `default:` line) - sed -i '' '/^default:$/q' etc/ldc2.conf - # 3) append all sections (except for wasm) - cat >>etc/ldc2.conf < etc/ldc2.conf/30-ldc-runtime-lib-${arch}.conf <> etc/ldc2.conf + done - cat etc/ldc2.conf + cat etc/ldc2.conf/* - name: Run x86_64/arm64 macOS/iOS cross-compilation smoke tests shell: bash diff --git a/.github/actions/merge-windows/action.yml b/.github/actions/merge-windows/action.yml index d9a9a9f619e..d0cebae7ba0 100644 --- a/.github/actions/merge-windows/action.yml +++ b/.github/actions/merge-windows/action.yml @@ -20,23 +20,23 @@ runs: mv ldc2-*-x64 ldc2-multilib cd ldc2-multilib mv lib lib64 + mv etc/ldc2.conf/30-ldc-runtime-{lib,lib64}.conf cp -R ../ldc2-x86/lib lib32 cp ../ldc2-x86/bin/{*.dll,*.pdb,curl-ca-bundle.crt} lib32/ - name: Merge ldc2.conf shell: pwsh run: | cd ldc2-multilib - (cat etc\ldc2.conf).replace('%%ldcbinarypath%%/../lib', '%%ldcbinarypath%%/../lib64') | Set-Content etc\ldc2.conf - $conf32 = ' - "i[3-6]86-.*-windows-msvc": + (cat etc\ldc2.conf\30-ldc-runtime-lib64.conf).replace('%%ldcbinarypath%%/../lib', '%%ldcbinarypath%%/../lib64') | Set-Content etc\ldc2.conf\30-ldc-runtime-lib64.conf + $conf32 = '"i[3-6]86-.*-windows-msvc": { lib-dirs = [ "%%ldcbinarypath%%/../lib32", ]; }; ' - Add-Content etc\ldc2.conf $conf32 -NoNewline - cat etc\ldc2.conf + Set-Content etc\ldc2.conf\31-ldc-runtime-lib32.conf $conf32 + cat etc\ldc2.conf\* - name: Generate hello.d shell: bash @@ -88,16 +88,15 @@ runs: shell: pwsh run: | cd ldc2-multilib - $conf = ' - "(aarch|arm)64-.*-windows-msvc": + $conf = '"(aarch|arm)64-.*-windows-msvc": { lib-dirs = [ "%%ldcbinarypath%%/../libarm64", ]; }; ' - Add-Content etc\ldc2.conf $conf -NoNewline - cat etc\ldc2.conf + Set-Content etc\ldc2.conf\31-ldc-runtime-libarm64.conf $conf + cat etc\ldc2.conf\* - name: Run arm64 hello-world cross-compilation smoke tests shell: cmd run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index e75e67c922f..ed8a7b7c474 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,9 @@ # LDC master #### Big news -- **Breaking change for dcompute**: The special `@kernel` UDA is now a function and _**requires**_ parentheses as in `@kernel() void foo(){}`. Optionally you can provide launch dimensions, `@kernel([2,4,8])`, to specify to the compute runtime how the kernel is intended to be launched. +- **Breaking change for dcompute**: The special `@kernel` UDA is now a function and _**requires**_ parentheses as in `@kernel() void foo(){}`. Optionally you can provide launch dimensions, `@kernel([2,4,8])`, to specify to the compute runtime how the kernel is intended to be launched. +- ldc2.conf can now be a directory. All the files inside it, ordered naturally, will be concatenated and treated like a big config. +- **Breaking change for ldc2.conf cmake generation**: The `cmake` build process now generates the `ldc2.conf` and `ldc2_install.conf` as directories. `ldc2*.conf.in` and `ADDITIONAL_DEFAULT_LDC_SWITCHES` have been removed, if you need to add switches check out `makeConfSection` in `LdcConfig.cmake` #### Platform support diff --git a/CMakeLists.txt b/CMakeLists.txt index 21aad6d367d..b3e477c35e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,23 +17,14 @@ project(ldc) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules") +include(LdcCommon) + include(FindDCompiler) include(CheckCXXCompilerFlag) include(CheckDSourceCompiles) include(CheckLinkFlag) include(BuildDExecutable) -# Helper function -function(append value) - foreach(variable ${ARGN}) - if(${variable} STREQUAL "") - set(${variable} "${value}" PARENT_SCOPE) - else() - set(${variable} "${${variable}} ${value}" PARENT_SCOPE) - endif() - endforeach(variable) -endfunction() - # # Locate LLVM. # @@ -128,20 +119,9 @@ set(DMDFE_PATCH_VERSION 0) set(DMD_VERSION ${DMDFE_MAJOR_VERSION}.${DMDFE_MINOR_VERSION}.${DMDFE_PATCH_VERSION}) -# Generally, we want to install everything into CMAKE_INSTALL_PREFIX, but when -# it is /usr, put the config files into /etc to meet common practice. -if(NOT DEFINED SYSCONF_INSTALL_DIR) - if(CMAKE_INSTALL_PREFIX STREQUAL "/usr") - set(SYSCONF_INSTALL_DIR "/etc") - else() - set(SYSCONF_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/etc") - endif() -endif() - set(D_VERSION ${DMDFE_MAJOR_VERSION} CACHE STRING "D language version") set(PROGRAM_PREFIX "" CACHE STRING "Prepended to ldc/ldmd binary names") set(PROGRAM_SUFFIX "" CACHE STRING "Appended to ldc/ldmd binary names") -set(CONF_INST_DIR ${SYSCONF_INSTALL_DIR} CACHE PATH "Directory ldc2.conf is installed to") set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include/d CACHE PATH "Path to install D modules to") # Note: LIB_SUFFIX should perhaps be renamed to LDC_LIBDIR_SUFFIX. @@ -923,10 +903,6 @@ if(NOT DEFINED COMPILER_RT_LIBDIR_CONFIG) set(COMPILER_RT_LIBDIR_CONFIG "${COMPILER_RT_LIBDIR}") endif() endif() -if(DEFINED COMPILER_RT_LIBDIR_CONFIG) - message(STATUS "Adding ${COMPILER_RT_LIBDIR_CONFIG} to lib-dirs in configuration file") - set(OPTIONAL_COMPILER_RT_DIR "\n \"${COMPILER_RT_LIBDIR_CONFIG}\", // compiler-rt directory") -endif() # # Auxiliary build and test utils. @@ -974,6 +950,59 @@ endif() # add_subdirectory(tools) +# +# Compiler ldc2.conf configuration +# + +set(switches) + +# LLVM 16: Disable function specializations by default. +# They cause miscompiles of e.g. the frontend for some targets (macOS x86_64 and Windows x64). +if(LDC_LLVM_VER GREATER 1599 AND LDC_LLVM_VER LESS 1700) + list(APPEND switches "-func-specialization-size-threshold=1000000000") +endif() + +if(DEFINED COMPILER_RT_LIBDIR_CONFIG) + message(STATUS "Adding ${COMPILER_RT_LIBDIR_CONFIG} to lib-dirs in configuration file") +endif() + +list(APPEND switches "-defaultlib=phobos2-ldc,druntime-ldc") + +makeConfSection(NAME "35-ldc-compiler" SECTION "default" + BUILD + SWITCHES ${switches} + # -defaultlib is configure in runtime/CMakeLists.txt + POST_SWITCHES + "-I${PROJECT_SOURCE_DIR}/runtime/druntime/src" + "-I${PROJECT_BINARY_DIR}/import" + "-I${PROJECT_SOURCE_DIR}/runtime/phobos" + "-I${PROJECT_SOURCE_DIR}/runtime/jit-rt/d" + LIB_DIRS ${COMPILER_RT_LIBDIR_CONFIG} + + INSTALL + SWITCHES ${switches} + POST_SWITCHES "-I${INCLUDE_INSTALL_DIR}" + LIB_DIRS ${COMPILER_RT_LIBDIR_CONFIG} +) + +set(wasm_switches) +list(APPEND wasm_switches -defaultlib=) +# Default wasm stack is only 64kb, this is rather small, let's bump it to 1mb +list(APPEND wasm_switches -L-z -Lstack-size=1048576) +# Protect from stack overflow overwriting global memory +list(APPEND wasm_switches -L--stack-first) +if(LDC_WITH_LLD) + list(APPEND wasm_switches -link-internally) +endif() +# LLD 8+ requires (new) `--export-dynamic` for WebAssembly (https://github.com/ldc-developers/ldc/issues/3023). +list(APPEND wasm_switches -L--export-dynamic) + +makeConfSection(NAME "40-ldc-wasm" + SECTION "^wasm(32|64)-" + SWITCHES ${wasm_switches} + LIB_DIRS OVERRIDE +) + # # Test and runtime targets. Note that enable_testing() is order-sensitive! # @@ -1006,6 +1035,15 @@ option(LDC_BUILD_RUNTIME "Build the runtime libraries" ${_LDC_BUILD_RUNTIME_DEFA if(LDC_BUILD_RUNTIME) add_subdirectory(runtime) + + # POST_BUILD can't be used for targets in a different directory so + # runtime/CMakeLists.txt can't directly add the commands. + if(_LDC_POST_BUILD_COMMANDS) + add_custom_command(TARGET ${LDC_EXE} POST_BUILD + ${_LDC_POST_BUILD_COMMANDS} + BYPRODUCTS ${_LDC_POST_BUILD_BYPRODUCTS} + ) + endif() else() message(STATUS "NOT building the runtime libraries (LDC_BUILD_RUNTIME=OFF)") endif() @@ -1045,6 +1083,11 @@ if(${BUILD_SHARED}) install(TARGETS ${LDC_LIB} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}) endif() +# Add some documentation to the installed config files +if(NOT DONT_INSTALL_CONF) + install(FILES "ldc2.conf.header" DESTINATION "${CONF_INST_DIR}/ldc2.conf" RENAME 00-docs.conf) +endif() + if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") if(NOT DEFINED BASH_COMPLETION_COMPLETIONSDIR) find_package(bash-completion QUIET) diff --git a/cmake/Modules/LdcCommon.cmake b/cmake/Modules/LdcCommon.cmake new file mode 100644 index 00000000000..4db35c16bc3 --- /dev/null +++ b/cmake/Modules/LdcCommon.cmake @@ -0,0 +1,13 @@ +# Common functionality shared by the compiler and the runtime build system. + +function(append value) + foreach(variable ${ARGN}) + if(${variable} STREQUAL "") + set(${variable} "${value}" PARENT_SCOPE) + else() + set(${variable} "${${variable}} ${value}" PARENT_SCOPE) + endif() + endforeach(variable) +endfunction() + +include(LdcConfig) diff --git a/cmake/Modules/LdcConfig.cmake b/cmake/Modules/LdcConfig.cmake new file mode 100644 index 00000000000..e986b212ad4 --- /dev/null +++ b/cmake/Modules/LdcConfig.cmake @@ -0,0 +1,233 @@ +# Functions used for generating and installing ldc2.conf + +function(defineIfUnset variable) + if(ARGC EQUAL 1) + set(args) + else() + list(SUBLIST ARGV 1 -1 args) + endif() + + if(NOT DEFINED ${variable}) + set(${variable} ${args} PARENT_SCOPE) + endif() +endfunction() + +function(formatArray out_var) + if(ARGC EQUAL 1) + set(${out_var} "[]" PARENT_SCOPE) + return() + endif() + + list(SUBLIST ARGV 1 -1 values) + set(result "[") + foreach(value ${values}) + set(result "${result}\n \"${value}\",") + endforeach() + set(result "${result}\n ]") + + set(${out_var} "${result}" PARENT_SCOPE) +endfunction() + +function(formatArraySetting out_var name) + if(ARGC EQUAL 2) + # Ignore `value ~= []` + set(${out_var} "" PARENT_SCOPE) + return() + endif() + + list(SUBLIST ARGV 2 -1 values) + list(GET values 0 maybe_override) + if(maybe_override STREQUAL "OVERRIDE") + set(operator "=") + list(POP_FRONT values) + else() + set(operator "~=") + endif() + formatArray(array ${values}) + set(${out_var} "\n ${name} ${operator} ${array};" PARENT_SCOPE) +endfunction() + +function(formatScalarSetting out_var name) + if(ARGC EQUAL 2) + set(${out_var} "" PARENT_SCOPE) + else() + set(${out_var} "\n ${name} = \"${ARGV2}\";" PARENT_SCOPE) + endif() +endfunction() + + +# Create a ldc2.conf section +# +# Example: +# +# makeConfSectionImpl( +# FILEPATH "${CMAKE_BINARY_DIR}/ldc2.conf" +# # The output filename +# +# SECTION "^wasm(32|64)-" +# # A regex to match a target triple or "default" +# +# SWITCHES -d-version=foo -L--linker-flag +# # The `switches` list +# +# POST_SWITCHES OVERRIDE -I/path/to/druntime/src +# # The `post-switches` list +# +# LIB_DIRS "${CMAKE_BINARY_DIR}/lib64" +# # The `lib-dirs` list +# +# RPATH "/path/to/dir" +# # The `rpath` value +# ) +# +# Would generate: +# +# $ cat "${CMAKE_BINARY_DIR}/ldc2.conf" +# "^wasm(32|64)-": +# { +# switches ~= [ +# "-d-version=foo", +# "-L--linker-flag", +# ]; +# post-switches = [ +# "-I/path/to/druntime/src" +# ]; +# lib-dirs ~= [ +# "${CMAKE_BINARY_DIR}/lib64" +# ]; +# rpath = "/path/to/dir" +# } +# +# You don't need to pass all setting keys, only the ones that have values. +# +# Array settings (SWITCHES, POST_SWITCHES, LIB_DIRS) may start with an +# OVERRIDE signifying that they should overwrite the (possibly) +# previously stored values. The default is to append to them. +function(makeConfSectionImpl) + set(oneValueArgs FILEPATH SECTION RPATH) + set(multiValueArgs SWITCHES POST_SWITCHES LIB_DIRS) + cmake_parse_arguments(args "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + foreach(var FILEPATH SECTION) + if(NOT DEFINED args_${var}) + message(SEND_ERROR "Expected ${var} argument") + endif() + endforeach() + if(DEFINED args_UNPARSED_ARGUMENTS) + message(SEND_ERROR "Unexpected arguments: ${args_UNPARSED_ARGUMENTS}") + endif() + + formatArraySetting(switches "switches" ${args_SWITCHES}) + formatArraySetting(post_switches "post-switches" ${args_POST_SWITCHES}) + formatArraySetting(lib_dirs "lib-dirs" ${args_LIB_DIRS}) + # Support `RPATH ""` to clear the setting + set(rpath) + if(args_RPATH OR "RPATH" IN_LIST args_KEYWORDS_MISSING_VALUES) + formatScalarSetting(rpath "rpath" "${args_RPATH}") + endif() + + file(WRITE "${args_FILEPATH}" + "\"${args_SECTION}\":\n" + "{" + "${switches}" + "${post_switches}" + "${lib_dirs}" + "${rpath}" + "\n};\n" + ) +endfunction() + +# Create a ldc2.conf section +# +# Example: +# +# makeConfSection( +# NAME 40-runtime +# # a unique name for the file that will store this section +# +# SECTION "x86_64-.*-linux-gnu" +# # A regex for a target triple or the string "default" +# +# BUILD +# # Settings for ldc2.conf when part of this cmake project +# SWITCHES -a -b +# POST_SWITCHES -I${CMAKE_SOURCE_DIR}/runtime/import -c +# +# INSTALL +# # Settings for ldc2.conf when installed on a user system +# SWITCHES OVERRIDE -bar +# LIB_DIRS "${CMAKE_INSTALL_PREFIX}/lib" +# RPATH "${CMAKE_INSTALL_PREFIX}/lib" +# ) +# +# The possible settings are described by makeConfSectionImpl. +# +# As a shortcut the BUILD and INSTALL arguments may be omitted, making the +# settings be applied to both build and install ldc2.conf. Example: +# +# makeConfSection(NAME 10-example SECTION default +# SWITCHES -my-important-switch +# ) +# +# Is equivalent to: +# +# makeConfSection(NAME 10-example SECTION default +# BUILD +# SWITCHES -my-important-switch +# INSTALL +# SWITCHES -my-important-switch +# ) +# +# It is also possible to generate a configuration file for either only the build +# or only the install. Simply pass only BUILD or INSTALL to this function. +function(makeConfSection) + set(oneValueArgs NAME SECTION) + set(multiValueArgs BUILD INSTALL) + cmake_parse_arguments(PARSE_ARGV 0 args "" "${oneValueArgs}" "${multiValueArgs}") + + foreach(var ${oneValueArgs}) + if(NOT DEFINED args_${var}) + message(SEND_ERROR "Expected defined ${var} argument") + endif() + endforeach() + if(DEFINED args_UNPARSED_ARGUMENTS) + if(NOT DEFINED args_BUILD AND NOT DEFINED args_INSTALL) + set(args_BUILD "${args_UNPARSED_ARGUMENTS}") + set(args_INSTALL "${args_UNPARSED_ARGUMENTS}") + else() + message(SEND_ERROR "Unexpected arguments: ${args_UNPARSED_ARGUMENTS}") + endif() + endif() + + if(args_BUILD) + set(build_conf "${LDC_BUILD_CONF}/${args_NAME}.conf") + makeConfSectionImpl(FILEPATH "${build_conf}" SECTION "${args_SECTION}" ${args_BUILD}) + endif() + if(args_INSTALL) + set(install_conf "${LDC_INSTALL_CONF}/${args_NAME}.conf") + makeConfSectionImpl(FILEPATH "${install_conf}" SECTION "${args_SECTION}" ${args_INSTALL}) + if(NOT DONT_INSTALL_CONF) + install(FILES "${install_conf}" DESTINATION "${CONF_INST_DIR}/ldc2.conf") + endif() + endif() +endfunction() + +# Generally, we want to install everything into CMAKE_INSTALL_PREFIX, but when +# it is /usr, put the config files into /etc to meet common practice. +if(NOT DEFINED SYSCONF_INSTALL_DIR) + if(CMAKE_INSTALL_PREFIX STREQUAL "/usr") + set(SYSCONF_INSTALL_DIR "/etc") + else() + set(SYSCONF_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/etc") + endif() +endif() + +set(CONF_INST_DIR ${SYSCONF_INSTALL_DIR} CACHE PATH "Directory in which to install ldc2.conf") +if(CONF_INST_DIR STREQUAL "") + set(DONT_INSTALL_CONF TRUE) +else() + set(DONT_INSTALL_CONF FALSE) +endif() + +defineIfUnset(LDC_BUILD_CONF "${CMAKE_BINARY_DIR}/etc/ldc2.conf") +defineIfUnset(LDC_INSTALL_CONF "${CMAKE_BINARY_DIR}/etc/ldc2_install.conf") diff --git a/driver/configfile.cpp b/driver/configfile.cpp index cac8c7854fc..f5510634976 100644 --- a/driver/configfile.cpp +++ b/driver/configfile.cpp @@ -16,9 +16,12 @@ #include "llvm/Support/Path.h" #include "llvm/Support/Regex.h" #include +#include #include #include #include +#include +#include #if _WIN32 #define WIN32_LEAN_AND_MEAN @@ -193,9 +196,43 @@ bool ConfigFile::read(const char *explicitConfFile, const char *triple) { } pathcstr = strdup(pathstr.c_str()); - auto binpath = exe_path::getBinDir(); + return iterateConfigFiles(pathstr, triple); +} + +bool ConfigFile::iterateConfigFiles(const std::string &path, const char *triple) { + auto bindirString = exe_path::getBinDir(); + auto bindir = bindirString.c_str(); + + if (sys::fs::is_directory(path)) { + llvm::SmallVector configFiles; + + std::error_code ec; + auto it = sys::fs::directory_iterator(path, ec); + do { + if (ec) { + fprintf(stderr, "Could not iterate config directory at %s: %s\n", + path.c_str(), ec.message().c_str()); + return false; + } + if (it->type() != sys::fs::file_type::regular_file) + continue; + + configFiles.emplace_back(it->path()); + } while (it.increment(ec) != sys::fs::directory_iterator{}); + + llvm::sort(configFiles, [](const std::string &a, const std::string &b) { + auto sa = llvm::StringRef(a), sb = llvm::StringRef(b); + return sa.compare_numeric(sb) < 0; + }); + + for (const auto &configPath: configFiles) + if (!readConfig(configPath.c_str(), triple, bindir)) + return false; + + return true; + } - return readConfig(pathcstr, triple, binpath.c_str()); + return readConfig(pathcstr, triple, bindir); } void ConfigFile::extendCommandLine(llvm::SmallVectorImpl &args) { diff --git a/driver/configfile.d b/driver/configfile.d index 11c7299416b..4bb6935ce63 100644 --- a/driver/configfile.d +++ b/driver/configfile.d @@ -29,9 +29,8 @@ string normalizeSlashes(const(char)* binDir) return cast(string)res; // assumeUnique } -const(string)[] findArraySetting(GroupSetting[] sections, string name) +void findArraySetting(GroupSetting[] sections, string name, void delegate(const ArraySetting as) callback) { - const(string)[] result = null; foreach (section; sections) { foreach (c; section.children) @@ -39,14 +38,10 @@ const(string)[] findArraySetting(GroupSetting[] sections, string name) if (c.type == Setting.Type.array && c.name == name) { auto as = cast(ArraySetting) c; - if (as.isAppending) - result ~= as.vals; - else - result = as.vals; + callback(as); } } } - return result; } string findScalarSetting(GroupSetting[] sections, string name) @@ -128,6 +123,49 @@ string replacePlaceholders(string str, CfgPaths cfgPaths) .replace("%%ldcversion%%", cast(string) global.ldc_version); } +/++ Check that a section only contains known config keys + + ldc recognizes: + - switches + - post-switches + - lib-dirs + - rpath ++/ +void validateSettingNames(const GroupSetting group, const char* filePath) { + static void fail(const Setting setting, const char* filePath) { + string fmt(Setting.Type type) { + final switch(type) { + static foreach (mem; __traits(allMembers, Setting.Type)) + case __traits(getMember, Setting.Type, mem): + return mem; + } + } + + import dmd.root.string : toDString; + string msg; + if (setting.type == Setting.Type.group) + msg = "Nested group " ~ setting.name ~ " is unsupported"; + else + msg = "Unknown " ~ fmt(setting.type) ~ " setting named " ~ setting.name; + + throw new Exception(msg); + } + + alias ST = Setting.Type; + const static knownSettings = [ + new Setting("switches", ST.array), + new Setting("post-switches", ST.array), + new Setting("lib-dirs", ST.array), + new Setting("rpath", ST.scalar), + ]; + outer: foreach (setting; group.children) { + foreach (known; knownSettings) + if (setting.name == known.name && setting.type == known.type) + continue outer; + fail(setting, filePath); + } +} + extern(C++) struct ConfigFile { __gshared ConfigFile instance; @@ -160,37 +198,34 @@ private: } } - if (sections.length == 0) - { - throw new Exception("No matching section for triple '" ~ cast(string) triple.toDString - ~ "'"); - } - - const switches = findArraySetting(sections, "switches"); - const postSwitches = findArraySetting(sections, "post-switches"); - if (switches.length + postSwitches.length == 0) - throw new Exception("Could not look up switches"); + foreach (group; sections) + validateSettingNames(group, cfPath); - void applyArray(ref Array!(const(char)*) output, const(string)[] input) + void readArraySetting(GroupSetting[] sections, string name, ref Array!(const(char)*) output) { - output.setDim(0); - - output.reserve(input.length); - foreach (sw; input) + void applyArray(const ArraySetting input) { - const finalSwitch = sw.replacePlaceholders(cfgPaths).toCString; - output.push(finalSwitch.ptr); + if (!input.isAppending) + output.setDim(0); + + output.reserve(input.vals.length); + foreach (sw; input.vals) + { + const finalSwitch = sw.replacePlaceholders(cfgPaths).toCString; + output.push(finalSwitch.ptr); + } } + findArraySetting(sections, name, &applyArray); } - applyArray(this.switches, switches); - applyArray(this.postSwitches, postSwitches); - - const libDirs = findArraySetting(sections, "lib-dirs"); - applyArray(_libDirs, libDirs); - + readArraySetting(sections, "switches", switches); + readArraySetting(sections, "post-switches", postSwitches); + readArraySetting(sections, "lib-dirs", _libDirs); const rpath = findScalarSetting(sections, "rpath"); - this.rpathcstr = rpath.length == 0 ? null : rpath.replacePlaceholders(cfgPaths).toCString.ptr; + // A missing rpath => do nothing + // An empty rpath => clear the setting + if (rpath.ptr !is null) + this.rpathcstr = rpath.length == 0 ? null : rpath.replacePlaceholders(cfgPaths).toCString.ptr; return true; } diff --git a/driver/configfile.h b/driver/configfile.h index c1f56a0403b..71e5c1622ee 100644 --- a/driver/configfile.h +++ b/driver/configfile.h @@ -43,6 +43,8 @@ struct ConfigFile { // implemented in D bool readConfig(const char *cfPath, const char *triple, const char *binDir); + bool iterateConfigFiles(const std::string &path, const char *triple); + const char *pathcstr = nullptr; Array switches; Array postSwitches; diff --git a/ldc2.conf.header b/ldc2.conf.header new file mode 100644 index 00000000000..9623834cc80 --- /dev/null +++ b/ldc2.conf.header @@ -0,0 +1,168 @@ +////////////////// Getting started +// +// These beginning comments are meant to help you understand how to +// configure ldc2 through ldc2.conf. +// +////////////////// Layout of ldc2.conf +// +// ldc2.conf can be either a file or a directory. In case of a +// directory the files *directly* inside it are read in a natural +// numerical order (e.g conf-10 comes after conf-9). Depending on how +// ldc2 has been installed you are either reading this as the +// beginning of ldc2.conf or as the file ldc2.conf/00-docs.conf. +// +// If ldc2.conf is a directory the extensions of the file inside it +// don't matter but the ones that come with ldc2 have a `.conf` +// extension for clarity. +// +////////////////// Structure of configuration files +// +// Each configuration file is formed by a series of sections, each +// section containing settings. For example: +// +// ``` +// // A section that applies regardless of the target system +// "default": { +// // default switches injected before all explicit command-line switches +// switches = [ +// "-link-defaultlib-shared=false", +// ]; +// // default switches appended after all explicit command-line switches +// post-switches = [ +// "-I/usr/local/include", +// ]; +// // default directories to be searched for libraries when linking +// lib-dirs = [ +// "/usr/local/lib/", +// ]; +// // default rpath when linking against the shared default libs +// rpath = "%%ldcbinarypath%%/../lib"; +// } +// +// // A section that only applies when compiling for WebAssembly +// "^wasm(32|64)-": { +// // `~=` appends the -defaultlib argument to the previous value +// switches ~= [ +// "-defaultlib=", +// ]; +// // `=` overwrites the previous value of the setting +// lib-dirs = []; +// }; +// ``` +// +// See comments in driver/config.d in the ldc source tree for grammar +// description of the config files. +// +////////////////// Defining sections +// +// A section is formed from a regex that is matched against the target +// triple followed by a group of settings. The string "default" is +// treated specially in this context as it means *any triple*, having +// its settings always be applied. +// +// The syntax for defining a section is: +// +// ``` +// "": { +// ... +// } +// ``` +// +// Where `` can be, for example: +// - x86_64-.*-linux-gnu :: matches when targeting x64 linux glibc +// - ^wasm(32|64)?- :: matches when targeting WebAssembly +// - default :: always matches +// +// To check what triple ldc is targeting pass the `-v` switch +// (alongside any `-mtriple` or `-m32` switches) and look for the +// `config` line: +// +// ``` +// $ ./bin/ldc2 -m32 -v +// binary /home/happy/git/ldc/build/bin/ldc2 +// version 1.41.0-git-f1f7373-dirty (DMD v2.111.0, LLVM 19.1.7) +// config /home/happy/git/ldc/build/etc/ldc2.conf (i686-pc-linux-gnu) +// ``` +// +// In the above example the target triple is `i686-pc-linux-gnu`. +// +////////////////// Assigning values +// +// There are two operators for assigning to settings: `=` and `~=`. The +// former overwrites the previous value and works on both array and +// string settings (so all settings) and the latter, like the D +// counterpart, appends the given array to the previous value, +// therefore it only works on the array settings ('switches', +// 'post-switches' and 'lib-dirs'). +// +// As an example, assuming that the next lines are in a section: +// +// ``` +// switches = [ "-flag-1" ]; +// switches = [ "-flag-2" ]; +// post-switches = [ "-pflag-1" ] +// post-switches ~= [ "-pflag-2" ] +// rpath = "/a/b/c" +// ``` +// +// The final values of the settings are: +// - switches :: [ "-flag-2" ] +// - post-switches :: [ "-pflag-1", "-pflag-2" ] +// - lib-dirs :: [] +// - rpath :: "/a/b/c" +// +// The trailing `;` after an assignment is optional. +// +// Please note that it is currently not possible to append a string to +// an array, you must wrap the value in [] like so: +// +// ``` +// switches ~= "-O"; // Error +// switches ~= [ "-O" ]; // Works +// ``` +// +////////////////// Placeholder variables +// +// There are currently three placeholder variables: +// +// - %%ldcbinarypath%% :: the directory which contains the ldc2 executable +// - %%ldcconfigpath%% :: the path to ldc2.conf (be it a directory or a file) +// - %%ldcversion%% :: the ldc2 version as a string (e.g. 1.41.0-git-f1f7373-dirty) +// +// You can use these patterns inside strings and they will be +// substituted at runtime with their values, like so: +// +// ``` +// lib-dirs ~= [ "%%ldcbinarypath%%/../lib32" ] +// ``` +// +////////////////// Example use cases +// +/////// 1. Disabling the -release switch +// +// ``` +// // ldc2.conf/9999-remove-release +// default: { +// post-switches ~= [ +// "--enable-asserts", +// "--enable-contracts", +// "--enable-invariants", +// "--enable-switch-errors", +// "--boundscheck=on", +// ] +// } +// ``` +// +/////// 2. Setting up cross compilation +// +// This assumes that you have built a aarch64 linux musl version of +// the runtime and have installed it in 'lib-rpi' alongside the native +// 'lib' folder of ldc2. +// +// ``` +// // This snippet is at the end of ldc2.conf +// "aarch64-.*-linux-musl": { +// switches ~= [ "-link-defaultlib-shared=false" ] +// lib-dirs = [ "%%ldcbinarypath%%/../lib-rpi" ] +// } +// ``` diff --git a/ldc2.conf.in b/ldc2.conf.in deleted file mode 100644 index f3b7be13398..00000000000 --- a/ldc2.conf.in +++ /dev/null @@ -1,43 +0,0 @@ -// See comments in driver/config.d in ldc source tree for grammar description of -// this config file. - -// For cross-compilation, you can add sections for specific target triples by -// naming the sections as (quoted) regex patterns. See LDC's `-v` output -// (`config` line) to figure out your normalized triple, depending on the used -// `-mtriple`, `-m32` etc. E.g.: -// -// "^arm.*-linux-gnueabihf$": { … }; -// "86(_64)?-.*-linux": { … }; -// "i[3-6]86-.*-windows-msvc": { … }; -// -// Later sections take precedence and override settings from previous matching -// sections while inheriting unspecified settings from previous sections. -// A `default` section always matches (treated as ".*") and is therefore usually -// the first section. -default: -{ - // default switches injected before all explicit command-line switches - switches = [ - "-defaultlib=druntime-ldc",@ADDITIONAL_DEFAULT_LDC_SWITCHES@ - ]; - // default switches appended after all explicit command-line switches - post-switches = [ - "-I@RUNTIME_DIR@/src", - "-I@LDC_GCCBUILTINS_IMPORT_DIR@", - "-I@JITRT_DIR@/d", - ]; - // default directories to be searched for libraries when linking - lib-dirs = [ - "@CMAKE_BINARY_DIR@/lib@LIB_SUFFIX@",@OPTIONAL_COMPILER_RT_DIR@ - ]; - // default rpath when linking against the shared default libs - rpath = "@SHARED_LIBS_RPATH@"; -}; - -"^wasm(32|64)-": -{ - switches = [ - "-defaultlib=",@WASM_DEFAULT_LDC_SWITCHES@ - ]; - lib-dirs = []; -}; diff --git a/ldc2_install.conf.in b/ldc2_install.conf.in deleted file mode 100644 index f8afa42613c..00000000000 --- a/ldc2_install.conf.in +++ /dev/null @@ -1,41 +0,0 @@ -// See comments in driver/config.d in ldc source tree for grammar description of -// this config file. - -// For cross-compilation, you can add sections for specific target triples by -// naming the sections as (quoted) regex patterns. See LDC's `-v` output -// (`config` line) to figure out your normalized triple, depending on the used -// `-mtriple`, `-m32` etc. E.g.: -// -// "^arm.*-linux-gnueabihf$": { … }; -// "86(_64)?-.*-linux": { … }; -// "i[3-6]86-.*-windows-msvc": { … }; -// -// Later sections take precedence and override settings from previous matching -// sections while inheriting unspecified settings from previous sections. -// A `default` section always matches (treated as ".*") and is therefore usually -// the first section. -default: -{ - // default switches injected before all explicit command-line switches - switches = [ - "-defaultlib=phobos2-ldc,druntime-ldc",@ADDITIONAL_DEFAULT_LDC_SWITCHES@ - ]; - // default switches appended after all explicit command-line switches - post-switches = [ - "-I@INCLUDE_INSTALL_DIR@", - ]; - // default directories to be searched for libraries when linking - lib-dirs = [ - "@CMAKE_INSTALL_LIBDIR@",@OPTIONAL_COMPILER_RT_DIR@ - ]; - // default rpath when linking against the shared default libs - rpath = "@SHARED_LIBS_INSTALL_RPATH@"; -}; - -"^wasm(32|64)-": -{ - switches = [ - "-defaultlib=",@WASM_DEFAULT_LDC_SWITCHES@ - ]; - lib-dirs = []; -}; diff --git a/ldc2_phobos.conf.in b/ldc2_phobos.conf.in deleted file mode 100644 index 3bb6e85c62b..00000000000 --- a/ldc2_phobos.conf.in +++ /dev/null @@ -1,44 +0,0 @@ -// See comments in driver/config.d in ldc source tree for grammar description of -// this config file. - -// For cross-compilation, you can add sections for specific target triples by -// naming the sections as (quoted) regex patterns. See LDC's `-v` output -// (`config` line) to figure out your normalized triple, depending on the used -// `-mtriple`, `-m32` etc. E.g.: -// -// "^arm.*-linux-gnueabihf$": { … }; -// "86(_64)?-.*-linux": { … }; -// "i[3-6]86-.*-windows-msvc": { … }; -// -// Later sections take precedence and override settings from previous matching -// sections while inheriting unspecified settings from previous sections. -// A `default` section always matches (treated as ".*") and is therefore usually -// the first section. -default: -{ - // default switches injected before all explicit command-line switches - switches = [ - "-defaultlib=phobos2-ldc,druntime-ldc",@ADDITIONAL_DEFAULT_LDC_SWITCHES@ - ]; - // default switches appended after all explicit command-line switches - post-switches = [ - "-I@RUNTIME_DIR@/src", - "-I@LDC_GCCBUILTINS_IMPORT_DIR@", - "-I@JITRT_DIR@/d", - "-I@PHOBOS2_DIR@", - ]; - // default directories to be searched for libraries when linking - lib-dirs = [ - "@CMAKE_BINARY_DIR@/lib@LIB_SUFFIX@",@OPTIONAL_COMPILER_RT_DIR@ - ]; - // default rpath when linking against the shared default libs - rpath = "@SHARED_LIBS_RPATH@"; -}; - -"^wasm(32|64)-": -{ - switches = [ - "-defaultlib=",@WASM_DEFAULT_LDC_SWITCHES@ - ]; - lib-dirs = []; -}; diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index b10172b8ad2..6bee423dc2e 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -1,8 +1,11 @@ cmake_minimum_required(VERSION 3.16.0) project(runtime C ASM) -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}) +cmake_path(GET CMAKE_CURRENT_SOURCE_DIR PARENT_PATH PROJECT_PARENT_DIR) +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR} "${PROJECT_PARENT_DIR}/cmake/Modules") + +include(LdcCommon) include(CheckIncludeFile) # Verify required variables if this CMake project is NOT embedded in the LDC CMake project. @@ -13,20 +16,6 @@ if(NOT LDC_EXE) if(NOT DEFINED DMDFE_MINOR_VERSION OR NOT DEFINED DMDFE_PATCH_VERSION) message(FATAL_ERROR "Please define the CMake variables DMDFE_MINOR_VERSION and DMDFE_PATCH_VERSION.") endif() - if(NOT DEFINED LDC_WITH_LLD) - message(FATAL_ERROR "Please define the CMake variable LDC_WITH_LLD.") - endif() - - # Helper function - function(append value) - foreach(variable ${ARGN}) - if(${variable} STREQUAL "") - set(${variable} "${value}" PARENT_SCOPE) - else() - set(${variable} "${${variable}} ${value}" PARENT_SCOPE) - endif() - endforeach(variable) - endfunction() endif() # @@ -271,103 +260,98 @@ endif() # Create configuration files. # -# Default -rpath linker option when linking against shared libraries. -if(SHARED_LIBS_SUPPORTED) - set(SHARED_LIBS_RPATH "${CMAKE_BINARY_DIR}/lib${LIB_SUFFIX}") - set(SHARED_LIBS_INSTALL_RPATH "${CMAKE_INSTALL_LIBDIR}") -endif() +set(switches) # Only have either shared or static libs? # Then explicitly default to linking against them via default LDC switch. if(${BUILD_SHARED_LIBS} STREQUAL "ON") - set(ADDITIONAL_DEFAULT_LDC_SWITCHES "${ADDITIONAL_DEFAULT_LDC_SWITCHES}\n \"-link-defaultlib-shared\",") + set(switches "-link-defaultlib-shared") elseif(${BUILD_SHARED_LIBS} STREQUAL "OFF") - set(ADDITIONAL_DEFAULT_LDC_SWITCHES "${ADDITIONAL_DEFAULT_LDC_SWITCHES}\n \"-link-defaultlib-shared=false\",") + set(switches "-link-defaultlib-shared=false") endif() -# LLVM 16: Disable function specializations by default. -# They cause miscompiles of e.g. the frontend for some targets (macOS x86_64 and Windows x64). -if(LDC_LLVM_VER GREATER 1599 AND LDC_LLVM_VER LESS 1700) - set(ADDITIONAL_DEFAULT_LDC_SWITCHES "${ADDITIONAL_DEFAULT_LDC_SWITCHES}\n \"-func-specialization-size-threshold=1000000000\",") -endif() +set(build_libdir "${CMAKE_BINARY_DIR}/lib${LIB_SUFFIX}") +set(install_libdir "${CMAKE_INSTALL_LIBDIR}") -# Default wasm stack is only 64kb, this is rather small, let's bump it to 1mb -set(WASM_DEFAULT_LDC_SWITCHES "${WASM_DEFAULT_LDC_SWITCHES}\n \"-L-z\", \"-Lstack-size=1048576\",") -# Protect from stack overflow overwriting global memory -set(WASM_DEFAULT_LDC_SWITCHES "${WASM_DEFAULT_LDC_SWITCHES}\n \"-L--stack-first\",") -if(LDC_WITH_LLD) - set(WASM_DEFAULT_LDC_SWITCHES "${WASM_DEFAULT_LDC_SWITCHES}\n \"-link-internally\",") +# Default -rpath linker option when linking against shared libraries. +if(SHARED_LIBS_SUPPORTED) + set(build_rpath "${build_libdir}") + set(install_rpath "${install_libdir}") endif() -# LLD 8+ requires (new) `--export-dynamic` for WebAssembly (https://github.com/ldc-developers/ldc/issues/3023). -set(WASM_DEFAULT_LDC_SWITCHES "${WASM_DEFAULT_LDC_SWITCHES}\n \"-L--export-dynamic\",") -# Note: normally inherited from LDC CMake parent build, and only needed for ldc2_install.conf -set(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include/d" CACHE PATH "Path the D modules are installed to") +makeConfSection(NAME "30-ldc-runtime-lib${LIB_SUFFIX}" + SECTION "default" -# Note: default value only works if embedded in LDC CMake parent build, but only needed for ImportC (__importc_builtins.di) and non-install ldc2.conf -set(LDC_GCCBUILTINS_IMPORT_DIR "${CMAKE_BINARY_DIR}/import" CACHE PATH "Directory filled with auto-generated ldc/gccbuiltins_*.di files") + BUILD + SWITCHES ${switches} + LIB_DIRS OVERRIDE ${build_libdir} + RPATH ${build_rpath} -# Generate .conf files -if(LDC_EXE) - set(CONFIG_BASE ${LDC_EXE}) -else() # not included from LDC parent build - set(CONFIG_BASE ldc2) -endif() -if(PHOBOS2_DIR) - set(CONFIG_NAME ${CONFIG_BASE}_phobos) -else() - set(CONFIG_NAME ${CONFIG_BASE}) -endif() -set(conf_path ${CMAKE_BINARY_DIR}/etc/${CONFIG_BASE}.conf) -set(install_conf_path ${CMAKE_BINARY_DIR}/etc/${CONFIG_BASE}_install.conf) -configure_file(${PROJECT_SOURCE_DIR}/../${CONFIG_NAME}.conf.in ${conf_path} @ONLY) -configure_file(${PROJECT_SOURCE_DIR}/../${CONFIG_BASE}_install.conf.in ${install_conf_path} @ONLY) + INSTALL + SWITCHES ${switches} + LIB_DIRS OVERRIDE ${install_libdir} + RPATH ${install_rpath} +) # macOS has fat libraries; otherwise, append a separate config file section for the # multilib target and override the lib directory. if(MULTILIB AND NOT "${TARGET_SYSTEM}" MATCHES "APPLE") - # Rename the just configured host-only *.conf files to *.conf.in during CMake invocation. - file(RENAME ${conf_path} ${conf_path}.in) - file(RENAME ${install_conf_path} ${install_conf_path}.in) - - set(MULTILIB_DIR "${CMAKE_BINARY_DIR}/lib${MULTILIB_SUFFIX}") - set(MULTILIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib${MULTILIB_SUFFIX}") - - # The helper script determines the multilib triple by parsing the - # `ldc2 -m32 -v` output. This means we depend on a built ldc2 - # executable; sadly, we cannot add post-build commands to that - # top-level target directly, so use a custom target (built as part - # of `all`) to finalize the 2 config files. - add_custom_command(OUTPUT ${conf_path} VERBATIM - COMMAND ${PROJECT_SOURCE_DIR}/../tools/add-multilib-section.sh - ${LDC_EXE_FULL} - ${MULTILIB_SUFFIX} - ${MULTILIB_DIR} - "$<$:${MULTILIB_DIR}>" - ${conf_path}.in - ${conf_path} - DEPENDS ${LDC_EXE_FULL} - ) - add_custom_command(OUTPUT ${install_conf_path} VERBATIM - COMMAND ${PROJECT_SOURCE_DIR}/../tools/add-multilib-section.sh - ${LDC_EXE_FULL} - ${MULTILIB_SUFFIX} - ${MULTILIB_INSTALL_DIR} - "$<$:${MULTILIB_INSTALL_DIR}>" - ${install_conf_path}.in - ${install_conf_path} - DEPENDS ${LDC_EXE_FULL} - ) - add_custom_target(add-multilib-section ALL - DEPENDS ${conf_path} ${install_conf_path} + set(build_libdir "${CMAKE_BINARY_DIR}/lib${MULTILIB_SUFFIX}") + set(install_libdir "${CMAKE_INSTALL_PREFIX}/lib${MULTILIB_SUFFIX}") + if(SHARED_LIBS_SUPPORTED) + set(build_rpath "${build_libdir}") + set(install_rpath "${install_libdir}") + endif() + + set(name "31-ldc-runtime-lib${MULTILIB_SUFFIX}") + set(sectionPlaceholder "LDC_CONF_MULTILIB_TRIPLE_REGEX") + makeConfSection(NAME "${name}" + SECTION "${sectionPlaceholder}" + BUILD + LIB_DIRS OVERRIDE ${build_libdir} + RPATH ${build_rpath} + INSTALL + LIB_DIRS OVERRIDE ${install_libdir} + RPATH ${install_rpath} ) -endif() -if(NOT DEFINED CONF_INST_DIR) # set by parent LDC build - set(CONF_INST_DIR "${CMAKE_INSTALL_PREFIX}/etc") + set(build_conf "${LDC_BUILD_CONF}/${name}.conf") + set(install_conf "${LDC_INSTALL_CONF}/${name}.conf") + set(confs "${build_conf}" "${install_conf}") + foreach(conf ${confs}) + # Rename the just-generated config files in order to replace sectionPlaceholder + file(RENAME "${conf}" "${conf}.in") + set(fill_cmd + "${PROJECT_PARENT_DIR}/tools/fill-multilib-triple.sh" + "${conf}.in" + "${conf}" + "${sectionPlaceholder}" + # Next arguments are a compiler invocation for the desired triple + "${LDC_EXE_FULL}" -m${MULTILIB_SUFFIX} + ) + if(LDC_EXE) + # We need to get the -m32 target triple but the compiler + # is not built yet. We can't depend on LDC_EXE since that + # would cause a cycle so pass-through the needed commands + # up to the root project and let it run them as POST_BUILD + # commands. This avoids adding the config_files as + # transitive dependencies to all compiled D files. + # + # The `COMMAND` comes from the syntax of + # add_custom_command. `BYPRODUCTS` is needed by ninja + # because it needs to know which command generates the + # config files that will be installed. + list(APPEND _LDC_POST_BUILD_COMMANDS "COMMAND" ${fill_cmd}) + list(APPEND _LDC_POST_BUILD_BYPRODUCTS "${conf}") + else() + execute_process(COMMAND ${fill_cmd}) + endif() + endforeach() endif() -if(NOT CONF_INST_DIR STREQUAL "") # allow skipping the ldc2.conf installation - install(FILES ${install_conf_path} DESTINATION ${CONF_INST_DIR} RENAME ${CONFIG_BASE}.conf) + +if(LDC_EXE) + set(_LDC_POST_BUILD_COMMANDS "${_LDC_POST_BUILD_COMMANDS}" PARENT_SCOPE) + set(_LDC_POST_BUILD_BYPRODUCTS "${_LDC_POST_BUILD_BYPRODUCTS}" PARENT_SCOPE) endif() # @@ -425,10 +409,6 @@ macro(dc src_files src_basedir d_flags output_basedir emit_bc all_at_once single # dc_deps can only contain paths, otherwise cmake will ignore the dependency. # See: https://github.com/ldc-developers/ldc/pull/4743#issuecomment-2323156173 set(dc_deps ${LDC_EXE_FULL}) - if(TARGET add-multilib-section) - # Make sure the config files are available before invoking LDC. - set(dc_deps ${dc_deps} add-multilib-section) - endif() set(relative_src_files "") set(new_o "") diff --git a/runtime/ldc-build-runtime.d.in b/runtime/ldc-build-runtime.d.in index 8f505f24646..60ae1620d28 100644 --- a/runtime/ldc-build-runtime.d.in +++ b/runtime/ldc-build-runtime.d.in @@ -159,8 +159,6 @@ void runCMake() { "-DLDMD_EXE_FULL=" ~ ldmdExecutable, "-DDMDFE_MINOR_VERSION=@DMDFE_MINOR_VERSION@", "-DDMDFE_PATCH_VERSION=@DMDFE_PATCH_VERSION@", - "-DLDC_WITH_LLD=@LDC_WITH_LLD@", - "-DINCLUDE_INSTALL_DIR=@INCLUDE_INSTALL_DIR@", ]; if (config.targetSystem.length) args ~= "-DTARGET_SYSTEM=" ~ config.targetSystem.join(";"); diff --git a/tests/driver/config_diag.d b/tests/driver/config_diag.d index eae17e18c0a..f0be3995a9c 100644 --- a/tests/driver/config_diag.d +++ b/tests/driver/config_diag.d @@ -1,13 +1,27 @@ -// RUN: %ldc -o- -conf=%S/inputs/noswitches.conf %s 2>&1 | FileCheck %s --check-prefix=NOSWITCHES -// NOSWITCHES: Error while reading config file: {{.*}}noswitches.conf -// NOSWITCHES-NEXT: Could not look up switches +// RUN: split-file %s %t -// RUN: %ldc -o- -conf=%S/inputs/section_aaa.conf %s 2>&1 | FileCheck %s --check-prefix=NO_SEC -// NO_SEC: Error while reading config file: {{.*}}section_aaa.conf -// NO_SEC-NEXT: No matching section for triple '{{.*}}' +// RUN: %ldc -o- -conf=%t/invalid_setting.conf %s 2>&1 | FileCheck %s --check-prefix=INV_SET +// INV_SET: Error while reading config file: {{.*}}invalid_setting.conf +// INV_SET-NEXT: Unknown scalar setting named blah-blah -// RUN: %ldc -o- -conf=%S/inputs/invalid_append.conf %s 2>&1 | FileCheck %s --check-prefix=APP +// RUN: %ldc -o- -conf=%t/invalid_append.conf %s 2>&1 | FileCheck %s --check-prefix=APP // APP: Error while reading config file: {{.*}}invalid_append.conf // APP-NEXT: line 3: '~=' is not supported with scalar values module object; + +/+ config dirs used by the tests + +//--- invalid_setting.conf +default: +{ + blah-blah = "12"; +}; + +//--- invalid_append.conf +default: +{ + rpath ~= "/path"; +} +//--- end_of_files ++/ diff --git a/tests/driver/config_dir.d b/tests/driver/config_dir.d new file mode 100644 index 00000000000..e8d443d7348 --- /dev/null +++ b/tests/driver/config_dir.d @@ -0,0 +1,101 @@ +// RUN: split-file %s %t +module object; + +alias string = immutable(char)[]; + +template Version(string ident) { + mixin(`version(` ~ ident ~ `) + enum Version = true; + else + enum Version = false; +`); +} + +// RUN: %ldc -d-version=TEST_ORDER -o- -conf=%t/order.conf %s 2>&1 +version (TEST_ORDER) { + static assert(!Version!"File1"); + static assert(Version!"File2"); + static assert(!Version!"File3"); +} + +// RUN: %ldc -d-version=TEST_APPENDING -o- -conf=%t/appending.conf %s 2>&1 +version (TEST_APPENDING) { + static assert(!Version!"File1_Sec1"); + static assert(!Version!"File1_Sec2"); + + static assert(!Version!"File2_Sec1"); + static assert(Version!"File2_Sec2"); + + static assert(Version!"File3_Sec1"); + static assert(Version!"File3_Sec2"); +} + +version (TEST_RPATH) {} +// RUN: not %ldc -d-version=TEST_RPATH -conf=%t/multiple_rpaths.conf -link-defaultlib-shared=true -v %s 2>&1 | FileCheck %s --check-prefix=RPATHS +// RPATHS-NOT: /first_rpath + +// RUN: not %ldc -d-version=TEST_RPATH -conf=%t/rpath_clear.conf -link-defaultlib-shared=true -v %s 2>&1 | FileCheck %s --check-prefix=RPATHSCLEAR +// RPATHSCLEAR-NOT: /first_rpath + + +/+ config dirs used by the tests + +//--- order.conf/conf-11 +default: { + switches = [ "-d-version=File1" ] +} +//--- order.conf/conf-102 +default: { + switches = [ "-d-version=File2" ] +} +//--- order.conf/conf-103/conf +default: { + switches = [ "-d-version=File3" ]; +} + +//--- appending.conf/01.conf +default: { + switches ~= [ "-d-version=File1_Sec1" ] +} +".?": { + switches = [ "-d-version=File1_Sec2" ] +} +//--- appending.conf/02.conf +default: { + switches ~= [ "-d-version=File2_Sec1" ] +} +".?": { + switches = [ "-d-version=File2_Sec2" ] +} +//--- appending.conf/03.conf +default: { + switches ~= [ "-d-version=File3_Sec1" ] +} +".?": { + switches ~= [ "-d-version=File3_Sec2" ] +} + +//--- multiple_rpaths.conf/01.conf +default: { + switches = [ "-link-defaultlib-shared" ] + rpath = "/first_rpath"; +} +//--- multiple_rpaths.conf/02.conf +default: { + rpath = "/second_rpath"; +} +//--- multiple_rpaths.conf/03.conf +default: { + // no rpath +} + +//--- rpath_clear.conf +default: { + rpath = "/first_rpath" +} +default: { + rpath = "" // this should clear the previous value +} + +//--- end_of_files ++/ diff --git a/tests/driver/inputs/invalid_append.conf b/tests/driver/inputs/invalid_append.conf deleted file mode 100644 index bca0b67c38f..00000000000 --- a/tests/driver/inputs/invalid_append.conf +++ /dev/null @@ -1,10 +0,0 @@ -default: -{ - rpath ~= "/path"; -} - -default: -{ - switches = []; - post-switches = []; -} diff --git a/tests/driver/inputs/noswitches.conf b/tests/driver/inputs/noswitches.conf deleted file mode 100644 index 8afe5dec6f6..00000000000 --- a/tests/driver/inputs/noswitches.conf +++ /dev/null @@ -1,3 +0,0 @@ -default: -{ -}; diff --git a/tests/driver/inputs/section_aaa.conf b/tests/driver/inputs/section_aaa.conf deleted file mode 100644 index a85b08f3083..00000000000 --- a/tests/driver/inputs/section_aaa.conf +++ /dev/null @@ -1,4 +0,0 @@ -aaa: -{ - switches = [ "" ]; -}; diff --git a/tools/add-multilib-section.sh b/tools/add-multilib-section.sh deleted file mode 100755 index b471ccd06e6..00000000000 --- a/tools/add-multilib-section.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -if [ "$#" -ne 6 ]; then - echo "Usage: $0 <32|64> " - exit 1 -fi - -ldc=$1 -bitness=$2 -libdir=$3 -rpath=$4 -input_conf=$5 -output_conf=$6 - -# parse multilib triple from `-v` output -set +e -# extract `config /path/to/ldc2.conf (i686-unknown-linux-gnu)` -triple="$(echo "module object;" | $ldc -m$bitness -v -o- -conf=$input_conf - | grep -m 1 '^config')" -triple="${triple##* (}" # `i686-unknown-linux-gnu)` -triple="${triple%)}" # `i686-unknown-linux-gnu` -if [ "${triple//[^-]/}" = "---" ]; then - # ignore vendor => `i686-.*-linux-gnu` - triple="$(echo "$triple" | sed -e 's/-[^-]*/-.*/')" -fi -set -e - -cp $input_conf $output_conf - -if [ -z "$triple" ]; then - echo "Error: failed to parse triple from \"$ldc -m$bitness -v\" output" - exit 1 -fi - -# append config file section -section=" -\"$triple\": -{ - lib-dirs = [ - \"$libdir\", - ]; - rpath = \"$rpath\"; -};" -echo "$section" >> $output_conf diff --git a/tools/fill-multilib-triple.sh b/tools/fill-multilib-triple.sh new file mode 100755 index 00000000000..dd41bdbaeaf --- /dev/null +++ b/tools/fill-multilib-triple.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +set -euo pipefail + +if [[ $# -le 3 ]]; then + echo "Usage: ${0} [...]" + exit 1 +fi + +input=$1 +shift +output=$1 +shift +placeholder=$1 +shift +ldc2=("${@}") + +set +e +triple="$(echo 'module object;' | "${ldc2[@]}" -v -o- - | grep -m 1 '^config')" +set -e +triple="${triple##* (}" # `i686-unknown-linux-gnu)` +triple="${triple%)}" # `i686-unknown-linux-gnu` +if [ "${triple//[^-]/}" = "---" ]; then + # ignore vendor => `i686-.*-linux-gnu` + triple="$(echo "$triple" | sed -e 's/-[^-]*/-.*/')" +fi + +if [[ ! ${triple} ]]; then + echo "Error: failed to parse triple from \"${ldc2[@]} -v\" output" + exit 1 +fi + +sed -e "s/${placeholder}/${triple}/" "${input}" > "${output}"