|
| 1 | +# Common functionality shared by the compiler and the runtime build system. |
| 2 | + |
| 3 | +function(append value) |
| 4 | + foreach(variable ${ARGN}) |
| 5 | + if(${variable} STREQUAL "") |
| 6 | + set(${variable} "${value}" PARENT_SCOPE) |
| 7 | + else() |
| 8 | + set(${variable} "${${variable}} ${value}" PARENT_SCOPE) |
| 9 | + endif() |
| 10 | + endforeach(variable) |
| 11 | +endfunction() |
| 12 | + |
| 13 | +function(defineIfUnset variable) |
| 14 | + if(ARGC EQUAL 1) |
| 15 | + set(args) |
| 16 | + else() |
| 17 | + list(SUBLIST ARGV 1 -1 args) |
| 18 | + endif() |
| 19 | + |
| 20 | + if(NOT DEFINED ${variable}) |
| 21 | + set(${variable} ${args} PARENT_SCOPE) |
| 22 | + endif() |
| 23 | +endfunction() |
| 24 | + |
| 25 | +function(formatArray out_var) |
| 26 | + if(ARGC EQUAL 1) |
| 27 | + set(${out_var} "[]" PARENT_SCOPE) |
| 28 | + return() |
| 29 | + endif() |
| 30 | + |
| 31 | + list(SUBLIST ARGV 1 -1 values) |
| 32 | + set(result "[") |
| 33 | + foreach(value ${values}) |
| 34 | + set(result "${result}\n \"${value}\",") |
| 35 | + endforeach() |
| 36 | + set(result "${result}\n ]") |
| 37 | + |
| 38 | + set(${out_var} "${result}" PARENT_SCOPE) |
| 39 | +endfunction() |
| 40 | + |
| 41 | +function(formatArraySetting out_var name) |
| 42 | + if(ARGC EQUAL 2) |
| 43 | + # Ignore `value ~= []` |
| 44 | + set(${out_var} "" PARENT_SCOPE) |
| 45 | + return() |
| 46 | + endif() |
| 47 | + |
| 48 | + list(SUBLIST ARGV 2 -1 values) |
| 49 | + list(GET values 0 maybe_override) |
| 50 | + if(maybe_override STREQUAL "OVERRIDE") |
| 51 | + set(operator "=") |
| 52 | + list(POP_FRONT values) |
| 53 | + else() |
| 54 | + set(operator "~=") |
| 55 | + endif() |
| 56 | + formatArray(array ${values}) |
| 57 | + set(${out_var} "\n ${name} ${operator} ${array};" PARENT_SCOPE) |
| 58 | +endfunction() |
| 59 | + |
| 60 | +function(formatScalarSetting out_var name value) |
| 61 | + if(value STREQUAL "") |
| 62 | + set(${out_var} "" PARENT_SCOPE) |
| 63 | + else() |
| 64 | + set(${out_var} "\n ${name} = \"${value}\";" PARENT_SCOPE) |
| 65 | + endif() |
| 66 | +endfunction() |
| 67 | + |
| 68 | + |
| 69 | +# Create a ldc2.conf section |
| 70 | +# |
| 71 | +# Example: |
| 72 | +# |
| 73 | +# makeConfSectionImpl( |
| 74 | +# FILEPATH "${CMAKE_BINARY_DIR}/ldc2.conf" |
| 75 | +# # The output filename |
| 76 | +# |
| 77 | +# SECTION "^wasm(32|64)-" |
| 78 | +# # A regex to match a target triple or "default" |
| 79 | +# |
| 80 | +# SWITCHES -d-version=foo -L--linker-flag |
| 81 | +# # The `switches` list |
| 82 | +# |
| 83 | +# POST_SWITCHES OVERRIDE -I/path/to/druntime/src |
| 84 | +# # The `post-switches` list |
| 85 | +# |
| 86 | +# LIB_DIRS "${CMAKE_BINARY_DIR}/lib64" |
| 87 | +# # The `lib-dirs` list |
| 88 | +# |
| 89 | +# RPATH "/path/to/dir" |
| 90 | +# # The `rpath` value |
| 91 | +# ) |
| 92 | +# |
| 93 | +# Would generate: |
| 94 | +# |
| 95 | +# $ cat "${CMAKE_BINARY_DIR}/ldc2.conf" |
| 96 | +# "^wasm(32|64)-": |
| 97 | +# { |
| 98 | +# switches ~= [ |
| 99 | +# "-d-version=foo", |
| 100 | +# "-L--linker-flag", |
| 101 | +# ]; |
| 102 | +# post-switches = [ |
| 103 | +# "-I/path/to/druntime/src" |
| 104 | +# ]; |
| 105 | +# lib-dirs ~= [ |
| 106 | +# "${CMAKE_BINARY_DIR}/lib64" |
| 107 | +# ]; |
| 108 | +# rpath = "/path/to/dir" |
| 109 | +# } |
| 110 | +# |
| 111 | +# You don't need to pass all setting keys, only the ones that have values. |
| 112 | +# |
| 113 | +# Array settings (SWITCHES, POST_SWITCHES, LIB_DIRS) may start with an |
| 114 | +# OVERRIDE signifying that they should overwrite the (possibly) |
| 115 | +# previously stored values. The default is to append to them. |
| 116 | +function(makeConfSectionImpl) |
| 117 | + set(oneValueArgs FILEPATH SECTION RPATH) |
| 118 | + set(multiValueArgs SWITCHES POST_SWITCHES LIB_DIRS) |
| 119 | + cmake_parse_arguments(args "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) |
| 120 | + |
| 121 | + foreach(var FILEPATH SECTION) |
| 122 | + if(NOT DEFINED args_${var}) |
| 123 | + message(SEND_ERROR "Expected ${var} argument") |
| 124 | + endif() |
| 125 | + endforeach() |
| 126 | + if(DEFINED args_UNPARSED_ARGUMENTS) |
| 127 | + message(SEND_ERROR "Unexpected arguments: ${args_UNPARSED_ARGUMENTS}") |
| 128 | + endif() |
| 129 | + |
| 130 | + formatArraySetting(switches "switches" ${args_SWITCHES}) |
| 131 | + formatArraySetting(post_switches "post-switches" ${args_POST_SWITCHES}) |
| 132 | + formatArraySetting(lib_dirs "lib-dirs" ${args_LIB_DIRS}) |
| 133 | + formatScalarSetting(rpath "rpath" "${args_RPATH}") |
| 134 | + |
| 135 | + file(WRITE "${args_FILEPATH}" |
| 136 | + "\"${args_SECTION}\":\n" |
| 137 | + "{" |
| 138 | + "${switches}" |
| 139 | + "${post_switches}" |
| 140 | + "${lib_dirs}" |
| 141 | + "${rpath}" |
| 142 | + "\n};\n\n" |
| 143 | + ) |
| 144 | +endfunction() |
| 145 | + |
| 146 | +# Create a ldc2.conf section |
| 147 | +# |
| 148 | +# Example: |
| 149 | +# |
| 150 | +# makeConfSection( |
| 151 | +# NAME 40-runtime |
| 152 | +# # a unique name for the file that will store this section |
| 153 | +# |
| 154 | +# SECTION "x86_64-.*-linux-gnu" |
| 155 | +# # A regex for a target triple or the string "default" |
| 156 | +# |
| 157 | +# BUILD |
| 158 | +# # Settings for ldc2.conf when part of this cmake project |
| 159 | +# SWITCHES -a -b |
| 160 | +# POST_SWITCHES -I${CMAKE_SOURCE_DIR}/runtime/import -c |
| 161 | +# |
| 162 | +# INSTALL |
| 163 | +# # Settings for ldc2.conf when installed on a user system |
| 164 | +# SWITCHES OVERRIDE -bar |
| 165 | +# LIB_DIRS "${CMAKE_INSTALL_PREFIX}/lib" |
| 166 | +# RPATH "${CMAKE_INSTALL_PREFIX}/lib" |
| 167 | +# ) |
| 168 | +# |
| 169 | +# The possible settings are described by makeConfSectionImpl. |
| 170 | +# |
| 171 | +# As a shortcut the BUILD and INSTALL arguments may be omitted, making the |
| 172 | +# settings be applied to both build and install ldc2.conf. Example: |
| 173 | +# |
| 174 | +# makeConfSection(NAME 10-example SECTION default |
| 175 | +# SWITCHES -my-important-switch |
| 176 | +# ) |
| 177 | +# |
| 178 | +# Is equivalent to: |
| 179 | +# |
| 180 | +# makeConfSection(NAME 10-example SECTION default |
| 181 | +# BUILD |
| 182 | +# SWITCHES -my-important-switch |
| 183 | +# INSTALL |
| 184 | +# SWITCHES -my-important-switch |
| 185 | +# ) |
| 186 | +# |
| 187 | +# It is also possible to generate a configuration file for either only the build |
| 188 | +# or only the install. Simply pass only BUILD or INSTALL to this function. |
| 189 | +function(makeConfSection) |
| 190 | + set(oneValueArgs NAME SECTION) |
| 191 | + set(multiValueArgs BUILD INSTALL) |
| 192 | + cmake_parse_arguments(PARSE_ARGV 0 args "" "${oneValueArgs}" "${multiValueArgs}") |
| 193 | + |
| 194 | + foreach(var ${oneValueArgs}) |
| 195 | + if(NOT DEFINED args_${var}) |
| 196 | + message(SEND_ERROR "Expected defined ${var} argument") |
| 197 | + endif() |
| 198 | + endforeach() |
| 199 | + if(DEFINED args_UNPARSED_ARGUMENTS) |
| 200 | + if(NOT DEFINED args_BUILD AND NOT DEFINED args_INSTALL) |
| 201 | + set(args_BUILD "${args_UNPARSED_ARGUMENTS}") |
| 202 | + set(args_INSTALL "${args_UNPARSED_ARGUMENTS}") |
| 203 | + else() |
| 204 | + message(SEND_ERROR "Unexpected arguments: ${args_UNPARSED_ARGUMENTS}") |
| 205 | + endif() |
| 206 | + endif() |
| 207 | + |
| 208 | + if(args_BUILD) |
| 209 | + set(build_conf "${LDC2_BUILD_CONF}/${args_NAME}.conf") |
| 210 | + makeConfSectionImpl(FILEPATH "${build_conf}" SECTION "${args_SECTION}" ${args_BUILD}) |
| 211 | + endif() |
| 212 | + if(args_INSTALL) |
| 213 | + set(install_conf "${LDC2_INSTALL_CONF}/${args_NAME}.conf") |
| 214 | + makeConfSectionImpl(FILEPATH "${install_conf}" SECTION "${args_SECTION}" ${args_INSTALL}) |
| 215 | + if(CONF_PREFER_DIR) |
| 216 | + if(NOT _DONT_INSTALL_CONF) |
| 217 | + install(FILES "${install_conf}" DESTINATION "${CONF_INST_DIR}/ldc2.conf") |
| 218 | + endif() |
| 219 | + else() |
| 220 | + get_filename_component(install_path "${install_path}" ABSOLUTE) |
| 221 | + list(APPEND _ALL_CONF_INSTALL_FILES "${install_conf}") |
| 222 | + set(_ALL_CONF_INSTALL_FILES "${_ALL_CONF_INSTALL_FILES}" PARENT_SCOPE) |
| 223 | + endif() |
| 224 | + endif() |
| 225 | +endfunction() |
| 226 | + |
| 227 | +function(installConf) |
| 228 | + if(CONF_PREFER_DIR OR _DONT_INSTALL_CONF) |
| 229 | + return() |
| 230 | + endif() |
| 231 | + |
| 232 | + set(out_dir "${CMAKE_BINARY_DIR}/etc") |
| 233 | + make_directory("${out_dir}") |
| 234 | + set(conf_file "${out_dir}/ldc2_install.conf") |
| 235 | + |
| 236 | + set(files) |
| 237 | + foreach(file ${_ALL_CONF_INSTALL_FILES}) |
| 238 | + get_filename_component(basename "${file}" NAME) |
| 239 | + get_filename_component(dir "${file}" DIRECTORY) |
| 240 | + if(NOT dir STREQUAL LDC2_INSTALL_CONF) |
| 241 | + message(SEND_ERROR "ldc2_install.conf ${file} not inside ${dir}") |
| 242 | + endif() |
| 243 | + list(APPEND files "${basename}") |
| 244 | + endforeach() |
| 245 | + list(SORT files COMPARE NATURAL) |
| 246 | + |
| 247 | + add_custom_command(OUTPUT "${conf_file}" |
| 248 | + # cat all files into OUTPUT |
| 249 | + COMMAND sh -c "output=\"\${1}\"; shift; cat \"\${@}\" > \"\${output}\"" |
| 250 | + script ${conf_file} ${files} |
| 251 | + VERBATIM |
| 252 | + WORKING_DIRECTORY "${LDC2_INSTALL_CONF}" |
| 253 | + DEPENDS ${_ALL_CONF_INSTALL_FILES} |
| 254 | + ) |
| 255 | + add_custom_target(gen_conf_file ALL DEPENDS "${conf_file}") |
| 256 | + install(FILES ${conf_file} DESTINATION "${CONF_INST_DIR}" RENAME ldc2.conf) |
| 257 | +endfunction() |
| 258 | + |
| 259 | +# Generally, we want to install everything into CMAKE_INSTALL_PREFIX, but when |
| 260 | +# it is /usr, put the config files into /etc to meet common practice. |
| 261 | +if(NOT DEFINED SYSCONF_INSTALL_DIR) |
| 262 | + if(CMAKE_INSTALL_PREFIX STREQUAL "/usr") |
| 263 | + set(SYSCONF_INSTALL_DIR "/etc") |
| 264 | + else() |
| 265 | + set(SYSCONF_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/etc") |
| 266 | + endif() |
| 267 | +endif() |
| 268 | + |
| 269 | +set(CONF_INST_DIR ${SYSCONF_INSTALL_DIR} CACHE PATH "Directory in which to install ldc2.conf") |
| 270 | +if(CONF_INST_DIR STREQUAL "") |
| 271 | + set(_DONT_INSTALL_CONF TRUE) |
| 272 | +else() |
| 273 | + set(_DONT_INSTALL_CONF FALSE) |
| 274 | +endif() |
| 275 | + |
| 276 | +option(CONF_PREFER_DIR "Prefer installing ldc2.conf as a directory") |
| 277 | +# Avoid making the D code check for all cmake truthy values |
| 278 | +if(CONF_PREFER_DIR) |
| 279 | + set(CONF_PREFER_DIR_D_BOOLEAN true) |
| 280 | +else() |
| 281 | + set(CONF_PREFER_DIR_D_BOOLEAN false) |
| 282 | +endif() |
| 283 | + |
| 284 | +set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include/d CACHE PATH "Path to install D modules to") |
| 285 | + |
| 286 | +defineIfUnset(LDC2_BUILD_CONF "${CMAKE_BINARY_DIR}/etc/ldc2.conf") |
| 287 | +defineIfUnset(LDC2_INSTALL_CONF "${CMAKE_BINARY_DIR}/etc/ldc2_install.conf.d") |
0 commit comments