16021
|
1 |
cmake_minimum_required(VERSION 3.15)
|
|
2 |
|
|
3 |
list(APPEND CMAKE_MESSAGE_CONTEXT "Corrosion")
|
|
4 |
|
|
5 |
message(DEBUG "Using Corrosion ${Corrosion_VERSION} with CMake ${CMAKE_VERSION} "
|
|
6 |
"and the `${CMAKE_GENERATOR}` Generator"
|
|
7 |
)
|
|
8 |
|
|
9 |
get_cmake_property(COR_IS_MULTI_CONFIG GENERATOR_IS_MULTI_CONFIG)
|
|
10 |
set(COR_IS_MULTI_CONFIG "${COR_IS_MULTI_CONFIG}" CACHE BOOL "Do not change this" FORCE)
|
|
11 |
mark_as_advanced(FORCE COR_IS_MULTI_CONFIG)
|
|
12 |
|
|
13 |
if (COR_IS_MULTI_CONFIG AND CMAKE_VERSION VERSION_LESS 3.20.0)
|
|
14 |
message(FATAL_ERROR "Corrosion requires at least CMake 3.20 with Multi-Config Generators such as "
|
|
15 |
"\"Ninja Multi-Config\" or Visual Studio. "
|
|
16 |
"Please use a different generator or update to cmake >= 3.20.\n"
|
|
17 |
"Note: You are using CMake ${CMAKE_VERSION} (Path: `${CMAKE_COMMAND}`) with "
|
|
18 |
" the `${CMAKE_GENERATOR}` Generator."
|
|
19 |
)
|
|
20 |
elseif(NOT COR_IS_MULTI_CONFIG AND DEFINED CMAKE_CONFIGURATION_TYPES)
|
|
21 |
message(WARNING "The Generator is ${CMAKE_GENERATOR}, which is not a multi-config "
|
|
22 |
"Generator, but CMAKE_CONFIGURATION_TYPES is set. Please don't set "
|
|
23 |
"CMAKE_CONFIGURATION_TYPES unless you are using a multi-config Generator."
|
|
24 |
)
|
|
25 |
endif()
|
|
26 |
|
|
27 |
option(CORROSION_VERBOSE_OUTPUT "Enables verbose output from Corrosion and Cargo" OFF)
|
|
28 |
|
|
29 |
set(CORROSION_NATIVE_TOOLING_DESCRIPTION
|
|
30 |
"Use native tooling - Required on CMake < 3.19 and available as a fallback option for recent versions"
|
|
31 |
)
|
|
32 |
|
|
33 |
set(CORROSION_RESPECT_OUTPUT_DIRECTORY_DESCRIPTION
|
|
34 |
"Respect the CMake target properties specifying the output directory of a target, such as
|
|
35 |
`RUNTIME_OUTPUT_DIRECTORY`. This requires CMake >= 3.19, otherwise this option is forced off."
|
|
36 |
)
|
|
37 |
|
|
38 |
option(
|
|
39 |
CORROSION_NATIVE_TOOLING
|
|
40 |
"${CORROSION_NATIVE_TOOLING_DESCRIPTION}"
|
|
41 |
OFF
|
|
42 |
)
|
|
43 |
|
|
44 |
option(CORROSION_RESPECT_OUTPUT_DIRECTORY
|
|
45 |
"${CORROSION_RESPECT_OUTPUT_DIRECTORY_DESCRIPTION}"
|
|
46 |
ON
|
|
47 |
)
|
|
48 |
|
|
49 |
option(
|
|
50 |
CORROSION_NO_WARN_PARSE_TARGET_TRIPLE_FAILED
|
|
51 |
"Surpresses a warning if the parsing the target triple failed."
|
|
52 |
OFF
|
|
53 |
)
|
|
54 |
|
|
55 |
# The native tooling is required on CMAke < 3.19 so we override whatever the user may have set.
|
|
56 |
if (CMAKE_VERSION VERSION_LESS 3.19.0)
|
|
57 |
set(CORROSION_NATIVE_TOOLING ON CACHE INTERNAL "${CORROSION_NATIVE_TOOLING_DESCRIPTION}" FORCE)
|
|
58 |
set(CORROSION_RESPECT_OUTPUT_DIRECTORY OFF CACHE INTERNAL
|
|
59 |
"${CORROSION_RESPECT_OUTPUT_DIRECTORY_DESCRIPTION}" FORCE
|
|
60 |
)
|
|
61 |
endif()
|
|
62 |
|
|
63 |
find_package(Rust REQUIRED)
|
|
64 |
|
|
65 |
if(Rust_TOOLCHAIN_IS_RUSTUP_MANAGED)
|
|
66 |
execute_process(COMMAND rustup target list --toolchain "${Rust_TOOLCHAIN}"
|
|
67 |
OUTPUT_VARIABLE AVAILABLE_TARGETS_RAW
|
|
68 |
)
|
|
69 |
string(REPLACE "\n" ";" AVAILABLE_TARGETS_RAW "${AVAILABLE_TARGETS_RAW}")
|
|
70 |
string(REPLACE " (installed)" "" "AVAILABLE_TARGETS" "${AVAILABLE_TARGETS_RAW}")
|
|
71 |
set(INSTALLED_TARGETS_RAW "${AVAILABLE_TARGETS_RAW}")
|
|
72 |
list(FILTER INSTALLED_TARGETS_RAW INCLUDE REGEX " \\(installed\\)")
|
|
73 |
string(REPLACE " (installed)" "" "INSTALLED_TARGETS" "${INSTALLED_TARGETS_RAW}")
|
|
74 |
list(TRANSFORM INSTALLED_TARGETS STRIP)
|
|
75 |
if("${Rust_CARGO_TARGET}" IN_LIST AVAILABLE_TARGETS)
|
|
76 |
message(DEBUG "Cargo target ${Rust_CARGO_TARGET} is an official target-triple")
|
|
77 |
message(DEBUG "Installed targets: ${INSTALLED_TARGETS}")
|
|
78 |
if(NOT ("${Rust_CARGO_TARGET}" IN_LIST INSTALLED_TARGETS))
|
|
79 |
message(FATAL_ERROR "Target ${Rust_CARGO_TARGET} is not installed for toolchain ${Rust_TOOLCHAIN}.\n"
|
|
80 |
"Help: Run `rustup target add --toolchain ${Rust_TOOLCHAIN} ${Rust_CARGO_TARGET}` to install "
|
|
81 |
"the missing target."
|
|
82 |
)
|
|
83 |
endif()
|
|
84 |
endif()
|
|
85 |
|
|
86 |
endif()
|
|
87 |
|
|
88 |
if(CMAKE_GENERATOR MATCHES "Visual Studio"
|
|
89 |
AND (NOT CMAKE_VS_PLATFORM_NAME STREQUAL CMAKE_VS_PLATFORM_NAME_DEFAULT)
|
|
90 |
AND Rust_VERSION VERSION_LESS "1.54")
|
|
91 |
message(FATAL_ERROR "Due to a cargo issue, cross-compiling with a Visual Studio generator and rust versions"
|
|
92 |
" before 1.54 is not supported. Rust build scripts would be linked with the cross-compiler linker, which"
|
|
93 |
" causes the build to fail. Please upgrade your Rust version to 1.54 or newer.")
|
|
94 |
endif()
|
|
95 |
|
|
96 |
if (NOT TARGET Corrosion::Generator)
|
|
97 |
message(STATUS "Using Corrosion as a subdirectory")
|
|
98 |
endif()
|
|
99 |
|
|
100 |
get_property(
|
|
101 |
RUSTC_EXECUTABLE
|
|
102 |
TARGET Rust::Rustc PROPERTY IMPORTED_LOCATION
|
|
103 |
)
|
|
104 |
|
|
105 |
get_property(
|
|
106 |
CARGO_EXECUTABLE
|
|
107 |
TARGET Rust::Cargo PROPERTY IMPORTED_LOCATION
|
|
108 |
)
|
|
109 |
|
|
110 |
# Note: Legacy function, used when respecting the `XYZ_OUTPUT_DIRECTORY` target properties is not
|
|
111 |
# possible.
|
|
112 |
function(_corrosion_set_imported_location_legacy target_name base_property filename)
|
|
113 |
foreach(config_type ${CMAKE_CONFIGURATION_TYPES})
|
|
114 |
set(binary_root "${CMAKE_CURRENT_BINARY_DIR}/${config_type}")
|
|
115 |
string(TOUPPER "${config_type}" config_type_upper)
|
|
116 |
message(DEBUG "Setting ${base_property}_${config_type_upper} for target ${target_name}"
|
|
117 |
" to `${binary_root}/${filename}`.")
|
|
118 |
# For Multiconfig we want to specify the correct location for each configuration
|
|
119 |
set_property(
|
|
120 |
TARGET ${target_name}
|
|
121 |
PROPERTY "${base_property}_${config_type_upper}"
|
|
122 |
"${binary_root}/${filename}"
|
|
123 |
)
|
|
124 |
endforeach()
|
|
125 |
if(NOT COR_IS_MULTI_CONFIG)
|
|
126 |
set(binary_root "${CMAKE_CURRENT_BINARY_DIR}")
|
|
127 |
endif()
|
|
128 |
|
|
129 |
message(DEBUG "Setting ${base_property} for target ${target_name}"
|
|
130 |
" to `${binary_root}/${filename}`.")
|
|
131 |
|
|
132 |
# IMPORTED_LOCATION must be set regardless of possible overrides. In the multiconfig case,
|
|
133 |
# the last configuration "wins".
|
|
134 |
set_property(
|
|
135 |
TARGET ${target_name}
|
|
136 |
PROPERTY "${base_property}" "${binary_root}/${filename}"
|
|
137 |
)
|
|
138 |
endfunction()
|
|
139 |
|
|
140 |
|
|
141 |
# Sets out_var to true if the byproduct copying and imported location is done in a deferred
|
|
142 |
# manner to respect target properties, etc. that may be set later.
|
|
143 |
function(_corrosion_determine_deferred_byproduct_copying_and_import_location_handling out_var)
|
|
144 |
set(${out_var} ${CORROSION_RESPECT_OUTPUT_DIRECTORY} PARENT_SCOPE)
|
|
145 |
endfunction()
|
|
146 |
|
|
147 |
function(_corrosion_bin_target_suffix target_name out_var_suffix)
|
|
148 |
get_target_property(hostbuild "${target_name}" ${_CORR_PROP_HOST_BUILD})
|
|
149 |
if((hostbuild AND CMAKE_HOST_WIN32)
|
|
150 |
OR ((NOT hostbuild) AND (Rust_CARGO_TARGET_OS STREQUAL "windows")))
|
|
151 |
set(_suffix ".exe")
|
|
152 |
elseif(Rust_CARGO_TARGET_OS STREQUAL "vxworks")
|
|
153 |
set(_suffix ".vxe")
|
|
154 |
else()
|
|
155 |
set(_suffix "")
|
|
156 |
endif()
|
|
157 |
set(${out_var_suffix} "${_suffix}" PARENT_SCOPE)
|
|
158 |
endfunction()
|
|
159 |
|
|
160 |
# Do not call this function directly!
|
|
161 |
#
|
|
162 |
# This function should be called deferred to evaluate target properties late in the configure stage.
|
|
163 |
# IMPORTED_LOCATION does not support Generator expressions, so we must evaluate the output
|
|
164 |
# directory target property value at configure time. This function must be deferred to the end of
|
|
165 |
# the configure stage, so we can be sure that the output directory is not modified afterwards.
|
|
166 |
function(_corrosion_set_imported_location_deferred target_name base_property output_directory_property filename)
|
|
167 |
# The output directory property is expected to be set on the exposed target (without postfix),
|
|
168 |
# but we need to set the imported location on the actual library target with postfix.
|
|
169 |
if("${target_name}" MATCHES "^(.+)-(static|shared)$")
|
|
170 |
set(output_dir_prop_target_name "${CMAKE_MATCH_1}")
|
|
171 |
else()
|
|
172 |
set(output_dir_prop_target_name "${target_name}")
|
|
173 |
endif()
|
|
174 |
|
|
175 |
# Append .exe suffix for executable by-products if the target is windows or if it's a host
|
|
176 |
# build and the host is Windows.
|
|
177 |
get_target_property(target_type ${target_name} TYPE)
|
|
178 |
if(${target_type} STREQUAL "EXECUTABLE" AND (NOT "${filename}" MATCHES "\.pdb$"))
|
|
179 |
_corrosion_bin_target_suffix(${target_name} "suffix")
|
|
180 |
if(suffix)
|
|
181 |
set(filename "${filename}${suffix}")
|
|
182 |
endif()
|
|
183 |
endif()
|
|
184 |
|
|
185 |
get_target_property(output_directory "${output_dir_prop_target_name}" "${output_directory_property}")
|
|
186 |
message(DEBUG "Output directory property (target ${output_dir_prop_target_name}): ${output_directory_property} dir: ${output_directory}")
|
|
187 |
|
|
188 |
foreach(config_type ${CMAKE_CONFIGURATION_TYPES})
|
|
189 |
string(TOUPPER "${config_type}" config_type_upper)
|
|
190 |
get_target_property(output_dir_curr_config ${output_dir_prop_target_name}
|
|
191 |
"${output_directory_property}_${config_type_upper}"
|
|
192 |
)
|
|
193 |
if(output_dir_curr_config)
|
|
194 |
set(curr_out_dir "${output_dir_curr_config}")
|
|
195 |
elseif(output_directory)
|
|
196 |
set(curr_out_dir "${output_directory}")
|
|
197 |
else()
|
|
198 |
set(curr_out_dir "${CMAKE_CURRENT_BINARY_DIR}")
|
|
199 |
endif()
|
|
200 |
message(DEBUG "Setting ${base_property}_${config_type_upper} for target ${target_name}"
|
|
201 |
" to `${curr_out_dir}/${filename}`.")
|
|
202 |
# For Multiconfig we want to specify the correct location for each configuration
|
|
203 |
set_property(
|
|
204 |
TARGET ${target_name}
|
|
205 |
PROPERTY "${base_property}_${config_type_upper}"
|
|
206 |
"${curr_out_dir}/${filename}"
|
|
207 |
)
|
|
208 |
set(base_output_directory "${curr_out_dir}")
|
|
209 |
endforeach()
|
|
210 |
|
|
211 |
if(NOT COR_IS_MULTI_CONFIG)
|
|
212 |
if(output_directory)
|
|
213 |
set(base_output_directory "${output_directory}")
|
|
214 |
else()
|
|
215 |
set(base_output_directory "${CMAKE_CURRENT_BINARY_DIR}")
|
|
216 |
endif()
|
|
217 |
endif()
|
|
218 |
|
|
219 |
message(DEBUG "Setting ${base_property} for target ${target_name}"
|
|
220 |
" to `${base_output_directory}/${filename}`.")
|
|
221 |
|
|
222 |
# IMPORTED_LOCATION must be set regardless of possible overrides. In the multiconfig case,
|
|
223 |
# the last configuration "wins" (IMPORTED_LOCATION is not documented to have Genex support).
|
|
224 |
set_property(
|
|
225 |
TARGET ${target_name}
|
|
226 |
PROPERTY "${base_property}" "${base_output_directory}/${filename}"
|
|
227 |
)
|
|
228 |
endfunction()
|
|
229 |
|
|
230 |
# Helper function to call _corrosion_set_imported_location_deferred while eagerly
|
|
231 |
# evaluating arguments.
|
|
232 |
# Refer to https://cmake.org/cmake/help/latest/command/cmake_language.html#deferred-call-examples
|
|
233 |
function(_corrosion_call_set_imported_location_deferred target_name base_property output_directory_property filename)
|
|
234 |
cmake_language(EVAL CODE "
|
|
235 |
cmake_language(DEFER
|
|
236 |
CALL
|
|
237 |
_corrosion_set_imported_location_deferred
|
|
238 |
[[${target_name}]]
|
|
239 |
[[${base_property}]]
|
|
240 |
[[${output_directory_property}]]
|
|
241 |
[[${filename}]]
|
|
242 |
)
|
|
243 |
")
|
|
244 |
endfunction()
|
|
245 |
|
|
246 |
# Set the imported location of a Rust target.
|
|
247 |
#
|
|
248 |
# Rust targets are built via custom targets / custom commands. The actual artifacts are exposed
|
|
249 |
# to CMake as imported libraries / executables that depend on the cargo_build command. For CMake
|
|
250 |
# to find the built artifact we need to set the IMPORTED location to the actual location on disk.
|
|
251 |
# Corrosion tries to copy the artifacts built by cargo to standard locations. The IMPORTED_LOCATION
|
|
252 |
# is set to point to the copy, and not the original from the cargo build directory.
|
|
253 |
#
|
|
254 |
# Parameters:
|
|
255 |
# - target_name: Name of the Rust target
|
|
256 |
# - base_property: Name of the base property - i.e. `IMPORTED_LOCATION` or `IMPORTED_IMPLIB`.
|
|
257 |
# - output_directory_property: Target property name that determines the standard location for the
|
|
258 |
# artifact.
|
|
259 |
# - filename of the artifact.
|
|
260 |
function(_corrosion_set_imported_location target_name base_property output_directory_property filename)
|
|
261 |
_corrosion_determine_deferred_byproduct_copying_and_import_location_handling("defer")
|
|
262 |
if(defer)
|
|
263 |
_corrosion_call_set_imported_location_deferred("${target_name}" "${base_property}" "${output_directory_property}" "${filename}")
|
|
264 |
else()
|
|
265 |
_corrosion_set_imported_location_legacy("${target_name}" "${base_property}" "${filename}")
|
|
266 |
endif()
|
|
267 |
endfunction()
|
|
268 |
|
|
269 |
function(_corrosion_copy_byproduct_legacy target_name cargo_build_dir file_names)
|
|
270 |
if(ARGN)
|
|
271 |
message(FATAL_ERROR "Unexpected additional arguments")
|
|
272 |
endif()
|
|
273 |
|
|
274 |
if(COR_IS_MULTI_CONFIG)
|
|
275 |
set(output_dir "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>")
|
|
276 |
else()
|
|
277 |
set(output_dir "${CMAKE_CURRENT_BINARY_DIR}")
|
|
278 |
endif()
|
|
279 |
|
|
280 |
list(TRANSFORM file_names PREPEND "${cargo_build_dir}/" OUTPUT_VARIABLE src_file_names)
|
|
281 |
list(TRANSFORM file_names PREPEND "${output_dir}/" OUTPUT_VARIABLE dst_file_names)
|
|
282 |
message(DEBUG "Adding command to copy byproducts `${file_names}` to ${dst_file_names}")
|
|
283 |
add_custom_command(TARGET _cargo-build_${target_name}
|
|
284 |
POST_BUILD
|
|
285 |
COMMAND ${CMAKE_COMMAND} -E make_directory "${output_dir}"
|
|
286 |
COMMAND
|
|
287 |
${CMAKE_COMMAND} -E copy_if_different
|
|
288 |
# tested to work with both multiple files and paths with spaces
|
|
289 |
${src_file_names}
|
|
290 |
"${output_dir}"
|
|
291 |
BYPRODUCTS ${dst_file_names}
|
|
292 |
COMMENT "Copying byproducts `${file_names}` to ${output_dir}"
|
|
293 |
VERBATIM
|
|
294 |
COMMAND_EXPAND_LISTS
|
|
295 |
)
|
|
296 |
endfunction()
|
|
297 |
|
|
298 |
function(_corrosion_copy_byproduct_deferred target_name output_dir_prop_name cargo_build_dir file_names)
|
|
299 |
if(ARGN)
|
|
300 |
message(FATAL_ERROR "Unexpected additional arguments")
|
|
301 |
endif()
|
|
302 |
get_target_property(output_dir ${target_name} "${output_dir_prop_name}")
|
|
303 |
|
|
304 |
# A Genex expanding to the output directory depending on the configuration.
|
|
305 |
set(multiconfig_out_dir_genex "")
|
|
306 |
|
|
307 |
foreach(config_type ${CMAKE_CONFIGURATION_TYPES})
|
|
308 |
string(TOUPPER "${config_type}" config_type_upper)
|
|
309 |
get_target_property(output_dir_curr_config ${target_name} "${output_dir_prop_name}_${config_type_upper}")
|
|
310 |
|
|
311 |
if(output_dir_curr_config)
|
|
312 |
set(curr_out_dir "${output_dir_curr_config}")
|
|
313 |
elseif(output_dir)
|
|
314 |
# Fallback to `output_dir` if specified
|
|
315 |
# Note: Multi-configuration generators append a per-configuration subdirectory to the
|
|
316 |
# specified directory unless a generator expression is used (from CMake documentation).
|
|
317 |
set(curr_out_dir "${output_dir}")
|
|
318 |
else()
|
|
319 |
# Fallback to the default directory. We do not append the configuration directory here
|
|
320 |
# and instead let CMake do this, since otherwise the resolving of dynamic library
|
|
321 |
# imported paths may fail.
|
|
322 |
set(curr_out_dir "${CMAKE_CURRENT_BINARY_DIR}")
|
|
323 |
endif()
|
|
324 |
set(multiconfig_out_dir_genex "${multiconfig_out_dir_genex}$<$<CONFIG:${config_type}>:${curr_out_dir}>")
|
|
325 |
endforeach()
|
|
326 |
|
|
327 |
if(COR_IS_MULTI_CONFIG)
|
|
328 |
set(output_dir "${multiconfig_out_dir_genex}")
|
|
329 |
else()
|
|
330 |
if(NOT output_dir)
|
|
331 |
# Fallback to default directory.
|
|
332 |
set(output_dir "${CMAKE_CURRENT_BINARY_DIR}")
|
|
333 |
endif()
|
|
334 |
endif()
|
|
335 |
|
|
336 |
# Append .exe suffix for executable by-products if the target is windows or if it's a host
|
|
337 |
# build and the host is Windows.
|
|
338 |
get_target_property(target_type "${target_name}" TYPE)
|
|
339 |
if (target_type STREQUAL "EXECUTABLE")
|
|
340 |
list(LENGTH file_names list_len)
|
|
341 |
if(NOT list_len EQUAL "1")
|
|
342 |
message(FATAL_ERROR
|
|
343 |
"Internal error: Exactly one filename should be passed for executable types.")
|
|
344 |
endif()
|
|
345 |
_corrosion_bin_target_suffix(${target_name} "suffix")
|
|
346 |
if(suffix AND (NOT "${file_names}" MATCHES "\.pdb$"))
|
|
347 |
# For executable targets we know / checked that only one file will be passed.
|
|
348 |
string(APPEND file_names "${suffix}")
|
|
349 |
endif()
|
|
350 |
endif()
|
|
351 |
|
|
352 |
list(TRANSFORM file_names PREPEND "${cargo_build_dir}/" OUTPUT_VARIABLE src_file_names)
|
|
353 |
list(TRANSFORM file_names PREPEND "${output_dir}/" OUTPUT_VARIABLE dst_file_names)
|
|
354 |
message(DEBUG "Adding command to copy byproducts `${file_names}` to ${dst_file_names}")
|
|
355 |
add_custom_command(TARGET _cargo-build_${target_name}
|
|
356 |
POST_BUILD
|
|
357 |
# output_dir may contain a Generator expression.
|
|
358 |
COMMAND ${CMAKE_COMMAND} -E make_directory "${output_dir}"
|
|
359 |
COMMAND
|
|
360 |
${CMAKE_COMMAND} -E copy_if_different
|
|
361 |
# tested to work with both multiple files and paths with spaces
|
|
362 |
${src_file_names}
|
|
363 |
"${output_dir}"
|
|
364 |
BYPRODUCTS ${dst_file_names}
|
|
365 |
COMMENT "Copying byproducts `${file_names}` to ${output_dir}"
|
|
366 |
VERBATIM
|
|
367 |
COMMAND_EXPAND_LISTS
|
|
368 |
)
|
|
369 |
endfunction()
|
|
370 |
|
|
371 |
function(_corrosion_call_copy_byproduct_deferred target_name output_dir_prop_name cargo_build_dir file_names)
|
|
372 |
cmake_language(EVAL CODE "
|
|
373 |
cmake_language(DEFER
|
|
374 |
CALL
|
|
375 |
_corrosion_copy_byproduct_deferred
|
|
376 |
[[${target_name}]]
|
|
377 |
[[${output_dir_prop_name}]]
|
|
378 |
[[${cargo_build_dir}]]
|
|
379 |
[[${file_names}]]
|
|
380 |
)
|
|
381 |
")
|
|
382 |
endfunction()
|
|
383 |
|
|
384 |
# Copy the artifacts generated by cargo to the appropriate destination.
|
|
385 |
#
|
|
386 |
# Parameters:
|
|
387 |
# - target_name: The name of the Rust target
|
|
388 |
# - output_dir_prop_name: The property name controlling the destination (e.g.
|
|
389 |
# `RUNTIME_OUTPUT_DIRECTORY`)
|
|
390 |
# - cargo_build_dir: the directory cargo build places it's output artifacts in.
|
|
391 |
# - filenames: the file names of any output artifacts as a list.
|
|
392 |
# - is_binary: TRUE if the byproducts are program executables.
|
|
393 |
function(_corrosion_copy_byproducts target_name output_dir_prop_name cargo_build_dir filenames)
|
|
394 |
_corrosion_determine_deferred_byproduct_copying_and_import_location_handling("defer")
|
|
395 |
if(defer)
|
|
396 |
_corrosion_call_copy_byproduct_deferred("${target_name}" "${output_dir_prop_name}" "${cargo_build_dir}" "${filenames}")
|
|
397 |
else()
|
|
398 |
_corrosion_copy_byproduct_legacy("${target_name}" "${cargo_build_dir}" "${filenames}")
|
|
399 |
endif()
|
|
400 |
endfunction()
|
|
401 |
|
|
402 |
|
|
403 |
# Add targets for the static and/or shared libraries of the rust target.
|
|
404 |
# The generated byproduct names are returned via the `OUT_<type>_BYPRODUCTS` arguments.
|
|
405 |
function(_corrosion_add_library_target)
|
|
406 |
set(OPTIONS "")
|
|
407 |
set(ONE_VALUE_KEYWORDS
|
|
408 |
WORKSPACE_MANIFEST_PATH
|
|
409 |
TARGET_NAME
|
|
410 |
OUT_ARCHIVE_OUTPUT_BYPRODUCTS
|
|
411 |
OUT_SHARED_LIB_BYPRODUCTS
|
|
412 |
OUT_PDB_BYPRODUCT
|
|
413 |
)
|
|
414 |
set(MULTI_VALUE_KEYWORDS LIB_KINDS)
|
|
415 |
cmake_parse_arguments(PARSE_ARGV 0 CALT "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}")
|
|
416 |
|
|
417 |
if(DEFINED CALT_UNPARSED_ARGUMENTS)
|
|
418 |
message(FATAL_ERROR "Internal error - unexpected arguments: ${CALT_UNPARSED_ARGUMENTS}")
|
|
419 |
elseif(DEFINED CALT_KEYWORDS_MISSING_VALUES)
|
|
420 |
message(FATAL_ERROR "Internal error - the following keywords had no associated value(s):"
|
|
421 |
"${CALT_KEYWORDS_MISSING_VALUES}")
|
|
422 |
endif()
|
|
423 |
list(TRANSFORM ONE_VALUE_KEYWORDS PREPEND CALT_ OUTPUT_VARIABLE required_arguments)
|
|
424 |
foreach(required_argument ${required_arguments} )
|
|
425 |
if(NOT DEFINED "${required_argument}")
|
|
426 |
message(FATAL_ERROR "Internal error: Missing required argument ${required_argument}."
|
|
427 |
"Complete argument list: ${ARGN}"
|
|
428 |
)
|
|
429 |
endif()
|
|
430 |
endforeach()
|
|
431 |
if("staticlib" IN_LIST CALT_LIB_KINDS)
|
|
432 |
set(has_staticlib TRUE)
|
|
433 |
endif()
|
|
434 |
if("cdylib" IN_LIST CALT_LIB_KINDS)
|
|
435 |
set(has_cdylib TRUE)
|
|
436 |
endif()
|
|
437 |
|
|
438 |
if(NOT (has_staticlib OR has_cdylib))
|
|
439 |
message(FATAL_ERROR "Unknown library type(s): ${CALT_LIB_KINDS}")
|
|
440 |
endif()
|
|
441 |
set(workspace_manifest_path "${CALT_WORKSPACE_MANIFEST_PATH}")
|
|
442 |
set(target_name "${CALT_TARGET_NAME}")
|
|
443 |
|
|
444 |
set(is_windows "")
|
|
445 |
set(is_windows_gnu "")
|
|
446 |
set(is_windows_msvc "")
|
|
447 |
set(is_macos "")
|
|
448 |
if(Rust_CARGO_TARGET_OS STREQUAL "windows")
|
|
449 |
set(is_windows TRUE)
|
|
450 |
if(Rust_CARGO_TARGET_ENV STREQUAL "msvc")
|
|
451 |
set(is_windows_msvc TRUE)
|
|
452 |
elseif(Rust_CARGO_TARGET_ENV STREQUAL "gnu")
|
|
453 |
set(is_windows_gnu TRUE)
|
|
454 |
endif()
|
|
455 |
elseif(Rust_CARGO_TARGET_OS STREQUAL "darwin")
|
|
456 |
set(is_macos TRUE)
|
|
457 |
endif()
|
|
458 |
|
|
459 |
# target file names
|
|
460 |
string(REPLACE "-" "_" lib_name "${target_name}")
|
|
461 |
|
|
462 |
if(is_windows_msvc)
|
|
463 |
set(static_lib_name "${lib_name}.lib")
|
|
464 |
else()
|
|
465 |
set(static_lib_name "lib${lib_name}.a")
|
|
466 |
endif()
|
|
467 |
|
|
468 |
if(is_windows)
|
|
469 |
set(dynamic_lib_name "${lib_name}.dll")
|
|
470 |
elseif(is_macos)
|
|
471 |
set(dynamic_lib_name "lib${lib_name}.dylib")
|
|
472 |
else()
|
|
473 |
set(dynamic_lib_name "lib${lib_name}.so")
|
|
474 |
endif()
|
|
475 |
|
|
476 |
if(is_windows_msvc)
|
|
477 |
set(implib_name "${lib_name}.dll.lib")
|
|
478 |
elseif(is_windows_gnu)
|
|
479 |
set(implib_name "lib${lib_name}.dll.a")
|
|
480 |
elseif(is_windows)
|
|
481 |
message(FATAL_ERROR "Unknown windows environment - Can't determine implib name")
|
|
482 |
endif()
|
|
483 |
|
|
484 |
|
|
485 |
set(pdb_name "${lib_name}.pdb")
|
|
486 |
|
|
487 |
set(archive_output_byproducts "")
|
|
488 |
if(has_staticlib)
|
|
489 |
list(APPEND archive_output_byproducts ${static_lib_name})
|
|
490 |
endif()
|
|
491 |
|
|
492 |
if(has_cdylib)
|
|
493 |
set("${CALT_OUT_SHARED_LIB_BYPRODUCTS}" "${dynamic_lib_name}" PARENT_SCOPE)
|
|
494 |
if(is_windows)
|
|
495 |
list(APPEND archive_output_byproducts ${implib_name})
|
|
496 |
endif()
|
|
497 |
if(is_windows_msvc)
|
|
498 |
set("${CALT_OUT_PDB_BYPRODUCT}" "${pdb_name}" PARENT_SCOPE)
|
|
499 |
endif()
|
|
500 |
endif()
|
|
501 |
set("${CALT_OUT_ARCHIVE_OUTPUT_BYPRODUCTS}" "${archive_output_byproducts}" PARENT_SCOPE)
|
|
502 |
|
|
503 |
add_library(${target_name} INTERFACE)
|
|
504 |
|
|
505 |
if(has_staticlib)
|
|
506 |
add_library(${target_name}-static STATIC IMPORTED GLOBAL)
|
|
507 |
add_dependencies(${target_name}-static cargo-build_${target_name})
|
|
508 |
|
|
509 |
_corrosion_set_imported_location("${target_name}-static" "IMPORTED_LOCATION"
|
|
510 |
"ARCHIVE_OUTPUT_DIRECTORY"
|
|
511 |
"${static_lib_name}")
|
|
512 |
|
|
513 |
# Todo: NO_STD target property?
|
|
514 |
if(NOT COR_NO_STD)
|
|
515 |
set_property(
|
|
516 |
TARGET ${target_name}-static
|
|
517 |
PROPERTY INTERFACE_LINK_LIBRARIES ${Rust_CARGO_TARGET_LINK_NATIVE_LIBS}
|
|
518 |
)
|
|
519 |
set_property(
|
|
520 |
TARGET ${target_name}-static
|
|
521 |
PROPERTY INTERFACE_LINK_OPTIONS ${Rust_CARGO_TARGET_LINK_OPTIONS}
|
|
522 |
)
|
|
523 |
if(is_macos)
|
|
524 |
set_property(TARGET ${target_name}-static
|
|
525 |
PROPERTY INTERFACE_LINK_DIRECTORIES "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib"
|
|
526 |
)
|
|
527 |
endif()
|
|
528 |
endif()
|
|
529 |
endif()
|
|
530 |
|
|
531 |
if(has_cdylib)
|
|
532 |
add_library(${target_name}-shared SHARED IMPORTED GLOBAL)
|
|
533 |
add_dependencies(${target_name}-shared cargo-build_${target_name})
|
|
534 |
|
|
535 |
# Todo: (Not new issue): What about IMPORTED_SONAME and IMPORTED_NO_SYSTEM?
|
|
536 |
_corrosion_set_imported_location("${target_name}-shared" "IMPORTED_LOCATION"
|
|
537 |
"LIBRARY_OUTPUT_DIRECTORY"
|
|
538 |
"${dynamic_lib_name}"
|
|
539 |
)
|
|
540 |
# In the future we would probably prefer to let Rust set the soname for packages >= 1.0.
|
|
541 |
# This is tracked in issue #333.
|
|
542 |
set_target_properties(${target_name}-shared PROPERTIES IMPORTED_NO_SONAME TRUE)
|
|
543 |
|
|
544 |
if(is_windows)
|
|
545 |
_corrosion_set_imported_location("${target_name}-shared" "IMPORTED_IMPLIB"
|
|
546 |
"ARCHIVE_OUTPUT_DIRECTORY"
|
|
547 |
"${implib_name}"
|
|
548 |
)
|
|
549 |
endif()
|
|
550 |
|
|
551 |
if(is_macos)
|
|
552 |
set_property(TARGET ${target_name}-shared
|
|
553 |
PROPERTY INTERFACE_LINK_DIRECTORIES "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib"
|
|
554 |
)
|
|
555 |
endif()
|
|
556 |
endif()
|
|
557 |
|
|
558 |
if(has_cdylib AND has_staticlib)
|
|
559 |
if(BUILD_SHARED_LIBS)
|
|
560 |
target_link_libraries(${target_name} INTERFACE ${target_name}-shared)
|
|
561 |
else()
|
|
562 |
target_link_libraries(${target_name} INTERFACE ${target_name}-static)
|
|
563 |
endif()
|
|
564 |
elseif(has_cdylib)
|
|
565 |
target_link_libraries(${target_name} INTERFACE ${target_name}-shared)
|
|
566 |
else()
|
|
567 |
target_link_libraries(${target_name} INTERFACE ${target_name}-static)
|
|
568 |
endif()
|
|
569 |
endfunction()
|
|
570 |
|
|
571 |
function(_corrosion_add_bin_target workspace_manifest_path bin_name out_bin_byproduct out_pdb_byproduct)
|
|
572 |
if(NOT bin_name)
|
|
573 |
message(FATAL_ERROR "No bin_name in _corrosion_add_bin_target for target ${target_name}")
|
|
574 |
endif()
|
|
575 |
|
|
576 |
string(REPLACE "-" "_" bin_name_underscore "${bin_name}")
|
|
577 |
|
|
578 |
set(pdb_name "${bin_name_underscore}.pdb")
|
|
579 |
|
|
580 |
if(Rust_CARGO_TARGET_ENV STREQUAL "msvc")
|
|
581 |
set(${out_pdb_byproduct} "${pdb_name}" PARENT_SCOPE)
|
|
582 |
endif()
|
|
583 |
|
|
584 |
set(bin_filename "${bin_name}")
|
|
585 |
_corrosion_determine_deferred_byproduct_copying_and_import_location_handling("defer")
|
|
586 |
if(defer)
|
|
587 |
# .exe suffix will be added later, also depending on possible hostbuild
|
|
588 |
# target property
|
|
589 |
else()
|
|
590 |
if(Rust_CARGO_TARGET_OS STREQUAL "windows")
|
|
591 |
set(bin_filename "${bin_name}.exe")
|
|
592 |
endif()
|
|
593 |
endif()
|
|
594 |
set(${out_bin_byproduct} "${bin_filename}" PARENT_SCOPE)
|
|
595 |
|
|
596 |
|
|
597 |
# Todo: This is compatible with the way corrosion previously exposed the bin name,
|
|
598 |
# but maybe we want to prefix the exposed name with the package name?
|
|
599 |
add_executable(${bin_name} IMPORTED GLOBAL)
|
|
600 |
add_dependencies(${bin_name} cargo-build_${bin_name})
|
|
601 |
|
|
602 |
if(Rust_CARGO_TARGET_OS STREQUAL "darwin")
|
|
603 |
set_property(TARGET ${bin_name}
|
|
604 |
PROPERTY INTERFACE_LINK_DIRECTORIES "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib"
|
|
605 |
)
|
|
606 |
endif()
|
|
607 |
|
|
608 |
_corrosion_set_imported_location("${bin_name}" "IMPORTED_LOCATION"
|
|
609 |
"RUNTIME_OUTPUT_DIRECTORY"
|
|
610 |
"${bin_filename}"
|
|
611 |
)
|
|
612 |
|
|
613 |
endfunction()
|
|
614 |
|
|
615 |
|
|
616 |
if (NOT CORROSION_NATIVE_TOOLING)
|
|
617 |
include(CorrosionGenerator)
|
|
618 |
endif()
|
|
619 |
|
|
620 |
# Note: `cmake_language(GET_MESSAGE_LOG_LEVEL <output_variable>)` requires CMake 3.25,
|
|
621 |
# so we offer our own option to control verbosity of downstream commands (e.g. cargo build)
|
|
622 |
if (CORROSION_VERBOSE_OUTPUT)
|
|
623 |
set(_CORROSION_VERBOSE_OUTPUT_FLAG --verbose CACHE INTERNAL "")
|
|
624 |
else()
|
|
625 |
# We want to silence some less important commands by default.
|
|
626 |
set(_CORROSION_QUIET_OUTPUT_FLAG --quiet CACHE INTERNAL "")
|
|
627 |
endif()
|
|
628 |
|
|
629 |
if(CORROSION_NATIVE_TOOLING)
|
|
630 |
if (NOT TARGET Corrosion::Generator )
|
|
631 |
add_subdirectory(generator)
|
|
632 |
endif()
|
|
633 |
get_property(
|
|
634 |
_CORROSION_GENERATOR_EXE
|
|
635 |
TARGET Corrosion::Generator PROPERTY IMPORTED_LOCATION
|
|
636 |
)
|
|
637 |
set(
|
|
638 |
_CORROSION_GENERATOR
|
|
639 |
${CMAKE_COMMAND} -E env
|
|
640 |
CARGO_BUILD_RUSTC=${RUSTC_EXECUTABLE}
|
|
641 |
${_CORROSION_GENERATOR_EXE}
|
|
642 |
--cargo ${CARGO_EXECUTABLE}
|
|
643 |
${_CORROSION_VERBOSE_OUTPUT_FLAG}
|
|
644 |
CACHE INTERNAL "corrosion-generator runner"
|
|
645 |
)
|
|
646 |
endif()
|
|
647 |
|
|
648 |
set(_CORROSION_CARGO_VERSION ${Rust_CARGO_VERSION} CACHE INTERNAL "cargo version used by corrosion")
|
|
649 |
set(_CORROSION_RUST_CARGO_TARGET ${Rust_CARGO_TARGET} CACHE INTERNAL "target triple used by corrosion")
|
|
650 |
set(_CORROSION_RUST_CARGO_HOST_TARGET ${Rust_CARGO_HOST_TARGET} CACHE INTERNAL "host triple used by corrosion")
|
|
651 |
set(_CORROSION_RUSTC "${RUSTC_EXECUTABLE}" CACHE INTERNAL "Path to rustc used by corrosion")
|
|
652 |
set(_CORROSION_CARGO "${CARGO_EXECUTABLE}" CACHE INTERNAL "Path to cargo used by corrosion")
|
|
653 |
|
|
654 |
string(REPLACE "-" "_" _CORROSION_RUST_CARGO_TARGET_UNDERSCORE "${Rust_CARGO_TARGET}")
|
|
655 |
set(_CORROSION_RUST_CARGO_TARGET_UNDERSCORE "${_CORROSION_RUST_CARGO_TARGET_UNDERSCORE}" CACHE INTERNAL "lowercase target triple with underscores")
|
|
656 |
string(TOUPPER "${_CORROSION_RUST_CARGO_TARGET_UNDERSCORE}" _CORROSION_TARGET_TRIPLE_UPPER)
|
|
657 |
set(_CORROSION_RUST_CARGO_TARGET_UPPER
|
|
658 |
"${_CORROSION_TARGET_TRIPLE_UPPER}"
|
|
659 |
CACHE INTERNAL
|
|
660 |
"target triple in uppercase with underscore"
|
|
661 |
)
|
|
662 |
|
|
663 |
# We previously specified some Custom properties as part of our public API, however the chosen names prevented us from
|
|
664 |
# supporting CMake versions before 3.19. In order to both support older CMake versions and not break existing code
|
|
665 |
# immediately, we are using a different property name depending on the CMake version. However users avoid using
|
|
666 |
# any of the properties directly, as they are no longer part of the public API and are to be considered deprecated.
|
|
667 |
# Instead use the corrosion_set_... functions as documented in the Readme.
|
|
668 |
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.19.0)
|
|
669 |
set(_CORR_PROP_FEATURES CORROSION_FEATURES CACHE INTERNAL "")
|
|
670 |
set(_CORR_PROP_ALL_FEATURES CORROSION_ALL_FEATURES CACHE INTERNAL "")
|
|
671 |
set(_CORR_PROP_NO_DEFAULT_FEATURES CORROSION_NO_DEFAULT_FEATURES CACHE INTERNAL "")
|
|
672 |
set(_CORR_PROP_ENV_VARS CORROSION_ENVIRONMENT_VARIABLES CACHE INTERNAL "")
|
|
673 |
set(_CORR_PROP_HOST_BUILD CORROSION_USE_HOST_BUILD CACHE INTERNAL "")
|
|
674 |
else()
|
|
675 |
set(_CORR_PROP_FEATURES INTERFACE_CORROSION_FEATURES CACHE INTERNAL "")
|
|
676 |
set(_CORR_PROP_ALL_FEATURES INTERFACE_CORROSION_ALL_FEATURES CACHE INTERNAL "")
|
|
677 |
set(_CORR_PROP_NO_DEFAULT_FEATURES INTERFACE_NO_DEFAULT_FEATURES CACHE INTERNAL "")
|
|
678 |
set(_CORR_PROP_ENV_VARS INTERFACE_CORROSION_ENVIRONMENT_VARIABLES CACHE INTERNAL "")
|
|
679 |
set(_CORR_PROP_HOST_BUILD INTERFACE_CORROSION_USE_HOST_BUILD CACHE INTERNAL "")
|
|
680 |
endif()
|
|
681 |
|
|
682 |
# Add custom command to build one target in a package (crate)
|
|
683 |
#
|
|
684 |
# A target may be either a specific bin
|
|
685 |
function(_add_cargo_build out_cargo_build_out_dir)
|
|
686 |
set(options NO_LINKER_OVERRIDE)
|
|
687 |
set(one_value_args PACKAGE TARGET MANIFEST_PATH WORKSPACE_MANIFEST_PATH)
|
|
688 |
set(multi_value_args BYPRODUCTS TARGET_KINDS)
|
|
689 |
cmake_parse_arguments(
|
|
690 |
ACB
|
|
691 |
"${options}"
|
|
692 |
"${one_value_args}"
|
|
693 |
"${multi_value_args}"
|
|
694 |
${ARGN}
|
|
695 |
)
|
|
696 |
|
|
697 |
if(DEFINED ACB_UNPARSED_ARGUMENTS)
|
|
698 |
message(FATAL_ERROR "Internal error - unexpected arguments: "
|
|
699 |
${ACB_UNPARSED_ARGUMENTS})
|
|
700 |
elseif(DEFINED ACB_KEYWORDS_MISSING_VALUES)
|
|
701 |
message(FATAL_ERROR "Internal error - missing values for the following arguments: "
|
|
702 |
${ACB_KEYWORDS_MISSING_VALUES})
|
|
703 |
endif()
|
|
704 |
|
|
705 |
set(package_name "${ACB_PACKAGE}")
|
|
706 |
set(target_name "${ACB_TARGET}")
|
|
707 |
set(path_to_toml "${ACB_MANIFEST_PATH}")
|
|
708 |
set(target_kinds "${ACB_TARGET_KINDS}")
|
|
709 |
set(workspace_manifest_path "${ACB_WORKSPACE_MANIFEST_PATH}")
|
|
710 |
|
|
711 |
|
|
712 |
if(NOT target_kinds)
|
|
713 |
message(FATAL_ERROR "TARGET_KINDS not specified")
|
|
714 |
elseif("staticlib" IN_LIST target_kinds OR "cdylib" IN_LIST target_kinds)
|
|
715 |
set(cargo_rustc_filter "--lib")
|
|
716 |
elseif("bin" IN_LIST target_kinds)
|
|
717 |
set(cargo_rustc_filter "--bin=${target_name}")
|
|
718 |
else()
|
|
719 |
message(FATAL_ERROR "TARGET_KINDS contained unknown kind `${target_kind}`")
|
|
720 |
endif()
|
|
721 |
|
|
722 |
if (NOT IS_ABSOLUTE "${path_to_toml}")
|
|
723 |
set(path_to_toml "${CMAKE_SOURCE_DIR}/${path_to_toml}")
|
|
724 |
endif()
|
|
725 |
get_filename_component(workspace_toml_dir ${path_to_toml} DIRECTORY )
|
|
726 |
|
|
727 |
if (CMAKE_VS_PLATFORM_NAME)
|
|
728 |
set (build_dir "${CMAKE_VS_PLATFORM_NAME}/$<CONFIG>")
|
|
729 |
elseif(COR_IS_MULTI_CONFIG)
|
|
730 |
set (build_dir "$<CONFIG>")
|
|
731 |
else()
|
|
732 |
set (build_dir .)
|
|
733 |
endif()
|
|
734 |
|
|
735 |
# If a CMake sysroot is specified, forward it to the linker rustc invokes, too. CMAKE_SYSROOT is documented
|
|
736 |
# to be passed via --sysroot, so we assume that when it's set, the linker supports this option in that style.
|
|
737 |
if(CMAKE_CROSSCOMPILING AND CMAKE_SYSROOT)
|
|
738 |
set(corrosion_link_args "--sysroot=${CMAKE_SYSROOT}")
|
|
739 |
endif()
|
|
740 |
|
|
741 |
if(COR_ALL_FEATURES)
|
|
742 |
set(all_features_arg --all-features)
|
|
743 |
endif()
|
|
744 |
if(COR_NO_DEFAULT_FEATURES)
|
|
745 |
set(no_default_features_arg --no-default-features)
|
|
746 |
endif()
|
|
747 |
|
|
748 |
set(global_rustflags_target_property "$<TARGET_GENEX_EVAL:${target_name},$<TARGET_PROPERTY:${target_name},INTERFACE_CORROSION_RUSTFLAGS>>")
|
|
749 |
set(local_rustflags_target_property "$<TARGET_GENEX_EVAL:${target_name},$<TARGET_PROPERTY:${target_name},INTERFACE_CORROSION_LOCAL_RUSTFLAGS>>")
|
|
750 |
|
|
751 |
# todo: this probably should be TARGET_GENEX_EVAL
|
|
752 |
set(features_target_property "$<GENEX_EVAL:$<TARGET_PROPERTY:${target_name},${_CORR_PROP_FEATURES}>>")
|
|
753 |
set(features_genex "$<$<BOOL:${features_target_property}>:--features=$<JOIN:${features_target_property},$<COMMA>>>")
|
|
754 |
|
|
755 |
# target property overrides corrosion_import_crate argument
|
|
756 |
set(all_features_target_property "$<GENEX_EVAL:$<TARGET_PROPERTY:${target_name},${_CORR_PROP_ALL_FEATURES}>>")
|
|
757 |
set(all_features_arg "$<$<BOOL:${all_features_target_property}>:--all-features>")
|
|
758 |
|
|
759 |
set(no_default_features_target_property "$<GENEX_EVAL:$<TARGET_PROPERTY:${target_name},${_CORR_PROP_NO_DEFAULT_FEATURES}>>")
|
|
760 |
set(no_default_features_arg "$<$<BOOL:${no_default_features_target_property}>:--no-default-features>")
|
|
761 |
|
|
762 |
set(build_env_variable_genex "$<GENEX_EVAL:$<TARGET_PROPERTY:${target_name},${_CORR_PROP_ENV_VARS}>>")
|
|
763 |
set(hostbuild_override "$<BOOL:$<TARGET_PROPERTY:${target_name},${_CORR_PROP_HOST_BUILD}>>")
|
|
764 |
set(if_not_host_build_condition "$<NOT:${hostbuild_override}>")
|
|
765 |
|
|
766 |
set(corrosion_link_args "$<${if_not_host_build_condition}:${corrosion_link_args}>")
|
|
767 |
# We always set `--target`, so that cargo always places artifacts into a directory with the
|
|
768 |
# target triple.
|
|
769 |
set(cargo_target_option "--target=$<IF:${hostbuild_override},${_CORROSION_RUST_CARGO_HOST_TARGET},${_CORROSION_RUST_CARGO_TARGET}>")
|
|
770 |
|
|
771 |
# The target may be a filepath to custom target json file. For host targets we assume that they are built-in targets.
|
|
772 |
_corrosion_strip_target_triple(${_CORROSION_RUST_CARGO_TARGET} stripped_target_triple)
|
|
773 |
set(target_artifact_dir "$<IF:${hostbuild_override},${_CORROSION_RUST_CARGO_HOST_TARGET},${stripped_target_triple}>")
|
|
774 |
|
|
775 |
set(flags_genex "$<GENEX_EVAL:$<TARGET_PROPERTY:${target_name},INTERFACE_CORROSION_CARGO_FLAGS>>")
|
|
776 |
|
|
777 |
set(explicit_linker_property "$<TARGET_PROPERTY:${target_name},INTERFACE_CORROSION_LINKER>")
|
|
778 |
set(explicit_linker_defined "$<BOOL:${explicit_linker_property}>")
|
|
779 |
|
|
780 |
set(cargo_profile_target_property "$<TARGET_GENEX_EVAL:${target_name},$<TARGET_PROPERTY:${target_name},INTERFACE_CORROSION_CARGO_PROFILE>>")
|
|
781 |
|
|
782 |
# Option to override the rustc/cargo binary to something other than the global default
|
|
783 |
set(rustc_override "$<TARGET_PROPERTY:${target_name},INTERFACE_CORROSION_RUSTC>")
|
|
784 |
set(cargo_override "$<TARGET_PROPERTY:${target_name},INTERFACE_CORROSION_CARGO>")
|
|
785 |
set(rustc_bin "$<IF:$<BOOL:${rustc_override}>,${rustc_override},${_CORROSION_RUSTC}>")
|
|
786 |
set(cargo_bin "$<IF:$<BOOL:${cargo_override}>,${cargo_override},${_CORROSION_CARGO}>")
|
|
787 |
|
|
788 |
|
|
789 |
# Rust will add `-lSystem` as a flag for the linker on macOS. Adding the -L flag via RUSTFLAGS only fixes the
|
|
790 |
# problem partially - buildscripts still break, since they won't receive the RUSTFLAGS. This seems to only be a
|
|
791 |
# problem if we specify the linker ourselves (which we do, since this is necessary for e.g. linking C++ code).
|
|
792 |
# We can however set `LIBRARY_PATH`, which is propagated to the build-script-build properly.
|
|
793 |
if(NOT CMAKE_CROSSCOMPILING AND CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
|
794 |
# not needed anymore on macos 13 (and causes issues)
|
|
795 |
if(${CMAKE_SYSTEM_VERSION} VERSION_LESS 22)
|
|
796 |
set(cargo_library_path "LIBRARY_PATH=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib")
|
|
797 |
endif()
|
|
798 |
elseif(CMAKE_CROSSCOMPILING AND CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
|
|
799 |
if(${CMAKE_HOST_SYSTEM_VERSION} VERSION_LESS 22)
|
|
800 |
set(cargo_library_path "$<${hostbuild_override}:LIBRARY_PATH=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib>")
|
|
801 |
endif()
|
|
802 |
endif()
|
|
803 |
|
|
804 |
set(cargo_profile_set "$<BOOL:${cargo_profile_target_property}>")
|
|
805 |
# In the default case just specify --release or nothing to stay compatible with
|
|
806 |
# older rust versions.
|
|
807 |
set(default_profile_option "$<$<NOT:$<OR:$<CONFIG:Debug>,$<CONFIG:>>>:--release>")
|
|
808 |
# evaluates to either `--profile=<custom_profile>`, `--release` or nothing (for debug).
|
|
809 |
set(cargo_profile "$<IF:${cargo_profile_set},--profile=${cargo_profile_target_property},${default_profile_option}>")
|
|
810 |
|
|
811 |
# If the profile name is `dev` change the dir name to `debug`.
|
|
812 |
set(is_dev_profile "$<STREQUAL:${cargo_profile_target_property},dev>")
|
|
813 |
set(profile_dir_override "$<${is_dev_profile}:debug>")
|
|
814 |
set(profile_dir_is_overridden "$<BOOL:${profile_dir_override}>")
|
|
815 |
set(custom_profile_build_type_dir "$<IF:${profile_dir_is_overridden},${profile_dir_override},${cargo_profile_target_property}>")
|
|
816 |
|
|
817 |
set(default_build_type_dir "$<IF:$<OR:$<CONFIG:Debug>,$<CONFIG:>>,debug,release>")
|
|
818 |
set(build_type_dir "$<IF:${cargo_profile_set},${custom_profile_build_type_dir},${default_build_type_dir}>")
|
|
819 |
|
|
820 |
set(cargo_target_dir "${CMAKE_BINARY_DIR}/${build_dir}/cargo/build")
|
|
821 |
set(cargo_build_dir "${cargo_target_dir}/${target_artifact_dir}/${build_type_dir}")
|
|
822 |
set("${out_cargo_build_out_dir}" "${cargo_build_dir}" PARENT_SCOPE)
|
|
823 |
|
|
824 |
set(corrosion_cc_rs_flags)
|
|
825 |
|
|
826 |
if(CMAKE_C_COMPILER)
|
|
827 |
# This variable is read by cc-rs (often used in build scripts) to determine the c-compiler.
|
|
828 |
# It can still be overridden if the user sets the non underscore variant via the environment variables
|
|
829 |
# on the target.
|
|
830 |
list(APPEND corrosion_cc_rs_flags "CC_${_CORROSION_RUST_CARGO_TARGET_UNDERSCORE}=${CMAKE_C_COMPILER}")
|
|
831 |
endif()
|
|
832 |
if(CMAKE_CXX_COMPILER)
|
|
833 |
list(APPEND corrosion_cc_rs_flags "CXX_${_CORROSION_RUST_CARGO_TARGET_UNDERSCORE}=${CMAKE_CXX_COMPILER}")
|
|
834 |
endif()
|
|
835 |
# cc-rs doesn't seem to support `llvm-ar` (commandline syntax), wo we might as well just use
|
|
836 |
# the default AR.
|
|
837 |
if(CMAKE_AR AND NOT (Rust_CARGO_TARGET_ENV STREQUAL "msvc"))
|
|
838 |
list(APPEND corrosion_cc_rs_flags "AR_${_CORROSION_RUST_CARGO_TARGET_UNDERSCORE}=${CMAKE_AR}")
|
|
839 |
endif()
|
|
840 |
|
|
841 |
# Since we instruct cc-rs to use the compiler found by CMake, it is likely one that requires also
|
|
842 |
# specifying the target sysroot to use. CMake's generator makes sure to pass --sysroot with
|
|
843 |
# CMAKE_OSX_SYSROOT. Fortunately the compilers Apple ships also respect the SDKROOT environment
|
|
844 |
# variable, which we can set for use when cc-rs invokes the compiler.
|
|
845 |
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_OSX_SYSROOT)
|
|
846 |
list(APPEND corrosion_cc_rs_flags "SDKROOT=${CMAKE_OSX_SYSROOT}")
|
|
847 |
endif()
|
|
848 |
|
|
849 |
corrosion_add_target_local_rustflags("${target_name}" "$<$<BOOL:${corrosion_link_args}>:-Clink-args=${corrosion_link_args}>")
|
|
850 |
|
|
851 |
# todo: this should probably also be guarded by if_not_host_build_condition.
|
|
852 |
if(COR_NO_STD)
|
|
853 |
corrosion_add_target_local_rustflags("${target_name}" "-Cdefault-linker-libraries=no")
|
|
854 |
else()
|
|
855 |
corrosion_add_target_local_rustflags("${target_name}" "-Cdefault-linker-libraries=yes")
|
|
856 |
endif()
|
|
857 |
|
|
858 |
set(global_joined_rustflags "$<JOIN:${global_rustflags_target_property}, >")
|
|
859 |
set(global_rustflags_genex "$<$<BOOL:${global_rustflags_target_property}>:RUSTFLAGS=${global_joined_rustflags}>")
|
|
860 |
set(local_rustflags_delimiter "$<$<BOOL:${local_rustflags_target_property}>:-->")
|
|
861 |
set(local_rustflags_genex "$<$<BOOL:${local_rustflags_target_property}>:${local_rustflags_target_property}>")
|
|
862 |
|
|
863 |
set(deps_link_languages_prop "$<TARGET_PROPERTY:_cargo-build_${target_name},CARGO_DEPS_LINKER_LANGUAGES>")
|
|
864 |
set(deps_link_languages "$<TARGET_GENEX_EVAL:_cargo-build_${target_name},${deps_link_languages_prop}>")
|
|
865 |
set(target_uses_cxx "$<IN_LIST:CXX,${deps_link_languages}>")
|
|
866 |
unset(default_linker)
|
|
867 |
# With the MSVC ABI rustc only supports directly invoking the linker - Invoking cl as the linker driver is not supported.
|
|
868 |
if(NOT (Rust_CARGO_TARGET_ENV STREQUAL "msvc" OR COR_NO_LINKER_OVERRIDE))
|
|
869 |
set(default_linker "$<IF:$<BOOL:${target_uses_cxx}>,${CMAKE_CXX_COMPILER},${CMAKE_C_COMPILER}>")
|
|
870 |
endif()
|
|
871 |
# Used to set a linker for a specific target-triple.
|
|
872 |
set(cargo_target_linker_var "CARGO_TARGET_${_CORROSION_RUST_CARGO_TARGET_UPPER}_LINKER")
|
|
873 |
set(linker "$<IF:${explicit_linker_defined},${explicit_linker_property},${default_linker}>")
|
|
874 |
set(cargo_target_linker $<$<BOOL:${linker}>:${cargo_target_linker_var}=${linker}>)
|
|
875 |
|
|
876 |
if(Rust_CROSSCOMPILING AND (CMAKE_C_COMPILER_TARGET OR CMAKE_CXX_COMPILER_TARGET))
|
|
877 |
set(linker_target_triple "$<IF:$<BOOL:${target_uses_cxx}>,${CMAKE_CXX_COMPILER_TARGET},${CMAKE_C_COMPILER_TARGET}>")
|
|
878 |
set(rustflag_linker_arg "-Clink-args=--target=${linker_target_triple}")
|
|
879 |
set(rustflag_linker_arg "$<${if_not_host_build_condition}:${rustflag_linker_arg}>")
|
|
880 |
# Skip adding the linker argument, if the linker is explicitly set, since the
|
|
881 |
# explicit_linker_property will not be set when this function runs.
|
|
882 |
# Passing this rustflag is necessary for clang.
|
|
883 |
corrosion_add_target_local_rustflags("${target_name}" "$<$<NOT:${explicit_linker_defined}>:${rustflag_linker_arg}>")
|
|
884 |
endif()
|
|
885 |
|
|
886 |
message(DEBUG "TARGET ${target_name} produces byproducts ${byproducts}")
|
|
887 |
|
|
888 |
add_custom_target(
|
|
889 |
_cargo-build_${target_name}
|
|
890 |
# Build crate
|
|
891 |
COMMAND
|
|
892 |
${CMAKE_COMMAND} -E env
|
|
893 |
"${build_env_variable_genex}"
|
|
894 |
"${global_rustflags_genex}"
|
|
895 |
"${cargo_target_linker}"
|
|
896 |
"${corrosion_cc_rs_flags}"
|
|
897 |
"${cargo_library_path}"
|
|
898 |
"CORROSION_BUILD_DIR=${CMAKE_CURRENT_BINARY_DIR}"
|
|
899 |
"CARGO_BUILD_RUSTC=${rustc_bin}"
|
|
900 |
"${cargo_bin}"
|
|
901 |
rustc
|
|
902 |
${cargo_rustc_filter}
|
|
903 |
${cargo_target_option}
|
|
904 |
${_CORROSION_VERBOSE_OUTPUT_FLAG}
|
|
905 |
${all_features_arg}
|
|
906 |
${no_default_features_arg}
|
|
907 |
${features_genex}
|
|
908 |
--package ${package_name}
|
|
909 |
--manifest-path "${path_to_toml}"
|
|
910 |
--target-dir "${cargo_target_dir}"
|
|
911 |
${cargo_profile}
|
|
912 |
${flags_genex}
|
|
913 |
# Any arguments to cargo must be placed before this line
|
|
914 |
${local_rustflags_delimiter}
|
|
915 |
${local_rustflags_genex}
|
|
916 |
|
|
917 |
# Note: Adding `build_byproducts` (the byproducts in the cargo target directory) here
|
|
918 |
# causes CMake to fail during the Generate stage, because the target `target_name` was not
|
|
919 |
# found. I don't know why this happens, so we just don't specify byproducts here and
|
|
920 |
# only specify the actual byproducts in the `POST_BUILD` custom command that copies the
|
|
921 |
# byproducts to the final destination.
|
|
922 |
# BYPRODUCTS ${build_byproducts}
|
|
923 |
# The build is conducted in the directory of the Manifest, so that configuration files such as
|
|
924 |
# `.cargo/config.toml` or `toolchain.toml` are applied as expected.
|
|
925 |
WORKING_DIRECTORY "${workspace_toml_dir}"
|
|
926 |
USES_TERMINAL
|
|
927 |
COMMAND_EXPAND_LISTS
|
|
928 |
VERBATIM
|
|
929 |
)
|
|
930 |
|
|
931 |
# User exposed custom target, that depends on the internal target.
|
|
932 |
# Corrosion post build steps are added on the internal target, which
|
|
933 |
# ensures that they run before any user defined post build steps on this
|
|
934 |
# target.
|
|
935 |
add_custom_target(
|
|
936 |
cargo-build_${target_name}
|
|
937 |
ALL
|
|
938 |
)
|
|
939 |
add_dependencies(cargo-build_${target_name} _cargo-build_${target_name})
|
|
940 |
|
|
941 |
# Add custom target before actual build that user defined custom commands (e.g. code generators) can
|
|
942 |
# use as a hook to do something before the build. This mainly exists to not expose the `_cargo-build` targets.
|
|
943 |
add_custom_target(cargo-prebuild_${target_name})
|
|
944 |
add_dependencies(_cargo-build_${target_name} cargo-prebuild_${target_name})
|
|
945 |
if(NOT TARGET cargo-prebuild)
|
|
946 |
add_custom_target(cargo-prebuild)
|
|
947 |
endif()
|
|
948 |
add_dependencies(cargo-prebuild cargo-prebuild_${target_name})
|
|
949 |
|
|
950 |
add_custom_target(
|
|
951 |
cargo-clean_${target_name}
|
|
952 |
COMMAND
|
|
953 |
"${cargo_bin}" clean ${cargo_target_option}
|
|
954 |
-p ${package_name} --manifest-path ${path_to_toml}
|
|
955 |
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/${build_dir}
|
|
956 |
USES_TERMINAL
|
|
957 |
)
|
|
958 |
|
|
959 |
if (NOT TARGET cargo-clean)
|
|
960 |
add_custom_target(cargo-clean)
|
|
961 |
endif()
|
|
962 |
add_dependencies(cargo-clean cargo-clean_${target_name})
|
|
963 |
endfunction()
|
|
964 |
|
|
965 |
#[=======================================================================[.md:
|
|
966 |
ANCHOR: corrosion-import-crate
|
|
967 |
```cmake
|
|
968 |
corrosion_import_crate(
|
|
969 |
MANIFEST_PATH <path/to/cargo.toml>
|
|
970 |
[ALL_FEATURES]
|
|
971 |
[NO_DEFAULT_FEATURES]
|
|
972 |
[NO_STD]
|
|
973 |
[NO_LINKER_OVERRIDE]
|
|
974 |
[LOCKED]
|
|
975 |
[FROZEN]
|
|
976 |
[PROFILE <cargo-profile>]
|
|
977 |
[IMPORTED_CRATES <variable-name>]
|
|
978 |
[CRATE_TYPES <crate_type1> ... <crate_typeN>]
|
|
979 |
[CRATES <crate1> ... <crateN>]
|
|
980 |
[FEATURES <feature1> ... <featureN>]
|
|
981 |
[FLAGS <flag1> ... <flagN>]
|
|
982 |
)
|
|
983 |
```
|
|
984 |
* **MANIFEST_PATH**: Path to a [Cargo.toml Manifest] file.
|
|
985 |
* **ALL_FEATURES**: Equivalent to [--all-features] passed to cargo build
|
|
986 |
* **NO_DEFAULT_FEATURES**: Equivalent to [--no-default-features] passed to cargo build
|
|
987 |
* **NO_STD**: Disable linking of standard libraries (required for no_std crates).
|
|
988 |
* **NO_LINKER_OVERRIDE**: Will let Rust/Cargo determine which linker to use instead of corrosion (when linking is invoked by Rust)
|
|
989 |
* **LOCKED**: Pass [`--locked`] to cargo build and cargo metadata.
|
|
990 |
* **FROZEN**: Pass [`--frozen`] to cargo build and cargo metadata.
|
|
991 |
* **PROFILE**: Specify cargo build profile (`dev`/`release` or a [custom profile]; `bench` and `test` are not supported)
|
|
992 |
* **IMPORTED_CRATES**: Save the list of imported crates into the variable with the provided name in the current scope.
|
|
993 |
* **CRATE_TYPES**: Only import the specified crate types. Valid values: `staticlib`, `cdylib`, `bin`.
|
|
994 |
* **CRATES**: Only import the specified crates from a workspace. Values: Crate names.
|
|
995 |
* **FEATURES**: Enable the specified features. Equivalent to [--features] passed to `cargo build`.
|
|
996 |
* **FLAGS**: Arbitrary flags to `cargo build`.
|
|
997 |
|
|
998 |
[custom profile]: https://doc.rust-lang.org/cargo/reference/profiles.html#custom-profiles
|
|
999 |
[--all-features]: https://doc.rust-lang.org/cargo/reference/features.html#command-line-feature-options
|
|
1000 |
[--no-default-features]: https://doc.rust-lang.org/cargo/reference/features.html#command-line-feature-options
|
|
1001 |
[--features]: https://doc.rust-lang.org/cargo/reference/features.html#command-line-feature-options
|
|
1002 |
[`--locked`]: https://doc.rust-lang.org/cargo/commands/cargo.html#manifest-options
|
|
1003 |
[`--frozen`]: https://doc.rust-lang.org/cargo/commands/cargo.html#manifest-options
|
|
1004 |
[Cargo.toml Manifest]: https://doc.rust-lang.org/cargo/appendix/glossary.html#manifest
|
|
1005 |
|
|
1006 |
ANCHOR_END: corrosion-import-crate
|
|
1007 |
#]=======================================================================]
|
|
1008 |
function(corrosion_import_crate)
|
|
1009 |
set(OPTIONS ALL_FEATURES NO_DEFAULT_FEATURES NO_STD NO_LINKER_OVERRIDE LOCKED FROZEN)
|
|
1010 |
set(ONE_VALUE_KEYWORDS MANIFEST_PATH PROFILE IMPORTED_CRATES)
|
|
1011 |
set(MULTI_VALUE_KEYWORDS CRATE_TYPES CRATES FEATURES FLAGS)
|
|
1012 |
cmake_parse_arguments(COR "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}" ${ARGN})
|
|
1013 |
list(APPEND CMAKE_MESSAGE_CONTEXT "corrosion_import_crate")
|
|
1014 |
|
|
1015 |
if(DEFINED COR_UNPARSED_ARGUMENTS)
|
|
1016 |
message(AUTHOR_WARNING "Unexpected arguments: " ${COR_UNPARSED_ARGUMENTS}
|
|
1017 |
"\nCorrosion will ignore these unexpected arguments."
|
|
1018 |
)
|
|
1019 |
endif()
|
|
1020 |
if(DEFINED COR_KEYWORDS_MISSING_VALUES)
|
|
1021 |
message(DEBUG "Note: the following keywords passed to corrosion_import_crate had no associated value(s): "
|
|
1022 |
${COR_KEYWORDS_MISSING_VALUES}
|
|
1023 |
)
|
|
1024 |
endif()
|
|
1025 |
if (NOT DEFINED COR_MANIFEST_PATH)
|
|
1026 |
message(FATAL_ERROR "MANIFEST_PATH is a required keyword to corrosion_add_crate")
|
|
1027 |
endif()
|
|
1028 |
_corrosion_option_passthrough_helper(NO_LINKER_OVERRIDE COR no_linker_override)
|
|
1029 |
_corrosion_option_passthrough_helper(LOCKED COR locked)
|
|
1030 |
_corrosion_option_passthrough_helper(FROZEN COR frozen)
|
|
1031 |
_corrosion_arg_passthrough_helper(CRATES COR crate_allowlist)
|
|
1032 |
_corrosion_arg_passthrough_helper(CRATE_TYPES COR crate_types)
|
|
1033 |
|
|
1034 |
if(COR_PROFILE)
|
|
1035 |
if(Rust_VERSION VERSION_LESS 1.57.0)
|
|
1036 |
message(FATAL_ERROR "Selecting custom profiles via `PROFILE` requires at least rust 1.57.0, but you "
|
|
1037 |
"have ${Rust_VERSION}."
|
|
1038 |
)
|
|
1039 |
# The profile name could be part of a Generator expression, so this won't catch all occurences.
|
|
1040 |
# Since it is hard to add an error message for genex, we don't do that here.
|
|
1041 |
elseif("${COR_PROFILE}" STREQUAL "test" OR "${COR_PROFILE}" STREQUAL "bench")
|
|
1042 |
message(FATAL_ERROR "Corrosion does not support building Rust crates with the cargo profiles"
|
|
1043 |
" `test` or `bench`. These profiles add a hash to the output artifact name that we"
|
|
1044 |
" cannot predict. Please consider using a custom cargo profile which inherits from the"
|
|
1045 |
" built-in profile instead."
|
|
1046 |
)
|
|
1047 |
endif()
|
|
1048 |
endif()
|
|
1049 |
|
|
1050 |
if (NOT IS_ABSOLUTE "${COR_MANIFEST_PATH}")
|
|
1051 |
set(COR_MANIFEST_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${COR_MANIFEST_PATH})
|
|
1052 |
endif()
|
|
1053 |
|
|
1054 |
set(additional_cargo_flags ${COR_FLAGS})
|
|
1055 |
|
|
1056 |
if(COR_LOCKED AND NOT "--locked" IN_LIST additional_cargo_flags)
|
|
1057 |
list(APPEND additional_cargo_flags "--locked")
|
|
1058 |
endif()
|
|
1059 |
if(COR_FROZEN AND NOT "--frozen" IN_LIST additional_cargo_flags)
|
|
1060 |
list(APPEND additional_cargo_flags "--frozen")
|
|
1061 |
endif()
|
|
1062 |
|
|
1063 |
set(imported_crates "")
|
|
1064 |
if (CORROSION_NATIVE_TOOLING)
|
|
1065 |
get_filename_component(manifest_directory "${COR_MANIFEST_PATH}" DIRECTORY)
|
|
1066 |
get_filename_component(toml_dir_name ${manifest_directory} NAME)
|
|
1067 |
|
|
1068 |
set(
|
|
1069 |
generated_cmake
|
|
1070 |
"${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/corrosion/${toml_dir_name}.dir/cargo-build.cmake"
|
|
1071 |
)
|
|
1072 |
|
|
1073 |
if (CMAKE_VS_PLATFORM_NAME)
|
|
1074 |
set (_CORROSION_CONFIGURATION_ROOT --configuration-root ${CMAKE_VS_PLATFORM_NAME})
|
|
1075 |
endif()
|
|
1076 |
|
|
1077 |
set(crates_args)
|
|
1078 |
foreach(crate ${COR_CRATES})
|
|
1079 |
list(APPEND crates_args --crates ${crate})
|
|
1080 |
endforeach()
|
|
1081 |
if(DEFINED COR_CRATE_TYPES)
|
|
1082 |
set(crate_types "--crate-type=${COR_CRATE_TYPES}")
|
|
1083 |
endif()
|
|
1084 |
|
|
1085 |
list(APPEND passthrough_to_acb_args ${no_linker_override})
|
|
1086 |
if(passthrough_to_acb_args)
|
|
1087 |
# 31 == 0x1f
|
|
1088 |
string(ASCII 31 unit_seperator)
|
|
1089 |
list(JOIN passthrough_to_acb_args "${unit_seperator}" joined_args)
|
|
1090 |
set(passthrough_to_acb "--passthrough-acb=${joined_args}")
|
|
1091 |
endif()
|
|
1092 |
|
|
1093 |
execute_process(
|
|
1094 |
COMMAND
|
|
1095 |
${_CORROSION_GENERATOR}
|
|
1096 |
--manifest-path ${COR_MANIFEST_PATH}
|
|
1097 |
gen-cmake
|
|
1098 |
${_CORROSION_CONFIGURATION_ROOT}
|
|
1099 |
${crates_args}
|
|
1100 |
${crate_types}
|
|
1101 |
--imported-crates=imported_crates
|
|
1102 |
${passthrough_to_acb}
|
|
1103 |
-o ${generated_cmake}
|
|
1104 |
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
|
1105 |
RESULT_VARIABLE ret)
|
|
1106 |
|
|
1107 |
if (NOT ret EQUAL "0")
|
|
1108 |
message(FATAL_ERROR "corrosion-generator failed")
|
|
1109 |
endif()
|
|
1110 |
|
|
1111 |
include(${generated_cmake})
|
|
1112 |
else()
|
|
1113 |
_generator_add_cargo_targets(
|
|
1114 |
MANIFEST_PATH
|
|
1115 |
"${COR_MANIFEST_PATH}"
|
|
1116 |
IMPORTED_CRATES
|
|
1117 |
imported_crates
|
|
1118 |
${crate_allowlist}
|
|
1119 |
${crate_types}
|
|
1120 |
${no_linker_override}
|
|
1121 |
)
|
|
1122 |
endif()
|
|
1123 |
|
|
1124 |
# Not target props yet:
|
|
1125 |
# NO_STD
|
|
1126 |
# NO_LINKER_OVERRIDE # We could simply zero INTERFACE_CORROSION_LINKER if this is set.
|
|
1127 |
# LOCKED / FROZEN get merged into FLAGS after cargo metadata.
|
|
1128 |
|
|
1129 |
# Initialize the target properties with the arguments to corrosion_import_crate.
|
|
1130 |
set_target_properties(
|
|
1131 |
${imported_crates}
|
|
1132 |
PROPERTIES
|
|
1133 |
"${_CORR_PROP_ALL_FEATURES}" "${COR_ALL_FEATURES}"
|
|
1134 |
"${_CORR_PROP_NO_DEFAULT_FEATURES}" "${COR_NO_DEFAULT_FEATURES}"
|
|
1135 |
"${_CORR_PROP_FEATURES}" "${COR_FEATURES}"
|
|
1136 |
INTERFACE_CORROSION_CARGO_PROFILE "${COR_PROFILE}"
|
|
1137 |
INTERFACE_CORROSION_CARGO_FLAGS "${additional_cargo_flags}"
|
|
1138 |
)
|
|
1139 |
|
|
1140 |
# _CORR_PROP_ENV_VARS
|
|
1141 |
if(DEFINED COR_IMPORTED_CRATES)
|
|
1142 |
set(${COR_IMPORTED_CRATES} ${imported_crates} PARENT_SCOPE)
|
|
1143 |
endif()
|
|
1144 |
endfunction()
|
|
1145 |
|
|
1146 |
function(corrosion_set_linker_language target_name language)
|
|
1147 |
message(FATAL_ERROR "corrosion_set_linker_language was deprecated and removed."
|
|
1148 |
"Please use corrosion_set_linker and set a specific linker.")
|
|
1149 |
endfunction()
|
|
1150 |
|
|
1151 |
function(corrosion_set_linker target_name linker)
|
|
1152 |
if(NOT linker)
|
|
1153 |
message(FATAL_ERROR "The linker passed to `corrosion_set_linker` may not be empty")
|
|
1154 |
elseif(NOT TARGET "${target_name}")
|
|
1155 |
message(FATAL_ERROR "The target `${target_name}` does not exist.")
|
|
1156 |
endif()
|
|
1157 |
if(MSVC)
|
|
1158 |
message(WARNING "Explicitly setting the linker with the MSVC toolchain is currently not supported and ignored")
|
|
1159 |
endif()
|
|
1160 |
|
|
1161 |
if(TARGET "${target_name}-static" AND NOT TARGET "${target_name}-shared")
|
|
1162 |
message(WARNING "The target ${target_name} builds a static library."
|
|
1163 |
"The linker is never invoked for a static library so specifying a linker has no effect."
|
|
1164 |
)
|
|
1165 |
endif()
|
|
1166 |
|
|
1167 |
set_property(
|
|
1168 |
TARGET ${target_name}
|
|
1169 |
PROPERTY INTERFACE_CORROSION_LINKER "${linker}"
|
|
1170 |
)
|
|
1171 |
endfunction()
|
|
1172 |
|
|
1173 |
function(corrosion_set_hostbuild target_name)
|
|
1174 |
# Configure the target to be compiled for the Host target and ignore any cross-compile configuration.
|
|
1175 |
set_property(
|
|
1176 |
TARGET ${target_name}
|
|
1177 |
PROPERTY ${_CORR_PROP_HOST_BUILD} 1
|
|
1178 |
)
|
|
1179 |
endfunction()
|
|
1180 |
|
|
1181 |
# Add flags for rustc (RUSTFLAGS) which affect the target and all of it's Rust dependencies
|
|
1182 |
#
|
|
1183 |
# Additional rustflags may be passed as optional parameters after rustflag.
|
|
1184 |
# Please note, that if you import multiple targets from a package or workspace, but set different
|
|
1185 |
# Rustflags via this function, the Rust dependencies will have to be rebuilt when changing targets.
|
|
1186 |
# Consider `corrosion_add_target_local_rustflags()` as an alternative to avoid this.
|
|
1187 |
function(corrosion_add_target_rustflags target_name rustflag)
|
|
1188 |
# Additional rustflags may be passed as optional parameters after rustflag.
|
|
1189 |
set_property(
|
|
1190 |
TARGET ${target_name}
|
|
1191 |
APPEND
|
|
1192 |
PROPERTY INTERFACE_CORROSION_RUSTFLAGS ${rustflag} ${ARGN}
|
|
1193 |
)
|
|
1194 |
endfunction()
|
|
1195 |
|
|
1196 |
# Add flags for rustc (RUSTFLAGS) which only affect the target, but none of it's (Rust) dependencies
|
|
1197 |
#
|
|
1198 |
# Additional rustflags may be passed as optional parameters after rustc_flag.
|
|
1199 |
function(corrosion_add_target_local_rustflags target_name rustc_flag)
|
|
1200 |
# Set Rustflags via `cargo rustc` which only affect the current crate, but not dependencies.
|
|
1201 |
set_property(
|
|
1202 |
TARGET ${target_name}
|
|
1203 |
APPEND
|
|
1204 |
PROPERTY INTERFACE_CORROSION_LOCAL_RUSTFLAGS ${rustc_flag} ${ARGN}
|
|
1205 |
)
|
|
1206 |
endfunction()
|
|
1207 |
|
|
1208 |
function(corrosion_set_env_vars target_name env_var)
|
|
1209 |
# Additional environment variables may be passed as optional parameters after env_var.
|
|
1210 |
set_property(
|
|
1211 |
TARGET ${target_name}
|
|
1212 |
APPEND
|
|
1213 |
PROPERTY ${_CORR_PROP_ENV_VARS} ${env_var} ${ARGN}
|
|
1214 |
)
|
|
1215 |
endfunction()
|
|
1216 |
|
|
1217 |
function(corrosion_set_cargo_flags target_name)
|
|
1218 |
# corrosion_set_cargo_flags(<target_name> [<flag1> ... ])
|
|
1219 |
|
|
1220 |
set_property(
|
|
1221 |
TARGET ${target_name}
|
|
1222 |
APPEND
|
|
1223 |
PROPERTY INTERFACE_CORROSION_CARGO_FLAGS ${ARGN}
|
|
1224 |
)
|
|
1225 |
endfunction()
|
|
1226 |
|
|
1227 |
function(corrosion_set_features target_name)
|
|
1228 |
# corrosion_set_features(<target_name> [ALL_FEATURES=Bool] [NO_DEFAULT_FEATURES] [FEATURES <feature1> ... ])
|
|
1229 |
set(options NO_DEFAULT_FEATURES)
|
|
1230 |
set(one_value_args ALL_FEATURES)
|
|
1231 |
set(multi_value_args FEATURES)
|
|
1232 |
cmake_parse_arguments(
|
|
1233 |
PARSE_ARGV 1
|
|
1234 |
SET
|
|
1235 |
"${options}"
|
|
1236 |
"${one_value_args}"
|
|
1237 |
"${multi_value_args}"
|
|
1238 |
)
|
|
1239 |
|
|
1240 |
if(DEFINED SET_ALL_FEATURES)
|
|
1241 |
set_property(
|
|
1242 |
TARGET ${target_name}
|
|
1243 |
PROPERTY ${_CORR_PROP_ALL_FEATURES} ${SET_ALL_FEATURES}
|
|
1244 |
)
|
|
1245 |
endif()
|
|
1246 |
if(SET_NO_DEFAULT_FEATURES)
|
|
1247 |
set_property(
|
|
1248 |
TARGET ${target_name}
|
|
1249 |
PROPERTY ${_CORR_PROP_NO_DEFAULT_FEATURES} 1
|
|
1250 |
)
|
|
1251 |
endif()
|
|
1252 |
if(SET_FEATURES)
|
|
1253 |
set_property(
|
|
1254 |
TARGET ${target_name}
|
|
1255 |
APPEND
|
|
1256 |
PROPERTY ${_CORR_PROP_FEATURES} ${SET_FEATURES}
|
|
1257 |
)
|
|
1258 |
endif()
|
|
1259 |
endfunction()
|
|
1260 |
|
|
1261 |
function(corrosion_link_libraries target_name)
|
|
1262 |
if(TARGET "${target_name}-static")
|
|
1263 |
message(DEBUG "The target ${target_name} builds a static Rust library."
|
|
1264 |
"Calling `target_link_libraries()` instead."
|
|
1265 |
)
|
|
1266 |
target_link_libraries("${target_name}-static" INTERFACE ${ARGN})
|
|
1267 |
if(NOT TARGET "${target_name}-shared")
|
|
1268 |
# Early return, since Rust won't invoke the linker for static libraries
|
|
1269 |
return()
|
|
1270 |
endif()
|
|
1271 |
endif()
|
|
1272 |
add_dependencies(_cargo-build_${target_name} ${ARGN})
|
|
1273 |
foreach(library ${ARGN})
|
|
1274 |
set_property(
|
|
1275 |
TARGET _cargo-build_${target_name}
|
|
1276 |
APPEND
|
|
1277 |
PROPERTY CARGO_DEPS_LINKER_LANGUAGES
|
|
1278 |
$<TARGET_PROPERTY:${library},LINKER_LANGUAGE>
|
|
1279 |
)
|
|
1280 |
|
|
1281 |
corrosion_add_target_local_rustflags(${target_name} "-L$<TARGET_LINKER_FILE_DIR:${library}>")
|
|
1282 |
corrosion_add_target_local_rustflags(${target_name} "-l$<TARGET_LINKER_FILE_BASE_NAME:${library}>")
|
|
1283 |
endforeach()
|
|
1284 |
endfunction()
|
|
1285 |
|
|
1286 |
function(corrosion_install)
|
|
1287 |
# Default install dirs
|
|
1288 |
include(GNUInstallDirs)
|
|
1289 |
|
|
1290 |
# Parse arguments to corrosion_install
|
|
1291 |
list(GET ARGN 0 INSTALL_TYPE)
|
|
1292 |
list(REMOVE_AT ARGN 0)
|
|
1293 |
|
|
1294 |
# The different install types that are supported. Some targets may have more than one of these
|
|
1295 |
# types. For example, on Windows, a shared library will have both an ARCHIVE component and a
|
|
1296 |
# RUNTIME component.
|
|
1297 |
set(INSTALL_TARGET_TYPES ARCHIVE LIBRARY RUNTIME PRIVATE_HEADER PUBLIC_HEADER)
|
|
1298 |
|
|
1299 |
# Arguments to each install target type
|
|
1300 |
set(OPTIONS)
|
|
1301 |
set(ONE_VALUE_ARGS DESTINATION)
|
|
1302 |
set(MULTI_VALUE_ARGS PERMISSIONS CONFIGURATIONS)
|
|
1303 |
set(TARGET_ARGS ${OPTIONS} ${ONE_VALUE_ARGS} ${MULTI_VALUE_ARGS})
|
|
1304 |
|
|
1305 |
if (INSTALL_TYPE STREQUAL "TARGETS")
|
|
1306 |
# corrosion_install(TARGETS ... [EXPORT <export-name>]
|
|
1307 |
# [[ARCHIVE|LIBRARY|RUNTIME|PRIVATE_HEADER|PUBLIC_HEADER]
|
|
1308 |
# [DESTINATION <dir>]
|
|
1309 |
# [PERMISSIONS permissions...]
|
|
1310 |
# [CONFIGURATIONS [Debug|Release|...]]
|
|
1311 |
# ] [...])
|
|
1312 |
|
|
1313 |
# Extract targets
|
|
1314 |
set(INSTALL_TARGETS)
|
|
1315 |
list(LENGTH ARGN ARGN_LENGTH)
|
|
1316 |
set(DELIMITERS EXPORT ${INSTALL_TARGET_TYPES} ${TARGET_ARGS})
|
|
1317 |
while(ARGN_LENGTH)
|
|
1318 |
# If we hit another keyword, stop - we've found all the targets
|
|
1319 |
list(GET ARGN 0 FRONT)
|
|
1320 |
if (FRONT IN_LIST DELIMITERS)
|
|
1321 |
break()
|
|
1322 |
endif()
|
|
1323 |
|
|
1324 |
list(APPEND INSTALL_TARGETS ${FRONT})
|
|
1325 |
list(REMOVE_AT ARGN 0)
|
|
1326 |
|
|
1327 |
# Update ARGN_LENGTH
|
|
1328 |
list(LENGTH ARGN ARGN_LENGTH)
|
|
1329 |
endwhile()
|
|
1330 |
|
|
1331 |
# Check if there are any args left before proceeding
|
|
1332 |
list(LENGTH ARGN ARGN_LENGTH)
|
|
1333 |
if (ARGN_LENGTH)
|
|
1334 |
list(GET ARGN 0 FRONT)
|
|
1335 |
if (FRONT STREQUAL "EXPORT")
|
|
1336 |
list(REMOVE_AT ARGN 0) # Pop "EXPORT"
|
|
1337 |
|
|
1338 |
list(GET ARGN 0 EXPORT_NAME)
|
|
1339 |
list(REMOVE_AT ARGN 0) # Pop <export-name>
|
|
1340 |
message(FATAL_ERROR "EXPORT keyword not yet implemented!")
|
|
1341 |
endif()
|
|
1342 |
endif()
|
|
1343 |
|
|
1344 |
# Loop over all arguments and get options for each install target type
|
|
1345 |
list(LENGTH ARGN ARGN_LENGTH)
|
|
1346 |
while(ARGN_LENGTH)
|
|
1347 |
# Check if we're dealing with arguments for a specific install target type, or with
|
|
1348 |
# default options for all target types.
|
|
1349 |
list(GET ARGN 0 FRONT)
|
|
1350 |
if (FRONT IN_LIST INSTALL_TARGET_TYPES)
|
|
1351 |
set(INSTALL_TARGET_TYPE ${FRONT})
|
|
1352 |
list(REMOVE_AT ARGN 0)
|
|
1353 |
else()
|
|
1354 |
set(INSTALL_TARGET_TYPE DEFAULT)
|
|
1355 |
endif()
|
|
1356 |
|
|
1357 |
# Gather the arguments to this install type
|
|
1358 |
set(ARGS)
|
|
1359 |
while(ARGN_LENGTH)
|
|
1360 |
# If the next keyword is an install target type, then break - arguments have been
|
|
1361 |
# gathered.
|
|
1362 |
list(GET ARGN 0 FRONT)
|
|
1363 |
if (FRONT IN_LIST INSTALL_TARGET_TYPES)
|
|
1364 |
break()
|
|
1365 |
endif()
|
|
1366 |
|
|
1367 |
list(APPEND ARGS ${FRONT})
|
|
1368 |
list(REMOVE_AT ARGN 0)
|
|
1369 |
|
|
1370 |
list(LENGTH ARGN ARGN_LENGTH)
|
|
1371 |
endwhile()
|
|
1372 |
|
|
1373 |
# Parse the arguments and register the file install
|
|
1374 |
cmake_parse_arguments(
|
|
1375 |
COR "${OPTIONS}" "${ONE_VALUE_ARGS}" "${MULTI_VALUE_ARGS}" ${ARGS})
|
|
1376 |
|
|
1377 |
if (COR_DESTINATION)
|
|
1378 |
set(COR_INSTALL_${INSTALL_TARGET_TYPE}_DESTINATION ${COR_DESTINATION})
|
|
1379 |
endif()
|
|
1380 |
|
|
1381 |
if (COR_PERMISSIONS)
|
|
1382 |
set(COR_INSTALL_${INSTALL_TARGET_TYPE}_PERMISSIONS ${COR_PERMISSIONS})
|
|
1383 |
endif()
|
|
1384 |
|
|
1385 |
if (COR_CONFIGURATIONS)
|
|
1386 |
set(COR_INSTALL_${INSTALL_TARGET_TYPE}_CONFIGURATIONS ${COR_CONFIGURATIONS})
|
|
1387 |
endif()
|
|
1388 |
|
|
1389 |
# Update ARG_LENGTH
|
|
1390 |
list(LENGTH ARGN ARGN_LENGTH)
|
|
1391 |
endwhile()
|
|
1392 |
|
|
1393 |
# Default permissions for all files
|
|
1394 |
set(DEFAULT_PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
|
|
1395 |
|
|
1396 |
# Loop through each install target and register file installations
|
|
1397 |
foreach(INSTALL_TARGET ${INSTALL_TARGETS})
|
|
1398 |
# Don't both implementing target type differentiation using generator expressions since
|
|
1399 |
# TYPE cannot change after target creation
|
|
1400 |
get_property(
|
|
1401 |
TARGET_TYPE
|
|
1402 |
TARGET ${INSTALL_TARGET} PROPERTY TYPE
|
|
1403 |
)
|
|
1404 |
|
|
1405 |
# Install executable files first
|
|
1406 |
if (TARGET_TYPE STREQUAL "EXECUTABLE")
|
|
1407 |
if (DEFINED COR_INSTALL_RUNTIME_DESTINATION)
|
|
1408 |
set(DESTINATION ${COR_INSTALL_RUNTIME_DESTINATION})
|
|
1409 |
elseif (DEFINED COR_INSTALL_DEFAULT_DESTINATION)
|
|
1410 |
set(DESTINATION ${COR_INSTALL_DEFAULT_DESTINATION})
|
|
1411 |
else()
|
|
1412 |
set(DESTINATION ${CMAKE_INSTALL_BINDIR})
|
|
1413 |
endif()
|
|
1414 |
|
|
1415 |
if (DEFINED COR_INSTALL_RUNTIME_PERMISSIONS)
|
|
1416 |
set(PERMISSIONS ${COR_INSTALL_RUNTIME_PERMISSIONS})
|
|
1417 |
elseif (DEFINED COR_INSTALL_DEFAULT_PERMISSIONS)
|
|
1418 |
set(PERMISSIONS ${COR_INSTALL_DEFAULT_PERMISSIONS})
|
|
1419 |
else()
|
|
1420 |
set(
|
|
1421 |
PERMISSIONS
|
|
1422 |
${DEFAULT_PERMISSIONS} OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE)
|
|
1423 |
endif()
|
|
1424 |
|
|
1425 |
if (DEFINED COR_INSTALL_RUNTIME_CONFIGURATIONS)
|
|
1426 |
set(CONFIGURATIONS CONFIGURATIONS ${COR_INSTALL_RUNTIME_CONFIGURATIONS})
|
|
1427 |
elseif (DEFINED COR_INSTALL_DEFAULT_CONFIGURATIONS)
|
|
1428 |
set(CONFIGURATIONS CONFIGURATIONS ${COR_INSTALL_DEFAULT_CONFIGURATIONS})
|
|
1429 |
else()
|
|
1430 |
set(CONFIGURATIONS)
|
|
1431 |
endif()
|
|
1432 |
|
|
1433 |
install(
|
|
1434 |
FILES $<TARGET_FILE:${INSTALL_TARGET}>
|
|
1435 |
DESTINATION ${DESTINATION}
|
|
1436 |
PERMISSIONS ${PERMISSIONS}
|
|
1437 |
${CONFIGURATIONS}
|
|
1438 |
)
|
|
1439 |
endif()
|
|
1440 |
endforeach()
|
|
1441 |
|
|
1442 |
elseif(INSTALL_TYPE STREQUAL "EXPORT")
|
|
1443 |
message(FATAL_ERROR "install(EXPORT ...) not yet implemented")
|
|
1444 |
endif()
|
|
1445 |
endfunction()
|
|
1446 |
|
|
1447 |
#[=======================================================================[.md:
|
|
1448 |
** EXPERIMENTAL **: This function is currently still considered experimental
|
|
1449 |
and is not officially released yet. Feedback and Suggestions are welcome.
|
|
1450 |
|
|
1451 |
ANCHOR: corrosion_add_cxxbridge
|
|
1452 |
|
|
1453 |
```cmake
|
|
1454 |
corrosion_add_cxxbridge(cxx_target
|
|
1455 |
CRATE <imported_target_name>
|
|
1456 |
[FILES <file1.rs> <file2.rs>]
|
|
1457 |
)
|
|
1458 |
```
|
|
1459 |
|
|
1460 |
Adds build-rules to create C++ bindings using the [cxx] crate.
|
|
1461 |
|
|
1462 |
### Arguments:
|
|
1463 |
* `cxxtarget`: Name of the C++ library target for the bindings, which corrosion will create.
|
|
1464 |
* **FILES**: Input Rust source file containing #[cxx::bridge].
|
|
1465 |
* **CRATE**: Name of an imported Rust target. Note: Parameter may be renamed before release
|
|
1466 |
|
|
1467 |
#### Currently missing arguments
|
|
1468 |
|
|
1469 |
The following arguments to cxxbridge **currently** have no way to be passed by the user:
|
|
1470 |
- `--cfg`
|
|
1471 |
- `--cxx-impl-annotations`
|
|
1472 |
- `--include`
|
|
1473 |
|
|
1474 |
The created rules approximately do the following:
|
|
1475 |
- Check which version of `cxx` the Rust crate specified by the `CRATE` argument depends on.
|
|
1476 |
- Check if the exact same version of `cxxbridge-cmd` is installed (available in `PATH`)
|
|
1477 |
- If not, create a rule to build the exact same version of `cxxbridge-cmd`.
|
|
1478 |
- Create rules to run `cxxbridge` and generate
|
|
1479 |
- The `rust/cxx.h` header
|
|
1480 |
- A header and source file for each of the files specified in `FILES`
|
|
1481 |
- The generated sources (and header include directories) are added to the `cxxtarget` CMake
|
|
1482 |
library target.
|
|
1483 |
|
|
1484 |
### Limitations
|
|
1485 |
|
|
1486 |
We currently require the `CRATE` argument to be a target imported by Corrosion, however,
|
|
1487 |
Corrosion does not import `rlib` only libraries. As a workaround users can add
|
|
1488 |
`staticlib` to their list of crate kinds. In the future this may be solved more properly,
|
|
1489 |
by either adding an option to also import Rlib targets (without build rules) or by
|
|
1490 |
adding a `MANIFEST_PATH` argument to this function, specifying where the crate is.
|
|
1491 |
|
|
1492 |
### Contributing
|
|
1493 |
|
|
1494 |
Specifically some more realistic test / demo projects and feedback about limitations would be
|
|
1495 |
welcome.
|
|
1496 |
|
|
1497 |
[cxx]: https://github.com/dtolnay/cxx
|
|
1498 |
|
|
1499 |
ANCHOR_END: corrosion_add_cxxbridge
|
|
1500 |
#]=======================================================================]
|
|
1501 |
function(corrosion_add_cxxbridge cxx_target)
|
|
1502 |
set(OPTIONS)
|
|
1503 |
set(ONE_VALUE_KEYWORDS CRATE)
|
|
1504 |
set(MULTI_VALUE_KEYWORDS FILES)
|
|
1505 |
cmake_parse_arguments(PARSE_ARGV 1 _arg "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}")
|
|
1506 |
|
|
1507 |
set(required_keywords CRATE FILES)
|
|
1508 |
foreach(keyword ${required_keywords})
|
|
1509 |
if(NOT DEFINED "_arg_${keyword}")
|
|
1510 |
message(FATAL_ERROR "Missing required parameter `${keyword}`.")
|
|
1511 |
elseif("${_arg_${keyword}}" STREQUAL "")
|
|
1512 |
message(FATAL_ERROR "Required parameter `${keyword}` may not be set to an empty string.")
|
|
1513 |
endif()
|
|
1514 |
endforeach()
|
|
1515 |
|
|
1516 |
get_target_property(manifest_path "${_arg_CRATE}" INTERFACE_COR_PACKAGE_MANIFEST_PATH)
|
|
1517 |
|
|
1518 |
if(NOT EXISTS "${manifest_path}")
|
|
1519 |
message(FATAL_ERROR "Internal error: No package manifest found at ${manifest_path}")
|
|
1520 |
endif()
|
|
1521 |
|
|
1522 |
get_filename_component(manifest_dir ${manifest_path} DIRECTORY)
|
|
1523 |
|
|
1524 |
execute_process(COMMAND ${CMAKE_COMMAND} -E env
|
|
1525 |
"CARGO_BUILD_RUSTC=${_CORROSION_RUSTC}"
|
|
1526 |
${_CORROSION_CARGO} tree -i cxx --depth=0
|
|
1527 |
WORKING_DIRECTORY "${manifest_dir}"
|
|
1528 |
RESULT_VARIABLE cxx_version_result
|
|
1529 |
OUTPUT_VARIABLE cxx_version_output
|
|
1530 |
)
|
|
1531 |
if(NOT "${cxx_version_result}" EQUAL "0")
|
|
1532 |
message(FATAL_ERROR "Crate ${_arg_CRATE} does not depend on cxx.")
|
|
1533 |
endif()
|
|
1534 |
if(cxx_version_output MATCHES "cxx v([0-9]+.[0-9]+.[0-9]+)")
|
|
1535 |
set(cxx_required_version "${CMAKE_MATCH_1}")
|
|
1536 |
else()
|
|
1537 |
message(FATAL_ERROR "Failed to parse cxx version from cargo tree output: `cxx_version_output`")
|
|
1538 |
endif()
|
|
1539 |
|
|
1540 |
# First check if a suitable version of cxxbridge is installed
|
|
1541 |
find_program(INSTALLED_CXXBRIDGE cxxbridge PATHS "$ENV{HOME}/.cargo/bin/")
|
|
1542 |
mark_as_advanced(INSTALLED_CXXBRIDGE)
|
|
1543 |
if(INSTALLED_CXXBRIDGE)
|
|
1544 |
execute_process(COMMAND ${INSTALLED_CXXBRIDGE} --version OUTPUT_VARIABLE cxxbridge_version_output)
|
|
1545 |
if(cxxbridge_version_output MATCHES "cxxbridge ([0-9]+.[0-9]+.[0-9]+)")
|
|
1546 |
set(cxxbridge_version "${CMAKE_MATCH_1}")
|
|
1547 |
else()
|
|
1548 |
set(cxxbridge_version "")
|
|
1549 |
endif()
|
|
1550 |
endif()
|
|
1551 |
|
|
1552 |
set(cxxbridge "")
|
|
1553 |
if(cxxbridge_version)
|
|
1554 |
if(cxxbridge_version VERSION_EQUAL cxx_required_version)
|
|
1555 |
set(cxxbridge "${INSTALLED_CXXBRIDGE}")
|
|
1556 |
if(NOT TARGET "cxxbridge_v${cxx_required_version}")
|
|
1557 |
# Add an empty target.
|
|
1558 |
add_custom_target("cxxbridge_v${cxx_required_version}"
|
|
1559 |
)
|
|
1560 |
endif()
|
|
1561 |
endif()
|
|
1562 |
endif()
|
|
1563 |
|
|
1564 |
# No suitable version of cxxbridge was installed, so use custom target to build correct version.
|
|
1565 |
if(NOT cxxbridge)
|
|
1566 |
if(NOT TARGET "cxxbridge_v${cxx_required_version}")
|
|
1567 |
add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/corrosion/cxxbridge_v${cxx_required_version}/bin/cxxbridge"
|
|
1568 |
COMMAND
|
|
1569 |
${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/corrosion/cxxbridge_v${cxx_required_version}"
|
|
1570 |
COMMAND
|
|
1571 |
${CMAKE_COMMAND} -E env
|
|
1572 |
"CARGO_BUILD_RUSTC=${_CORROSION_RUSTC}"
|
|
1573 |
${_CORROSION_CARGO} install
|
|
1574 |
cxxbridge-cmd
|
|
1575 |
--version "${cxx_required_version}"
|
|
1576 |
--root "${CMAKE_BINARY_DIR}/corrosion/cxxbridge_v${cxx_required_version}"
|
|
1577 |
--quiet
|
|
1578 |
# todo: use --target-dir to potentially reuse artifacts
|
|
1579 |
COMMENT "Building cxxbridge (version ${cxx_required_version})"
|
|
1580 |
)
|
|
1581 |
add_custom_target("cxxbridge_v${cxx_required_version}"
|
|
1582 |
DEPENDS "${CMAKE_BINARY_DIR}/corrosion/cxxbridge_v${cxx_required_version}/bin/cxxbridge"
|
|
1583 |
)
|
|
1584 |
endif()
|
|
1585 |
set(cxxbridge "${CMAKE_BINARY_DIR}/corrosion/cxxbridge_v${cxx_required_version}/bin/cxxbridge")
|
|
1586 |
endif()
|
|
1587 |
|
|
1588 |
|
|
1589 |
# The generated folder structure will be of the following form
|
|
1590 |
#
|
|
1591 |
# CMAKE_CURRENT_BINARY_DIR
|
|
1592 |
# corrosion_generated
|
|
1593 |
# cxxbridge
|
|
1594 |
# <cxx_target>
|
|
1595 |
# include
|
|
1596 |
# <cxx_target>
|
|
1597 |
# <headers>
|
|
1598 |
# rust
|
|
1599 |
# cxx.h
|
|
1600 |
# src
|
|
1601 |
# <sourcefiles>
|
|
1602 |
# cbindgen
|
|
1603 |
# ...
|
|
1604 |
# other
|
|
1605 |
# ...
|
|
1606 |
|
|
1607 |
set(corrosion_generated_dir "${CMAKE_CURRENT_BINARY_DIR}/corrosion_generated")
|
|
1608 |
set(generated_dir "${corrosion_generated_dir}/cxxbridge/${cxx_target}")
|
|
1609 |
set(header_placement_dir "${generated_dir}/include/${cxx_target}")
|
|
1610 |
set(source_placement_dir "${generated_dir}/src")
|
|
1611 |
|
|
1612 |
add_library(${cxx_target} STATIC)
|
|
1613 |
target_include_directories(${cxx_target}
|
|
1614 |
PUBLIC
|
|
1615 |
$<BUILD_INTERFACE:${generated_dir}/include>
|
|
1616 |
$<INSTALL_INTERFACE:include>
|
|
1617 |
)
|
|
1618 |
|
|
1619 |
# cxx generated code is using c++11 features in headers, so propagate c++11 as minimal requirement
|
|
1620 |
target_compile_features(${cxx_target} PUBLIC cxx_std_11)
|
|
1621 |
|
|
1622 |
# Todo: target_link_libraries is only necessary for rust2c projects.
|
|
1623 |
# It is possible that checking if the rust crate is an executable is a sufficient check,
|
|
1624 |
# but some more thought may be needed here.
|
|
1625 |
# Maybe we should also let the user do this, since for c2rust, the user also has to call
|
|
1626 |
# corrosion_link_libraries() themselves.
|
|
1627 |
get_target_property(crate_target_type ${_arg_CRATE} TYPE)
|
|
1628 |
if (NOT crate_target_type STREQUAL "EXECUTABLE")
|
|
1629 |
target_link_libraries(${cxx_target} PRIVATE ${_arg_CRATE})
|
|
1630 |
endif()
|
|
1631 |
|
|
1632 |
file(MAKE_DIRECTORY "${generated_dir}/include/rust")
|
|
1633 |
add_custom_command(
|
|
1634 |
OUTPUT "${generated_dir}/include/rust/cxx.h"
|
|
1635 |
COMMAND
|
|
1636 |
${cxxbridge} --header --output "${generated_dir}/include/rust/cxx.h"
|
|
1637 |
DEPENDS "cxxbridge_v${cxx_required_version}"
|
|
1638 |
COMMENT "Generating rust/cxx.h header"
|
|
1639 |
)
|
|
1640 |
|
|
1641 |
foreach(filepath ${_arg_FILES})
|
|
1642 |
get_filename_component(filename ${filepath} NAME_WE)
|
|
1643 |
get_filename_component(directory ${filepath} DIRECTORY)
|
|
1644 |
set(directory_component "")
|
|
1645 |
if(directory)
|
|
1646 |
set(directory_component "${directory}/")
|
|
1647 |
endif()
|
|
1648 |
# todo: convert potentially absolute paths to relative paths..
|
|
1649 |
set(cxx_header ${directory_component}${filename}.h)
|
|
1650 |
set(cxx_source ${directory_component}${filename}.cpp)
|
|
1651 |
|
|
1652 |
# todo: not all projects may use the `src` directory.
|
|
1653 |
set(rust_source_path "${manifest_dir}/src/${filepath}")
|
|
1654 |
|
|
1655 |
file(MAKE_DIRECTORY "${header_placement_dir}/${directory}" "${source_placement_dir}/${directory}")
|
|
1656 |
|
|
1657 |
add_custom_command(
|
|
1658 |
OUTPUT
|
|
1659 |
"${header_placement_dir}/${cxx_header}"
|
|
1660 |
"${source_placement_dir}/${cxx_source}"
|
|
1661 |
COMMAND
|
|
1662 |
${cxxbridge} ${rust_source_path} --header --output "${header_placement_dir}/${cxx_header}"
|
|
1663 |
COMMAND
|
|
1664 |
${cxxbridge} ${rust_source_path}
|
|
1665 |
--output "${source_placement_dir}/${cxx_source}"
|
|
1666 |
--include "${cxx_target}/${cxx_header}"
|
|
1667 |
DEPENDS "cxxbridge_v${cxx_required_version}" "${rust_source_path}"
|
|
1668 |
COMMENT "Generating cxx bindings for crate ${_arg_CRATE}"
|
|
1669 |
)
|
|
1670 |
|
|
1671 |
target_sources(${cxx_target}
|
|
1672 |
PRIVATE
|
|
1673 |
"${header_placement_dir}/${cxx_header}"
|
|
1674 |
"${generated_dir}/include/rust/cxx.h"
|
|
1675 |
"${source_placement_dir}/${cxx_source}"
|
|
1676 |
)
|
|
1677 |
endforeach()
|
|
1678 |
endfunction()
|
|
1679 |
|
|
1680 |
#[=======================================================================[.md:
|
|
1681 |
ANCHOR: corrosion_cbindgen
|
|
1682 |
```cmake
|
|
1683 |
corrosion_cbindgen(
|
|
1684 |
TARGET <imported_target_name>
|
|
1685 |
HEADER_NAME <output_header_name>
|
|
1686 |
[MANIFEST_DIRECTORY <package_manifest_directory>]
|
|
1687 |
[CBINDGEN_VERSION <version>]
|
|
1688 |
[FLAGS <flag1> ... <flagN>]
|
|
1689 |
)
|
|
1690 |
```
|
|
1691 |
|
|
1692 |
A helper function which uses [cbindgen] to generate C/C++ bindings for a Rust crate.
|
|
1693 |
If `cbindgen` is not in `PATH` the helper function will automatically try to download
|
|
1694 |
`cbindgen` and place the built binary into `CMAKE_BINARY_DIR`. The binary is shared
|
|
1695 |
between multiple invocations of this function.
|
|
1696 |
|
|
1697 |
|
|
1698 |
* **TARGET**: The name of an imported Rust library target (crate), for which bindings should be generated.
|
|
1699 |
If the target was not previously imported by Corrosion, because the crate only produces an
|
|
1700 |
`rlib`, you must additionally specify `MANIFEST_DIRECTORY`.
|
|
1701 |
|
|
1702 |
* **MANIFEST_DIRECTORY**: Directory of the package defining the library crate bindings should be generated for.
|
|
1703 |
If you want to avoid specifying `MANIFEST_DIRECTORY` you could add a `staticlib` target to your package
|
|
1704 |
manifest as a workaround to make corrosion import the crate.
|
|
1705 |
|
|
1706 |
* **HEADER_NAME**: The name of the generated header file. This will be the name which you include in your C/C++ code
|
|
1707 |
(e.g. `#include "myproject/myheader.h" if you specify `HEADER_NAME "myproject/myheader.h"`.
|
|
1708 |
* **CBINDGEN_VERSION**: Version requirement for cbindgen. Exact semantics to be specified. Currently not implemented.
|
|
1709 |
* **FLAGS**: Arbitrary other flags for `cbindgen`. Run `cbindgen --help` to see the possible flags.
|
|
1710 |
|
|
1711 |
[cbindgen]: https://github.com/eqrion/cbindgen
|
|
1712 |
|
|
1713 |
ANCHOR_END: corrosion_cbindgen
|
|
1714 |
#]=======================================================================]
|
|
1715 |
function(corrosion_experimental_cbindgen)
|
|
1716 |
set(OPTIONS "")
|
|
1717 |
set(ONE_VALUE_KEYWORDS TARGET MANIFEST_DIRECTORY HEADER_NAME CBINDGEN_VERSION)
|
|
1718 |
set(MULTI_VALUE_KEYWORDS "FLAGS")
|
|
1719 |
cmake_parse_arguments(PARSE_ARGV 0 CCN "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}")
|
|
1720 |
|
|
1721 |
set(required_keywords TARGET HEADER_NAME)
|
|
1722 |
foreach(keyword ${required_keywords})
|
|
1723 |
if(NOT DEFINED "CCN_${keyword}")
|
|
1724 |
message(FATAL_ERROR "Missing required parameter `${keyword}`.")
|
|
1725 |
elseif("${CCN_${keyword}}" STREQUAL "")
|
|
1726 |
message(FATAL_ERROR "Required parameter `${keyword}` may not be set to an empty string.")
|
|
1727 |
endif()
|
|
1728 |
endforeach()
|
|
1729 |
set(rust_target "${CCN_TARGET}")
|
|
1730 |
unset(package_manifest_dir)
|
|
1731 |
|
|
1732 |
|
|
1733 |
set(hostbuild_override "$<BOOL:$<TARGET_PROPERTY:${rust_target},${_CORR_PROP_HOST_BUILD}>>")
|
|
1734 |
set(cbindgen_target_triple "$<IF:${hostbuild_override},${_CORROSION_RUST_CARGO_HOST_TARGET},${_CORROSION_RUST_CARGO_TARGET}>")
|
|
1735 |
|
|
1736 |
if(TARGET "${rust_target}")
|
|
1737 |
get_target_property(package_manifest_path "${rust_target}" INTERFACE_COR_PACKAGE_MANIFEST_PATH)
|
|
1738 |
if(NOT EXISTS "${package_manifest_path}")
|
|
1739 |
message(FATAL_ERROR "Internal error: No package manifest found at ${package_manifest_path}")
|
|
1740 |
endif()
|
|
1741 |
get_filename_component(package_manifest_dir "${package_manifest_path}" DIRECTORY)
|
|
1742 |
# todo: as an optimization we could cache the cargo metadata output (but --no-deps makes that slightly more complicated)
|
|
1743 |
else()
|
|
1744 |
if(NOT DEFINED CCN_MANIFEST_DIRECTORY)
|
|
1745 |
message(FATAL_ERROR
|
|
1746 |
"`${rust_target}` is not a target imported by corrosion and `MANIFEST_DIRECTORY` was not provided."
|
|
1747 |
)
|
|
1748 |
else()
|
|
1749 |
set(package_manifest_dir "${CCN_MANIFEST_DIRECTORY}")
|
|
1750 |
endif()
|
|
1751 |
endif()
|
|
1752 |
|
|
1753 |
unset(rust_cargo_package)
|
|
1754 |
if(NOT DEFINED CCN_CARGO_PACKAGE)
|
|
1755 |
get_target_property(rust_cargo_package "${rust_target}" INTERFACE_COR_CARGO_PACKAGE_NAME )
|
|
1756 |
if(NOT rust_cargo_package)
|
|
1757 |
message(FATAL_ERROR "Could not determine cargo package name for cbindgen!")
|
|
1758 |
endif()
|
|
1759 |
else()
|
|
1760 |
set(rust_cargo_package "${CCN_CARGO_PACKAGE}")
|
|
1761 |
endif()
|
|
1762 |
message(STATUS "Using package ${rust_cargo_package} as crate for cbindgen")
|
|
1763 |
|
|
1764 |
|
|
1765 |
set(output_header_name "${CCN_HEADER_NAME}")
|
|
1766 |
|
|
1767 |
find_program(installed_cbindgen cbindgen)
|
|
1768 |
|
|
1769 |
# Install the newest cbindgen version into our build tree.
|
|
1770 |
if(installed_cbindgen)
|
|
1771 |
set(cbindgen "${installed_cbindgen}")
|
|
1772 |
else()
|
|
1773 |
set(local_cbindgen_install_dir "${CMAKE_BINARY_DIR}/corrosion/cbindgen")
|
|
1774 |
unset(executable_postfix)
|
|
1775 |
if(Rust_CARGO_HOST_OS STREQUAL "windows")
|
|
1776 |
set(executable_postfix ".exe")
|
|
1777 |
endif()
|
|
1778 |
set(cbindgen "${local_cbindgen_install_dir}/bin/cbindgen${executable_postfix}")
|
|
1779 |
if(NOT TARGET "_corrosion_cbindgen")
|
|
1780 |
file(MAKE_DIRECTORY "${local_cbindgen_install_dir}")
|
|
1781 |
add_custom_command(OUTPUT "${cbindgen}"
|
|
1782 |
COMMAND ${CMAKE_COMMAND}
|
|
1783 |
-E env
|
|
1784 |
"CARGO_BUILD_RUSTC=${_CORROSION_RUSTC}"
|
|
1785 |
${_CORROSION_CARGO} install
|
|
1786 |
cbindgen
|
|
1787 |
--root "${local_cbindgen_install_dir}"
|
|
1788 |
${_CORROSION_QUIET_OUTPUT_FLAG}
|
|
1789 |
COMMENT "Building cbindgen"
|
|
1790 |
)
|
|
1791 |
add_custom_target("_corrosion_cbindgen"
|
|
1792 |
DEPENDS "${cbindgen}"
|
|
1793 |
)
|
|
1794 |
endif()
|
|
1795 |
endif()
|
|
1796 |
|
|
1797 |
set(corrosion_generated_dir "${CMAKE_CURRENT_BINARY_DIR}/corrosion_generated")
|
|
1798 |
set(generated_dir "${corrosion_generated_dir}/cbindgen/${rust_target}")
|
|
1799 |
set(header_placement_dir "${generated_dir}/include/")
|
|
1800 |
set(depfile_placement_dir "${generated_dir}/depfile")
|
|
1801 |
set(generated_depfile "${depfile_placement_dir}/${output_header_name}.d")
|
|
1802 |
set(generated_header "${header_placement_dir}/${output_header_name}")
|
|
1803 |
message(STATUS "rust target is ${rust_target}")
|
|
1804 |
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.23")
|
|
1805 |
target_sources(${rust_target}
|
|
1806 |
INTERFACE
|
|
1807 |
FILE_SET HEADERS
|
|
1808 |
BASE_DIRS "${header_placement_dir}"
|
|
1809 |
FILES "${header_placement_dir}/${output_header_name}"
|
|
1810 |
)
|
|
1811 |
else()
|
|
1812 |
# Note: not clear to me how install would best work before CMake 3.23
|
|
1813 |
target_include_directories(${rust_target}
|
|
1814 |
INTERFACE
|
|
1815 |
$<BUILD_INTERFACE:${header_placement_dir}>
|
|
1816 |
$<INSTALL_INTERFACE:include>
|
|
1817 |
)
|
|
1818 |
endif()
|
|
1819 |
|
|
1820 |
# This may be different from $header_placement_dir since the user specified HEADER_NAME may contain
|
|
1821 |
# relative directories.
|
|
1822 |
get_filename_component(generated_header_dir "${generated_header}" DIRECTORY)
|
|
1823 |
file(MAKE_DIRECTORY "${generated_header_dir}")
|
|
1824 |
|
|
1825 |
unset(depfile_cbindgen_arg)
|
|
1826 |
unset(depfile_cmake_arg)
|
|
1827 |
get_filename_component(generated_depfile_dir "${generated_depfile}" DIRECTORY)
|
|
1828 |
file(MAKE_DIRECTORY "${generated_depfile_dir}")
|
|
1829 |
set(depfile_cbindgen_arg "--depfile=${generated_depfile}")
|
|
1830 |
|
|
1831 |
# Users might want to call cbindgen multiple times, e.g. to generate separate C++ and C header files.
|
|
1832 |
string(MAKE_C_IDENTIFIER "${output_header_name}" header_identifier )
|
|
1833 |
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.22")
|
|
1834 |
add_custom_command(
|
|
1835 |
OUTPUT
|
|
1836 |
"${generated_header}"
|
|
1837 |
COMMAND
|
|
1838 |
"${CMAKE_COMMAND}" -E env
|
|
1839 |
TARGET="${cbindgen_target_triple}"
|
|
1840 |
"${cbindgen}"
|
|
1841 |
--output "${generated_header}"
|
|
1842 |
--crate "${rust_cargo_package}"
|
|
1843 |
${depfile_cbindgen_arg}
|
|
1844 |
${CCN_FLAGS}
|
|
1845 |
COMMENT "Generate cbindgen bindings for package ${rust_cargo_package} and output header ${generated_header}"
|
|
1846 |
DEPFILE "${generated_depfile}"
|
|
1847 |
COMMAND_EXPAND_LISTS
|
|
1848 |
WORKING_DIRECTORY "${package_manifest_dir}"
|
|
1849 |
)
|
|
1850 |
add_custom_target("_corrosion_cbindgen_${rust_target}_bindings_${header_identifier}"
|
|
1851 |
DEPENDS "${generated_header}"
|
|
1852 |
COMMENT "Generate ${generated_header} for ${rust_target}"
|
|
1853 |
)
|
|
1854 |
else()
|
|
1855 |
add_custom_target("_corrosion_cbindgen_${rust_target}_bindings_${header_identifier}"
|
|
1856 |
"${CMAKE_COMMAND}" -E env
|
|
1857 |
TARGET="${cbindgen_target_triple}"
|
|
1858 |
"${cbindgen}"
|
|
1859 |
--output "${generated_header}"
|
|
1860 |
--crate "${rust_cargo_package}"
|
|
1861 |
${depfile_cbindgen_arg}
|
|
1862 |
${CCN_FLAGS}
|
|
1863 |
COMMENT "Generate ${generated_header} for ${rust_target}"
|
|
1864 |
COMMAND_EXPAND_LISTS
|
|
1865 |
WORKING_DIRECTORY "${package_manifest_dir}"
|
|
1866 |
)
|
|
1867 |
endif()
|
|
1868 |
|
|
1869 |
if(NOT installed_cbindgen)
|
|
1870 |
add_custom_command(
|
|
1871 |
OUTPUT "${generated_header}"
|
|
1872 |
APPEND
|
|
1873 |
DEPENDS _corrosion_cbindgen
|
|
1874 |
)
|
|
1875 |
endif()
|
|
1876 |
|
|
1877 |
if(NOT TARGET "_corrosion_cbindgen_${rust_target}_bindings")
|
|
1878 |
add_custom_target(_corrosion_cbindgen_${rust_target}_bindings
|
|
1879 |
COMMENT "Generate cbindgen bindings for package ${rust_cargo_package}"
|
|
1880 |
)
|
|
1881 |
endif()
|
|
1882 |
|
|
1883 |
add_dependencies("_corrosion_cbindgen_${rust_target}_bindings" "_corrosion_cbindgen_${rust_target}_bindings_${header_identifier}")
|
|
1884 |
add_dependencies(${rust_target} "_corrosion_cbindgen_${rust_target}_bindings")
|
|
1885 |
endfunction()
|
|
1886 |
|
|
1887 |
# Parse the version of a Rust package from it's package manifest (Cargo.toml)
|
|
1888 |
function(corrosion_parse_package_version package_manifest_path out_package_version)
|
|
1889 |
if(NOT EXISTS "${package_manifest_path}")
|
|
1890 |
message(FATAL_ERROR "Package manifest `${package_manifest_path}` does not exist.")
|
|
1891 |
endif()
|
|
1892 |
|
|
1893 |
file(READ "${package_manifest_path}" package_manifest)
|
|
1894 |
|
|
1895 |
# Find the package table. It may contain arrays, so match until \n\[, which should mark the next
|
|
1896 |
# table. Note: backslashes must be doubled to escape the backslash for the bracket. LF is single
|
|
1897 |
# backslash however. On windows the line also ends in \n, so matching against \n\[ is sufficient
|
|
1898 |
# to detect an opening bracket on a new line.
|
|
1899 |
set(package_table_regex "\\[package\\](.*)\n\\[")
|
|
1900 |
|
|
1901 |
string(REGEX MATCH "${package_table_regex}" _package_table "${package_manifest}")
|
|
1902 |
|
|
1903 |
if(CMAKE_MATCH_COUNT EQUAL "1")
|
|
1904 |
set(package_table "${CMAKE_MATCH_1}")
|
|
1905 |
else()
|
|
1906 |
message(DEBUG
|
|
1907 |
"Failed to find `[package]` table in package manifest `${package_manifest_path}`.\n"
|
|
1908 |
"Matches: ${CMAKE_MATCH_COUNT}\n"
|
|
1909 |
)
|
|
1910 |
set(${out_package_version}
|
|
1911 |
"NOTFOUND"
|
|
1912 |
PARENT_SCOPE
|
|
1913 |
)
|
|
1914 |
endif()
|
|
1915 |
# Match `version = "0.3.2"`, `"version" = "0.3.2" Contains one matching group for the version
|
|
1916 |
set(version_regex "[\r]?\n[\"']?version[\"']?[ \t]*=[ \t]*[\"']([0-9\.]+)[\"']")
|
|
1917 |
|
|
1918 |
string(REGEX MATCH "${version_regex}" _version "${package_table}")
|
|
1919 |
|
|
1920 |
if("${package_table}" MATCHES "${version_regex}")
|
|
1921 |
set(${out_package_version}
|
|
1922 |
"${CMAKE_MATCH_1}"
|
|
1923 |
PARENT_SCOPE
|
|
1924 |
)
|
|
1925 |
else()
|
|
1926 |
message(DEBUG "Failed to extract package version from manifest `${package_manifest_path}`.")
|
|
1927 |
set(${out_package_version}
|
|
1928 |
"NOTFOUND"
|
|
1929 |
PARENT_SCOPE
|
|
1930 |
)
|
|
1931 |
endif()
|
|
1932 |
endfunction()
|
|
1933 |
|
|
1934 |
# Helper macro to pass through an optional `OPTION` argument parsed via `cmake_parse_arguments`
|
|
1935 |
# to another function that takes the same OPTION.
|
|
1936 |
# If the option was set, then the variable <var_name> will be set to the same option name again,
|
|
1937 |
# otherwise <var_name> will be unset.
|
|
1938 |
macro(_corrosion_option_passthrough_helper option_name prefix var_name)
|
|
1939 |
if(${${prefix}_${option_name}})
|
|
1940 |
set("${var_name}" "${option_name}")
|
|
1941 |
else()
|
|
1942 |
unset("${var_name}")
|
|
1943 |
endif()
|
|
1944 |
endmacro()
|
|
1945 |
|
|
1946 |
# Helper macro to pass through an optional argument with value(s), parsed via `cmake_parse_arguments`,
|
|
1947 |
# to another function that takes the same keyword + associated values.
|
|
1948 |
# If the argument was given, then the variable <var_name> will be a list of the argument name and the values,
|
|
1949 |
# which will be expanded, when calling the function (assuming no quotes).
|
|
1950 |
macro(_corrosion_arg_passthrough_helper arg_name prefix var_name)
|
|
1951 |
if(DEFINED "${prefix}_${arg_name}")
|
|
1952 |
set("${var_name}" "${arg_name}" "${${prefix}_${arg_name}}")
|
|
1953 |
else()
|
|
1954 |
unset("${var_name}")
|
|
1955 |
endif()
|
|
1956 |
endmacro()
|
|
1957 |
|
|
1958 |
list(POP_BACK CMAKE_MESSAGE_CONTEXT)
|
|
1959 |
|