10 |
10 |
11 #]=======================================================================] |
11 #]=======================================================================] |
12 |
12 |
13 cmake_minimum_required(VERSION 3.12) |
13 cmake_minimum_required(VERSION 3.12) |
14 |
14 |
|
15 option( |
|
16 Rust_RUSTUP_INSTALL_MISSING_TARGET |
|
17 "Use Rustup to automatically install missing targets instead of giving up" |
|
18 OFF |
|
19 ) |
|
20 |
15 # search for Cargo here and set up a bunch of cool flags and stuff |
21 # search for Cargo here and set up a bunch of cool flags and stuff |
16 include(FindPackageHandleStandardArgs) |
22 include(FindPackageHandleStandardArgs) |
17 |
23 |
18 list(APPEND CMAKE_MESSAGE_CONTEXT "FindRust") |
24 list(APPEND CMAKE_MESSAGE_CONTEXT "FindRust") |
19 |
25 |
20 # Print error message and return. |
26 # Print error message and return. Should not be used from inside functions |
21 macro(_findrust_failed) |
27 macro(_findrust_failed) |
22 if("${Rust_FIND_REQUIRED}") |
28 if("${Rust_FIND_REQUIRED}") |
23 message(FATAL_ERROR ${ARGN}) |
29 message(FATAL_ERROR ${ARGN}) |
24 elseif(NOT "${Rust_FIND_QUIETLY}") |
30 elseif(NOT "${Rust_FIND_QUIETLY}") |
25 message(WARNING ${ARGN}) |
31 message(WARNING ${ARGN}) |
26 endif() |
32 endif() |
27 # Note: PARENT_SCOPE is the scope of the caller of the caller of this macro. |
33 set(Rust_FOUND "") |
28 set(Rust_FOUND "" PARENT_SCOPE) |
|
29 return() |
34 return() |
30 endmacro() |
35 endmacro() |
31 |
36 |
32 # Checks if the actual version of a Rust toolchain matches the VERSION requirements specified in find_package. |
37 # Checks if the actual version of a Rust toolchain matches the VERSION requirements specified in find_package. |
33 function(_findrust_version_ok ACTUAL_VERSION OUT_IS_OK) |
38 function(_findrust_version_ok ACTUAL_VERSION OUT_IS_OK) |
177 continue() |
182 continue() |
178 endif() |
183 endif() |
179 |
184 |
180 # Flags start with / for MSVC |
185 # Flags start with / for MSVC |
181 if (lib MATCHES "^/" AND ${target_triple} MATCHES "msvc$") |
186 if (lib MATCHES "^/" AND ${target_triple} MATCHES "msvc$") |
182 list(APPEND flag_list "${lib}") |
187 # Windows GNU uses the compiler to invoke the linker, so -Wl, prefix is needed |
|
188 # https://gitlab.kitware.com/cmake/cmake/-/blob/9bed4f4d817f139f0c2e050d7420e1e247949fe4/Modules/Platform/Windows-GNU.cmake#L156 |
|
189 if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU") |
|
190 list(APPEND flag_list "-Wl,${lib}") |
|
191 else() |
|
192 list(APPEND flag_list "${lib}") |
|
193 endif() |
183 else() |
194 else() |
184 # Strip leading `-l` (unix) and potential .lib suffix (windows) |
195 # Strip leading `-l` (unix) and potential .lib suffix (windows) |
185 string(REGEX REPLACE "^-l" "" "stripped_lib" "${lib}") |
196 string(REGEX REPLACE "^-l" "" "stripped_lib" "${lib}") |
186 string(REGEX REPLACE "\.lib$" "" "stripped_lib" "${stripped_lib}") |
197 string(REGEX REPLACE "\.lib$" "" "stripped_lib" "${stripped_lib}") |
187 list(APPEND stripped_lib_list "${stripped_lib}") |
198 list(APPEND stripped_lib_list "${stripped_lib}") |
188 endif() |
199 endif() |
189 endforeach() |
200 endforeach() |
190 set(libs_list "${stripped_lib_list}") |
201 set(libs_list "${stripped_lib_list}") |
191 # Special case `msvcrt` to link with the debug version in Debug mode. |
202 # We leave it up to the C/C++ executable that links in the Rust static-library |
192 list(TRANSFORM libs_list REPLACE "^msvcrt$" "\$<\$<CONFIG:Debug>:msvcrtd>") |
203 # to determine which version of the msvc runtime library it should select. |
|
204 list(FILTER libs_list EXCLUDE REGEX "^msvcrtd?") |
|
205 list(FILTER flag_list EXCLUDE REGEX "^(-Wl,)?/defaultlib:msvcrtd?") |
193 else() |
206 else() |
194 message(DEBUG "Determining required native libraries - failed: Regex match failure.") |
207 message(DEBUG "Determining required native libraries - failed: Regex match failure.") |
195 message(DEBUG "`native-static-libs` not found in: `${cargo_build_error_message}`") |
208 message(DEBUG "`native-static-libs` not found in: `${cargo_build_error_message}`") |
196 return() |
209 return() |
197 endif() |
210 endif() |
240 return() |
253 return() |
241 endif() |
254 endif() |
242 else() |
255 else() |
243 find_program(_Rust_COMPILER_TEST rustc PATHS "$ENV{HOME}/.cargo/bin") |
256 find_program(_Rust_COMPILER_TEST rustc PATHS "$ENV{HOME}/.cargo/bin") |
244 if(NOT EXISTS "${_Rust_COMPILER_TEST}") |
257 if(NOT EXISTS "${_Rust_COMPILER_TEST}") |
245 set(_ERROR_MESSAGE "`rustc` not found in PATH or `$ENV{HOME}/.cargo/bin`.\n" |
258 cmake_path(CONVERT "$ENV{HOME}/.cargo/bin" TO_CMAKE_PATH_LIST _cargo_bin_dir) |
|
259 set(_ERROR_MESSAGE "`rustc` not found in PATH or `${_cargo_bin_dir}`.\n" |
246 "Hint: Check if `rustc` is in PATH or manually specify the location " |
260 "Hint: Check if `rustc` is in PATH or manually specify the location " |
247 "by setting `Rust_COMPILER` to the path to `rustc`.") |
261 "by setting `Rust_COMPILER` to the path to `rustc`.") |
248 _findrust_failed(${_ERROR_MESSAGE}) |
262 _findrust_failed(${_ERROR_MESSAGE}) |
249 endif() |
263 endif() |
250 endif() |
264 endif() |
387 "List lengths: ${_toolchain_len} toolchains, ${_toolchain_rustc_len} rustc, ${_toolchain_cargo_len} cargo," |
401 "List lengths: ${_toolchain_len} toolchains, ${_toolchain_rustc_len} rustc, ${_toolchain_cargo_len} cargo," |
388 " ${_toolchain_version_len} version. The lengths should be the same." |
402 " ${_toolchain_version_len} version. The lengths should be the same." |
389 ) |
403 ) |
390 endif() |
404 endif() |
391 |
405 |
392 set(Rust_RUSTUP_TOOLCHAINS CACHE INTERNAL "List of available Rustup toolchains" "${_DISCOVERED_TOOLCHAINS}") |
406 set(Rust_RUSTUP_TOOLCHAINS "${_DISCOVERED_TOOLCHAINS}" CACHE INTERNAL "List of available Rustup toolchains") |
393 set(Rust_RUSTUP_TOOLCHAINS_RUSTC_PATH |
407 set(Rust_RUSTUP_TOOLCHAINS_RUSTC_PATH "${_DISCOVERED_TOOLCHAINS_RUSTC_PATH}" |
394 CACHE INTERNAL |
408 CACHE INTERNAL |
395 "List of the rustc paths corresponding to the toolchain at the same index in `Rust_RUSTUP_TOOLCHAINS`." |
409 "List of the rustc paths corresponding to the toolchain at the same index in `Rust_RUSTUP_TOOLCHAINS`." |
396 "${_DISCOVERED_TOOLCHAINS_RUSTC_PATH}" |
410 ) |
397 ) |
411 set(Rust_RUSTUP_TOOLCHAINS_CARGO_PATH "${_DISCOVERED_TOOLCHAINS_CARGO_PATH}" |
398 set(Rust_RUSTUP_TOOLCHAINS_CARGO_PATH |
|
399 CACHE INTERNAL |
412 CACHE INTERNAL |
400 "List of the cargo paths corresponding to the toolchain at the same index in `Rust_RUSTUP_TOOLCHAINS`. \ |
413 "List of the cargo paths corresponding to the toolchain at the same index in `Rust_RUSTUP_TOOLCHAINS`. \ |
401 May also be `NOTFOUND` if the toolchain does not have a cargo executable." |
414 May also be `NOTFOUND` if the toolchain does not have a cargo executable." |
402 "${_DISCOVERED_TOOLCHAINS_CARGO_PATH}" |
415 ) |
403 ) |
416 set(Rust_RUSTUP_TOOLCHAINS_VERSION "${_DISCOVERED_TOOLCHAINS_VERSION}" |
404 set(Rust_RUSTUP_TOOLCHAINS_VERSION |
|
405 CACHE INTERNAL |
417 CACHE INTERNAL |
406 "List of the rust toolchain version corresponding to the toolchain at the same index in \ |
418 "List of the rust toolchain version corresponding to the toolchain at the same index in \ |
407 `Rust_RUSTUP_TOOLCHAINS`." |
419 `Rust_RUSTUP_TOOLCHAINS`." |
408 "${_DISCOVERED_TOOLCHAINS_VERSION}" |
|
409 ) |
420 ) |
410 |
421 |
411 # Rust_TOOLCHAIN is preferred over a requested version if it is set. |
422 # Rust_TOOLCHAIN is preferred over a requested version if it is set. |
412 if (NOT DEFINED Rust_TOOLCHAIN) |
423 if (NOT DEFINED Rust_TOOLCHAIN) |
413 if (NOT DEFINED _TOOLCHAIN_OVERRIDE) |
424 if (NOT DEFINED _TOOLCHAIN_OVERRIDE) |
484 find_program( |
495 find_program( |
485 Rust_COMPILER_CACHED |
496 Rust_COMPILER_CACHED |
486 rustc |
497 rustc |
487 HINTS "${_RUST_TOOLCHAIN_PATH}/bin" |
498 HINTS "${_RUST_TOOLCHAIN_PATH}/bin" |
488 NO_DEFAULT_PATH) |
499 NO_DEFAULT_PATH) |
489 elseif (Rust_RUSTUP) |
|
490 get_filename_component(_RUST_TOOLCHAIN_PATH "${Rust_RUSTUP}" DIRECTORY) |
|
491 get_filename_component(_RUST_TOOLCHAIN_PATH "${_RUST_TOOLCHAIN_PATH}" DIRECTORY) |
|
492 find_program( |
|
493 Rust_COMPILER_CACHED |
|
494 rustc |
|
495 HINTS "${_RUST_TOOLCHAIN_PATH}/bin" |
|
496 NO_DEFAULT_PATH) |
|
497 else() |
500 else() |
498 find_program(Rust_COMPILER_CACHED rustc) |
501 message(DEBUG "Rust_RESOLVE_RUSTUP_TOOLCHAINS=OFF and Rust_RUSTUP=${Rust_RUSTUP}") |
|
502 if(Rust_RUSTUP) |
|
503 get_filename_component(_RUSTUP_DIR "${Rust_RUSTUP}" DIRECTORY) |
|
504 find_program(Rust_COMPILER_CACHED rustc HINTS "${_RUSTUP_DIR}") |
|
505 else() |
|
506 find_program(Rust_COMPILER_CACHED rustc) |
|
507 endif() |
|
508 message(DEBUG "find_program rustc: ${Rust_COMPILER_CACHED}") |
499 if (EXISTS "${Rust_COMPILER_CACHED}") |
509 if (EXISTS "${Rust_COMPILER_CACHED}") |
500 # rustc is expected to be at `<toolchain_path>/bin/rustc`. |
510 # rustc is expected to be at `<toolchain_path>/bin/rustc`. |
501 get_filename_component(_RUST_TOOLCHAIN_PATH "${Rust_COMPILER_CACHED}" DIRECTORY) |
511 get_filename_component(_RUST_TOOLCHAIN_PATH "${Rust_COMPILER_CACHED}" DIRECTORY) |
502 get_filename_component(_RUST_TOOLCHAIN_PATH "${_RUST_TOOLCHAIN_PATH}" DIRECTORY) |
512 get_filename_component(_RUST_TOOLCHAIN_PATH "${_RUST_TOOLCHAIN_PATH}" DIRECTORY) |
503 endif() |
513 endif() |
684 OR "${CMAKE_C_COMPILER_TARGET}" MATCHES "-msvc$" |
694 OR "${CMAKE_C_COMPILER_TARGET}" MATCHES "-msvc$" |
685 ) |
695 ) |
686 set(_CARGO_ABI msvc) |
696 set(_CARGO_ABI msvc) |
687 elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" |
697 elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" |
688 OR "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" |
698 OR "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" |
689 OR "${CMAKE_CXX_COMPILER_TARGET}" MATCHES "-gnu$" |
699 OR (NOT CMAKE_CROSSCOMPILING |
690 OR "${CMAKE_C_COMPILER_TARGET}" MATCHES "-gnu$" |
700 AND NOT DEFINED CMAKE_CXX_COMPILER_ID |
691 OR (NOT CMAKE_CROSSCOMPILING AND "${Rust_DEFAULT_HOST_TARGET}" MATCHES "-gnu$") |
701 AND NOT DEFINED CMAKE_C_COMPILER_ID |
|
702 AND "${Rust_DEFAULT_HOST_TARGET}" MATCHES "-gnu$" |
692 ) |
703 ) |
|
704 ) |
693 set(_CARGO_ABI gnu) |
705 set(_CARGO_ABI gnu) |
|
706 elseif(("${CMAKE_C_COMPILER_ID}" MATCHES "Clang$" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang$") |
|
707 AND ("${CMAKE_CXX_COMPILER_TARGET}" MATCHES "-gnu(llvm)?$" |
|
708 OR "${CMAKE_C_COMPILER_TARGET}" MATCHES "-gnu(llvm)?$") |
|
709 ) |
|
710 if("${Rust_VERSION}" VERSION_GREATER_EQUAL "1.79") |
|
711 set(_CARGO_ABI gnullvm) |
|
712 else() |
|
713 message(WARNING "Your selected C/C++ compilers suggest you want to use the -gnullvm" |
|
714 " rust targets, however your Rust compiler version is ${Rust_VERSION}, which is" |
|
715 " before the promotion of the gnullvm target to tier2." |
|
716 " Please either use a more recent rust compiler or manually choose a target " |
|
717 " triple by specifying `Rust_CARGO_TARGET` manually." |
|
718 ) |
|
719 endif() |
694 elseif(NOT "${CMAKE_CROSSCOMPILING}" AND "${Rust_DEFAULT_HOST_TARGET}" MATCHES "-msvc$") |
720 elseif(NOT "${CMAKE_CROSSCOMPILING}" AND "${Rust_DEFAULT_HOST_TARGET}" MATCHES "-msvc$") |
695 # We first check if the gnu branch matches to ensure this fallback is only used |
721 # We first check if the gnu branches match to ensure this fallback is only used |
696 # if no compiler is enabled. |
722 # if no compiler is enabled. |
697 set(_CARGO_ABI msvc) |
723 set(_CARGO_ABI msvc) |
698 else() |
724 else() |
699 message(WARNING "Could not determine the target ABI. Please specify `Rust_CARGO_TARGET` manually.") |
725 message(WARNING "Could not determine the target ABI. Please specify `Rust_CARGO_TARGET` manually.") |
700 endif() |
726 endif() |
746 endif() |
772 endif() |
747 |
773 |
748 message(STATUS "Rust Target: ${Rust_CARGO_TARGET_CACHED}") |
774 message(STATUS "Rust Target: ${Rust_CARGO_TARGET_CACHED}") |
749 endif() |
775 endif() |
750 |
776 |
|
777 |
|
778 if(Rust_TOOLCHAIN_IS_RUSTUP_MANAGED) |
|
779 execute_process(COMMAND rustup target list --toolchain "${Rust_TOOLCHAIN}" |
|
780 OUTPUT_VARIABLE AVAILABLE_TARGETS_RAW |
|
781 ) |
|
782 string(REPLACE "\n" ";" AVAILABLE_TARGETS_RAW "${AVAILABLE_TARGETS_RAW}") |
|
783 string(REPLACE " (installed)" "" "AVAILABLE_TARGETS" "${AVAILABLE_TARGETS_RAW}") |
|
784 set(INSTALLED_TARGETS_RAW "${AVAILABLE_TARGETS_RAW}") |
|
785 list(FILTER INSTALLED_TARGETS_RAW INCLUDE REGEX " \\(installed\\)") |
|
786 string(REPLACE " (installed)" "" "INSTALLED_TARGETS" "${INSTALLED_TARGETS_RAW}") |
|
787 list(TRANSFORM INSTALLED_TARGETS STRIP) |
|
788 if("${Rust_CARGO_TARGET_CACHED}" IN_LIST AVAILABLE_TARGETS) |
|
789 message(DEBUG "Cargo target ${Rust_CARGO_TARGET} is an official target-triple") |
|
790 message(DEBUG "Installed targets: ${INSTALLED_TARGETS}") |
|
791 if(NOT ("${Rust_CARGO_TARGET_CACHED}" IN_LIST INSTALLED_TARGETS)) |
|
792 if(Rust_RUSTUP_INSTALL_MISSING_TARGET) |
|
793 message(STATUS "Cargo target ${Rust_CARGO_TARGET_CACHED} is not installed. Installing via rustup.") |
|
794 execute_process(COMMAND "${Rust_RUSTUP}" target add |
|
795 --toolchain ${Rust_TOOLCHAIN} |
|
796 ${Rust_CARGO_TARGET_CACHED} |
|
797 RESULT_VARIABLE target_add_result |
|
798 ) |
|
799 if(NOT "${target_add_result}" EQUAL "0") |
|
800 message(FATAL_ERROR "Target ${Rust_CARGO_TARGET_CACHED} is not installed for toolchain " |
|
801 "${Rust_TOOLCHAIN} and automatically installing failed with ${target_add_result}.\n" |
|
802 "You can try to manually install by running\n" |
|
803 "`rustup target add --toolchain ${Rust_TOOLCHAIN} ${Rust_CARGO_TARGET}`." |
|
804 ) |
|
805 endif() |
|
806 message(STATUS "Installed target ${Rust_CARGO_TARGET_CACHED} successfully.") |
|
807 else() |
|
808 message(FATAL_ERROR "Target ${Rust_CARGO_TARGET_CACHED} is not installed for toolchain ${Rust_TOOLCHAIN}.\n" |
|
809 "Help: Run `rustup target add --toolchain ${Rust_TOOLCHAIN} ${Rust_CARGO_TARGET_CACHED}` to install " |
|
810 "the missing target or configure corrosion with `Rust_RUSTUP_INSTALL_MISSING_TARGET=ON`." |
|
811 ) |
|
812 endif() |
|
813 endif() |
|
814 endif() |
|
815 endif() |
|
816 |
751 if(Rust_CARGO_TARGET_CACHED STREQUAL Rust_DEFAULT_HOST_TARGET) |
817 if(Rust_CARGO_TARGET_CACHED STREQUAL Rust_DEFAULT_HOST_TARGET) |
752 set(Rust_CROSSCOMPILING FALSE CACHE INTERNAL "Rust is configured for cross-compiling") |
818 set(Rust_CROSSCOMPILING FALSE CACHE INTERNAL "Rust is configured for cross-compiling") |
753 else() |
819 else() |
754 set(Rust_CROSSCOMPILING TRUE CACHE INTERNAL "Rust is configured for cross-compiling") |
820 set(Rust_CROSSCOMPILING TRUE CACHE INTERNAL "Rust is configured for cross-compiling") |
755 endif() |
821 endif() |