diff --git a/.github/actions/setup_test/action.yaml b/.github/actions/setup_test/action.yaml index 4406e886..f36944e2 100644 --- a/.github/actions/setup_test/action.yaml +++ b/.github/actions/setup_test/action.yaml @@ -177,6 +177,8 @@ runs: "${{steps.arch_flags.outputs.cmake}}" "${{steps.pick_compiler.outputs.c_compiler}}" "${{steps.pick_compiler.outputs.cxx_compiler}}" + ${{ steps.pick_compiler.outputs.c_compiler_target }} + ${{ steps.pick_compiler.outputs.cxx_compiler_target }} "${{steps.determine_cross_compile.outputs.system_name}}" "${{steps.pick_generator.outputs.generator}}" ${{steps.install_prefix.outputs.install_path}} diff --git a/.github/scripts/determine_compiler.sh b/.github/scripts/determine_compiler.sh index 302d25c6..f93bf1a9 100755 --- a/.github/scripts/determine_compiler.sh +++ b/.github/scripts/determine_compiler.sh @@ -41,6 +41,12 @@ echo "Compiler Family: '${compiler_kind}'" if [[ "${compiler_kind}" == "clang" ]]; then c_compiler="clang" cxx_compiler="clang++" + if [[ -n "${target_system_name}" ]]; then + # In CI we only cross-compile to linux for now + compiler_target="${target_arch}-linux-gnu" + echo "c_compiler_target=-DCMAKE_C_COMPILER_TARGET=${compiler_target}" >> "$GITHUB_OUTPUT" + echo "cxx_compiler_target=-DCMAKE_CXX_COMPILER_TARGET=${compiler_target}" >> "$GITHUB_OUTPUT" + fi elif [[ "${compiler_kind}" == "msvc" ]]; then c_compiler="cl" cxx_compiler="cl" @@ -55,5 +61,5 @@ elif [[ "${compiler_kind}" == "gcc" ]]; then fi echo "Chose C compiler: '${c_compiler}'" echo "Chose C++ compiler: '${cxx_compiler}'" -echo "c_compiler=-DCMAKE_C_COMPILER=${c_compiler}" >> $GITHUB_OUTPUT -echo "cxx_compiler=-DCMAKE_CXX_COMPILER=${cxx_compiler}" >> $GITHUB_OUTPUT +echo "c_compiler=-DCMAKE_C_COMPILER=${c_compiler}" >> "$GITHUB_OUTPUT" +echo "cxx_compiler=-DCMAKE_CXX_COMPILER=${cxx_compiler}" >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 60d1f803..c7c69578 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -28,6 +28,19 @@ jobs: os: windows-2019 rust: 1.46.0 + test_legacy_stable: + name: Legacy CMake + stable Rust + uses: ./.github/workflows/test_legacy.yaml + strategy: + fail-fast: false + matrix: + os: + - windows-2019 # windows-latest is currently not having a supported MSVC compiler + - ubuntu-20.04 + - macos-12 + with: + os: ${{ matrix.os }} + rust: stable test: name: Test Corrosion @@ -90,6 +103,20 @@ jobs: cmake: 3.20.0 rust: 1.54 generator: ninja-multiconfig + # Test cross-compiling with clang and bash script + - os: ubuntu-latest + arch: aarch64 + abi: gnu + cmake: 3.20.6 + rust: 1.68.1 + compiler: clang + # Test cross-compiling with clang and rust wrapper + - os: ubuntu-latest + arch: aarch64 + abi: gnu + cmake: 3.15.7 + rust: 1.68.1 + compiler: clang exclude: @@ -305,6 +332,7 @@ jobs: - test_legacy_linux - test_legacy_mac - test_legacy_windows + - test_legacy_stable - test - test_msvc - test_cxxbridge diff --git a/CMakeLists.txt b/CMakeLists.txt index c23d7b5d..50c3c0f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,8 @@ project(Corrosion HOMEPAGE_URL "https://corrosion-rs.github.io/corrosion/" ) +message(STATUS "Main project CMAKE_C_COMPILER_TARGET: ${CMAKE_C_COMPILER_TARGET}") + # Default behavior: # - If the project is being used as a subdirectory, then don't build tests and # don't enable any languages. diff --git a/RELEASES.md b/RELEASES.md index 993cd432..4a10841d 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,9 @@ +# Unreleased + +### Fixes + +- Fix the PROFILE option with CMake < 3.19 [#427] + # 0.4.2 (2023-07-16) ### Fixes diff --git a/cmake/Corrosion.cmake b/cmake/Corrosion.cmake index 70c3160e..2c82e528 100644 --- a/cmake/Corrosion.cmake +++ b/cmake/Corrosion.cmake @@ -662,6 +662,129 @@ else() set(_CORR_PROP_HOST_BUILD INTERFACE_CORROSION_USE_HOST_BUILD CACHE INTERNAL "") endif() +function(_corrosion_create_linker_wrapper lang out_compiler_wrapper_path) + if(NOT lang MATCHES "^(C|CXX)$") + message(FATAL_ERROR "Internal corrosion error in _corrosion_create_linker_wrapper: lang was ${lang}") + endif() + set(COMPILER_DRIVER "${CMAKE_${lang}_COMPILER}") + set(COMPILER_TARGET "${CMAKE_${lang}_COMPILER_TARGET}") + message(STATUS "Creating linker wrapper script to fix cross-linking with `${COMPILER_DRIVER}` for target `${COMPILER_TARGET}`") + set("bash_wrapper_template" +[==[#!/usr/bin/env bash + +@COMPILER_DRIVER@ --target=@COMPILER_TARGET@ "${@}" +]==] + ) + set(rust_wrapper_template +[==[ +use std::process::Command; + +fn main() { + let mut args = std::env::args_os(); + // Strip the first arg (name of self) so we get the same as "${@}" with bash + let _our_name = args.next().expect("Corrosion linker driver called with no arguments"); + let mut handle = Command::new("@COMPILER_DRIVER@") + .arg("--target=@COMPILER_TARGET@") + .args(args) + .spawn() + .expect("Failed to spawn"); + let res = handle.wait().expect("Command wasn't running"); + let exit_code = res.code().unwrap_or(127); + std::process::exit(exit_code); +} + +]==] +) + set(rust_cargo_toml_template + [==[[package] +name = "wrapper" +version = "0.1.0" +edition = "2018" + +[[bin]] +name = "compiler-driver" +path = "main.rs" +]==] + ) + set(compiler_driver_dir "${CMAKE_CURRENT_BINARY_DIR}/corrosion/compiler_driver/${lang}") + file(MAKE_DIRECTORY "${compiler_driver_dir}") + # rustc linker-flavor inference parses the linker driver name, so we use the same name as the original + get_filename_component(COMPILER_NAME "${COMPILER_DRIVER}" NAME) + + if(CMAKE_HOST_WIN32 OR (CMAKE_VERSION VERSION_LESS "3.20")) + set(compiler_driver_main_rs "${compiler_driver_dir}/main.rs") + set(compiler_driver_cargo_toml "${compiler_driver_dir}/Cargo.toml") + + file(WRITE "${compiler_driver_main_rs}.in" "${rust_wrapper_template}") + file(WRITE "${compiler_driver_cargo_toml}.in" "${rust_cargo_toml_template}") + configure_file("${compiler_driver_main_rs}.in" "${compiler_driver_main_rs}" @ONLY) + configure_file("${compiler_driver_cargo_toml}.in" "${compiler_driver_cargo_toml}" @ONLY) + + # The name in the Cargo.toml may not contain certain characters, e.g. `clang++` is not valid. + # As a workaround we copy to the required filename after building. + set(compiler_driver_artifact_path "${compiler_driver_dir}/target/release/compiler-driver") + set(compiler_driver_path "${compiler_driver_dir}/${COMPILER_NAME}") + execute_process( + COMMAND ${CMAKE_COMMAND} -E env + "CARGO_BUILD_RUSTC=${_CORROSION_RUSTC}" + "${_CORROSION_CARGO}" + build --release + COMMAND_ECHO "STDOUT" + # OUTPUT_FILE "${compiler_driver_dir}/build_stdout.log" + # ERROR_FILE "${compiler_driver_dir}/build_stderr.log" + WORKING_DIRECTORY "${compiler_driver_dir}" + RESULT_VARIABLE build_compiler_wrapper_res + ) + if(NOT build_compiler_wrapper_res EQUAL "0") + message(FATAL_ERROR "Failed to compile linker wrapper script in ${compiler_driver_dir} with ${build_compiler_wrapper_res}") + endif() + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy_if_different "${compiler_driver_artifact_path}" "${compiler_driver_path}" + COMMAND_ECHO "STDOUT" + # OUTPUT_FILE "${compiler_driver_dir}/build_stdout.log" + # ERROR_FILE "${compiler_driver_dir}/build_stderr.log" + WORKING_DIRECTORY "${compiler_driver_dir}" + RESULT_VARIABLE build_compiler_wrapper_res + ) + if(NOT build_compiler_wrapper_res EQUAL "0") + message(FATAL_ERROR "Failed to copy linker driver to ${compiler_driver_path}: ${build_compiler_wrapper_res}") + endif() + if(CMAKE_HOST_WIN32) + set(compiler_driver_path "${compiler_driver_path}.exe") + endif() + else() + # requires CMake 3.20 + + set(compiler_driver_path "${compiler_driver_dir}/${COMPILER_NAME}") + file(CONFIGURE OUTPUT "${compiler_driver_path}" + CONTENT "${bash_wrapper_template}" + @ONLY + ) + file(CHMOD "${compiler_driver_path}" "${compiler_driver_dir}" + FILE_PERMISSIONS + "OWNER_READ" + "OWNER_WRITE" + "OWNER_EXECUTE" + "GROUP_READ" + "GROUP_EXECUTE" + "WORLD_READ" + "WORLD_EXECUTE" + ) + endif() + set("${out_compiler_wrapper_path}" "${compiler_driver_path}" PARENT_SCOPE) +endfunction() + +if(Rust_CROSSCOMPILING AND (CMAKE_C_COMPILER_TARGET OR CMAKE_CXX_COMPILER_TARGET)) + if(CMAKE_C_COMPILER_TARGET) + _corrosion_create_linker_wrapper(C c_linker_driver) + set(_CORR_CROSS_C_LINKER_DRIVER "${c_linker_driver}" CACHE INTERNAL "" FORCE) + endif() + if(CMAKE_CXX_COMPILER_TARGET) + _corrosion_create_linker_wrapper(CXX cxx_linker_driver) + set(_CORR_CROSS_CXX_LINKER_DRIVER "${cxx_linker_driver}" CACHE INTERNAL "" FORCE) + endif() +endif() + # Add custom command to build one target in a package (crate) # # A target may be either a specific bin @@ -851,19 +974,30 @@ function(_add_cargo_build out_cargo_build_out_dir) set(cargo_target_linker $<$:${cargo_target_linker_var}=${linker}>) if(Rust_CROSSCOMPILING AND (CMAKE_C_COMPILER_TARGET OR CMAKE_CXX_COMPILER_TARGET)) - set(linker_target_triple "$,${CMAKE_CXX_COMPILER_TARGET},${CMAKE_C_COMPILER_TARGET}>") - set(rustflag_linker_arg "-Clink-args=--target=${linker_target_triple}") - set(rustflag_linker_arg "$<${if_not_host_build_condition}:${rustflag_linker_arg}>") - # 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}" "$<$:${rustflag_linker_arg}>") + set(cross_linker "$,${_CORR_CROSS_CXX_LINKER_DRIVER},${_CORR_CROSS_C_LINKER_DRIVER}>") + set(cross_linker "$<${if_not_host_build_condition}:${cross_linker}>") + set(linker "$") + set(cargo_target_linker $<$:${cargo_target_linker_var}=${linker}>) + else() + message(STATUS "Not adding CC args") endif() message(DEBUG "TARGET ${target_name} produces byproducts ${byproducts}") add_custom_target( _cargo-build_${target_name} + COMMAND + ${CMAKE_COMMAND} -E echo + "Environment variables..." + "${build_env_variable_genex}" + "${global_rustflags_genex}" + "${cargo_target_linker}" + "${corrosion_cc_rs_flags}" + "${cargo_library_path}" + COMMAND + ${CMAKE_COMMAND} -E echo + "local rustflags: ${local_rustflags_genex}" + # Build crate COMMAND ${CMAKE_COMMAND} -E env @@ -1022,8 +1156,6 @@ function(corrosion_import_crate) " cannot predict. Please consider using a custom cargo profile which inherits from the" " built-in profile instead." ) - else() - set(cargo_profile_native_generator --profile=${COR_PROFILE}) endif() endif() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index fd036e70..16776647 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -5,6 +5,9 @@ if(NOT CORROSION_TESTS) return() endif() +message(STATUS "Main project tests CMAKE_C_COMPILER_TARGET: ${CMAKE_C_COMPILER_TARGET}") + + option(CORROSION_TESTS_CXXBRIDGE "Build cxxbridge tests which requires cxxbridge executable being available" OFF) @@ -87,6 +90,7 @@ function(corrosion_tests_add_test test_name bin_names) set(test_dir "${test_name}") endif() + message(STATUS "corrosion_tests_add_test CMAKE_C_COMPILER_TARGET: ${CMAKE_C_COMPILER_TARGET}") if(CMAKE_C_COMPILER) set(TEST_C_COMPILER "C_COMPILER" "${CMAKE_C_COMPILER}") @@ -94,6 +98,13 @@ function(corrosion_tests_add_test test_name bin_names) if(CMAKE_CXX_COMPILER) set(TEST_CXX_COMPILER "CXX_COMPILER" "${CMAKE_CXX_COMPILER}") endif() + if(CMAKE_C_COMPILER_TARGET) + set(TEST_C_COMPILER_TARGET "C_COMPILER_TARGET" "${CMAKE_C_COMPILER_TARGET}") + endif() + if(CMAKE_CXX_COMPILER_TARGET) + set(TEST_CXX_COMPILER_TARGET "CXX_COMPILER_TARGET" "${CMAKE_CXX_COMPILER_TARGET}") + endif() + message(STATUS "before add test: TEST_C_COMPILER_TARGET: ${TEST_C_COMPILER_TARGET}") if(CMAKE_GENERATOR_PLATFORM) set(TEST_GENERATOR_PLATFORM "GENERATOR_PLATFORM" "${CMAKE_GENERATOR_PLATFORM}") endif() @@ -117,6 +128,8 @@ function(corrosion_tests_add_test test_name bin_names) "${TEST_SYSTEM_NAME}" "${TEST_C_COMPILER}" "${TEST_CXX_COMPILER}" + "${TEST_C_COMPILER_TARGET}" + "${TEST_CXX_COMPILER_TARGET}" "${TEST_GENERATOR_PLATFORM}" "${TEST_GENERATOR_BIN}" ${pass_through_arguments} diff --git a/test/ConfigureAndBuild.cmake b/test/ConfigureAndBuild.cmake index 513e506e..7ae3588b 100644 --- a/test/ConfigureAndBuild.cmake +++ b/test/ConfigureAndBuild.cmake @@ -18,6 +18,8 @@ set(oneValueArgs C_COMPILER CXX_COMPILER SYSTEM_NAME + C_COMPILER_TARGET + CXX_COMPILER_TARGET EXTERNAL_CORROSION_GENERATOR CARGO_PROFILE ) @@ -25,6 +27,7 @@ set(multiValueArgs "PASS_THROUGH_ARGS") cmake_parse_arguments(TEST "${options}" "${oneValueArgs}" "${multiValueArgs}" ${TEST_ARG_LIST} ) +message(STATUS "ConfigureAndBuild unparsed arguments: ${TEST_UNPARSED_ARGUMENT}") if(TEST_CARGO_TARGET) set(TEST_Rust_CARGO_TARGET "-DRust_CARGO_TARGET=${TEST_CARGO_TARGET}") endif() @@ -40,6 +43,14 @@ endif() if(TEST_CXX_COMPILER) set(TEST_CXX_COMPILER "-DCMAKE_CXX_COMPILER=${TEST_CXX_COMPILER}") endif() +message(STATUS "TEST_C_COMPILER_TARGET before if: ${TEST_C_COMPILER_TARGET}, cxx: ${TEST_CXX_COMPILER_TARGET}") +if(TEST_C_COMPILER_TARGET) + set(TEST_C_COMPILER_TARGET "-DCMAKE_C_COMPILER_TARGET=${TEST_C_COMPILER_TARGET}") +endif() +if(TEST_CXX_COMPILER_TARGET) + set(TEST_CXX_COMPILER_TARGET "-DCMAKE_CXX_COMPILER_TARGET=${TEST_CXX_COMPILER_TARGET}") +endif() +message(STATUS "TEST_C_COMPILER_TARGET: ${TEST_C_COMPILER_TARGET}") if(TEST_SYSTEM_NAME) set(TEST_SYSTEM_NAME "-DCMAKE_SYSTEM_NAME=${TEST_SYSTEM_NAME}") endif() @@ -70,6 +81,8 @@ execute_process( ${TEST_GENERATOR_PLATFORM} ${TEST_C_COMPILER} ${TEST_CXX_COMPILER} + ${TEST_C_COMPILER_TARGET} + ${TEST_CXX_COMPILER_TARGET} ${TEST_SYSTEM_NAME} ${TEST_EXTERNAL_CORROSION_GENERATOR} ${TEST_CARGO_PROFILE} @@ -92,6 +105,7 @@ if ("${TEST_GENERATOR}" STREQUAL "Ninja Multi-Config" COMMAND "${CMAKE_COMMAND}" --build "${TEST_BINARY_DIR}" --config "${config}" + --verbose COMMAND_ECHO STDOUT RESULT_VARIABLE EXIT_CODE ) @@ -102,7 +116,7 @@ if ("${TEST_GENERATOR}" STREQUAL "Ninja Multi-Config" endforeach() else() execute_process( - COMMAND "${CMAKE_COMMAND}" --build "${TEST_BINARY_DIR}" + COMMAND "${CMAKE_COMMAND}" --build "${TEST_BINARY_DIR}" --verbose COMMAND_ECHO STDOUT RESULT_VARIABLE EXIT_CODE ) diff --git a/test/multitarget/multitarget/CMakeLists.txt b/test/multitarget/multitarget/CMakeLists.txt index 0d7a4102..4bba266d 100644 --- a/test/multitarget/multitarget/CMakeLists.txt +++ b/test/multitarget/multitarget/CMakeLists.txt @@ -10,3 +10,4 @@ set_property(TARGET cpp-lib4 PROPERTY POSITION_INDEPENDENT_CODE ON) corrosion_link_libraries(bin1 cpp-lib4) corrosion_link_libraries(bin2 cpp-lib4) corrosion_link_libraries(bin3 cpp-lib4) +corrosion_link_libraries(multitarget_lib cpp-lib4) diff --git a/test/output directory/CMakeLists.txt b/test/output directory/CMakeLists.txt index 3cd92e47..cb15d594 100644 --- a/test/output directory/CMakeLists.txt +++ b/test/output directory/CMakeLists.txt @@ -11,6 +11,15 @@ endif() if(CMAKE_GENERATOR_PLATFORM) set(TEST_GENERATOR_PLATFORM "GENERATOR_PLATFORM" "${CMAKE_GENERATOR_PLATFORM}") endif() +if(CMAKE_C_COMPILER_TARGET) + set(TEST_C_COMPILER_TARGET "C_COMPILER_TARGET" "${CMAKE_C_COMPILER_TARGET}") +endif() +if(CMAKE_CXX_COMPILER_TARGET) + set(TEST_CXX_COMPILER_TARGET "CXX_COMPILER_TARGET" "${CMAKE_CXX_COMPILER_TARGET}") +endif() +if(CMAKE_CROSSCOMPILING) + set(TEST_SYSTEM_NAME SYSTEM_NAME "${CMAKE_SYSTEM_NAME}") +endif() add_test(NAME "output_directory_build" COMMAND @@ -25,6 +34,9 @@ add_test(NAME "output_directory_build" "${TEST_C_COMPILER}" "${TEST_CXX_COMPILER}" "${TEST_GENERATOR_PLATFORM}" + "${TEST_C_COMPILER_TARGET}" + "${TEST_CXX_COMPILER_TARGET}" + "${TEST_SYSTEM_NAME}" COMMAND_EXPAND_LISTS )