-
-
Notifications
You must be signed in to change notification settings - Fork 96
/
Corrosion.cmake
1449 lines (1257 loc) · 61.1 KB
/
Corrosion.cmake
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
cmake_minimum_required(VERSION 3.15)
if (CMAKE_GENERATOR STREQUAL "Ninja Multi-Config" AND CMAKE_VERSION VERSION_LESS 3.20.0)
message(FATAL_ERROR "Corrosion requires at least CMake 3.20 with the \"Ninja Multi-Config\" "
"generator. Please use a different generator or update to cmake >= 3.20.")
elseif(CMAKE_VERSION VERSION_LESS 3.20.0 AND CMAKE_CONFIGURATION_TYPES)
message(DEPRECATION "Corrosion will require at least CMake 3.20 for use with all Multi-Config"
"Generators starting with Corrosion 0.4. Please consider upgrading your CMake version"
" or using a different Generator."
)
endif()
option(CORROSION_VERBOSE_OUTPUT "Enables verbose output from Corrosion and Cargo" OFF)
set(CORROSION_NATIVE_TOOLING_DESCRIPTION
"Use native tooling - Required on CMake < 3.19 and available as a fallback option for recent versions"
)
set(CORROSION_RESPECT_OUTPUT_DIRECTORY_DESCRIPTION
"Respect the CMake target properties specifying the output directory of a target, such as
`RUNTIME_OUTPUT_DIRECTORY`. This requires CMake >= 3.19, otherwise this option is forced off."
)
option(
CORROSION_NATIVE_TOOLING
"${CORROSION_NATIVE_TOOLING_DESCRIPTION}"
OFF
)
option(CORROSION_RESPECT_OUTPUT_DIRECTORY
"${CORROSION_RESPECT_OUTPUT_DIRECTORY_DESCRIPTION}"
ON
)
option(
CORROSION_NO_WARN_PARSE_TARGET_TRIPLE_FAILED
"Surpresses a warning if the parsing the target triple failed."
OFF
)
# The native tooling is required on CMAke < 3.19 so we override whatever the user may have set.
if (CMAKE_VERSION VERSION_LESS 3.19.0)
set(CORROSION_NATIVE_TOOLING ON CACHE INTERNAL "${CORROSION_NATIVE_TOOLING_DESCRIPTION}" FORCE)
set(CORROSION_RESPECT_OUTPUT_DIRECTORY OFF CACHE INTERNAL
"${CORROSION_RESPECT_OUTPUT_DIRECTORY_DESCRIPTION}" FORCE
)
endif()
find_package(Rust REQUIRED)
if(Rust_TOOLCHAIN_IS_RUSTUP_MANAGED)
execute_process(COMMAND rustup target list --toolchain "${Rust_TOOLCHAIN}"
OUTPUT_VARIABLE AVAILABLE_TARGETS_RAW
)
string(REPLACE "\n" ";" AVAILABLE_TARGETS_RAW "${AVAILABLE_TARGETS_RAW}")
string(REPLACE " (installed)" "" "AVAILABLE_TARGETS" "${AVAILABLE_TARGETS_RAW}")
set(INSTALLED_TARGETS_RAW "${AVAILABLE_TARGETS_RAW}")
list(FILTER INSTALLED_TARGETS_RAW INCLUDE REGEX " \\(installed\\)")
string(REPLACE " (installed)" "" "INSTALLED_TARGETS" "${INSTALLED_TARGETS_RAW}")
list(TRANSFORM INSTALLED_TARGETS STRIP)
if("${Rust_CARGO_TARGET}" IN_LIST AVAILABLE_TARGETS)
message(DEBUG "Cargo target ${Rust_CARGO_TARGET} is an official target-triple")
message(DEBUG "Installed targets: ${INSTALLED_TARGETS}")
if(NOT ("${Rust_CARGO_TARGET}" IN_LIST INSTALLED_TARGETS))
message(FATAL_ERROR "Target ${Rust_CARGO_TARGET} is not installed for toolchain ${Rust_TOOLCHAIN}.\n"
"Help: Run `rustup target add --toolchain ${Rust_TOOLCHAIN} ${Rust_CARGO_TARGET}` to install "
"the missing target."
)
endif()
endif()
endif()
if(CMAKE_GENERATOR MATCHES "Visual Studio"
AND (NOT CMAKE_VS_PLATFORM_NAME STREQUAL CMAKE_VS_PLATFORM_NAME_DEFAULT)
AND Rust_VERSION VERSION_LESS "1.54")
message(FATAL_ERROR "Due to a cargo issue, cross-compiling with a Visual Studio generator and rust versions"
" before 1.54 is not supported. Rust build scripts would be linked with the cross-compiler linker, which"
" causes the build to fail. Please upgrade your Rust version to 1.54 or newer.")
endif()
if (NOT TARGET Corrosion::Generator)
message(STATUS "Using Corrosion as a subdirectory")
endif()
get_property(
RUSTC_EXECUTABLE
TARGET Rust::Rustc PROPERTY IMPORTED_LOCATION
)
get_property(
CARGO_EXECUTABLE
TARGET Rust::Cargo PROPERTY IMPORTED_LOCATION
)
# Note: Legacy function, used when respecting the `XYZ_OUTPUT_DIRECTORY` target properties is not
# possible.
function(_corrosion_set_imported_location_legacy target_name base_property filename)
if(CMAKE_CONFIGURATION_TYPES AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.20.0)
foreach(config_type ${CMAKE_CONFIGURATION_TYPES})
set(binary_root "${CMAKE_CURRENT_BINARY_DIR}/${config_type}")
string(TOUPPER "${config_type}" config_type_upper)
message(DEBUG "Setting ${base_property}_${config_type_upper} for target ${target_name}"
" to `${binary_root}/${filename}`.")
# For Multiconfig we want to specify the correct location for each configuration
set_property(
TARGET ${target_name}
PROPERTY "${base_property}_${config_type_upper}"
"${binary_root}/${filename}"
)
endforeach()
else()
set(binary_root "${CMAKE_CURRENT_BINARY_DIR}")
endif()
message(DEBUG "Setting ${base_property} for target ${target_name}"
" to `${binary_root}/${filename}`.")
# IMPORTED_LOCATION must be set regardless of possible overrides. In the multiconfig case,
# the last configuration "wins".
set_property(
TARGET ${target_name}
PROPERTY "${base_property}" "${binary_root}/${filename}"
)
endfunction()
# Do not call this function directly!
#
# This function should be called deferred to evaluate target properties late in the configure stage.
# IMPORTED_LOCATION does not support Generator expressions, so we must evaluate the output
# directory target property value at configure time. This function must be deferred to the end of
# the configure stage, so we can be sure that the output directory is not modified afterwards.
function(_corrosion_set_imported_location_deferred target_name base_property output_directory_property filename)
# The output directory property is expected to be set on the exposed target (without postfix),
# but we need to set the imported location on the actual library target with postfix.
if("${target_name}" MATCHES "^(.+)-(static|shared)$")
set(output_dir_prop_target_name "${CMAKE_MATCH_1}")
else()
set(output_dir_prop_target_name "${target_name}")
endif()
get_target_property(output_directory "${output_dir_prop_target_name}" "${output_directory_property}")
message(DEBUG "Output directory property (target ${output_dir_prop_target_name}): ${output_directory_property} dir: ${output_directory}")
if(CMAKE_CONFIGURATION_TYPES AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.20.0)
foreach(config_type ${CMAKE_CONFIGURATION_TYPES})
string(TOUPPER "${config_type}" config_type_upper)
get_target_property(output_dir_curr_config "${output_dir_prop_target_name}"
"${output_directory_property}_${config_type_upper}"
)
if(output_dir_curr_config)
set(curr_out_dir "${output_dir_curr_config}")
elseif(output_directory)
set(curr_out_dir "${output_directory}")
else()
set(curr_out_dir "${CMAKE_CURRENT_BINARY_DIR}/${config_type}")
endif()
message(DEBUG "Setting ${base_property}_${config_type_upper} for target ${target_name}"
" to `${curr_out_dir}/${filename}`.")
# For Multiconfig we want to specify the correct location for each configuration
set_property(
TARGET ${target_name}
PROPERTY "${base_property}_${config_type_upper}"
"${curr_out_dir}/${filename}"
)
set(base_output_directory "${curr_out_dir}")
endforeach()
elseif(CMAKE_CONFIGURATION_TYPES)
# Fallback path needed for MSVC + CMake < 3.20
if(output_directory)
string(GENEX_STRIP "${output_directory}" stripped_output_dir)
if("${stripped_output_dir}" STREQUAL "${output_directory}")
# Output directory does not contain a genex and can be respected.
set(base_output_directory "${output_directory}")
else()
# Fallback to default directory if output_dir contains a genex.
set(base_output_directory "${CMAKE_CURRENT_BINARY_DIR}")
endif()
else()
# Fallback to default directory.
set(base_output_directory "${CMAKE_CURRENT_BINARY_DIR}")
endif()
else()
if(output_directory)
set(base_output_directory "${output_directory}")
else()
set(base_output_directory "${CMAKE_CURRENT_BINARY_DIR}")
endif()
endif()
message(DEBUG "Setting ${base_property} for target ${target_name}"
" to `${base_output_directory}/${filename}`.")
# IMPORTED_LOCATION must be set regardless of possible overrides. In the multiconfig case,
# the last configuration "wins" (IMPORTED_LOCATION is not documented to have Genex support).
set_property(
TARGET ${target_name}
PROPERTY "${base_property}" "${base_output_directory}/${filename}"
)
endfunction()
# Helper function to call _corrosion_set_imported_location_deferred while eagerly
# evaluating arguments.
# Refer to https://cmake.org/cmake/help/latest/command/cmake_language.html#deferred-call-examples
function(_corrosion_call_set_imported_location_deferred target_name base_property output_directory_property filename)
cmake_language(EVAL CODE "
cmake_language(DEFER
CALL
_corrosion_set_imported_location_deferred
[[${target_name}]]
[[${base_property}]]
[[${output_directory_property}]]
[[${filename}]]
)
")
endfunction()
# Set the imported location of a Rust target.
#
# Rust targets are built via custom targets / custom commands. The actual artifacts are exposed
# to CMake as imported libraries / executables that depend on the cargo_build command. For CMake
# to find the built artifact we need to set the IMPORTED location to the actual location on disk.
# Corrosion tries to copy the artifacts built by cargo to standard locations. The IMPORTED_LOCATION
# is set to point to the copy, and not the original from the cargo build directory.
#
# Parameters:
# - target_name: Name of the Rust target
# - base_property: Name of the base property - i.e. `IMPORTED_LOCATION` or `IMPORTED_IMPLIB`.
# - output_directory_property: Target property name that determines the standard location for the
# artifact.
# - filename of the artifact.
function(_corrosion_set_imported_location target_name base_property output_directory_property filename)
if(CORROSION_RESPECT_OUTPUT_DIRECTORY)
_corrosion_call_set_imported_location_deferred("${target_name}" "${base_property}" "${output_directory_property}" "${filename}")
else()
_corrosion_set_imported_location_legacy("${target_name}" "${base_property}" "${filename}")
endif()
endfunction()
function(_corrosion_copy_byproduct_legacy target_name cargo_build_dir file_names)
if(ARGN)
message(FATAL_ERROR "Unexpected additional arguments")
endif()
if(CMAKE_CONFIGURATION_TYPES AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.20.0)
set(output_dir "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>")
else()
set(output_dir "${CMAKE_CURRENT_BINARY_DIR}")
endif()
list(TRANSFORM file_names PREPEND "${cargo_build_dir}/" OUTPUT_VARIABLE src_file_names)
list(TRANSFORM file_names PREPEND "${output_dir}/" OUTPUT_VARIABLE dst_file_names)
message(DEBUG "Adding command to copy byproducts `${file_names}` to ${dst_file_names}")
add_custom_command(TARGET _cargo-build_${target_name}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory "${output_dir}"
COMMAND
${CMAKE_COMMAND} -E copy_if_different
# tested to work with both multiple files and paths with spaces
${src_file_names}
"${output_dir}"
BYPRODUCTS ${dst_file_names}
COMMENT "Copying byproducts `${file_names}` to ${output_dir}"
VERBATIM
COMMAND_EXPAND_LISTS
)
endfunction()
function(_corrosion_copy_byproduct_deferred target_name output_dir_prop_name cargo_build_dir file_names)
if(ARGN)
message(FATAL_ERROR "Unexpected additional arguments")
endif()
get_target_property(output_dir ${target_name} "${output_dir_prop_name}")
# A Genex expanding to the output directory depending on the configuration.
set(multiconfig_out_dir_genex "")
foreach(config_type ${CMAKE_CONFIGURATION_TYPES})
string(TOUPPER "${config_type}" config_type_upper)
get_target_property(output_dir_curr_config ${target_name} "${output_dir_prop_name}_${config_type_upper}")
if(output_dir_curr_config)
set(curr_out_dir "${output_dir_curr_config}")
elseif(output_dir)
# Fallback to `output_dir` if specified
# Note: Multi-configuration generators append a per-configuration subdirectory to the
# specified directory unless a generator expression is used (from CMake documentation).
set(curr_out_dir "${output_dir}")
else()
# Fallback to default directory.
set(curr_out_dir "${CMAKE_CURRENT_BINARY_DIR}/${config_type}")
endif()
set(multiconfig_out_dir_genex "${multiconfig_out_dir_genex}$<$<CONFIG:${config_type}>:${curr_out_dir}>")
endforeach()
if(CMAKE_CONFIGURATION_TYPES AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.20.0)
set(output_dir "${multiconfig_out_dir_genex}")
elseif(CMAKE_CONFIGURATION_TYPES)
# Fallback support for MSVC with CMake < 3.20.0 (byproducts may not contain genexes)
if(output_dir)
string(GENEX_STRIP "${output_dir}" stripped_output_dir)
if(NOT ("${stripped_output_dir}" STREQUAL "${output_dir}"))
# Fallback to default directory if output_dir contains a genex.
set(output_dir "${CMAKE_CURRENT_BINARY_DIR}")
endif()
else()
# Fallback to default directory.
set(output_dir "${CMAKE_CURRENT_BINARY_DIR}")
endif()
else()
if(NOT output_dir)
# Fallback to default directory.
set(output_dir "${CMAKE_CURRENT_BINARY_DIR}")
endif()
endif()
list(TRANSFORM file_names PREPEND "${cargo_build_dir}/" OUTPUT_VARIABLE src_file_names)
list(TRANSFORM file_names PREPEND "${output_dir}/" OUTPUT_VARIABLE dst_file_names)
message(DEBUG "Adding command to copy byproducts `${file_names}` to ${dst_file_names}")
add_custom_command(TARGET _cargo-build_${target_name}
POST_BUILD
# output_dir may contain a Generator expression.
COMMAND ${CMAKE_COMMAND} -E make_directory "${output_dir}"
COMMAND
${CMAKE_COMMAND} -E copy_if_different
# tested to work with both multiple files and paths with spaces
${src_file_names}
"${output_dir}"
BYPRODUCTS ${dst_file_names}
COMMENT "Copying byproducts `${file_names}` to ${output_dir}"
VERBATIM
COMMAND_EXPAND_LISTS
)
endfunction()
function(_corrosion_call_copy_byproduct_deferred target_name output_dir_prop_name cargo_build_dir file_names)
cmake_language(EVAL CODE "
cmake_language(DEFER
CALL
_corrosion_copy_byproduct_deferred
[[${target_name}]]
[[${output_dir_prop_name}]]
[[${cargo_build_dir}]]
[[${file_names}]]
)
")
endfunction()
# Copy the artifacts generated by cargo to the appropriate destination.
#
# Parameters:
# - target_name: The name of the Rust target
# - output_dir_prop_name: The property name controlling the destination (e.g.
# `RUNTIME_OUTPUT_DIRECTORY`)
# - cargo_build_dir: the directory cargo build places it's output artifacts in.
# - filenames: the file names of any output artifacts as a list.
function(_corrosion_copy_byproducts target_name output_dir_prop_name cargo_build_dir filenames)
if(CORROSION_RESPECT_OUTPUT_DIRECTORY)
_corrosion_call_copy_byproduct_deferred("${target_name}" "${output_dir_prop_name}" "${cargo_build_dir}" "${filenames}")
else()
_corrosion_copy_byproduct_legacy("${target_name}" "${cargo_build_dir}" "${filenames}")
endif()
endfunction()
function(_corrosion_strip_target_triple input_triple_or_path output_triple)
# If the target_triple is a path to a custom target specification file, then strip everything
# except the filename from `target_triple`.
get_filename_component(target_triple_ext "${input_triple_or_path}" EXT)
set(target_triple "${input_triple_or_path}")
if(target_triple_ext)
if(target_triple_ext STREQUAL ".json")
get_filename_component(target_triple "${input_triple_or_path}" NAME_WE)
endif()
endif()
set(${output_triple} "${target_triple}" PARENT_SCOPE)
endfunction()
# The Rust target triple and C target may mismatch (slightly) in some rare usecases.
# So instead of relying on CMake to provide System information, we parse the Rust target triple,
# since that is relevant for determining which libraries the Rust code requires for linking.
function(_corrosion_parse_platform manifest rust_version target_triple)
_corrosion_strip_target_triple(${target_triple} target_triple)
# The vendor part may be left out from the target triple, and since `env` is also optional,
# we determine if vendor is present by matching against a list of known vendors.
set(known_vendors "apple"
"esp" # riscv32imc-esp-espidf
"fortanix"
"kmc"
"pc"
"nintendo"
"nvidia"
"openwrt"
"unknown"
"uwp" # aarch64-uwp-windows-msvc
"wrs" # e.g. aarch64-wrs-vxworks
"sony"
"sun"
)
# todo: allow users to add additional vendors to the list via a cmake variable.
list(JOIN known_vendors "|" known_vendors_joined)
# vendor is optional - We detect if vendor is present by matching against a known list of
# vendors. The next field is the OS, which we assume to always be present, while the last field
# is again optional and contains the environment.
string(REGEX MATCH
"^([a-z0-9_\.]+)-((${known_vendors_joined})-)?([a-z0-9_]+)(-([a-z0-9_]+))?$"
whole_match
"${target_triple}"
)
if((NOT whole_match) AND (NOT CORROSION_NO_WARN_PARSE_TARGET_TRIPLE_FAILED))
message(WARNING "Failed to parse target-triple `${target_triple}`."
"Corrosion attempts to link required C libraries depending on the OS "
"specified in the Rust target-triple for Linux, MacOS and windows.\n"
"Note: If you are targeting a different OS you can surpress this warning by"
" setting the CMake cache variable "
"`CORROSION_NO_WARN_PARSE_TARGET_TRIPLE_FAILED`."
"Please consider opening an issue on github if you encounter this warning."
)
endif()
set(target_arch "${CMAKE_MATCH_1}")
set(target_vendor "${CMAKE_MATCH_3}")
set(os "${CMAKE_MATCH_4}")
set(env "${CMAKE_MATCH_6}")
message(DEBUG "Parsed Target triple: arch: ${target_arch}, vendor: ${target_vendor}, "
"OS: ${os}, env: ${env}")
set(libs "")
set(is_windows FALSE)
set(is_windows_msvc FALSE)
set(is_windows_gnu FALSE)
set(is_macos FALSE)
if(os STREQUAL "windows")
set(is_windows TRUE)
if(NOT COR_NO_STD)
list(APPEND libs "advapi32" "userenv" "ws2_32")
endif()
if(env STREQUAL "msvc")
set(is_windows_msvc TRUE)
if(NOT COR_NO_STD)
list(APPEND libs "$<$<CONFIG:Debug>:msvcrtd>")
# CONFIG takes a comma seperated list starting with CMake 3.19, but we still need to
# support older CMake versions.
set(config_is_release "$<OR:$<CONFIG:Release>,$<CONFIG:MinSizeRel>,$<CONFIG:RelWithDebInfo>>")
list(APPEND libs "$<${config_is_release}:msvcrt>")
endif()
elseif(env STREQUAL "gnu")
set(is_windows_gnu TRUE)
if(NOT COR_NO_STD)
list(APPEND libs "gcc_eh" "pthread")
endif()
endif()
if(NOT COR_NO_STD)
if(rust_version VERSION_LESS "1.33.0")
list(APPEND libs "shell32" "kernel32")
endif()
if(rust_version VERSION_GREATER_EQUAL "1.57.0")
list(APPEND libs "bcrypt")
endif()
endif()
elseif(target_vendor STREQUAL "apple" AND os STREQUAL "darwin")
set(is_macos TRUE)
if(NOT COR_NO_STD)
list(APPEND libs "System" "resolv" "c" "m")
endif()
elseif(os STREQUAL "linux")
if(NOT COR_NO_STD)
list(APPEND libs "dl" "rt" "pthread" "gcc_s" "c" "m" "util")
endif()
endif()
set_source_files_properties(
${manifest}
PROPERTIES
CORROSION_PLATFORM_LIBS "${libs}"
CORROSION_PLATFORM_IS_WINDOWS "${is_windows}"
CORROSION_PLATFORM_IS_WINDOWS_MSVC "${is_windows_msvc}"
CORROSION_PLATFORM_IS_WINDOWS_GNU "${is_windows_gnu}"
CORROSION_PLATFORM_IS_MACOS "${is_macos}"
)
endfunction()
# Add targets for the static and/or shared libraries of the rust target.
# The generated byproduct names are returned via the `out_lib_byproducts` variable name.
function(_corrosion_add_library_target workspace_manifest_path target_name has_staticlib has_cdylib
out_archive_output_byproducts out_shared_lib_byproduct out_pdb_byproduct)
if(NOT (has_staticlib OR has_cdylib))
message(FATAL_ERROR "Unknown library type")
endif()
get_source_file_property(is_windows ${workspace_manifest_path} CORROSION_PLATFORM_IS_WINDOWS)
get_source_file_property(is_windows_msvc ${workspace_manifest_path} CORROSION_PLATFORM_IS_WINDOWS_MSVC)
get_source_file_property(is_windows_gnu ${workspace_manifest_path} CORROSION_PLATFORM_IS_WINDOWS_GNU)
get_source_file_property(is_macos ${workspace_manifest_path} CORROSION_PLATFORM_IS_MACOS)
# target file names
string(REPLACE "-" "_" lib_name "${target_name}")
if(is_windows_msvc)
set(static_lib_name "${lib_name}.lib")
else()
set(static_lib_name "lib${lib_name}.a")
endif()
if(is_windows)
set(dynamic_lib_name "${lib_name}.dll")
elseif(is_macos)
set(dynamic_lib_name "lib${lib_name}.dylib")
else()
set(dynamic_lib_name "lib${lib_name}.so")
endif()
if(is_windows_msvc)
set(implib_name "${lib_name}.dll.lib")
elseif(is_windows_gnu)
set(implib_name "lib${lib_name}.dll.a")
elseif(is_windows)
message(FATAL_ERROR "Unknown windows environment - Can't determine implib name")
endif()
set(pdb_name "${lib_name}.pdb")
set(archive_output_byproducts "")
if(has_staticlib)
list(APPEND archive_output_byproducts ${static_lib_name})
endif()
if(has_cdylib)
set(${out_shared_lib_byproduct} "${dynamic_lib_name}" PARENT_SCOPE)
if(is_windows)
list(APPEND archive_output_byproducts ${implib_name})
endif()
if(is_windows_msvc)
set(${out_pdb_byproduct} "${pdb_name}" PARENT_SCOPE)
endif()
endif()
set(${out_archive_output_byproducts} "${archive_output_byproducts}" PARENT_SCOPE)
if(has_staticlib)
add_library(${target_name}-static STATIC IMPORTED GLOBAL)
add_dependencies(${target_name}-static cargo-build_${target_name})
_corrosion_set_imported_location("${target_name}-static" "IMPORTED_LOCATION"
"ARCHIVE_OUTPUT_DIRECTORY"
"${static_lib_name}")
get_source_file_property(libs ${workspace_manifest_path} CORROSION_PLATFORM_LIBS)
if(libs)
set_property(
TARGET ${target_name}-static
PROPERTY INTERFACE_LINK_LIBRARIES ${libs}
)
if(is_macos)
set_property(TARGET ${target_name}-static
PROPERTY INTERFACE_LINK_DIRECTORIES "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib"
)
endif()
endif()
endif()
if(has_cdylib)
add_library(${target_name}-shared SHARED IMPORTED GLOBAL)
add_dependencies(${target_name}-shared cargo-build_${target_name})
# Todo: (Not new issue): What about IMPORTED_SONAME and IMPORTED_NO_SYSTEM?
_corrosion_set_imported_location("${target_name}-shared" "IMPORTED_LOCATION"
"LIBRARY_OUTPUT_DIRECTORY"
"${dynamic_lib_name}"
)
if(is_windows)
_corrosion_set_imported_location("${target_name}-shared" "IMPORTED_IMPLIB"
"ARCHIVE_OUTPUT_DIRECTORY"
"${implib_name}"
)
endif()
if(is_macos)
set_property(TARGET ${target_name}-shared
PROPERTY INTERFACE_LINK_DIRECTORIES "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib"
)
endif()
endif()
add_library(${target_name} INTERFACE)
if(has_cdylib AND has_staticlib)
if(BUILD_SHARED_LIBS)
target_link_libraries(${target_name} INTERFACE ${target_name}-shared)
else()
target_link_libraries(${target_name} INTERFACE ${target_name}-static)
endif()
elseif(has_cdylib)
target_link_libraries(${target_name} INTERFACE ${target_name}-shared)
else()
target_link_libraries(${target_name} INTERFACE ${target_name}-static)
endif()
endfunction()
function(_corrosion_add_bin_target workspace_manifest_path bin_name out_bin_byproduct out_pdb_byproduct)
if(NOT bin_name)
message(FATAL_ERROR "No bin_name in _corrosion_add_bin_target for target ${target_name}")
endif()
string(REPLACE "-" "_" bin_name_underscore "${bin_name}")
set(pdb_name "${bin_name_underscore}.pdb")
get_source_file_property(is_windows ${workspace_manifest_path} CORROSION_PLATFORM_IS_WINDOWS)
get_source_file_property(is_windows_msvc ${workspace_manifest_path} CORROSION_PLATFORM_IS_WINDOWS_MSVC)
get_source_file_property(is_macos ${workspace_manifest_path} CORROSION_PLATFORM_IS_MACOS)
if(is_windows_msvc)
set(${out_pdb_byproduct} "${pdb_name}" PARENT_SCOPE)
endif()
if(is_windows)
set(bin_filename "${bin_name}.exe")
else()
set(bin_filename "${bin_name}")
endif()
set(${out_bin_byproduct} "${bin_filename}" PARENT_SCOPE)
# Todo: This is compatible with the way corrosion previously exposed the bin name,
# but maybe we want to prefix the exposed name with the package name?
add_executable(${bin_name} IMPORTED GLOBAL)
add_dependencies(${bin_name} cargo-build_${bin_name})
if(is_macos)
set_property(TARGET ${bin_name}
PROPERTY INTERFACE_LINK_DIRECTORIES "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib"
)
endif()
_corrosion_set_imported_location("${bin_name}" "IMPORTED_LOCATION"
"RUNTIME_OUTPUT_DIRECTORY"
"${bin_filename}"
)
endfunction()
if (NOT CORROSION_NATIVE_TOOLING)
include(CorrosionGenerator)
endif()
if (CORROSION_VERBOSE_OUTPUT)
set(_CORROSION_VERBOSE_OUTPUT_FLAG --verbose)
endif()
if(CORROSION_NATIVE_TOOLING)
if (NOT TARGET Corrosion::Generator )
set(_CORROSION_GENERATOR_EXE
${CARGO_EXECUTABLE} run --quiet --manifest-path "${CMAKE_CURRENT_LIST_DIR}/../generator/Cargo.toml" --)
if (CORROSION_DEV_MODE)
# If you're developing Corrosion, you want to make sure to re-configure whenever the
# generator changes.
file(GLOB_RECURSE _RUST_FILES CONFIGURE_DEPENDS generator/src/*.rs)
file(GLOB _CARGO_FILES CONFIGURE_DEPENDS generator/Cargo.*)
set_property(
DIRECTORY APPEND
PROPERTY CMAKE_CONFIGURE_DEPENDS
${_RUST_FILES} ${_CARGO_FILES})
endif()
else()
get_property(
_CORROSION_GENERATOR_EXE
TARGET Corrosion::Generator PROPERTY IMPORTED_LOCATION
)
endif()
set(
_CORROSION_GENERATOR
${CMAKE_COMMAND} -E env
CARGO_BUILD_RUSTC=${RUSTC_EXECUTABLE}
${_CORROSION_GENERATOR_EXE}
--cargo ${CARGO_EXECUTABLE}
${_CORROSION_VERBOSE_OUTPUT_FLAG}
CACHE INTERNAL "corrosion-generator runner"
)
endif()
set(_CORROSION_CARGO_VERSION ${Rust_CARGO_VERSION} CACHE INTERNAL "cargo version used by corrosion")
set(_CORROSION_RUST_CARGO_TARGET ${Rust_CARGO_TARGET} CACHE INTERNAL "target triple used by corrosion")
set(_CORROSION_RUST_CARGO_HOST_TARGET ${Rust_CARGO_HOST_TARGET} CACHE INTERNAL "host triple used by corrosion")
set(_CORROSION_RUSTC "${RUSTC_EXECUTABLE}" CACHE INTERNAL "Path to rustc used by corrosion")
set(_CORROSION_CARGO "${CARGO_EXECUTABLE}" CACHE INTERNAL "Path to cargo used by corrosion")
string(REPLACE "-" "_" _CORROSION_RUST_CARGO_TARGET_UNDERSCORE "${Rust_CARGO_TARGET}")
string(TOUPPER "${_CORROSION_RUST_CARGO_TARGET_UNDERSCORE}" _CORROSION_TARGET_TRIPLE_UPPER)
set(_CORROSION_RUST_CARGO_TARGET_UNDERSCORE ${Rust_CARGO_TARGET} CACHE INTERNAL "lowercase target triple with underscores")
set(_CORROSION_RUST_CARGO_TARGET_UPPER
"${_CORROSION_TARGET_TRIPLE_UPPER}"
CACHE INTERNAL
"target triple in uppercase with underscore"
)
# We previously specified some Custom properties as part of our public API, however the chosen names prevented us from
# supporting CMake versions before 3.19. In order to both support older CMake versions and not break existing code
# immediately, we are using a different property name depending on the CMake version. However users avoid using
# any of the properties directly, as they are no longer part of the public API and are to be considered deprecated.
# Instead use the corrosion_set_... functions as documented in the Readme.
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.19.0)
set(_CORR_PROP_FEATURES CORROSION_FEATURES CACHE INTERNAL "")
set(_CORR_PROP_ALL_FEATURES CORROSION_ALL_FEATURES CACHE INTERNAL "")
set(_CORR_PROP_NO_DEFAULT_FEATURES CORROSION_NO_DEFAULT_FEATURES CACHE INTERNAL "")
set(_CORR_PROP_ENV_VARS CORROSION_ENVIRONMENT_VARIABLES CACHE INTERNAL "")
set(_CORR_PROP_HOST_BUILD CORROSION_USE_HOST_BUILD CACHE INTERNAL "")
else()
set(_CORR_PROP_FEATURES INTERFACE_CORROSION_FEATURES CACHE INTERNAL "")
set(_CORR_PROP_ALL_FEATURES INTERFACE_CORROSION_ALL_FEATURES CACHE INTERNAL "")
set(_CORR_PROP_NO_DEFAULT_FEATURES INTERFACE_NO_DEFAULT_FEATURES CACHE INTERNAL "")
set(_CORR_PROP_ENV_VARS INTERFACE_CORROSION_ENVIRONMENT_VARIABLES CACHE INTERNAL "")
set(_CORR_PROP_HOST_BUILD INTERFACE_CORROSION_USE_HOST_BUILD CACHE INTERNAL "")
endif()
# Add custom command to build one target in a package (crate)
#
# A target may be either a specific bin
function(_add_cargo_build out_cargo_build_out_dir)
set(options NO_LINKER_OVERRIDE)
set(one_value_args PACKAGE TARGET MANIFEST_PATH PROFILE WORKSPACE_MANIFEST_PATH)
set(multi_value_args BYPRODUCTS TARGET_KINDS)
cmake_parse_arguments(
ACB
"${options}"
"${one_value_args}"
"${multi_value_args}"
${ARGN}
)
set(package_name "${ACB_PACKAGE}")
set(target_name "${ACB_TARGET}")
set(path_to_toml "${ACB_MANIFEST_PATH}")
set(cargo_profile_name "${ACB_PROFILE}")
set(target_kinds "${ACB_TARGET_KINDS}")
set(workspace_manifest_path "${ACB_WORKSPACE_MANIFEST_PATH}")
if(NOT target_kinds)
message(FATAL_ERROR "TARGET_KINDS not specified")
elseif("staticlib" IN_LIST target_kinds OR "cdylib" IN_LIST target_kinds)
set(cargo_rustc_filter "--lib")
elseif("bin" IN_LIST target_kinds)
set(cargo_rustc_filter "--bin=${target_name}")
else()
message(FATAL_ERROR "TARGET_KINDS contained unknown kind `${target_kind}`")
endif()
if (NOT IS_ABSOLUTE "${path_to_toml}")
set(path_to_toml "${CMAKE_SOURCE_DIR}/${path_to_toml}")
endif()
get_filename_component(workspace_toml_dir ${path_to_toml} DIRECTORY )
if (CMAKE_VS_PLATFORM_NAME)
set (build_dir "${CMAKE_VS_PLATFORM_NAME}/$<CONFIG>")
elseif(CMAKE_CONFIGURATION_TYPES)
set (build_dir "$<CONFIG>")
else()
set (build_dir .)
endif()
unset(is_windows_msvc)
get_source_file_property(is_windows_msvc "${workspace_manifest_path}" CORROSION_PLATFORM_IS_WINDOWS_MSVC)
# Corrosions currently attempts to select a correct linker, based on the enabled languages.
# This approach is flawed and should be revisited in the future.
# Currently we disable this approach for the MSVC abi, because it just doesn't work
# and for static libraries, because the linker shouldn't be invoked for those, but
# potentially could be if Rust side build scripts or proc macros etc. happened to be involved.
# Overriding the linker in those cases is probably unwanted.
if(is_windows_msvc)
set(determine_linker_preference FALSE)
elseif("staticlib" IN_LIST target_kinds AND NOT "cdylib" IN_LIST target_kinds)
set(determine_linker_preference FALSE)
else()
set(determine_linker_preference TRUE)
endif()
if(determine_linker_preference)
set(languages C CXX Fortran)
set(has_compiler OFF)
foreach(language ${languages})
if (CMAKE_${language}_COMPILER)
set(has_compiler ON)
endif()
endforeach()
# When cross-compiling a Rust crate, at the very least we need a C linker
if (NOT has_compiler AND CMAKE_CROSSCOMPILING)
message(STATUS "Enabling the C compiler for linking Rust programs")
enable_language(C)
endif()
# Determine the linker CMake prefers based on the enabled languages.
set(_CORROSION_LINKER_PREFERENCE_SCORE "0")
foreach(language ${languages})
if( ${CMAKE_${language}_LINKER_PREFERENCE} )
if(NOT CORROSION_LINKER_PREFERENCE
OR (${CMAKE_${language}_LINKER_PREFERENCE} GREATER ${_CORROSION_LINKER_PREFERENCE_SCORE}))
set(CORROSION_LINKER_PREFERENCE "${CMAKE_${language}_COMPILER}")
set(CORROSION_LINKER_PREFERENCE_TARGET "${CMAKE_${language}_COMPILER_TARGET}")
set(CORROSION_LINKER_PREFERENCE_LANGUAGE "${language}")
set(_CORROSION_LINKER_PREFERENCE_SCORE "${CMAKE_${language}_LINKER_PREFERENCE}")
endif()
endif()
endforeach()
message(VERBOSE "CORROSION_LINKER_PREFERENCE for target ${target_name}: ${CORROSION_LINKER_PREFERENCE}")
endif()
if (NOT CMAKE_CONFIGURATION_TYPES)
set(target_dir ${CMAKE_CURRENT_BINARY_DIR})
if (CMAKE_BUILD_TYPE STREQUAL "" OR CMAKE_BUILD_TYPE STREQUAL Debug)
set(build_type_dir debug)
else()
set(build_type_dir release)
endif()
else()
set(target_dir ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>)
set(build_type_dir $<IF:$<OR:$<CONFIG:Debug>,$<CONFIG:>>,debug,release>)
endif()
# If a CMake sysroot is specified, forward it to the linker rustc invokes, too. CMAKE_SYSROOT is documented
# to be passed via --sysroot, so we assume that when it's set, the linker supports this option in that style.
if(CMAKE_CROSSCOMPILING AND CMAKE_SYSROOT)
set(corrosion_link_args "--sysroot=${CMAKE_SYSROOT}")
endif()
if(COR_ALL_FEATURES)
set(all_features_arg --all-features)
endif()
if(COR_NO_DEFAULT_FEATURES)
set(no_default_features_arg --no-default-features)
endif()
if(COR_NO_STD)
set(no_default_libraries_arg --no-default-libraries)
endif()
set(global_rustflags_target_property "$<TARGET_GENEX_EVAL:${target_name},$<TARGET_PROPERTY:${target_name},INTERFACE_CORROSION_RUSTFLAGS>>")
set(local_rustflags_target_property "$<TARGET_GENEX_EVAL:${target_name},$<TARGET_PROPERTY:${target_name},INTERFACE_CORROSION_LOCAL_RUSTFLAGS>>")
set(features_target_property "$<GENEX_EVAL:$<TARGET_PROPERTY:${target_name},${_CORR_PROP_FEATURES}>>")
set(features_genex "$<$<BOOL:${features_target_property}>:--features=$<JOIN:${features_target_property},$<COMMA>>>")
# target property overrides corrosion_import_crate argument
set(all_features_target_property "$<GENEX_EVAL:$<TARGET_PROPERTY:${target_name},${_CORR_PROP_ALL_FEATURES}>>")
set(all_features_property_exists_condition "$<NOT:$<STREQUAL:${all_features_target_property},>>")
set(all_features_property_arg "$<IF:$<BOOL:${all_features_target_property}>,--all-features,>")
set(all_features_arg "$<IF:${all_features_property_exists_condition},${all_features_property_arg},${all_features_arg}>")
set(no_default_features_target_property "$<GENEX_EVAL:$<TARGET_PROPERTY:${target_name},${_CORR_PROP_NO_DEFAULT_FEATURES}>>")
set(no_default_features_property_exists_condition "$<NOT:$<STREQUAL:${no_default_features_target_property},>>")
set(no_default_features_property_arg "$<IF:$<BOOL:${no_default_features_target_property}>,--no-default-features,>")
set(no_default_features_arg "$<IF:${no_default_features_property_exists_condition},${no_default_features_property_arg},${no_default_features_arg}>")
set(build_env_variable_genex "$<GENEX_EVAL:$<TARGET_PROPERTY:${target_name},${_CORR_PROP_ENV_VARS}>>")
set(if_not_host_build_condition "$<NOT:$<BOOL:$<TARGET_PROPERTY:${target_name},${_CORR_PROP_HOST_BUILD}>>>")
set(corrosion_link_args "$<${if_not_host_build_condition}:${corrosion_link_args}>")
set(cargo_target_option "$<IF:${if_not_host_build_condition},--target=${_CORROSION_RUST_CARGO_TARGET},--target=${_CORROSION_RUST_CARGO_HOST_TARGET}>")
# The target may be a filepath to custom target json file. For host targets we assume that they are built-in targets.
_corrosion_strip_target_triple(${_CORROSION_RUST_CARGO_TARGET} stripped_target_triple)
set(target_artifact_dir "$<IF:${if_not_host_build_condition},${stripped_target_triple},${_CORROSION_RUST_CARGO_HOST_TARGET}>")
set(flags_genex "$<GENEX_EVAL:$<TARGET_PROPERTY:${target_name},INTERFACE_CORROSION_CARGO_FLAGS>>")
set(explicit_linker_property "$<TARGET_PROPERTY:${target_name},INTERFACE_CORROSION_LINKER>")
# Rust will add `-lSystem` as a flag for the linker on macOS. Adding the -L flag via RUSTFLAGS only fixes the
# problem partially - buildscripts still break, since they won't receive the RUSTFLAGS. This seems to only be a
# problem if we specify the linker ourselves (which we do, since this is necessary for e.g. linking C++ code).
# We can however set `LIBRARY_PATH`, which is propagated to the build-script-build properly.
if(NOT CMAKE_CROSSCOMPILING AND CMAKE_SYSTEM_NAME STREQUAL "Darwin")
# not needed anymore on macos 13 (and causes issues)
if(${CMAKE_SYSTEM_VERSION} VERSION_LESS 22)
set(cargo_library_path "LIBRARY_PATH=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib")
endif()
elseif(CMAKE_CROSSCOMPILING AND CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
if(${CMAKE_HOST_SYSTEM_VERSION} VERSION_LESS 22)
set(cargo_library_path "$<IF:${if_not_host_build_condition},,LIBRARY_PATH=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib>")
endif()
endif()
if(cargo_profile_name)
set(cargo_profile "--profile=${cargo_profile_name}")
set(build_type_dir "${cargo_profile_name}")
else()
set(cargo_profile $<$<NOT:$<OR:$<CONFIG:Debug>,$<CONFIG:>>>:--release>)
endif()
set(cargo_target_dir "${CMAKE_BINARY_DIR}/${build_dir}/cargo/build")
set(cargo_build_dir "${cargo_target_dir}/${target_artifact_dir}/${build_type_dir}")
set("${out_cargo_build_out_dir}" "${cargo_build_dir}" PARENT_SCOPE)
set(features_args)
foreach(feature ${COR_FEATURES})
list(APPEND features_args --features ${feature})
endforeach()
set(flag_args)
foreach(flag ${COR_FLAGS})
list(APPEND flag_args ${flag})
endforeach()
set(corrosion_cc_rs_flags)
if(CMAKE_C_COMPILER AND _CORROSION_RUST_CARGO_TARGET_UNDERSCORE)
# This variable is read by cc-rs (often used in build scripts) to determine the c-compiler.
# It can still be overridden if the user sets the non underscore variant via the environment variables
# on the target.
list(APPEND corrosion_cc_rs_flags "CC_${_CORROSION_RUST_CARGO_TARGET_UNDERSCORE}=${CMAKE_C_COMPILER}")
endif()
if(CMAKE_CXX_COMPILER AND _CORROSION_RUST_CARGO_TARGET_UNDERSCORE)
list(APPEND corrosion_cc_rs_flags "CXX_${_CORROSION_RUST_CARGO_TARGET_UNDERSCORE}=${CMAKE_CXX_COMPILER}")
endif()
# Since we instruct cc-rs to use the compiler found by CMake, it is likely one that requires also
# specifying the target sysroot to use. CMake's generator makes sure to pass --sysroot with
# CMAKE_OSX_SYSROOT. Fortunately the compilers Apple ships also respect the SDKROOT environment
# variable, which we can set for use when cc-rs invokes the compiler.
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_OSX_SYSROOT)
list(APPEND corrosion_cc_rs_flags "SDKROOT=${CMAKE_OSX_SYSROOT}")
endif()
corrosion_add_target_local_rustflags("${target_name}" "$<$<BOOL:${corrosion_link_args}>:-Clink-args=${corrosion_link_args}>")
# todo: this should probably also be guarded by if_not_host_build_condition.
if(COR_NO_STD)
corrosion_add_target_local_rustflags("${target_name}" "-Cdefault-linker-libraries=no")
else()
corrosion_add_target_local_rustflags("${target_name}" "-Cdefault-linker-libraries=yes")
endif()
set(global_joined_rustflags "$<JOIN:${global_rustflags_target_property}, >")
set(global_rustflags_genex "$<$<BOOL:${global_rustflags_target_property}>:RUSTFLAGS=${global_joined_rustflags}>")
set(local_rustflags_delimiter "$<$<BOOL:${local_rustflags_target_property}>:-->")
set(local_rustflags_genex "$<$<BOOL:${local_rustflags_target_property}>:${local_rustflags_target_property}>")
# Used to set a linker for a specific target-triple.
set(cargo_target_linker_var "CARGO_TARGET_${_CORROSION_RUST_CARGO_TARGET_UPPER}_LINKER")
if(NOT ACB_NO_LINKER_OVERRIDE)
if(CORROSION_LINKER_PREFERENCE)
set(cargo_target_linker_arg "$<IF:$<BOOL:${explicit_linker_property}>,${explicit_linker_property},${CORROSION_LINKER_PREFERENCE}>")
set(cargo_target_linker "${cargo_target_linker_var}=${cargo_target_linker_arg}")
if(CMAKE_CROSSCOMPILING)
# CMake does not offer a host compiler we could select when configured for cross-compiling. This
# effectively means that by default cc will be selected for builds targeting host. The user can still
# override this by manually adding the appropriate rustflags to select the compiler for the target!
set(cargo_target_linker "$<${if_not_host_build_condition}:${cargo_target_linker}>")
endif()
# Will be only set for cross-compilers like clang, c.f. `CMAKE_<LANG>_COMPILER_TARGET`.
if(CORROSION_LINKER_PREFERENCE_TARGET)
set(rustflag_linker_arg "-Clink-args=--target=${CORROSION_LINKER_PREFERENCE_TARGET}")
# Skip adding the linker argument, if the linker is explicitly set, since the
# explicit_linker_property will not be set when this function runs.
# Passing this rustflag is necessary for clang.
corrosion_add_target_local_rustflags("${target_name}" "$<$<NOT:$<BOOL:${explicit_linker_property}>>:${rustflag_linker_arg}>")
endif()
else()
message(DEBUG "No linker preference for target ${target_name} could be detected.")
# Note: Adding quotes here introduces wierd errors when using MSVC. Since there are no spaces here at
# configure time, we can omit the quotes without problems
set(cargo_target_linker $<$<BOOL:${explicit_linker_property}>:${cargo_target_linker_var}=${explicit_linker_property}>)
endif()
else()
# Disable the linker override by setting it to an empty string.
set(cargo_target_linker "")
endif()
message(DEBUG "TARGET ${target_name} produces byproducts ${byproducts}")
add_custom_target(
_cargo-build_${target_name}
# Build crate
COMMAND
${CMAKE_COMMAND} -E env
"${build_env_variable_genex}"
"${global_rustflags_genex}"
"${cargo_target_linker}"
"${corrosion_cc_rs_flags}"
"${cargo_library_path}"
"CORROSION_BUILD_DIR=${CMAKE_CURRENT_BINARY_DIR}"