|
1 function(_cargo_metadata out manifest) |
|
2 set(OPTIONS LOCKED FROZEN) |
|
3 set(ONE_VALUE_KEYWORDS "") |
|
4 set(MULTI_VALUE_KEYWORDS "") |
|
5 cmake_parse_arguments(PARSE_ARGV 2 CM "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}") |
|
6 |
|
7 list(APPEND CMAKE_MESSAGE_CONTEXT "_cargo_metadata") |
|
8 |
|
9 if(DEFINED CM_UNPARSED_ARGUMENTS) |
|
10 message(FATAL_ERROR "Internal error - unexpected arguments: ${CM_UNPARSED_ARGUMENTS}") |
|
11 elseif(DEFINED CM_KEYWORDS_MISSING_VALUES) |
|
12 message(FATAL_ERROR "Internal error - the following keywords had no associated value(s):" |
|
13 "${CM_KEYWORDS_MISSING_VALUES}") |
|
14 endif() |
|
15 |
|
16 set(cargo_locked "") |
|
17 set(cargo_frozen "") |
|
18 if(LOCKED) |
|
19 set(cargo_locked "--locked") |
|
20 endif() |
|
21 if(FROZEN) |
|
22 set(cargo_frozen "--frozen") |
|
23 endif() |
|
24 execute_process( |
|
25 COMMAND |
|
26 ${CMAKE_COMMAND} -E env |
|
27 "CARGO_BUILD_RUSTC=${_CORROSION_RUSTC}" |
|
28 "${_CORROSION_CARGO}" |
|
29 metadata |
|
30 --manifest-path "${manifest}" |
|
31 --format-version 1 |
|
32 # We don't care about non-workspace dependencies |
|
33 --no-deps |
|
34 ${cargo_locked} |
|
35 ${cargo_frozen} |
|
36 |
|
37 OUTPUT_VARIABLE json |
|
38 COMMAND_ERROR_IS_FATAL ANY |
|
39 ) |
|
40 |
|
41 set(${out} "${json}" PARENT_SCOPE) |
|
42 endfunction() |
|
43 |
|
44 # Add targets (crates) of one package |
|
45 function(_generator_add_package_targets) |
|
46 set(OPTIONS NO_LINKER_OVERRIDE) |
|
47 set(ONE_VALUE_KEYWORDS WORKSPACE_MANIFEST_PATH PACKAGE_MANIFEST_PATH PACKAGE_NAME PACKAGE_VERSION TARGETS_JSON OUT_CREATED_TARGETS) |
|
48 set(MULTI_VALUE_KEYWORDS CRATE_TYPES) |
|
49 cmake_parse_arguments(PARSE_ARGV 0 GAPT "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}") |
|
50 |
|
51 if(DEFINED GAPT_UNPARSED_ARGUMENTS) |
|
52 message(FATAL_ERROR "Internal error - unexpected arguments: ${GAPT_UNPARSED_ARGUMENTS}") |
|
53 elseif(DEFINED GAPT_KEYWORDS_MISSING_VALUES) |
|
54 message(FATAL_ERROR "Internal error - the following keywords had no associated value(s):" |
|
55 "${GAPT_KEYWORDS_MISSING_VALUES}") |
|
56 endif() |
|
57 |
|
58 _corrosion_option_passthrough_helper(NO_LINKER_OVERRIDE GAPT no_linker_override) |
|
59 |
|
60 set(workspace_manifest_path "${GAPT_WORKSPACE_MANIFEST_PATH}") |
|
61 set(package_manifest_path "${GAPT_PACKAGE_MANIFEST_PATH}") |
|
62 set(package_name "${GAPT_PACKAGE_NAME}") |
|
63 set(package_version "${GAPT_PACKAGE_VERSION}") |
|
64 set(targets "${GAPT_TARGETS_JSON}") |
|
65 set(out_created_targets "${GAPT_OUT_CREATED_TARGETS}") |
|
66 set(crate_types "${GAPT_CRATE_TYPES}") |
|
67 |
|
68 set(corrosion_targets "") |
|
69 |
|
70 file(TO_CMAKE_PATH "${package_manifest_path}" manifest_path) |
|
71 |
|
72 string(JSON targets_len LENGTH "${targets}") |
|
73 math(EXPR targets_len-1 "${targets_len} - 1") |
|
74 |
|
75 message(DEBUG "Found ${targets_len} targets in package ${package_name}") |
|
76 |
|
77 foreach(ix RANGE ${targets_len-1}) |
|
78 string(JSON target GET "${targets}" ${ix}) |
|
79 string(JSON target_name GET "${target}" "name") |
|
80 string(JSON target_kind GET "${target}" "kind") |
|
81 string(JSON target_kind_len LENGTH "${target_kind}") |
|
82 |
|
83 math(EXPR target_kind_len-1 "${target_kind_len} - 1") |
|
84 set(kinds) |
|
85 foreach(ix RANGE ${target_kind_len-1}) |
|
86 string(JSON kind GET "${target_kind}" ${ix}) |
|
87 if(NOT crate_types OR ${kind} IN_LIST crate_types) |
|
88 list(APPEND kinds ${kind}) |
|
89 endif() |
|
90 endforeach() |
|
91 |
|
92 if(TARGET "${target_name}" |
|
93 AND ("staticlib" IN_LIST kinds OR "cdylib" IN_LIST kinds OR "bin" IN_LIST kinds) |
|
94 ) |
|
95 message(WARNING "Failed to import Rust crate ${target_name} (kind: `${target_kind}`) because a target " |
|
96 "with the same name already exists. Skipping this target.\n" |
|
97 "Help: If you are importing a package which exposes both a `lib` and " |
|
98 "a `bin` target, please consider explicitly naming the targets in your `Cargo.toml` manifest.\n" |
|
99 "Note: If you have multiple different packages which have targets with the same name, please note that " |
|
100 "this is currently not supported by Corrosion. Feel free to open an issue on Github to request " |
|
101 "supporting this scenario." |
|
102 ) |
|
103 # Skip this target to prevent a hard error. |
|
104 continue() |
|
105 endif() |
|
106 |
|
107 if("staticlib" IN_LIST kinds OR "cdylib" IN_LIST kinds) |
|
108 # Explicitly set library names have always been forbidden from using dashes (by cargo). |
|
109 # Starting with Rust 1.79, names inherited from the package name will have dashes replaced |
|
110 # by underscores too. Corrosion will thus replace dashes with underscores, to make the target |
|
111 # name consistent independent of the Rust version. `bin` target names are not affected. |
|
112 # See https://github.com/corrosion-rs/corrosion/issues/501 for more details. |
|
113 string(REPLACE "\-" "_" target_name "${target_name}") |
|
114 |
|
115 set(archive_byproducts "") |
|
116 set(shared_lib_byproduct "") |
|
117 set(pdb_byproduct "") |
|
118 |
|
119 _corrosion_add_library_target( |
|
120 WORKSPACE_MANIFEST_PATH "${workspace_manifest_path}" |
|
121 TARGET_NAME "${target_name}" |
|
122 LIB_KINDS ${kinds} |
|
123 OUT_ARCHIVE_OUTPUT_BYPRODUCTS archive_byproducts |
|
124 OUT_SHARED_LIB_BYPRODUCTS shared_lib_byproduct |
|
125 OUT_PDB_BYPRODUCT pdb_byproduct |
|
126 ) |
|
127 |
|
128 set(byproducts "") |
|
129 list(APPEND byproducts "${archive_byproducts}" "${shared_lib_byproduct}" "${pdb_byproduct}") |
|
130 |
|
131 set(cargo_build_out_dir "") |
|
132 _add_cargo_build( |
|
133 cargo_build_out_dir |
|
134 PACKAGE ${package_name} |
|
135 TARGET ${target_name} |
|
136 MANIFEST_PATH "${manifest_path}" |
|
137 WORKSPACE_MANIFEST_PATH "${workspace_manifest_path}" |
|
138 TARGET_KINDS "${kinds}" |
|
139 BYPRODUCTS "${byproducts}" |
|
140 # Optional |
|
141 ${no_linker_override} |
|
142 ) |
|
143 if(archive_byproducts) |
|
144 _corrosion_copy_byproducts( |
|
145 ${target_name} ARCHIVE_OUTPUT_DIRECTORY "${cargo_build_out_dir}" "${archive_byproducts}" |
|
146 ) |
|
147 endif() |
|
148 if(shared_lib_byproduct) |
|
149 _corrosion_copy_byproducts( |
|
150 ${target_name} LIBRARY_OUTPUT_DIRECTORY "${cargo_build_out_dir}" "${shared_lib_byproduct}" |
|
151 ) |
|
152 endif() |
|
153 if(pdb_byproduct) |
|
154 _corrosion_copy_byproducts( |
|
155 ${target_name} PDB_OUTPUT_DIRECTORY "${cargo_build_out_dir}" "${pdb_byproduct}" |
|
156 ) |
|
157 endif() |
|
158 list(APPEND corrosion_targets ${target_name}) |
|
159 set_property(TARGET "${target_name}" PROPERTY INTERFACE_COR_CARGO_PACKAGE_NAME "${package_name}" ) |
|
160 # Note: "bin" is mutually exclusive with "staticlib/cdylib", since `bin`s are seperate crates from libraries. |
|
161 elseif("bin" IN_LIST kinds) |
|
162 set(bin_byproduct "") |
|
163 set(pdb_byproduct "") |
|
164 _corrosion_add_bin_target("${workspace_manifest_path}" "${target_name}" |
|
165 "bin_byproduct" "pdb_byproduct" |
|
166 ) |
|
167 |
|
168 set(byproducts "") |
|
169 list(APPEND byproducts "${bin_byproduct}" "${pdb_byproduct}") |
|
170 |
|
171 set(cargo_build_out_dir "") |
|
172 _add_cargo_build( |
|
173 cargo_build_out_dir |
|
174 PACKAGE "${package_name}" |
|
175 TARGET "${target_name}" |
|
176 MANIFEST_PATH "${manifest_path}" |
|
177 WORKSPACE_MANIFEST_PATH "${workspace_manifest_path}" |
|
178 TARGET_KINDS "bin" |
|
179 BYPRODUCTS "${byproducts}" |
|
180 # Optional |
|
181 ${no_linker_override} |
|
182 ) |
|
183 _corrosion_copy_byproducts( |
|
184 ${target_name} RUNTIME_OUTPUT_DIRECTORY "${cargo_build_out_dir}" "${bin_byproduct}" |
|
185 ) |
|
186 if(pdb_byproduct) |
|
187 _corrosion_copy_byproducts( |
|
188 ${target_name} PDB_OUTPUT_DIRECTORY "${cargo_build_out_dir}" "${pdb_byproduct}" |
|
189 ) |
|
190 endif() |
|
191 list(APPEND corrosion_targets ${target_name}) |
|
192 set_property(TARGET "${target_name}" PROPERTY INTERFACE_COR_CARGO_PACKAGE_NAME "${package_name}" ) |
|
193 else() |
|
194 # ignore other kinds (like examples, tests, build scripts, ...) |
|
195 endif() |
|
196 endforeach() |
|
197 |
|
198 if(NOT corrosion_targets) |
|
199 message(DEBUG "No relevant targets found in package ${package_name} - Ignoring") |
|
200 else() |
|
201 set_target_properties(${corrosion_targets} PROPERTIES INTERFACE_COR_PACKAGE_MANIFEST_PATH "${package_manifest_path}") |
|
202 endif() |
|
203 set(${out_created_targets} "${corrosion_targets}" PARENT_SCOPE) |
|
204 |
|
205 endfunction() |
|
206 |
|
207 # Add all cargo targets defined in the packages defined in the Cargo.toml manifest at |
|
208 # `MANIFEST_PATH`. |
|
209 function(_generator_add_cargo_targets) |
|
210 set(options NO_LINKER_OVERRIDE) |
|
211 set(one_value_args MANIFEST_PATH IMPORTED_CRATES) |
|
212 set(multi_value_args CRATES CRATE_TYPES) |
|
213 cmake_parse_arguments( |
|
214 GGC |
|
215 "${options}" |
|
216 "${one_value_args}" |
|
217 "${multi_value_args}" |
|
218 ${ARGN} |
|
219 ) |
|
220 list(APPEND CMAKE_MESSAGE_CONTEXT "_add_cargo_targets") |
|
221 |
|
222 _corrosion_option_passthrough_helper(NO_LINKER_OVERRIDE GGC no_linker_override) |
|
223 _corrosion_arg_passthrough_helper(CRATE_TYPES GGC crate_types) |
|
224 |
|
225 _cargo_metadata(json "${GGC_MANIFEST_PATH}") |
|
226 string(JSON packages GET "${json}" "packages") |
|
227 string(JSON workspace_members GET "${json}" "workspace_members") |
|
228 |
|
229 string(JSON pkgs_len LENGTH "${packages}") |
|
230 math(EXPR pkgs_len-1 "${pkgs_len} - 1") |
|
231 |
|
232 string(JSON ws_mems_len LENGTH ${workspace_members}) |
|
233 math(EXPR ws_mems_len-1 "${ws_mems_len} - 1") |
|
234 |
|
235 set(created_targets "") |
|
236 set(available_package_names "") |
|
237 foreach(ix RANGE ${pkgs_len-1}) |
|
238 string(JSON pkg GET "${packages}" ${ix}) |
|
239 string(JSON pkg_id GET "${pkg}" "id") |
|
240 string(JSON pkg_name GET "${pkg}" "name") |
|
241 string(JSON pkg_manifest_path GET "${pkg}" "manifest_path") |
|
242 string(JSON pkg_version GET "${pkg}" "version") |
|
243 list(APPEND available_package_names "${pkg_name}") |
|
244 |
|
245 if(DEFINED GGC_CRATES) |
|
246 if(NOT pkg_name IN_LIST GGC_CRATES) |
|
247 continue() |
|
248 endif() |
|
249 endif() |
|
250 |
|
251 # probably this loop is not necessary at all, since when using --no-deps, the |
|
252 # contents of packages should already be only workspace members! |
|
253 unset(pkg_is_ws_member) |
|
254 foreach(ix RANGE ${ws_mems_len-1}) |
|
255 string(JSON ws_mem GET "${workspace_members}" ${ix}) |
|
256 if(ws_mem STREQUAL pkg_id) |
|
257 set(pkg_is_ws_member YES) |
|
258 break() |
|
259 endif() |
|
260 endforeach() |
|
261 |
|
262 if(NOT DEFINED pkg_is_ws_member) |
|
263 # Since we pass `--no-deps` to cargo metadata now, I think this situation can't happen, but lets check for |
|
264 # it anyway, just to discover any potential issues. |
|
265 # If nobody complains for a while, it should be safe to remove this check and the previous loop, which |
|
266 # should speed up the configuration process. |
|
267 message(WARNING "The package `${pkg_name}` unexpectedly is not part of the workspace." |
|
268 "Please open an issue at corrosion with some background information on the package" |
|
269 ) |
|
270 endif() |
|
271 |
|
272 string(JSON targets GET "${pkg}" "targets") |
|
273 |
|
274 _generator_add_package_targets( |
|
275 WORKSPACE_MANIFEST_PATH "${GGC_MANIFEST_PATH}" |
|
276 PACKAGE_MANIFEST_PATH "${pkg_manifest_path}" |
|
277 PACKAGE_NAME "${pkg_name}" |
|
278 PACKAGE_VERSION "${pkg_version}" |
|
279 TARGETS_JSON "${targets}" |
|
280 OUT_CREATED_TARGETS curr_created_targets |
|
281 ${no_linker_override} |
|
282 ${crate_types} |
|
283 ) |
|
284 list(APPEND created_targets "${curr_created_targets}") |
|
285 endforeach() |
|
286 |
|
287 if(NOT created_targets) |
|
288 set(crates_error_message "") |
|
289 if(DEFINED GGC_CRATES) |
|
290 set(crates_error_message "\n`corrosion_import_crate()` was called with the `CRATES` " |
|
291 "parameter set to `${GGC_CRATES}`. Corrosion will only attempt to import packages matching " |
|
292 "names from this list." |
|
293 ) |
|
294 endif() |
|
295 message(FATAL_ERROR |
|
296 "Found no targets in ${pkgs_len} packages." |
|
297 ${crates_error_message}. |
|
298 "\nPlease keep in mind that corrosion will only import Rust `bin` targets or" |
|
299 "`staticlib` or `cdylib` library targets." |
|
300 "The following packages were found in the Manifest: ${available_package_names}" |
|
301 ) |
|
302 else() |
|
303 message(DEBUG "Corrosion created the following CMake targets: ${created_targets}") |
|
304 endif() |
|
305 |
|
306 if(GGC_IMPORTED_CRATES) |
|
307 set(${GGC_IMPORTED_CRATES} "${created_targets}" PARENT_SCOPE) |
|
308 endif() |
|
309 |
|
310 foreach(target_name ${created_targets}) |
|
311 foreach(output_var RUNTIME_OUTPUT_DIRECTORY ARCHIVE_OUTPUT_DIRECTORY LIBRARY_OUTPUT_DIRECTORY PDB_OUTPUT_DIRECTORY) |
|
312 get_target_property(output_dir ${target_name} "${output_var}") |
|
313 if (NOT output_dir AND DEFINED "CMAKE_${output_var}") |
|
314 set_property(TARGET ${target_name} PROPERTY ${output_var} "${CMAKE_${output_var}}") |
|
315 endif() |
|
316 |
|
317 foreach(config_type ${CMAKE_CONFIGURATION_TYPES}) |
|
318 string(TOUPPER "${config_type}" config_type_upper) |
|
319 get_target_property(output_dir ${target_name} "${output_var}_${config_type_upper}") |
|
320 if (NOT output_dir AND DEFINED "CMAKE_${output_var}_${config_type_upper}") |
|
321 set_property(TARGET ${target_name} PROPERTY "${output_var}_${config_type_upper}" "${CMAKE_${output_var}_${config_type_upper}}") |
|
322 endif() |
|
323 endforeach() |
|
324 endforeach() |
|
325 endforeach() |
|
326 endfunction() |