Skip to content

Commit be53ec3

Browse files
committed
Rewrite ldc2.conf cmake generation
When building, always generate separate files for each ldc2.conf section. This allows creating a full ldc2.conf, part by part, without carrying about the statements' order in the cmake file. When installing, `cat` all the configured files and install it as a single ldc2.conf file. Added the CONF_PREF_DIR cmake option for installing the conf files as a directory, without concatenating them. This is useful when building the runtime as a separate project as this setting would allow generating a (partial) ldc2.conf, enough to support the runtime libraries, which could latter be merged with the config generated by the root ldc project to get a fully functional ldc2. This is a requirement when cross-compiling and installing the libraries on another device or when performing multilib builds outside of -DMULTILIB=ON Signed-off-by: Andrei Horodniceanu <a.horodniceanu@proton.me>
1 parent 58c2651 commit be53ec3

File tree

6 files changed

+452
-158
lines changed

6 files changed

+452
-158
lines changed

CMakeLists.txt

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,14 @@ project(ldc)
1717

1818
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules")
1919

20+
include(LdcCommon)
21+
2022
include(FindDCompiler)
2123
include(CheckCXXCompilerFlag)
2224
include(CheckDSourceCompiles)
2325
include(CheckLinkFlag)
2426
include(BuildDExecutable)
2527

26-
# Helper function
27-
function(append value)
28-
foreach(variable ${ARGN})
29-
if(${variable} STREQUAL "")
30-
set(${variable} "${value}" PARENT_SCOPE)
31-
else()
32-
set(${variable} "${${variable}} ${value}" PARENT_SCOPE)
33-
endif()
34-
endforeach(variable)
35-
endfunction()
36-
3728
#
3829
# Locate LLVM.
3930
#
@@ -128,21 +119,9 @@ set(DMDFE_PATCH_VERSION 0)
128119

129120
set(DMD_VERSION ${DMDFE_MAJOR_VERSION}.${DMDFE_MINOR_VERSION}.${DMDFE_PATCH_VERSION})
130121

131-
# Generally, we want to install everything into CMAKE_INSTALL_PREFIX, but when
132-
# it is /usr, put the config files into /etc to meet common practice.
133-
if(NOT DEFINED SYSCONF_INSTALL_DIR)
134-
if(CMAKE_INSTALL_PREFIX STREQUAL "/usr")
135-
set(SYSCONF_INSTALL_DIR "/etc")
136-
else()
137-
set(SYSCONF_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/etc")
138-
endif()
139-
endif()
140-
141122
set(D_VERSION ${DMDFE_MAJOR_VERSION} CACHE STRING "D language version")
142123
set(PROGRAM_PREFIX "" CACHE STRING "Prepended to ldc/ldmd binary names")
143124
set(PROGRAM_SUFFIX "" CACHE STRING "Appended to ldc/ldmd binary names")
144-
set(CONF_INST_DIR ${SYSCONF_INSTALL_DIR} CACHE PATH "Directory ldc2.conf is installed to")
145-
set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include/d CACHE PATH "Path to install D modules to")
146125

147126
# Note: LIB_SUFFIX should perhaps be renamed to LDC_LIBDIR_SUFFIX.
148127
set(LIB_SUFFIX "" CACHE STRING "Appended to the library installation directory. Set to '64' to install libraries into ${PREFIX}/lib64.")
@@ -925,7 +904,7 @@ if(NOT DEFINED COMPILER_RT_LIBDIR_CONFIG)
925904
endif()
926905
if(DEFINED COMPILER_RT_LIBDIR_CONFIG)
927906
message(STATUS "Adding ${COMPILER_RT_LIBDIR_CONFIG} to lib-dirs in configuration file")
928-
set(OPTIONAL_COMPILER_RT_DIR "\n \"${COMPILER_RT_LIBDIR_CONFIG}\", // compiler-rt directory")
907+
makeConfSection(NAME "35-ldc-compiler-rt" SECTION "default" LIB_DIRS "${COMPILER_RT_LIBDIR}")
929908
endif()
930909

931910
#
@@ -1006,6 +985,15 @@ option(LDC_BUILD_RUNTIME "Build the runtime libraries" ${_LDC_BUILD_RUNTIME_DEFA
1006985

1007986
if(LDC_BUILD_RUNTIME)
1008987
add_subdirectory(runtime)
988+
989+
# POST_BUILD can't be used for targets in a different directory so
990+
# runtime/CMakeLists.txt can't directly add the commands.
991+
if(_LDC_POST_BUILD_COMMANDS)
992+
add_custom_command(TARGET ${LDC_EXE} POST_BUILD
993+
${_LDC_POST_BUILD_COMMANDS}
994+
BYPRODUCTS ${_LDC_POST_BUILD_BYPRODUCTS}
995+
)
996+
endif()
1009997
else()
1010998
message(STATUS "NOT building the runtime libraries (LDC_BUILD_RUNTIME=OFF)")
1011999
endif()
@@ -1044,6 +1032,7 @@ if(${BUILD_SHARED})
10441032
# as well, for the time being this just bloats the normal packages.
10451033
install(TARGETS ${LDC_LIB} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX})
10461034
endif()
1035+
installConf()
10471036

10481037
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
10491038
if(NOT DEFINED BASH_COMPLETION_COMPLETIONSDIR)

cmake/Modules/LdcCommon.cmake

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
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

Comments
 (0)