diff --git a/.ci/build.py b/.ci/build.py index 75eefcce36b..cb3e00cf6b5 100644 --- a/.ci/build.py +++ b/.ci/build.py @@ -58,6 +58,21 @@ platforms=["linux"], build_dir="build/posix-freertos", ), + "posix-rust": BuildOpTpl( + config_cmd="cmake --preset posix-rust", + build_cmd="cmake --build --preset posix-rust", + configs=["Debug", "Release"], + platforms=["linux"], + build_dir="build/posix-rust", + ), + "s32k148-rust-gcc": BuildOpTpl( + config_cmd="cmake --preset s32k148-rust-gcc", + build_cmd="cmake --build --preset s32k148-rust-gcc", + configs=["Debug", "Release", "RelWithDebInfo"], + platforms=["arm"], + cxxids=["gcc"], + build_dir="build/s32k148-rust-gcc", + ), "s32k148-freertos-gcc": BuildOpTpl( config_cmd="cmake --preset s32k148-freertos-gcc", build_cmd="cmake --build --preset s32k148-freertos-gcc", diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5723b3d11bd..f6419c3546c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,7 +8,7 @@ jobs: strategy: # max-parallel: 1 matrix: - preset: [ "tests-posix-debug", "tests-posix-release", "tests-s32k1xx-debug", "tests-s32k1xx-release", "posix-freertos", "posix-threadx", "posix-freertos-with-tracing", "s32k148-freertos-gcc", "s32k148-threadx-gcc", "s32k148-freertos-clang", "s32k148-threadx-clang"] + preset: [ "tests-posix-debug", "tests-posix-release", "tests-s32k1xx-debug", "tests-s32k1xx-release", "posix-freertos", "posix-threadx", "posix-freertos-with-tracing", "posix-rust", "s32k148-freertos-gcc", "s32k148-threadx-gcc", "s32k148-freertos-clang", "s32k148-threadx-clang", "s32k148-rust-gcc" ] platform: [ "arm", "linux" ] config: [ "Debug", "Release", "RelWithDebInfo" ] cxxid: ["gcc", "clang"] @@ -53,14 +53,23 @@ jobs: - preset: "posix-freertos-with-tracing" config: "RelWithDebInfo" + - preset: "posix-rust" + platform: "arm" + - preset: "posix-rust" + config: "RelWithDebInfo" + - preset: "s32k148-freertos-gcc" platform: "linux" - preset: "s32k148-threadx-gcc" platform: "linux" + - preset: "s32k148-rust-gcc" + platform: "linux" - preset: "s32k148-freertos-gcc" cxxid: "clang" - preset: "s32k148-threadx-gcc" cxxid: "clang" + - preset: "s32k148-rust-gcc" + cxxid: "clang" - preset: "s32k148-freertos-clang" platform: "linux" diff --git a/CMakeLists.txt b/CMakeLists.txt index f4faa54ef70..8c0c3033b32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,6 +74,8 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules") option(BUILD_TRACING "Build CTF tracing" OFF) +option(BUILD_RUST "Build Rust components" OFF) + add_compile_options( #[[ Supressing stringop-overflow and maybe-uninitialized, as they are often @@ -82,6 +84,26 @@ add_compile_options( "$<$:-Wno-error=stringop-overflow;-Wno-error=maybe-uninitialized>" ) +# Rust support Note: Only one static Rust library can be linked in the final +# binary, otherwise the linker will complain about duplicate symbol definitions +# from the Rust core crate. +if (BUILD_RUST) + # Set Rust target for cross-compilation (ARM Cortex-M4F for S32K148) + if (BUILD_TARGET_PLATFORM STREQUAL "S32K148EVB") + set(Rust_CARGO_TARGET + "thumbv7em-none-eabihf" + CACHE STRING "Rust target triple") + endif () + + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libs/3rdparty/corrosion) + + corrosion_import_crate( + MANIFEST_PATH + ${CMAKE_CURRENT_SOURCE_DIR}/executables/referenceApp/rustHelloWorld/Cargo.toml + ) + +endif () + if (BUILD_EXECUTABLE STREQUAL "unitTest") include(GoogleTest) include(CTest) diff --git a/CMakePresets.json b/CMakePresets.json index 2fc1b3eda6d..ec6272009d2 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -85,6 +85,39 @@ "BUILD_TARGET_RTOS": "THREADX" } }, + { + "name": "posix-rust", + "displayName": "POSIX with Rust configuration and FreeRTOS", + "description": "Configure for POSIX-compliant environment with Rust support enabled, gcc and FreeRTOS", + "inherits": "_config-base", + "binaryDir": "${sourceDir}/build/${presetName}", + "cacheVariables": { + "BUILD_EXECUTABLE": "referenceApp", + "BUILD_RUST": "ON", + "BUILD_TARGET_PLATFORM": "POSIX", + "BUILD_TARGET_RTOS": "FREERTOS" + } + }, + { + "name": "s32k148-rust-gcc", + "generator": "Ninja Multi-Config", + "displayName": "S32K148 with Rust configuration and FreeRTOS", + "description": "Configure for S32K148 platform with Rust support enabled, gcc and FreeRTOS", + "inherits": "_config-base", + "toolchainFile": "${sourceDir}/cmake/toolchains/ArmNoneEabi-gcc.cmake", + "binaryDir": "${sourceDir}/build/${presetName}", + "cacheVariables": { + "BUILD_EXECUTABLE": "referenceApp", + "BUILD_RUST": "ON", + "BUILD_TARGET_PLATFORM": "S32K148EVB", + "BUILD_TARGET_RTOS": "FREERTOS", + "CMAKE_ASM_FLAGS_RELWITHDEBINFO": "-g3", + "CMAKE_CONFIGURATION_TYPES": "RelWithDebInfo;Debug;Release", + "CMAKE_C_FLAGS_RELWITHDEBINFO": "-g3 -O2 -DNDEBUG", + "CMAKE_CXX_FLAGS_RELWITHDEBINFO": "-g3 -O2 -DNDEBUG", + "CMAKE_DEFAULT_BUILD_TYPE": "RelWithDebInfo" + } + }, { "name": "s32k148-freertos-gcc", "generator": "Ninja Multi-Config", @@ -207,6 +240,18 @@ "description": "Build reference application for POSIX-compliant environment (Release by default; for Debug use --config Debug)", "configurePreset": "posix-threadx" }, + { + "name": "posix-rust", + "displayName": "build POSIX with Rust build and FreeRTOS", + "description": "Build reference application for POSIX-compliant environment with Rust support, gcc and FreeRTOS (Release by default; for Debug use --config Debug)", + "configurePreset": "posix-rust" + }, + { + "name": "s32k148-rust-gcc", + "displayName": "S32K148 with Rust build and FreeRTOS", + "description": "Build reference application for S32K148 platform with Rust support, gcc and FreeRTOS", + "configurePreset": "s32k148-rust-gcc" + }, { "name": "s32k148-freertos-gcc", "displayName": "S32K148 FreeRTOS build (GCC)", diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000000..86f9b846f51 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "rust_hello_world" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000000..5c10ed99ff5 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,30 @@ +[workspace] +resolver = "3" + +members = [ + "executables/referenceApp/rustHelloWorld", +] + +[workspace.package] +version = "0.1.0" +documentation = "https://eclipse-openbsw.github.io/openbsw/" + +# Workspace dependencies - add new Rust crates here as they are developed +[workspace.dependencies] + +# Similar to C++ we always build optimized (matching C++ -O2) +[profile.dev] +panic = "abort" +lto = true +opt-level = 2 +incremental = false +codegen-units = 1 +debug = true + +[profile.release] +panic = "abort" +lto = true +opt-level = 2 +incremental = false +codegen-units = 1 +debug = true diff --git a/NOTICE.md b/NOTICE.md index 06114f921a0..78acff4f633 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -34,6 +34,7 @@ We recommend to read their licenses, as their terms may differ from the terms de | Project | Version | License | Path | |---------------------------|---------|-----------|----------------------------------------------------------------------| +| Corrosion | 0.6 | MIT | ``libs/3rdparty/corrosion/LICENSE`` | | ETL | 20.45.0 | MIT | ``libs/3rdparty/etl/LICENSE`` | | LwIP | 2.2.1 | BSD-3 | ``libs/3rdparty/lwip/COPYING`` | | googletest | 1.12.1 | BSD-3 | ``libs/3rdparty/googletest/LICENSE`` | diff --git a/doc/dev/guidelines/3rdparty.rst b/doc/dev/guidelines/3rdparty.rst index a67b24e2a00..c0c66ec4b1f 100644 --- a/doc/dev/guidelines/3rdparty.rst +++ b/doc/dev/guidelines/3rdparty.rst @@ -5,6 +5,7 @@ Third party libraries under the project root's ``libs/3rdparty`` are recommended to be maintained by `RIM `, if possible: +* ``corrosion`` * ``etl`` * ``googletest`` * ``lwip`` diff --git a/doc/dev/learning/setup/setup_posix_build.rst b/doc/dev/learning/setup/setup_posix_build.rst index e376c490679..267d7c720c2 100644 --- a/doc/dev/learning/setup/setup_posix_build.rst +++ b/doc/dev/learning/setup/setup_posix_build.rst @@ -75,3 +75,24 @@ You should be able to run and see output like this in your shell terminal... Press ``CTRL-C`` should exit the running application. Now that you can build the code and run it, you can explore the code, make changes and learn how it works. + +Optional: Rust Support +---------------------- + +To build OpenBSW with Rust components for the POSIX platform, you need: + +1. The build tools set up as described above (gcc, cmake, make) +2. The Rust compiler + +Install Rust 1.90.0 to be compatible with the CI builds: + +.. code-block:: bash + + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain 1.90.0 + +Then build using the Rust preset: + +.. code-block:: bash + + cmake --preset posix-rust + cmake --build --preset posix-rust --parallel diff --git a/doc/dev/learning/setup/setup_s32k148_ubuntu_build.rst b/doc/dev/learning/setup/setup_s32k148_ubuntu_build.rst index 7fd509bfdf4..b2a98ba1744 100644 --- a/doc/dev/learning/setup/setup_s32k148_ubuntu_build.rst +++ b/doc/dev/learning/setup/setup_s32k148_ubuntu_build.rst @@ -107,4 +107,26 @@ The build files should be written to a new subdirectory named ``build/s32k148-gc and the built executable should be found at ``build/s32k148-clang/executables/referenceApp/application/RelWithDebInfo/app.referenceApp.elf`` which you can flash on the S32K148 development board. +Optional: Rust Support +---------------------- + +To build OpenBSW with Rust components for the S32K148 platform, you need: + +1. The GCC toolchain set up as described in `Using the GCC toolchain`_ above (including CC and CXX environment variables) +2. The Rust compiler with the ARM cross-compilation target + +Install Rust 1.90.0 to be compatible with the CI builds and add the ARM target: + +.. code-block:: bash + + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain 1.90.0 + rustup target add thumbv7em-none-eabihf + +Then, with the GCC toolchain environment variables set, build using the Rust preset: + +.. code-block:: bash + + cmake --preset s32k148-rust-gcc + cmake --build --preset s32k148-rust-gcc + Next :doc:`setup_s32k148_ubuntu_nxpide` diff --git a/docker/development/Dockerfile b/docker/development/Dockerfile index 55ada9d5c93..54d8cd2a2ab 100644 --- a/docker/development/Dockerfile +++ b/docker/development/Dockerfile @@ -73,6 +73,14 @@ RUN tar -xf treefmt.tar.gz \ RUN gem install esr-rim + +ENV RUSTUP_HOME=/opt/rustup +ENV CARGO_HOME=/opt/cargo +ENV PATH=/opt/cargo/bin:${PATH} +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.90.0 --profile minimal \ + && rustup target add thumbv7em-none-eabihf \ + && cargo install cbindgen --version 0.27.0 --locked + RUN python3 -m venv /opt/venv ENV PATH=/opt/venv/bin:${PATH} RUN --mount=type=bind,source=files/requirements.lock,target=/tmp/requirements.lock pip3 install -r /tmp/requirements.lock diff --git a/executables/referenceApp/application/CMakeLists.txt b/executables/referenceApp/application/CMakeLists.txt index 764feb6cb8f..dcee58d8b46 100644 --- a/executables/referenceApp/application/CMakeLists.txt +++ b/executables/referenceApp/application/CMakeLists.txt @@ -112,3 +112,13 @@ endif () if (PLATFORM_SUPPORT_ROM_CHECK) target_link_libraries(app.referenceApp PRIVATE safeMemory) endif () + +if (BUILD_RUST) + target_compile_definitions(app.referenceApp PRIVATE BUILD_RUST) + # Link against Rust static library(should be only one static library) + target_link_libraries(app.referenceApp PRIVATE rust_hello_world) + # Add include directory for Rust C/C++ headers + target_include_directories( + app.referenceApp + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../rustHelloWorld/include) +endif () diff --git a/executables/referenceApp/application/src/app/app.cpp b/executables/referenceApp/application/src/app/app.cpp index 28f2e4570bb..e8a5f411974 100644 --- a/executables/referenceApp/application/src/app/app.cpp +++ b/executables/referenceApp/application/src/app/app.cpp @@ -51,6 +51,12 @@ #include #include +#include + +#ifdef BUILD_RUST +#include +#endif + alignas(32)::async::internal::Stack safetyStack; #ifdef PLATFORM_SUPPORT_CAN @@ -214,6 +220,10 @@ void run() { staticInit(); etl::print("hello\r\n"); +#ifdef BUILD_RUST + etl::print("Hello Rust!\r\n"); + etl::print("Rust add(3, 4) = {}\r\n", static_cast(rust_add(3U, 4U))); +#endif idleHandler.init(); AsyncAdapter::run(AsyncAdapter::StartAppFunctionType::create<&startApp>()); } diff --git a/executables/referenceApp/rustHelloWorld/Cargo.toml b/executables/referenceApp/rustHelloWorld/Cargo.toml new file mode 100644 index 00000000000..9630dc5135f --- /dev/null +++ b/executables/referenceApp/rustHelloWorld/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "rust_hello_world" +version.workspace = true +documentation.workspace = true +edition = "2024" + +[lib] +crate-type = ["staticlib"] + +[dependencies] + diff --git a/executables/referenceApp/rustHelloWorld/include/rust_hello_world.h b/executables/referenceApp/rustHelloWorld/include/rust_hello_world.h new file mode 100644 index 00000000000..52fcdf59ea5 --- /dev/null +++ b/executables/referenceApp/rustHelloWorld/include/rust_hello_world.h @@ -0,0 +1,24 @@ +// Copyright 2026 Accenture. + +#ifndef RUST_HELLO_WORLD_H +#define RUST_HELLO_WORLD_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/// Adds two numbers and returns the result. +/// +/// \param a First number to add +/// \param b Second number to add +/// \return The sum of a and b +uint32_t rust_add(uint32_t a, uint32_t b); + +#ifdef __cplusplus +} +#endif + +#endif // RUST_HELLO_WORLD_H diff --git a/executables/referenceApp/rustHelloWorld/src/lib.rs b/executables/referenceApp/rustHelloWorld/src/lib.rs new file mode 100644 index 00000000000..292f8559bdb --- /dev/null +++ b/executables/referenceApp/rustHelloWorld/src/lib.rs @@ -0,0 +1,47 @@ +// Copyright 2026 Accenture. + +//! A simple "Hello World" Rust library demonstrating Rust integration with OpenBSW. +//! +//! This crate provides a minimal example of how to expose Rust functions to C++ code +//! in the OpenBSW build system. +//! +//! # FFI Approach +//! +//! This example uses the **manual FFI approach**, where: +//! - Rust functions are marked with `#[no_mangle]` and `extern "C"` +//! - A corresponding C/C++ header file is written by hand +//! +//! This is not the only way to expose Rust to C++. Alternative approaches include: +//! - **[cbindgen](https://github.com/mozilla/cbindgen)**: Automatically generates C/C++ headers from Rust code +//! - **[cxx](https://cxx.rs/)**: Provides safe bidirectional interop between Rust and C++ +//! +//! The manual approach was chosen here for simplicity. +//! +//! # Target Compatibility +//! +//! Uses `no_std` for compatibility with both POSIX and embedded targets. + +#![no_std] + +/// Panic handler for no_std environments. +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} + + + +/// Adds two numbers and returns the result. +/// +/// # Arguments +/// +/// * `a` - First number to add +/// * `b` - Second number to add +/// +/// # Returns +/// +/// The sum of `a` and `b`. +#[unsafe(no_mangle)] +pub extern "C" fn rust_add(a: u32, b: u32) -> u32 { + a.wrapping_add(b) +} diff --git a/libs/3rdparty/corrosion/.github/FUNDING.yml b/libs/3rdparty/corrosion/.github/FUNDING.yml new file mode 100644 index 00000000000..a36eb8cfc07 --- /dev/null +++ b/libs/3rdparty/corrosion/.github/FUNDING.yml @@ -0,0 +1 @@ +github: ["jschwe"] diff --git a/libs/3rdparty/corrosion/.github/ISSUE_TEMPLATE/bug_report.yml b/libs/3rdparty/corrosion/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 00000000000..22bda5e7d56 --- /dev/null +++ b/libs/3rdparty/corrosion/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,81 @@ +name: Bug Report +description: File a bug report +title: "[Bug]: " +labels: ["bug", "triage"] +assignees: + - jschwe +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + - type: textarea + attributes: + label: Current Behavior + description: A concise description of what you're experiencing. + validations: + required: false + - type: textarea + attributes: + label: Expected Behavior + description: A concise description of what you expected to happen. + validations: + required: false + - type: textarea + attributes: + label: Steps To Reproduce + description: Steps to reproduce the behavior. + placeholder: | + 1. In this environment... + 2. With this config... + 3. Run '...' + 4. See error... + validations: + required: false + - type: textarea + attributes: + label: Environment + description: | + examples: + - **OS**: Ubuntu 22.04 + - **CMake**: 3.22.0 + - **CMake Generator**: Ninja 1.11 + value: | + - OS: + - CMake: + - CMake Generator: + render: markdown + validations: + required: false + - type: textarea + attributes: + label: CMake configure log with Debug log-level + description: | + Output when configuring with `cmake -S -B --log-level=DEBUG `: +
CMake configure log +

+ + ``` + + ``` + +

+
+ validations: + required: false + - type: textarea + attributes: + label: CMake Build step log + description: | + Output when building with `cmake --build --verbose`: +
CMake build log +

+ + ``` + + ``` + +

+
+ validations: + required: false diff --git a/libs/3rdparty/corrosion/.github/scripts/determine_compiler.sh b/libs/3rdparty/corrosion/.github/scripts/determine_compiler.sh new file mode 100755 index 00000000000..302d25c6410 --- /dev/null +++ b/libs/3rdparty/corrosion/.github/scripts/determine_compiler.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash + +compiler_kind="$1" +runner_os="$2" +target_abi="$3" +target_system_name="$4" +target_arch="$5" + +set -e + +if [[ -z "$GITHUB_OUTPUT" ]]; then + echo "Error: This script should only be run in github actions environment" + exit 1 +fi +if [[ -z "${runner_os}" || -z "${target_abi}" || -z "${target_arch}" ]]; then + echo "Error: Not all required parameters where set" + exit 1 +fi +if [[ -z "${compiler_kind}" || "${compiler_kind}" == "default" ]]; then + echo "compiler option was not set. Determining default compiler." + if [[ "${runner_os}" == "Windows" ]]; then + if [[ "${target_abi}" == "msvc" ]]; then + compiler_kind=msvc + elif [[ "${target_abi}" == "gnu" ]]; then + compiler_kind=gcc + else + echo "Unknown abi for Windows: ${target_abi}" + exit 1 + fi + elif [[ "${runner_os}" == "macOS" ]]; then + compiler_kind="clang" + elif [[ "${runner_os}" == "Linux" ]]; then + compiler_kind="gcc" + else + echo "Unknown Runner OS: ${runner_os}" + exit 1 + fi +fi +echo "Compiler Family: '${compiler_kind}'" + +if [[ "${compiler_kind}" == "clang" ]]; then + c_compiler="clang" + cxx_compiler="clang++" +elif [[ "${compiler_kind}" == "msvc" ]]; then + c_compiler="cl" + cxx_compiler="cl" +elif [[ "${compiler_kind}" == "gcc" ]]; then + if [[ -z "${target_system_name}" ]]; then + c_compiler="gcc" + cxx_compiler="g++" + else + c_compiler="${target_arch}-linux-gnu-gcc" + cxx_compiler="${target_arch}-linux-gnu-g++" + fi +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 diff --git a/libs/3rdparty/corrosion/.github/scripts/toolchains/aarch64-apple-darwin-clang.cmake b/libs/3rdparty/corrosion/.github/scripts/toolchains/aarch64-apple-darwin-clang.cmake new file mode 100644 index 00000000000..51fc2e24d0c --- /dev/null +++ b/libs/3rdparty/corrosion/.github/scripts/toolchains/aarch64-apple-darwin-clang.cmake @@ -0,0 +1,5 @@ +set(CMAKE_C_COMPILER "clang") +set(CMAKE_CXX_COMPILER "clang++") +set(CMAKE_C_COMPILER_TARGET "aarch64-apple-darwin") +set(CMAKE_CXX_COMPILER_TARGET "aarch64-apple-darwin") +set(CMAKE_OSX_ARCHITECTURES "arm64" CACHE STRING "") diff --git a/libs/3rdparty/corrosion/.github/scripts/toolchains/aarch64-unknown-linux-gnu-clang.cmake b/libs/3rdparty/corrosion/.github/scripts/toolchains/aarch64-unknown-linux-gnu-clang.cmake new file mode 100644 index 00000000000..901de7130ea --- /dev/null +++ b/libs/3rdparty/corrosion/.github/scripts/toolchains/aarch64-unknown-linux-gnu-clang.cmake @@ -0,0 +1,4 @@ +set(CMAKE_C_COMPILER "clang") +set(CMAKE_CXX_COMPILER "clang++") +set(CMAKE_C_COMPILER_TARGET "aarch64-linux-gnu") +set(CMAKE_CXX_COMPILER_TARGET "aarch64-linux-gnu") diff --git a/libs/3rdparty/corrosion/.github/scripts/toolchains/aarch64-unknown-linux-gnu-gcc.cmake b/libs/3rdparty/corrosion/.github/scripts/toolchains/aarch64-unknown-linux-gnu-gcc.cmake new file mode 100644 index 00000000000..8b5a7e4057d --- /dev/null +++ b/libs/3rdparty/corrosion/.github/scripts/toolchains/aarch64-unknown-linux-gnu-gcc.cmake @@ -0,0 +1,3 @@ +set(CMAKE_C_COMPILER "aarch64-linux-gnu-gcc") +set(CMAKE_CXX_COMPILER "aarch64-linux-gnu-g++") +set(CMAKE_SYSTEM_NAME "Linux") diff --git a/libs/3rdparty/corrosion/.github/scripts/toolchains/i686-unknown-linux-gnu-clang.cmake b/libs/3rdparty/corrosion/.github/scripts/toolchains/i686-unknown-linux-gnu-clang.cmake new file mode 100644 index 00000000000..1e9575b4e56 --- /dev/null +++ b/libs/3rdparty/corrosion/.github/scripts/toolchains/i686-unknown-linux-gnu-clang.cmake @@ -0,0 +1,4 @@ +set(CMAKE_C_COMPILER "clang") +set(CMAKE_CXX_COMPILER "clang++") +set(CMAKE_C_COMPILER_TARGET "i686-pc-linux-gnu") +set(CMAKE_CXX_COMPILER_TARGET "i686-pc-linux-gnu") diff --git a/libs/3rdparty/corrosion/.github/scripts/toolchains/i686-unknown-linux-gnu-gcc.cmake b/libs/3rdparty/corrosion/.github/scripts/toolchains/i686-unknown-linux-gnu-gcc.cmake new file mode 100644 index 00000000000..2871ad5b829 --- /dev/null +++ b/libs/3rdparty/corrosion/.github/scripts/toolchains/i686-unknown-linux-gnu-gcc.cmake @@ -0,0 +1,3 @@ +set(CMAKE_C_COMPILER "i686-linux-gnu-gcc") +set(CMAKE_CXX_COMPILER "i686-linux-gnu-g++") +set(CMAKE_SYSTEM_NAME "Linux") diff --git a/libs/3rdparty/corrosion/.github/scripts/toolchains/x86_64-apple-darwin-clang.cmake b/libs/3rdparty/corrosion/.github/scripts/toolchains/x86_64-apple-darwin-clang.cmake new file mode 100644 index 00000000000..582131e4052 --- /dev/null +++ b/libs/3rdparty/corrosion/.github/scripts/toolchains/x86_64-apple-darwin-clang.cmake @@ -0,0 +1,7 @@ +set(CMAKE_C_COMPILER "clang") +set(CMAKE_CXX_COMPILER "clang++") +set(CMAKE_C_COMPILER_TARGET "x86_64-apple-darwin") +set(CMAKE_CXX_COMPILER_TARGET "x86_64-apple-darwin") +set(CMAKE_SYSTEM_NAME "Darwin") +set(CMAKE_SYSTEM_VERSION ${CMAKE_HOST_SYSTEM_VERSION}) +set(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE STRING "") diff --git a/libs/3rdparty/corrosion/.github/scripts/toolchains/x86_64-pc-windows-gnullvm.cmake b/libs/3rdparty/corrosion/.github/scripts/toolchains/x86_64-pc-windows-gnullvm.cmake new file mode 100644 index 00000000000..a250bcf0df6 --- /dev/null +++ b/libs/3rdparty/corrosion/.github/scripts/toolchains/x86_64-pc-windows-gnullvm.cmake @@ -0,0 +1,4 @@ +set(CMAKE_C_COMPILER "clang") +set(CMAKE_CXX_COMPILER "clang++") +set(CMAKE_C_COMPILER_TARGET "x86_64-pc-windows-gnu") +set(CMAKE_CXX_COMPILER_TARGET "x86_64-pc-windows-gnu") diff --git a/libs/3rdparty/corrosion/.github/scripts/toolchains/x86_64-unknown-linux-gnu-clang.cmake b/libs/3rdparty/corrosion/.github/scripts/toolchains/x86_64-unknown-linux-gnu-clang.cmake new file mode 100644 index 00000000000..2c2d0fa82bb --- /dev/null +++ b/libs/3rdparty/corrosion/.github/scripts/toolchains/x86_64-unknown-linux-gnu-clang.cmake @@ -0,0 +1,3 @@ +# Assumption: This is the native host target. +set(CMAKE_C_COMPILER "clang") +set(CMAKE_CXX_COMPILER "clang++") diff --git a/libs/3rdparty/corrosion/.github/scripts/toolchains/x86_64-unknown-linux-gnu-gcc.cmake b/libs/3rdparty/corrosion/.github/scripts/toolchains/x86_64-unknown-linux-gnu-gcc.cmake new file mode 100644 index 00000000000..82e15f7ef9a --- /dev/null +++ b/libs/3rdparty/corrosion/.github/scripts/toolchains/x86_64-unknown-linux-gnu-gcc.cmake @@ -0,0 +1,3 @@ +# Assumption: This is the native host target. +set(CMAKE_C_COMPILER "gcc") +set(CMAKE_CXX_COMPILER "g++") diff --git a/libs/3rdparty/corrosion/.github/workflows/gh-pages.yaml b/libs/3rdparty/corrosion/.github/workflows/gh-pages.yaml new file mode 100644 index 00000000000..fe8605635e7 --- /dev/null +++ b/libs/3rdparty/corrosion/.github/workflows/gh-pages.yaml @@ -0,0 +1,78 @@ +name: Deploy GH pages +on: + push: + branches: + - master + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow one concurrent deployment +concurrency: + group: "pages" + cancel-in-progress: true + +jobs: + # Build and deploy the documentation of master and the stable/v0.5 branch + deploy: + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Install mdbook + env: + MDBOOK_VERSION: 'v0.4.27' + run: | + mkdir mdbook + curl -sSL https://github.com/rust-lang/mdBook/releases/download/${MDBOOK_VERSION}/mdbook-${MDBOOK_VERSION}-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook + echo `pwd`/mdbook >> $GITHUB_PATH + - name: Checkout master + uses: actions/checkout@v4 + with: + path: main + - name: Checkout stable/v0.5 + uses: actions/checkout@v4 + with: + path: stable-v0.5 + ref: 'stable/v0.5' + - name: Setup Pages + uses: actions/configure-pages@v5 + - name: Build mdbook for main branch + working-directory: 'main/doc' + run: mdbook build + - name: Build mdbook for stable/v0.5 branch + working-directory: 'stable-v0.5/doc' + run: mdbook build + # Override mdbooks default highlight.js with a custom version containing CMake support. + - uses: actions/checkout@v4 + with: + repository: 'highlightjs/highlight.js' + # mdbook currently (as of v0.4.27) does not support v11 yet. + ref: '10.7.3' + path: highlightjs + - name: Build custom highlight.js + run: | + npm install + node tools/build.js :common cmake yaml + working-directory: highlightjs + - name: Override highlightjs + run: | + cp highlightjs/build/highlight.min.js main/doc/book/highlight.js + cp highlightjs/build/highlight.min.js stable-v0.5/doc/book/highlight.js + - name: Copy stable doc into main + run: mkdir main/doc/book/v0.5 && cp -a stable-v0.5/doc/book/. main/doc/book/v0.5/ + - name: Debug print + run: ls -la main/doc/book/v0.5 + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: 'main/doc/book' + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/libs/3rdparty/corrosion/.github/workflows/linux.yaml b/libs/3rdparty/corrosion/.github/workflows/linux.yaml new file mode 100644 index 00000000000..b5cbfc9ee20 --- /dev/null +++ b/libs/3rdparty/corrosion/.github/workflows/linux.yaml @@ -0,0 +1,59 @@ +# Workflow file for Linux hosts +name: Corrosion on Linux +on: + workflow_call: + inputs: + ubuntu_version: + required: false + type: string + default: "latest" + cmake: + required: false + type: string + default: "3.22.6" + generator: + required: true + type: string + c_compiler: + required: true + type: string + rust: + required: false + type: string + default: 1.46.0 + target_arch: + required: false + type: string + default: x86_64 + +jobs: + linux: + name: Test Linux + runs-on: ubuntu-${{ inputs.ubuntu_version }} + steps: + - uses: actions/checkout@v4 + - name: Install CMake + uses: lukka/get-cmake@519de0c7b4812477d74976b2523a9417f552d126 + with: + cmakeVersion: "${{ inputs.cmake }}" + ninjaVersion: "~1.10.0" + - name: Install Rust + id: install_rust + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{inputs.rust}} + targets: ${{inputs.target_arch}}-unknown-linux-gnu + components: rust-src + - name: Install Cross Compiler + shell: bash + run: | + echo "::group::apt-install" + sudo apt-get update + sudo apt-get install -y "g++-${{inputs.target_arch}}-linux-gnu" + echo "::endgroup::" + if: ${{ 'Linux' == runner.os && inputs.target_arch != 'x86_64' }} + - name: Configure Corrosion + run: cmake -S. -Bbuild -G "${{ inputs.generator }}" "-DRust_TOOLCHAIN=${{steps.install_rust.outputs.name}}" --preset "${{ inputs.target_arch }}-unknown-linux-gnu-${{ inputs.c_compiler }}" + - name: Run Tests + working-directory: build + run: ctest --output-on-failure --build-config Debug -j 3 diff --git a/libs/3rdparty/corrosion/.github/workflows/test.yaml b/libs/3rdparty/corrosion/.github/workflows/test.yaml new file mode 100644 index 00000000000..b0b9a733664 --- /dev/null +++ b/libs/3rdparty/corrosion/.github/workflows/test.yaml @@ -0,0 +1,460 @@ +name: Tests +on: + push: + branches: + - master + pull_request: + branches: + - 'master' + - 'stable/**' +jobs: + + visual_studio_base: + name: Test Visual Studio (base) + uses: ./.github/workflows/visual_studio.yaml + with: + vs_version: "2022" + rust: 1.46.0 + + visual_studio_stage2: + name: Test Visual Studio + uses: ./.github/workflows/visual_studio.yaml + needs: + - visual_studio_base + strategy: + matrix: + vs_version: + - "2022" + arch: + - x86_64 + - i686 + - aarch64 + rust: + - "1.54.0" + include: + - arch: x86_64 + vs_version: 2022 + rust: stable + - arch: x86_64 + vs_version: 2022 + rust: nightly + with: + vs_version: "${{ matrix.vs_version}}" + rust: 1.54.0 + target_arch: "${{ matrix.arch}}" + + windows_ninja_cl: + name: Test Windows Ninja MSVC + runs-on: ${{ matrix.os }} + needs: + - visual_studio_base + strategy: + fail-fast: false + matrix: + os: + - windows-2022 + arch: + - x86_64 + - i686 + - aarch64 + compiler: + - cl + - clang-cl + - clang + include: + - os: windows-2022 + vs_version: vs-2022 + cmake: 3.22.6 + - rust: 1.54.0 + # Add variable mapping for ilammy/msvc-dev-cmd action + - arch: x86_64 + msvc_dev_arch: amd64 + - arch: i686 + msvc_dev_arch: amd64_x86 + - arch: aarch64 + msvc_dev_arch: amd64_arm64 + exclude: + # Not sure what parameters CMake needs when cross-compiling with clang-cl, so exclude for now + - compiler: clang-cl + arch: i686 + - compiler: clang-cl + arch: aarch64 + - compiler: clang + arch: i686 + - compiler: clang + arch: aarch64 + + steps: + - uses: actions/checkout@v4 + - name: Install CMake + uses: lukka/get-cmake@519de0c7b4812477d74976b2523a9417f552d126 + with: + cmakeVersion: "${{ matrix.cmake }}" + ninjaVersion: "~1.10.0" + - name: Install Rust + id: install_rust + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{matrix.rust}} + targets: ${{matrix.arch}}-pc-windows-msvc + components: rust-src + - name: Setup MSVC Development Environment + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: ${{ matrix.msvc_dev_arch }} + - name: Configure + run: cmake -S. -Bbuild "-DRust_TOOLCHAIN=${{steps.install_rust.outputs.name}}" --preset "ninja-${{ matrix.arch }}-pc-windows-msvc-${{ matrix.compiler }}" + - name: Run Tests + working-directory: build + run: ctest --output-on-failure --build-config Debug -j 3 + + windows_gnu: + name: Test Windows GNU + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - windows-2022 + arch: + - x86_64 + # - i686 + # - aarch64 + compiler: + - gcc # Clang only has experimental support for Cygwin / MinGW, so we don't test it + generator: + - ninja + - make + include: + - cmake: 3.22.6 + - rust: 1.54.0 + + steps: + - uses: actions/checkout@v4 + - name: Install CMake + uses: lukka/get-cmake@519de0c7b4812477d74976b2523a9417f552d126 + with: + cmakeVersion: "${{ matrix.cmake }}" + ninjaVersion: "~1.10.0" + - name: Install Rust + id: install_rust + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{matrix.rust}} + targets: ${{matrix.arch}}-pc-windows-gnu + components: rust-src + - name: Configure + run: cmake -S. -Bbuild "-DRust_TOOLCHAIN=${{steps.install_rust.outputs.name}}" --preset "${{ matrix.generator }}-${{ matrix.arch }}-pc-windows-gnu-${{ matrix.compiler }}" + - name: Run Tests + working-directory: build + run: ctest --output-on-failure --build-config Debug -j 3 + + windows_gnullvm_msys2: + name: Test Windows gnullvm on msys2 + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - windows-2022 + arch: + - x86_64 + # - i686 + # - aarch64 + generator: + - Ninja + - MSYS Makefiles + include: + - arch: x86_64 + msystem: CLANG64 +# - arch: i686 +# msystem: CLANG32 +# - arch: aarch64 +# msystem: CLANGARM64 + defaults: + run: + shell: msys2 {0} + steps: + - uses: actions/checkout@v4 + - name: Install Rust + id: install_rust + uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + targets: ${{matrix.arch}}-pc-windows-gnullvm + components: rust-src + - uses: msys2/setup-msys2@v2 + with: + msystem: ${{matrix.msystem}} + path-type: inherit + install: >- + git + make + pacboy: >- + toolchain:p + cmake:p + ninja:p + - name: Configure + run: cmake -S. -Bbuild -G "${{matrix.generator}}" --toolchain=.github/scripts/toolchains/${{matrix.arch}}-pc-windows-gnullvm.cmake + - name: Run Tests + working-directory: build + run: ctest --output-on-failure --build-config Debug -j 3 + +# For now just test if hostbuild works when cross-compiling on windows. +# For testing everything we would also need to install a cross-compiler first. + windows_cross_hostbuild: + name: Test Windows Cross + runs-on: windows-2022 + steps: + - uses: actions/checkout@v4 + - name: Install CMake + uses: lukka/get-cmake@519de0c7b4812477d74976b2523a9417f552d126 + with: + cmakeVersion: "~3.22.0" + ninjaVersion: "~1.10.0" + - name: Install Rust + id: install_rust + uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + targets: aarch64-unknown-linux-gnu + components: rust-src + - name: Configure + run: cmake -S. -Bbuild "-DRust_TOOLCHAIN=${{steps.install_rust.outputs.name}}" -DRust_CARGO_TARGET=aarch64-unknown-linux-gnu + - name: Run Tests + working-directory: build + run: ctest --output-on-failure --build-config Debug -R hostbuild + + linux_base: + name: Test Linux (base) + uses: ./.github/workflows/linux.yaml + with: + c_compiler: "gcc" + generator: "Ninja" + + linux_stage2: + name: Test Linux + needs: + - linux_base + uses: ./.github/workflows/linux.yaml + with: + target_arch: "${{ matrix.arch }}" + c_compiler: "${{ matrix.compiler }}" + generator: "${{ matrix.generator }}" + strategy: + fail-fast: false + matrix: + arch: + - x86_64 + - i686 + - aarch64 + compiler: + - gcc + generator: + - "Ninja" + - "Unix Makefiles" + include: + # rustc doesn't support cross-compiling with clang out of the box, since + # clang requires a --target parameter. Corrosion currently can only pass + # this for the top-level crate, so linking of cdylibs that are built as + # dependencies of this crate will fail if they exist. + # Solutions would be to make cross-compiling with clang work out-of-the-box + # in rustc, or working around it in corrosion by adding a linker-wrapper. + # For this reason we only test clang with the host target for now. + - arch: x86_64 + compiler: clang + generator: "Ninja" + - arch: x86_64 + generator: "Ninja Multi-Config" + compiler: gcc + + darwin: + name: Test MacOS + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + arch: + - x86_64 + - aarch64 + compiler: + - clang + generator: + - "Ninja" + - "Xcode" + include: + - os: macos-latest + - cmake: 3.22.6 + - rust: 1.54.0 + + steps: + - uses: actions/checkout@v4 + - name: Install CMake + uses: lukka/get-cmake@519de0c7b4812477d74976b2523a9417f552d126 + with: + cmakeVersion: "${{ matrix.cmake }}" + ninjaVersion: "~1.10.0" + # Install cbindgen before Rust to use recent default Rust version. + - name: Install cbindgen + run: cargo install cbindgen + - name: Install Rust + id: install_rust + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{matrix.rust}} + targets: ${{matrix.arch}}-apple-darwin + components: rust-src + - name: Configure + run: cmake -S. -Bbuild --log-level=DEBUG -G "${{ matrix.generator }}" "-DRust_TOOLCHAIN=${{steps.install_rust.outputs.name}}" --preset "${{ matrix.arch }}-apple-darwin-${{ matrix.compiler }}" + - name: Run Tests + working-directory: build + run: ctest --output-on-failure --build-config Debug -j 3 + + + test_cxxbridge: + name: Test cxxbridge integration + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - windows-2022 + - ubuntu-latest + - macos-15 + include: + # Should be in sync with the `cxx` version the Carg.lock of the cxxbridge tests, + # otherwise the caching will not work and the cmd will be built from source. + - cxxbridge_version: "1.0.86" + steps: + - uses: actions/checkout@v4 + - uses: actions/cache@v4 + id: cache_cxxbridge + with: + path: "~/.cargo/bin/cxxbridge*" + key: ${{ runner.os }}-cxxbridge_${{ matrix.cxxbridge_version }} + - name: Install cxxbridge + if: steps.cache_cxxbridge.outputs.cache-hit != 'true' + run: cargo install cxxbridge-cmd@${{ matrix.cxxbridge_version }} + - name: Install lld + run: sudo apt update && sudo apt install -y lld + if: ${{ 'Linux' == runner.os }} + - name: Setup MSVC Development Environment + uses: ilammy/msvc-dev-cmd@v1 + if: runner.os == 'Windows' + - name: Install CMake + uses: lukka/get-cmake@519de0c7b4812477d74976b2523a9417f552d126 + with: + cmakeVersion: "~3.24.0" + ninjaVersion: "~1.10.0" + - name: Install Rust + uses: dtolnay/rust-toolchain@master + with: + toolchain: stable minus 2 releases + components: rust-src + - name: Configure + run: > + cmake + -S. + -Bbuild + -GNinja + -DCORROSION_VERBOSE_OUTPUT=ON + -DCORROSION_TESTS_CXXBRIDGE=ON + - name: Run Tests + working-directory: build + run: ctest --output-on-failure --build-config Debug -j 3 -R "^cxxbridge" + + autoinstall_cargo_target: + name: Test Auto-installing Cargo target via rustup + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - name: Install CMake + uses: lukka/get-cmake@519de0c7b4812477d74976b2523a9417f552d126 + - name: Install Rust + id: install_rust + uses: dtolnay/rust-toolchain@stable + - name: Install Cross Compiler + shell: bash + run: | + echo "::group::apt-install" + sudo apt-get update + sudo apt-get install -y gcc-aarch64-linux-gnu + echo "::endgroup::" + - name: Assert rustup target is not installed + run: rustup show | ( ! grep aarch64) + - name: Configure Corrosion + run: cmake -S. -Bbuild -GNinja -DRust_RUSTUP_INSTALL_MISSING_TARGET=ON --preset "aarch64-unknown-linux-gnu-gcc" + - name: Check rustup target is installed after configuring + run: rustup show | grep aarch64 + + install: + name: Test Corrosion as a Library + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - windows-2022 + - ubuntu-latest + - macos-15 + include: + - rust: 1.54.0 + + steps: + - uses: actions/checkout@v4 + - name: Setup MSVC Development Environment + uses: ilammy/msvc-dev-cmd@v1 + if: runner.os == 'Windows' + - name: Install CMake + uses: lukka/get-cmake@519de0c7b4812477d74976b2523a9417f552d126 + with: + cmakeVersion: "~3.22.0" + ninjaVersion: "~1.10.0" + # Install cbindgen before Rust to use recent default Rust version. + - name: Install cbindgen + run: cargo install cbindgen + - name: Install Rust + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{matrix.rust}} + components: rust-src + - name: Test Corrosion as installed module + run: > + cmake + -S. + -Bbuild + -GNinja + -DCORROSION_VERBOSE_OUTPUT=ON + -DCMAKE_BUILD_TYPE=Release + -DCORROSION_TESTS_INSTALL_CORROSION=ON + && + cd build + && + ctest --output-on-failure -C Release -j 3 + + # We want an "accumulation" job here because it is easier to specify required + # jobs here via needs, then in the github UI, since we use matrix jobs. + ci-success: + name: bors-ci-status + if: ${{ always() }} + needs: + - visual_studio_stage2 + - windows_ninja_cl + - windows_gnu + - windows_gnullvm_msys2 + - linux_stage2 + - darwin + - test_cxxbridge + - autoinstall_cargo_target + - install + runs-on: ubuntu-latest + # Step copied from: https://github.com/cross-rs/cross/blob/80c9f9109a719ffb0f694060ddc6e371d5b3a540/.github/workflows/ci.yml#L361 + steps: + - name: Result + run: | + jq -C <<< "${needs}" + # Check if all needs were successful or skipped. + "$(jq -r 'all(.result as $result | (["success", "skipped"] | contains([$result])))' <<< "${needs}")" + env: + needs: ${{ toJson(needs) }} + diff --git a/libs/3rdparty/corrosion/.github/workflows/visual_studio.yaml b/libs/3rdparty/corrosion/.github/workflows/visual_studio.yaml new file mode 100644 index 00000000000..4b7beee5232 --- /dev/null +++ b/libs/3rdparty/corrosion/.github/workflows/visual_studio.yaml @@ -0,0 +1,54 @@ +name: Corrosion with Visual Studio + +on: + workflow_call: + inputs: + vs_version: + required: true + type: string + default: 2022 + cmake: + required: false + type: string + default: "3.22.6" + rust: + required: false + type: string + default: 1.46.0 + target_arch: + required: false + type: string + default: x86_64 + +jobs: + visual_studio: + name: Test Visual Studio ${{ inputs.vs_version }} + runs-on: "windows-${{ inputs.vs_version }}" + steps: + - uses: actions/checkout@v4 + - name: Install CMake + uses: lukka/get-cmake@519de0c7b4812477d74976b2523a9417f552d126 + with: + cmakeVersion: "${{ inputs.cmake }}" + ninjaVersion: "~1.10.0" + - name: Install Rust + id: install_rust + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{inputs.rust}} + targets: ${{inputs.target_arch}}-pc-windows-msvc + components: rust-src + # The initial configure for MSVC is quite slow, so we cache the build directory + # (including the build directories of the tests) since reconfiguring is + # significantly faster. + # - name: Cache MSVC build directory + # id: cache-msvc-builddir + # uses: actions/cache@v4 + # with: + # path: build + # key: ${{ inputs.os }}-${{ inputs.target_arch }}-${{ inputs.rust }}-msvc-${{ inputs.vs_version}}-build + - name: Configure + run: cmake -S. -Bbuild -DCORROSION_TESTS_KEEP_BUILDDIRS=ON "-DRust_TOOLCHAIN=${{steps.install_rust.outputs.name}}" --preset "vs-${{ inputs.vs_version }}-${{ inputs.target_arch }}" + - name: Run Tests + working-directory: build + run: ctest --output-on-failure --build-config Debug -j 3 diff --git a/libs/3rdparty/corrosion/.gitignore b/libs/3rdparty/corrosion/.gitignore new file mode 100644 index 00000000000..3a618f37a64 --- /dev/null +++ b/libs/3rdparty/corrosion/.gitignore @@ -0,0 +1,8 @@ + +**/target/ +**/*.rs.bk +build*/ +.vscode +.idea +cmake-build-* +test/test_header.cmake diff --git a/libs/3rdparty/corrosion/.riminfo b/libs/3rdparty/corrosion/.riminfo new file mode 100644 index 00000000000..36a7b893199 --- /dev/null +++ b/libs/3rdparty/corrosion/.riminfo @@ -0,0 +1,15 @@ +d558b4af3ea3930f0aecadf831c823b6aea2ab21 + +RIM Info file. You're welcome to read but don't write it. +Instead, use RIM commands to do the things you want to do. +BEWARE: Any manual modification will invalidate the file! + +remote_url : https://github.com/corrosion-rs/corrosion.git +revision_sha1 : 5239c1b64742bb03e13f10822ca8ef5e52f75f71 +target_revision: v0.6 +ignores : +checksum : b9f2e0c7d6136e9b33bfba61935020cdc8d44ee6 +subdir : + +committer_date : 2025-11-23 13:14:15 +0100 + diff --git a/libs/3rdparty/corrosion/CMakeLists.txt b/libs/3rdparty/corrosion/CMakeLists.txt new file mode 100644 index 00000000000..6761950cc73 --- /dev/null +++ b/libs/3rdparty/corrosion/CMakeLists.txt @@ -0,0 +1,81 @@ +cmake_minimum_required(VERSION 3.22) +project(Corrosion + VERSION 0.6.0 + LANGUAGES NONE + HOMEPAGE_URL "https://corrosion-rs.github.io/corrosion/" +) + +# ==== Corrosion Configuration ==== + +option( + CORROSION_BUILD_TESTS + "Build Corrosion test project" + ${PROJECT_IS_TOP_LEVEL} +) + +if (PROJECT_IS_TOP_LEVEL) + # We need to enable a language for corrosions test to work. + # For projects using corrosion this is not needed + enable_language(C) +endif() + +# This little bit self-hosts the Corrosion toolchain to build the generator +# tool. +# +# It is strongly encouraged to install Corrosion separately and use +# `find_package(Corrosion REQUIRED)` instead if that works with your workflow. +option(CORROSION_INSTALL_ONLY "Only add rules for installing Corrosion itself." OFF) +if (NOT CORROSION_INSTALL_ONLY) + list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) + include(Corrosion) +endif() + +# Testing +if (CORROSION_BUILD_TESTS) + include(CTest) + add_subdirectory(test) +endif() + +# If Corrosion is a subdirectory, do not enable its install code +if (NOT PROJECT_IS_TOP_LEVEL) + return() +endif() + +# Installation + +include(GNUInstallDirs) + +# Generate the Config file +include(CMakePackageConfigHelpers) + +configure_package_config_file( + cmake/CorrosionConfig.cmake.in CorrosionConfig.cmake + INSTALL_DESTINATION + "${CMAKE_INSTALL_FULL_LIBDIR}/cmake/Corrosion" +) + +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/CorrosionConfigVersion.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY + SameMajorVersion + ARCH_INDEPENDENT +) + +install( + FILES + "${CMAKE_CURRENT_BINARY_DIR}/CorrosionConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/CorrosionConfigVersion.cmake" + DESTINATION + "${CMAKE_INSTALL_FULL_LIBDIR}/cmake/Corrosion" +) + +# These CMake scripts are needed both for the install and as a subdirectory +install( + FILES + cmake/Corrosion.cmake + cmake/CorrosionGenerator.cmake + cmake/FindRust.cmake + DESTINATION + "${CMAKE_INSTALL_FULL_DATADIR}/cmake" +) diff --git a/libs/3rdparty/corrosion/CMakePresets.json b/libs/3rdparty/corrosion/CMakePresets.json new file mode 100644 index 00000000000..1be202983f0 --- /dev/null +++ b/libs/3rdparty/corrosion/CMakePresets.json @@ -0,0 +1,290 @@ +{ + "version": 3, + "cmakeMinimumRequired": { + "major": 3, + "minor": 22, + "patch": 0 + }, + "configurePresets": [ + { + "name": "ninja", + "hidden": true, + "generator": "Ninja" + }, + { + "name": "ninja-mc", + "hidden": true, + "generator": "Ninja Multi-Config" + }, + { + "name": "make", + "hidden": true, + "generator": "Unix Makefiles" + }, + { + "name": "vs-2019", + "hidden": true, + "generator": "Visual Studio 16 2019" + }, + { + "name": "vs-2022", + "hidden": true, + "generator": "Visual Studio 17 2022" + }, + { + "name": "windows-only", + "hidden": true, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, + { + "name": "windows-10-cross", + "hidden": true, + "cacheVariables": { + "CMAKE_SYSTEM_NAME": "Windows", + "CMAKE_SYSTEM_VERSION": "10.0" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, + { + "name": "x86_64-pc-windows-msvc", + "hidden": true, + "inherits": ["windows-only"], + "cacheVariables": { + "Rust_CARGO_TARGET": "x86_64-pc-windows-msvc" + } + }, + { + "name": "i686-pc-windows-msvc", + "hidden": true, + "cacheVariables": { + "Rust_CARGO_TARGET": "i686-pc-windows-msvc" + } + }, + { + "name": "aarch64-pc-windows-msvc", + "hidden": true, + "cacheVariables": { + "Rust_CARGO_TARGET": "aarch64-pc-windows-msvc" + } + }, + { + "name": "x86_64-unknown-linux-gnu", + "hidden": true, + "cacheVariables": { + "Rust_CARGO_TARGET": "x86_64-unknown-linux-gnu" + } + }, + { + "name": "i686-unknown-linux-gnu", + "hidden": true, + "cacheVariables": { + "Rust_CARGO_TARGET": "i686-unknown-linux-gnu" + } + }, + { + "name": "aarch64-unknown-linux-gnu", + "hidden": true, + "cacheVariables": { + "Rust_CARGO_TARGET": "aarch64-unknown-linux-gnu" + } + }, + { + "name": "x86_64-apple-darwin", + "hidden": true, + "cacheVariables": { + "Rust_CARGO_TARGET": "x86_64-apple-darwin" + } + }, + { + "name": "aarch64-apple-darwin", + "hidden": true, + "cacheVariables": { + "Rust_CARGO_TARGET": "aarch64-apple-darwin" + } + }, + { + "name": "vs-platform-arm64", + "hidden": true, + "inherits": ["aarch64-pc-windows-msvc","windows-10-cross"], + "architecture": { + "value": "ARM64" + } + }, + { + "name": "vs-platform-x64", + "hidden": true, + "inherits": ["x86_64-pc-windows-msvc"], + "architecture": { + "value": "x64" + } + }, + { + "name": "vs-platform-i686", + "hidden": true, + "inherits": ["i686-pc-windows-msvc", "windows-10-cross"], + "architecture": { + "value": "Win32" + } + }, + { + "name": "vs-2019-x86_64", + "inherits": ["vs-platform-x64", "vs-2019"] + }, + { + "name": "vs-2022-x86_64", + "inherits": ["vs-platform-x64", "vs-2022"] + }, + { + "name": "vs-2019-i686", + "inherits": ["vs-platform-i686", "vs-2019"] + }, + { + "name": "vs-2022-i686", + "inherits": ["vs-platform-i686", "vs-2022"] + }, + { + "name": "vs-2019-aarch64", + "inherits": ["vs-platform-arm64", "vs-2019"] + }, + { + "name": "vs-2022-aarch64", + "inherits": ["vs-platform-arm64", "vs-2022"] + }, + { + "name": "clang", + "hidden": true, + "cacheVariables": { + "CMAKE_C_COMPILER": "clang", + "CMAKE_CXX_COMPILER": "clang++" + } + }, + { + "name": "host-gcc", + "hidden": true, + "cacheVariables": { + "CMAKE_C_COMPILER": "gcc", + "CMAKE_CXX_COMPILER": "g++" + } + }, + { + "name": "clang-cl", + "hidden": true, + "inherits": ["windows-only"], + "cacheVariables": { + "CMAKE_C_COMPILER": "clang-cl", + "CMAKE_CXX_COMPILER": "clang-cl" + } + }, + { + "name": "cl", + "hidden": true, + "inherits": ["windows-only"], + "cacheVariables": { + "CMAKE_C_COMPILER": "cl", + "CMAKE_CXX_COMPILER": "cl" + } + }, + { + "name": "ninja-x86_64-pc-windows-msvc-cl", + "inherits": ["ninja", "x86_64-pc-windows-msvc", "cl"] + }, + { + "name": "ninja-x86_64-pc-windows-msvc-clang-cl", + "inherits": ["ninja", "x86_64-pc-windows-msvc", "clang-cl"] + }, + { + "name": "ninja-x86_64-pc-windows-msvc-clang", + "inherits": ["ninja", "x86_64-pc-windows-msvc", "clang"] + }, + { + "name": "ninja-i686-pc-windows-msvc-cl", + "inherits": ["ninja", "i686-pc-windows-msvc", "cl", "windows-10-cross"] + }, + { + "name": "ninja-i686-pc-windows-msvc-clang-cl", + "inherits": ["ninja", "i686-pc-windows-msvc", "clang-cl", "windows-10-cross"] + }, + { + "name": "ninja-i686-pc-windows-msvc-clang", + "inherits": ["ninja", "i686-pc-windows-msvc", "clang", "windows-10-cross"] + }, + { + "name": "ninja-aarch64-pc-windows-msvc-cl", + "inherits": ["ninja", "aarch64-pc-windows-msvc", "cl", "windows-10-cross"] + }, + { + "name": "ninja-aarch64-pc-windows-msvc-clang-cl", + "inherits": ["ninja", "aarch64-pc-windows-msvc", "clang-cl", "windows-10-cross"] + }, + { + "name": "ninja-aarch64-pc-windows-msvc-clang", + "inherits": ["ninja", "aarch64-pc-windows-msvc", "clang", "windows-10-cross"] + }, + { + "name": "ninja-x86_64-pc-windows-gnullvm", + "inherits": ["ninja", "windows-only", "clang"], + "toolchainFile": "${sourceDir}/.github/scripts/toolchains/x86_64-pc-windows-gnullvm.cmake" + }, + { + "name": "make-x86_64-pc-windows-gnullvm", + "inherits": ["make", "windows-only", "clang"], + "toolchainFile": "${sourceDir}/.github/scripts/toolchains/x86_64-pc-windows-gnullvm.cmake" + }, + { + "name": "ninja-x86_64-pc-windows-gnu-gcc", + "inherits": ["ninja", "host-gcc", "windows-only"] + }, + { + "name": "make-x86_64-pc-windows-gnu-gcc", + "inherits": ["make", "host-gcc", "windows-only"] + }, + { + "name": "x86_64-unknown-linux-gnu-clang", + "inherits": ["x86_64-unknown-linux-gnu"], + "toolchainFile": "${sourceDir}/.github/scripts/toolchains/${presetName}.cmake" + }, + { + "name": "x86_64-unknown-linux-gnu-gcc", + "inherits": ["x86_64-unknown-linux-gnu"], + "toolchainFile": "${sourceDir}/.github/scripts/toolchains/${presetName}.cmake" + }, + { + "name": "i686-unknown-linux-gnu-clang", + "inherits": ["i686-unknown-linux-gnu"], + "toolchainFile": "${sourceDir}/.github/scripts/toolchains/${presetName}.cmake" + }, + { + "name": "i686-unknown-linux-gnu-gcc", + "inherits": ["i686-unknown-linux-gnu"], + "toolchainFile": "${sourceDir}/.github/scripts/toolchains/${presetName}.cmake" + }, + { + "name": "aarch64-unknown-linux-gnu-clang", + "inherits": ["aarch64-unknown-linux-gnu"], + "toolchainFile": "${sourceDir}/.github/scripts/toolchains/${presetName}.cmake" + }, + { + "name": "aarch64-unknown-linux-gnu-gcc", + "inherits": ["aarch64-unknown-linux-gnu"], + "toolchainFile": "${sourceDir}/.github/scripts/toolchains/${presetName}.cmake" + }, + { + "name": "x86_64-apple-darwin-clang", + "inherits": ["x86_64-apple-darwin", "clang"], + "toolchainFile": "${sourceDir}/.github/scripts/toolchains/${presetName}.cmake" + }, + { + "name": "aarch64-apple-darwin-clang", + "inherits": ["aarch64-apple-darwin"], + "toolchainFile": "${sourceDir}/.github/scripts/toolchains/${presetName}.cmake" + } + ] +} diff --git a/libs/3rdparty/corrosion/LICENSE b/libs/3rdparty/corrosion/LICENSE new file mode 100644 index 00000000000..5e30d776d6d --- /dev/null +++ b/libs/3rdparty/corrosion/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Andrew Gaspar + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/libs/3rdparty/corrosion/README.md b/libs/3rdparty/corrosion/README.md new file mode 100644 index 00000000000..63c6f7fcb47 --- /dev/null +++ b/libs/3rdparty/corrosion/README.md @@ -0,0 +1,50 @@ +# Corrosion +[![Build Status](https://github.com/corrosion-rs/corrosion/actions/workflows/test.yaml/badge.svg)](https://github.com/corrosion-rs/corrosion/actions?query=branch%3Amaster) +[![Documentation](https://img.shields.io/badge/docs-latest-blue.svg)](https://corrosion-rs.github.io/corrosion/) +![License](https://img.shields.io/badge/license-MIT-blue) + +Corrosion, formerly known as cmake-cargo, is a tool for integrating Rust into an existing CMake +project. Corrosion can automatically import executables, static libraries, and dynamic libraries +from a workspace or package manifest (`Cargo.toml` file). + +## Features +- Automatic Import of Executable, Static, and Shared Libraries from Rust Crate +- Easy Installation of Rust Executables +- Trivially Link Rust Executables to C/C++ Libraries in Tree +- Multi-Config Generator Support +- Simple Cross-Compilation + +## Sample Usage with FetchContent + +Using the CMake `FetchContent` module allows you to easily integrate corrosion into your build. +Other methods including installing corrosion or adding it as a subdirectory are covered in the +[setup chapter](https://corrosion-rs.github.io/corrosion/setup_corrosion.html) of the +corrosion [documentation](https://corrosion-rs.github.io/corrosion/). + +```cmake +include(FetchContent) + +FetchContent_Declare( + Corrosion + GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git + GIT_TAG v0.6 # Optionally specify a commit hash, version tag or branch here +) +FetchContent_MakeAvailable(Corrosion) + +# Import targets defined in a package or workspace manifest `Cargo.toml` file +corrosion_import_crate(MANIFEST_PATH rust-lib/Cargo.toml) + +add_executable(your_cpp_bin main.cpp) +target_link_libraries(your_cpp_bin PUBLIC rust-lib) +``` + +## Requirements + +### v0.6 Release + +- CMake 3.22 or newer + +### v0.5 Release (Critical backports only) + +- CMake 3.15 or newer. Some features may only be available on more recent CMake versions +- Rust 1.46 or newer. Some platforms / features may require more recent Rust versions diff --git a/libs/3rdparty/corrosion/RELEASES.md b/libs/3rdparty/corrosion/RELEASES.md new file mode 100644 index 00000000000..244a2f12256 --- /dev/null +++ b/libs/3rdparty/corrosion/RELEASES.md @@ -0,0 +1,500 @@ +# v0.6.0 (2025-11-23) + +### Breaking Changes + +- Corrosion now requires CMake 3.22. See also the + [v0.4.0 Release notes](#040-lts-2023-06-01) for more details. +- Removed native tooling and the corresponding option `CORROSION_NATIVE_TOOLING`. + Corrosion now always uses pure CMake. +- Fix Corrosion placing artifacts into the wrong directory when: + 1. using a Multi-Config Generator (e.g Visual Studio or XCode) AND + 2. `OUTPUT_DIRECTORY_` is not set AND + 3. `OUTPUT_DIRECTORY` is set AND + 4. `OUTPUT_DIRECTORY` does not contain a generator expression + + Corrosion now places artifacts into a `$` subdirectory of the + specified `OUTPUT_DIRECTORY`. This matches the [documented behavior][doc-cmake-rt-output-dir] + of CMake for regular CMake targets. ([#568]). + +### New features + +- Support using the `$` generator expression in `OUTPUT_DIRECTORY`. [#459] +- Add `OVERRIDE_CRATE_TYPE` option to corrosion_import_crate, allowing users to override + the crate-types of Rust libraries (e.g. force building as a staticlib instead of an rlib). +- Support *-windows-gnullvm targets. +- experimental support in corrosion_install for installing libraries and header files +- Add `CORROSION_TOOLS_RUST_TOOLCHAIN` cache variable which allows users to select a different + rust toolchain for compiling build-tools used by corrosion (currently cbindgen and cxxbridge). + This mainly allows using a newer toolchain for such build-tools then for the actual project. +- Initial support for iOS targets [#636](https://github.com/corrosion-rs/corrosion/pull/636) + +[doc-cmake-rt-output-dir]: https://cmake.org/cmake/help/latest/prop_tgt/RUNTIME_OUTPUT_DIRECTORY.html +[#459]: https://github.com/corrosion-rs/corrosion/pull/459 +[#568]: https://github.com/corrosion-rs/corrosion/pull/568 + +# v0.5.1 (2024-12-29) + +### Fixes + +- Update FindRust to support `rustup` v1.28.0. Support for older rustup versions is retained, + so updating corrosion quickly is recommended to all rustup users. + + +# v0.5.0 (2024-05-11) + +### Breaking Changes + +- Dashes (`-`) in names of imported CMake **library** targets are now replaced with underscores (`_`). + See [issue #501] for details. Users on older Corrosion versions will experience the same + change when using Rust 1.79 or newer. `bin` targets are not affected by this change. + +[issue #501]: https://github.com/corrosion-rs/corrosion/issues/501 + +# v0.4.10 (2024-05-11) + +### New features + +- `corrosion_experimental_cbindgen()` can now be called multiple times on the same Rust target, + as long as the output header name differs. This may be useful to generate separate C and C++ + bindings. [#507] +- If `corrosion_link_libraries()` is called on a Rust static library target, then + `target_link_libraries()` is called to propagate the dependencies to C/C++ consumers. + Previously a warning was emitted in this case and the arguments ignored. [#506] + +### Fixes + +- Combine `-framework` flags on macos to avoid linker deduplication errors [#455] +- `corrosion_experimental_cbindgen()` will now correctly use the package name, instead of assuming that + the package and crate name are identical. ([11e27c]) +- Set the `AR_` variable for `cc-rs` (except for msvc targets) [#456] +- Fix hostbuild when cross-compiling to windows [#477] +- Consider vworks executable suffix [#504] +- `corrosion_experimental_cbindgen()` now forwards the Rust target-triple (e.g. `aarch64-unknown-linux-gnu`) + to cbindgen via the `TARGET` environment variable. The `hostbuild` property is considered. [#507] +- Fix linking errors with Rust >= 1.79 and `-msvc` targets.` [#511] + + +[#455]: https://github.com/corrosion-rs/corrosion/pull/455 +[#456]: https://github.com/corrosion-rs/corrosion/pull/456 +[#477]: https://github.com/corrosion-rs/corrosion/pull/477 +[#504]: https://github.com/corrosion-rs/corrosion/pull/504 +[#506]: https://github.com/corrosion-rs/corrosion/pull/506 +[#507]: https://github.com/corrosion-rs/corrosion/pull/507 +[#511]: https://github.com/corrosion-rs/corrosion/pull/511 +[11e27c]: https://github.com/corrosion-rs/corrosion/pull/514/commits/11e27cde2cf32c7ed539c96eb03c2f10035de538 + +# v0.4.9 (2024-05-01) + +### New Features + +- Automatically detect Rust target for OpenHarmony ([#510]). + +### Fixes + +- Make find_package portable ([#509]). + +[#510]: https://github.com/corrosion-rs/corrosion/pull/510 +[#509]: https://github.com/corrosion-rs/corrosion/pull/509 + +# v0.4.8 (2024-04-03) + +### Fixes + +- Fix an internal error when passing both the `PROFILE` and `CRATES` option to + `corrosion_import_crate()` ([#496]). + +[#496]: https://github.com/corrosion-rs/corrosion/pull/496 + +# v0.4.7 (2024-01-19) + +### Fixes + +- The C/C++ compiler passed from corrosion to `cc-rs` can now be overridden by users setting + `CC_` (e.g. `CC_x86_64-unknown-linux-gnu=/path/to/my-compiler`) environment variables ([#475]). + +[#475]: https://github.com/corrosion-rs/corrosion/pull/475 + +# v0.4.6 (2024-01-17) + +### Fixes + +- Fix hostbuild executables when cross-compiling from non-windows to windows targets. + (Only with CMake >= 3.19). + +# v0.4.5 (2023-11-30) + +### Fixes + +- Fix hostbuild executables when cross-compiling on windows to non-windows targets + (Only with CMake >= 3.19). + +# v0.4.4 (2023-10-06) + +### Fixes + +- Add `chimera` ([#445]) and `unikraft` ([#446]) to the list of known vendors + +[#445]: https://github.com/corrosion-rs/corrosion/pull/445 +[#446]: https://github.com/corrosion-rs/corrosion/pull/446 + +# v0.4.3 (2023-09-09) + +### Fixes + +- Fix the PROFILE option with CMake < 3.19 [#427] +- Relax vendor parsing for espressif targets (removes warnings) +- Fix an issue detecting required link libraries with Rust >= 1.71 + when the cmake build directory is located in a Cargo workspace. + +# 0.4.2 (2023-07-16) + +### Fixes + +- Fix an issue when cross-compiling with clang +- Fix detecting required libraries with cargo 1.71 + +### New features + +- Users can now set `Rust_RESOLVE_RUSTUP_TOOLCHAINS` to `OFF`, which will result in Corrosion + not attempting to resolve rustc/cargo. + +# 0.4.1 (2023-06-03) + +This is a bugfix release. + +### Fixes + +- Fixes a regression on multi-config Generators + +# 0.4.0 LTS (2023-06-01) + +No changes compared to v0.4.0-beta2. + +## Announcements + +The `v0.4.x` LTS series will be the last release to support older CMake and Rust versions. +If necessary, fixes will be backported to the v0.4 branch. New features will not be +actively backported after the next major release, but community contributions are possible. +The `v0.4.x` series is currently planned to be maintained until the end of 2024. + +The following major release will increase the minimum required CMake version to 3.22. The +minimum supported Rust version will also be increased to make use of newly added flags, but +the exact version is not fixed yet. + + +## Changes compared to v0.3.5: + +### Breaking Changes + +- The Visual Studio Generators now require at least CMake 3.20. + This was previously announced in the 0.3.0 release notes and is the same + requirement as for the other Multi-Config Generators. +- The previously deprecated function `corrosion_set_linker_language()` + will now raise an error when called and may be removed without further + notice in future stable releases. Use `corrosion_set_linker()` instead. +- Improved the FindRust target triple detection, which may cause different behavior in some cases. + The detection does not require an enabled language anymore and will always fall back + to the default host target triple. A warning is issued if target triple detection failed. + +### Potentially Breaking Changes + +- Corrosion now sets the `IMPORTED_NO_SONAME` property for shared rust libraries, since by + default they won't have an `soname` field. + If you add a rustflag like `-Clink-arg=-Wl,-soname,libmycrate.so` in your project, + you should set this property to false on the shared rust library. +- Corrosion now uses a mechanism to determine which native libraries need to be linked with + Rust `staticlib` targets into C/C++ targets. The previous mechanism contained a hardcoded list. + The new mechanism asks `rustc` which libraries are needed at minimum for a given + target triple (with `std` support). This should not be a breaking change, but if you + do encounter a new linking issue when upgrading with `staticlib` targets, please open an + issue. + +### New features + +- `corrosion_import_crate()` has two new options `LOCKED` and `FROZEN` which pass the + `--locked` and `--frozen` flags to all invocations of cargo. +- `FindRust` now provides cache variables containing information on the default host + target triple: + - `Rust_CARGO_HOST_ARCH` + - `Rust_CARGO_HOST_VENDOR` + - `Rust_CARGO_HOST_OS` + - `Rust_CARGO_HOST_ENV` + +### Other changes + +- When installing Corrosion with CMake >= 3.19, the legacy Generator tool is + no longer built and installed by default. +- Corrosion now issues a warning when setting the linker or setting linker + options for a Rust static library. +- Corrosion no longer enables the `C` language when CMake is in crosscompiling mode and + no languages where previously enabled. This is not considered a breaking change. +- `corrosion_import_crate()` now warns about unexpected arguments. + +### Fixes + +- Fix building when the `dev` profile is explicitly set by the user. + +## Experimental features (may be changed or removed without a major version bump) + +- Experimental cxxbridge and cbindgen integration. +- Add a helper function to parse the package version from a Cargo.toml file +- Expose rustup toolchains discovered by `FindRust` in the following cache variables + which contain a list. + - `Rust_RUSTUP_TOOLCHAINS`: List of toolchains names + - `Rust_RUSTUP_TOOLCHAINS_VERSION`: List of `rustc` version of the toolchains + - `Rust_RUSTUP_TOOLCHAINS_RUSTC_PATH`: List of the path to `rustc` + - `Rust_RUSTUP_TOOLCHAINS_CARGO_PATH`: List of the path to `cargo`. Entries may be `NOTFOUND` if cargo + is not available for that toolchain. +- Add target properties `INTERFACE_CORROSION_RUSTC` and `INTERFACE_CORROSION_CARGO`, which may + be set to paths to `rustc` and `cargo` respectively to override the toolchain for a specific + target. + +# 0.3.5 (2023-03-19) + +- Fix building the Legacy Generator on Rust toolchains < 1.56 ([#365]) + +[#365]: https://github.com/corrosion-rs/corrosion/pull/365 + +# 0.3.4 (2023-03-02) + +## Fixes + +- Fix hostbuild (when CMake/Cargo is configured for cross-compiling) if clang is used ([#338]). + +## Other + +- Pass `--no-deps` to cargo metadata ([#334]). +- Bump the legacy generator dependencies + +[#334]: https://github.com/corrosion-rs/corrosion/pull/334 +[#338]: https://github.com/corrosion-rs/corrosion/pull/338 + + +# 0.3.3 (2023-02-17) + +## New features (Only available on CMake >= 3.19) + +- Add new `IMPORTED_CRATES` flag to `corrosion_import_crate()` to retrieve the list of imported crates in the current + scope ([#312](https://github.com/corrosion-rs/corrosion/pull/312)). + +## Fixes + +- Fix imported location target property when the rust target name contains dashes + and a custom OUTPUT_DIRECTORY was specified by the user ([#322](https://github.com/corrosion-rs/corrosion/pull/322)). +- Fix building for custom rust target-triples ([#316](https://github.com/corrosion-rs/corrosion/pull/316)) + +# 0.3.2 (2023-01-11) + +## New features (Only available on CMake >= 3.19) + +- Add new `CRATE_TYPES` flag to `corrosion_import_crate()` to restrict which + crate types should be imported ([#269](https://github.com/corrosion-rs/corrosion/pull/269)). +- Add `NO_LINKER_OVERRIDE` flag to let Rust choose the default linker for the target + instead of what Corrosion thinks is the appropriate linker driver ([#272](https://github.com/corrosion-rs/corrosion/pull/272)). + +## Fixes + +- Fix clean target when cross-compiling ([#291](https://github.com/corrosion-rs/corrosion/pull/291)). +- Don't set the linker for Rust static libraries ([#275](https://github.com/corrosion-rs/corrosion/pull/275)). +- Minor fixes in FindRust [#297](https://github.com/corrosion-rs/corrosion/pull/297): + - fix a logic error in the version detection + - fix a logic error in `QUIET` mode when rustup is not found. + +# 0.3.1 (2022-12-13) + +### Fixes + +- Fix a regression in detecting the MSVC abi ([#256]) +- Fix an issue on macOS 13 which affected rust crates compiling C++ code in build scripts ([#254]). +- Fix corrosion not respecting `CMAKE__OUTPUT_DIRECTORY` values ([#268]). +- Don't override rusts linker choice for the msvc abi (previously this was only skipped for msvc generators) ([#271]) + +[#254]: https://github.com/corrosion-rs/corrosion/pull/254 +[#256]: https://github.com/corrosion-rs/corrosion/pull/256 +[#268]: https://github.com/corrosion-rs/corrosion/pull/268 +[#271]: https://github.com/corrosion-rs/corrosion/pull/271 + +# 0.3.0 (2022-10-31) + +## Breaking + +- The minimum supported rust version (MSRV) was increased to 1.46, due to a cargo issue that recently + surfaced on CI when using crates.io. On MacOS 12 and Windows-2022 at least Rust 1.54 is required. +- MacOS 10 and 11 are no longer officially supported and untested in CI. +- The minimum required CMake version is now 3.15. +- Adding a `PRE_BUILD` custom command on a `cargo-build_` CMake target will no + longer work as expected. To support executing user defined commands before cargo build is + invoked users should use the newly added targets `cargo-prebuild` (before all cargo build invocations) + or `cargo-prebuild_` as a dependency target. + Example: `add_dependencies(cargo-prebuild code_generator_target)` + +### Breaking: Removed previously deprecated functionality +- Removed `add_crate()` function. Use `corrosio_import_crate()` instead. +- Removed `cargo_link_libraries()` function. Use `corrosion_link_libraries()` instead. +- Removed experimental CMake option `CORROSION_EXPERIMENTAL_PARSER`. + The corresponding stable option is `CORROSION_NATIVE_TOOLING` albeit with inverted semantics. +- Previously Corrosion would set the `HOST_CC` and `HOST_CXX` environment variables when invoking + cargo build, if the environment variables `CC` and `CXX` outside of CMake where set. + However this did not work as expected in all cases and sometimes the `HOST_CC` variable would be set + to a cross-compiler for unknown reasons. For this reason `HOST_CC` and `HOST_CXX` are not set by + corrosion anymore, but users can still set them manually if required via `corrosion_set_env_vars()`. +- The `CARGO_RUST_FLAGS` family of cache variables were removed. Corrosion does not internally use them + anymore. + +## Potentially breaking + +- The working directory when invoking `cargo build` was changed to the directory of the Manifest + file. This now allows cargo to pick up `.cargo/config.toml` files located in the source tree. + ([205](https://github.com/corrosion-rs/corrosion/pull/205)) +- Corrosion internally invokes `cargo build`. When passing arguments to `cargo build`, Corrosion + now uses the CMake `VERBATIM` option. In rare cases this may require you to change how you quote + parameters passed to corrosion (e.g. via `corrosion_add_target_rustflags()`). + For example setting a `cfg` option previously required double escaping the rustflag like this + `"--cfg=something=\\\"value\\\""`, but now it can be passed to corrosion without any escapes: + `--cfg=something="value"`. +- Corrosion now respects the CMake `OUTPUT_DIRECTORY` target properties. More details in the "New features" section. + +## New features + +- Support setting rustflags for only the main target and none of its dependencies ([215](https://github.com/corrosion-rs/corrosion/pull/215)). + A new function `corrosion_add_target_local_rustflags(target_name rustc_flag [more_flags ...])` + is added for this purpose. + This is useful in cases where you only need rustflags on the main-crate, but need to set different + flags for different targets. Without "local" Rustflags this would require rebuilds of the + dependencies when switching targets. +- Support explicitly selecting a linker ([208](https://github.com/corrosion-rs/corrosion/pull/208)). + The linker can be selected via `corrosion_set_linker(target_name linker)`. + Please note that this only has an effect for targets, where the final linker invocation is done + by cargo, i.e. targets where foreign code is linked into rust code and not the other way around. +- Corrosion now respects the CMake `OUTPUT_DIRECTORY` target properties and copies build artifacts to the expected + locations ([217](https://github.com/corrosion-rs/corrosion/pull/217)), if the properties are set. + This feature requires at least CMake 3.19 and is enabled by default if supported. Please note that the `OUTPUT_NAME` + target properties are currently not supported. + Specifically, the following target properties are now respected: + - [ARCHIVE_OUTPUT_DIRECTORY](https://cmake.org/cmake/help/latest/prop_tgt/ARCHIVE_OUTPUT_DIRECTORY.html) + - [LIBRARY_OUTPUT_DIRECTORY](https://cmake.org/cmake/help/latest/prop_tgt/LIBRARY_OUTPUT_DIRECTORY.html) + - [RUNTIME_OUTPUT_DIRECTORY](https://cmake.org/cmake/help/latest/prop_tgt/RUNTIME_OUTPUT_DIRECTORY.html) + - [PDB_OUTPUT_DIRECTORY](https://cmake.org/cmake/help/latest/prop_tgt/PDB_OUTPUT_DIRECTORY.html) +- Corrosion now supports packages with potentially multiple binaries (bins) and a library (lib) at the + same time. The only requirement is that the names of all `bin`s and `lib`s in the whole project must be unique. + Users can set the names in the `Cargo.toml` by adding `name = ` in the `[[bin]]` and `[lib]` tables. +- FindRust now has improved support for the `VERSION` option of `find_package` and will now attempt to find a matching + toolchain version. Previously it was only checked if the default toolchain matched to required version. +- For rustup managed toolchains a CMake error is issued with a helpful message if the required target for + the selected toolchain is not installed. + +## Fixes + +- Fix a CMake developer Warning when a Multi-Config Generator and Rust executable targets + ([#213](https://github.com/corrosion-rs/corrosion/pull/213)). +- FindRust now respects the `QUIET` option to `find_package()` in most cases. + +## Deprecation notice + +- Support for the MSVC Generators with CMake toolchains before 3.20 is deprecated and will be removed in the next + release (v0.4). All other Multi-config Generators already require CMake 3.20. + +## Internal Changes + +- The CMake Generator written in Rust and `CorrosionGenerator.cmake` which are responsible for parsing + `cargo metadata` output to create corresponding CMake targets for all Rust targets now share most code. + This greatly simplified the CMake generator written in Rust and makes it much easier maintaining and adding + new features regardless of how `cargo metadata` is parsed. + +# 0.2.2 (2022-09-01) + +## Fixes + +- Do not use C++17 in the tests (makes tests work with older C++ compilers) ([184](https://github.com/corrosion-rs/corrosion/pull/184)) +- Fix finding cargo on NixOS ([192](https://github.com/corrosion-rs/corrosion/pull/192)) +- Fix issue with Rustflags test when using a Build type other than Debug and Release ([203](https://github.com/corrosion-rs/corrosion/pull/203)). + +# 0.2.1 (2022-05-07) + +## Fixes + +- Fix missing variables provided by corrosion, when corrosion is used as a subdirectory ([181](https://github.com/corrosion-rs/corrosion/pull/181)): + Public [Variables](https://github.com/corrosion-rs/corrosion#information-provided-by-corrosion) set + by Corrosion were not visible when using Corrosion as a subdirectory, due to the wrong scope of + the variables. This was fixed by promoting the respective variables to Cache variables. + +# 0.2.0 (2022-05-05) + +## Breaking changes + +- Removed the integrator build script ([#156](https://github.com/corrosion-rs/corrosion/pull/156)). + The build script provided by corrosion (for rust code that links in foreign code) is no longer necessary, + so users can just remove the dependency. + +## Deprecations + +- Direct usage of the following target properties has been deprecated. The names of the custom properties are + no longer considered part of the public API and may change in the future. Instead, please use the functions + provided by corrosion. Internally different property names are used depending on the CMake version. + - `CORROSION_FEATURES`, `CORROSION_ALL_FEATURES`, `CORROSION_NO_DEFAULT_FEATURES`. Instead please use + `corrosion_set_features()`. See the updated Readme for details. + - `CORROSION_ENVIRONMENT_VARIABLES`. Please use `corrosion_set_env_vars()` instead. + - `CORROSION_USE_HOST_BUILD`. Please use `corrosion_set_hostbuild()` instead. +- The Minimum CMake version will likely be increased for the next major release. At the very least we want to drop + support for CMake 3.12, but requiring CMake 3.16 or even 3.18 is also on the table. If you are using a CMake version + that would be no longer supported by corrosion, please comment on issue + [#168](https://github.com/corrosion-rs/corrosion/issues/168), so that we can gauge the number of affected users. + +## New features + +- Add `NO_STD` option to `corrosion_import_crate` ([#154](https://github.com/corrosion-rs/corrosion/pull/154)). +- Remove the requirement of building the Rust based generator crate for CMake >= 3.19. This makes using corrosion as + a subdirectory as fast as the installed version (since everything is done in CMake). + ([#131](https://github.com/corrosion-rs/corrosion/pull/131), [#161](https://github.com/corrosion-rs/corrosion/pull/161)) + If you do choose to install Corrosion, then by default the old Generator is still compiled and installed, so you can + fall back to using it in case you use multiple cmake versions on the same machine for different projects. + +## Fixes + +- Fix Corrosion on MacOS 11 and 12 ([#167](https://github.com/corrosion-rs/corrosion/pull/167) and + [#164](https://github.com/corrosion-rs/corrosion/pull/164)). +- Improve robustness of parsing the LLVM version (exported in `Rust_LLVM_VERSION`). It now also works for + Rust versions, where the LLVM version is reported as `MAJOR.MINOR`. ([#148](https://github.com/corrosion-rs/corrosion/pull/148)) +- Fix a bug which occurred when Corrosion was added multiple times via `add_subdirectory()` + ([#143](https://github.com/corrosion-rs/corrosion/pull/143)). +- Set `CC_` and `CXX_` environment variables for the invocation of + `cargo build` to the compilers selected by CMake (if any) + ([#138](https://github.com/corrosion-rs/corrosion/pull/138) and [#161](https://github.com/corrosion-rs/corrosion/pull/161)). + This should ensure that C dependencies built in cargo buildscripts via [cc-rs](https://github.com/alexcrichton/cc-rs) + use the same compiler as CMake built dependencies. Users can override the compiler by specifying the higher + priority environment variable variants with dashes instead of underscores (See cc-rs documentation for details). +- Fix Ninja-Multiconfig Generator support for CMake versions >= 3.20. Previous CMake versions are missing a feature, + which prevents us from supporting the Ninja-Multiconfig generator. ([#137](https://github.com/corrosion-rs/corrosion/pull/137)) + + +# 0.1.0 (2022-02-01) + +This is the first release of corrosion after it was moved to the new corrosion-rs organization. +Since there are no previous releases, this is not a complete changelog but only lists changes since +September 2021. + +## New features +- [Add --profile support for rust >= 1.57](https://github.com/corrosion-rs/corrosion/pull/130): + Allows users to specify a custom cargo profile with + `corrosion_import_crate(... PROFILE )`. +- [Add support for specifying per-target Rustflags](https://github.com/corrosion-rs/corrosion/pull/127): + Rustflags can be added via `corrosion_add_target_rustflags( [rustflags1...])` +- [Add `Rust_IS_NIGHTLY` and `Rust_LLVM_VERSION` variables](https://github.com/corrosion-rs/corrosion/pull/123): + This may be useful if you want to conditionally enabled features when using a nightly toolchain + or a specific LLVM Version. +- [Let `FindRust` fail gracefully if rustc is not found](https://github.com/corrosion-rs/corrosion/pull/111): + This allows using `FindRust` in a more general setting (without corrosion). +- [Add support for cargo feature selection](https://github.com/corrosion-rs/corrosion/pull/108): + See the [README](https://github.com/corrosion-rs/corrosion#cargo-feature-selection) for details on + how to select features. + + +## Fixes +- [Fix the cargo-clean target](https://github.com/corrosion-rs/corrosion/pull/129) +- [Fix #84: CorrosionConfig.cmake looks in wrong place for Corrosion::Generator when CMAKE_INSTALL_LIBEXEC is an absolute path](https://github.com/corrosion-rs/corrosion/pull/122/commits/6f29af3ac53917ca2e0638378371e715a18a532d) +- [Fix #116: (Option CORROSION_INSTALL_EXECUTABLE not working)](https://github.com/corrosion-rs/corrosion/commit/97d44018fac1b1a2a7c095288c628f5bbd9b3184) +- [Fix building on Windows with rust >= 1.57](https://github.com/corrosion-rs/corrosion/pull/120) + +## Known issues: +- Corrosion is currently not working on macos-11 and newer. See issue [#104](https://github.com/corrosion-rs/corrosion/issues/104). + Contributions are welcome. diff --git a/libs/3rdparty/corrosion/cmake/Corrosion.cmake b/libs/3rdparty/corrosion/cmake/Corrosion.cmake new file mode 100644 index 00000000000..f71911ce0be --- /dev/null +++ b/libs/3rdparty/corrosion/cmake/Corrosion.cmake @@ -0,0 +1,2385 @@ +cmake_minimum_required(VERSION 3.22) + +list(APPEND CMAKE_MESSAGE_CONTEXT "Corrosion") + +message(DEBUG "Using Corrosion ${Corrosion_VERSION} with CMake ${CMAKE_VERSION} " + "and the `${CMAKE_GENERATOR}` Generator" +) + +get_cmake_property(COR_IS_MULTI_CONFIG GENERATOR_IS_MULTI_CONFIG) +set(COR_IS_MULTI_CONFIG "${COR_IS_MULTI_CONFIG}" CACHE BOOL "Do not change this" FORCE) +mark_as_advanced(FORCE COR_IS_MULTI_CONFIG) + + +if(NOT COR_IS_MULTI_CONFIG AND DEFINED CMAKE_CONFIGURATION_TYPES) + message(WARNING "The Generator is ${CMAKE_GENERATOR}, which is not a multi-config " + "Generator, but CMAKE_CONFIGURATION_TYPES is set. Please don't set " + "CMAKE_CONFIGURATION_TYPES unless you are using a multi-config Generator." + ) +endif() + +option(CORROSION_VERBOSE_OUTPUT "Enables verbose output from Corrosion and Cargo" OFF) + +if(DEFINED CORROSION_RESPECT_OUTPUT_DIRECTORY AND NOT CORROSION_RESPECT_OUTPUT_DIRECTORY) + message(WARNING "The option CORROSION_RESPECT_OUTPUT_DIRECTORY was removed." + " Corrosion now always attempts to respect the output directory.") +endif() + +option( + CORROSION_NO_WARN_PARSE_TARGET_TRIPLE_FAILED + "Surpresses a warning if the parsing the target triple failed." + OFF +) + +find_package(Rust REQUIRED) + +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() + +# message(STATUS "Using Corrosion as a subdirectory") + +get_property( + RUSTC_EXECUTABLE + TARGET Rust::Rustc PROPERTY IMPORTED_LOCATION +) + +get_property( + CARGO_EXECUTABLE + TARGET Rust::Cargo PROPERTY IMPORTED_LOCATION +) + +if(Rust_TOOLCHAIN_IS_RUSTUP_MANAGED AND DEFINED Rust_RUSTUP_TOOLCHAINS) + set(corrosion_tools_rust_toolchain_docstring "Rust toolchain to use for building helper tools such as cbindgen or cxx-bridge") + if(DEFINED CORROSION_TOOLS_RUST_TOOLCHAIN) + set(cor_default_tools_toolchain "${CORROSION_TOOLS_RUST_TOOLCHAIN}") + else() + set(cor_default_tools_toolchain "${Rust_TOOLCHAIN}") + endif() + set(CORROSION_TOOLS_RUST_TOOLCHAIN "${cor_default_tools_toolchain}" CACHE STRING + "${corrosion_tools_rust_toolchain_docstring}" FORCE) + set_property(CACHE CORROSION_TOOLS_RUST_TOOLCHAIN PROPERTY STRINGS "${Rust_RUSTUP_TOOLCHAINS}") + if(NOT "$CACHE{CORROSION_TOOLS_RUST_TOOLCHAIN}" IN_LIST Rust_RUSTUP_TOOLCHAINS) + if("$CACHE{CORROSION_TOOLS_RUST_TOOLCHAIN}-${Rust_CARGO_HOST_TARGET}" IN_LIST Rust_RUSTUP_TOOLCHAINS) + set(CORROSION_TOOLS_RUST_TOOLCHAIN "$CACHE{CORROSION_TOOLS_RUST_TOOLCHAIN}-${Rust_CARGO_HOST_TARGET}" + CACHE PATH "${corrosion_tools_rust_toolchain_docstring}" FORCE) + else() + message(FATAL_ERROR "CORROSION_TOOLS_RUST_TOOLCHAIN must be set to a valid rustup managed toolchain path." + "Rust_RUSTUP_TOOLCHAINS contains a list of valid installed toolchains." + ) + endif() + endif() + foreach(toolchain tc_rustc tc_cargo IN ZIP_LISTS Rust_RUSTUP_TOOLCHAINS Rust_RUSTUP_TOOLCHAINS_RUSTC_PATH Rust_RUSTUP_TOOLCHAINS_CARGO_PATH) + if("${toolchain}" STREQUAL $CACHE{CORROSION_TOOLS_RUST_TOOLCHAIN}) + # Minimum CMake version 3.29 for `IS_EXECUTABLE`. + if(NOT (tc_cargo AND tc_rustc )) + message(FATAL_ERROR "Failed to find executable rustc or cargo for toolchain `$CACHE{CORROSION_TOOLS_RUST_TOOLCHAIN}`") + endif() + set(CORROSION_TOOLS_RUSTC "${tc_rustc}" CACHE INTERNAL "" FORCE) + set(CORROSION_TOOLS_CARGO "${tc_cargo}" CACHE INTERNAL "" FORCE) + break() + endif() + endforeach() + if(NOT DEFINED CACHE{CORROSION_TOOLS_CARGO}) + message(FATAL_ERROR "Internal error: Failed to find toolchain $CACHE{CORROSION_TOOLS_RUST_TOOLCHAIN} in " + "list of rustup managed toolchains: ${Rust_RUSTUP_TOOLCHAINS}" + ) + endif() +else() + # Fallback to the default project toolchain if rust is not rustup managed. + if(DEFINED CORROSION_TOOLS_RUST_TOOLCHAIN) + message(DEBUG "Ignoring `CORROSION_TOOLS_RUST_TOOLCHAIN=${CORROSION_TOOLS_RUST_TOOLCHAIN}` " + "since the toolchains are not rustup managed. Falling back to the default rust toolchain" + " for this project." + ) + endif() + set(CORROSION_TOOLS_RUSTC "${RUSTC_EXECUTABLE}" CACHE INTERNAL "" FORCE) + set(CORROSION_TOOLS_CARGO "${CARGO_EXECUTABLE}" CACHE INTERNAL "" FORCE) +endif() + +function(_corrosion_bin_target_suffix target_name out_var_suffix) + get_target_property(hostbuild "${target_name}" ${_CORR_PROP_HOST_BUILD}) + if((hostbuild AND CMAKE_HOST_WIN32) + OR ((NOT hostbuild) AND (Rust_CARGO_TARGET_OS STREQUAL "windows"))) + set(_suffix ".exe") + elseif(Rust_CARGO_TARGET_OS STREQUAL "vxworks") + set(_suffix ".vxe") + else() + set(_suffix "") + endif() + set(${out_var_suffix} "${_suffix}" PARENT_SCOPE) +endfunction() + +function(_handle_output_directory_genex input_path config_type output_path) + if("${config_type}" STREQUAL "") + # Prevent new path from being `dir//file`, since that causes issues with the + # file dependency. + string(REPLACE "/\$" "${config_type}" curr_out_dir "${input_path}") + string(REPLACE "\$" "${config_type}" curr_out_dir "${curr_out_dir}") + else() + string(REPLACE "\$" "${config_type}" curr_out_dir "${input_path}") + endif() + string(GENEX_STRIP "${curr_out_dir}" stripped_out_dir) + if("${stripped_out_dir}" STREQUAL "${curr_out_dir}") + set("${output_path}" "${curr_out_dir}" PARENT_SCOPE) + else() + unset("${output_path}" PARENT_SCOPE) + message(WARNING "Encountered output directory path with unsupported genex. " + "Output dir: `${curr_out_dir}`" + "Note: Corrosion only supports the `\$` generator expression for output directories.") + endif() +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() + + # Append .exe suffix for executable by-products if the target is windows or if it's a host + # build and the host is Windows. + get_target_property(target_type ${target_name} TYPE) + if(${target_type} STREQUAL "EXECUTABLE" AND (NOT "${filename}" MATCHES "\.pdb$")) + _corrosion_bin_target_suffix(${target_name} "suffix") + string(APPEND filename "${suffix}") + 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}") + + 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) + string(GENEX_STRIP "${output_directory}" output_dir_no_genex) + # Only add config dir if there is no genex in here. See + # https://cmake.org/cmake/help/latest/prop_tgt/RUNTIME_OUTPUT_DIRECTORY.html + if(output_directory STREQUAL output_dir_no_genex) + set(curr_out_dir "${output_directory}/${config_type}") + else() + set(curr_out_dir "${output_directory}") + endif() + else() + set(curr_out_dir "${CMAKE_CURRENT_BINARY_DIR}") + endif() + _handle_output_directory_genex("${curr_out_dir}" "${config_type}" sanitized_out_dir) + if(NOT DEFINED sanitized_out_dir) + message(FATAL_ERROR "${output_directory_property} for target ${output_dir_prop_target_name} " + "contained an unexpected Generator expression. Output dir: `${curr_out_dir}`" + "Note: Corrosion only supports the `\$` generator expression for output directories.") + endif() + + # For Multiconfig we want to specify the correct location for each configuration + set_property( + TARGET ${target_name} + PROPERTY "${base_property}_${config_type_upper}" + "${sanitized_out_dir}/${filename}" + ) + set(base_output_directory "${sanitized_out_dir}") + endforeach() + + if(NOT COR_IS_MULTI_CONFIG) + if(output_directory) + set(base_output_directory "${output_directory}") + else() + set(base_output_directory "${CMAKE_CURRENT_BINARY_DIR}") + endif() + _handle_output_directory_genex("${base_output_directory}" "${CMAKE_BUILD_TYPE}" sanitized_output_directory) + if(NOT DEFINED sanitized_output_directory) + message(FATAL_ERROR "${output_dir_prop_target_name} for target ${output_dir_prop_target_name} " + "contained an unexpected Generator expression. Output dir: `${base_output_directory}`." + "Note: Corrosion only supports the `\$` generator expression for output directories.") + endif() + set(base_output_directory "${sanitized_output_directory}") + 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() + +# 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) + cmake_language(EVAL CODE " + cmake_language(DEFER + CALL + _corrosion_set_imported_location_deferred + [[${target_name}]] + [[${base_property}]] + [[${output_directory_property}]] + [[${filename}]] + ) + ") +endfunction() + +function(_corrosion_copy_byproduct_deferred target_name output_dir_prop_names cargo_build_dir file_names) + if(ARGN) + message(FATAL_ERROR "Unexpected additional arguments") + endif() + + foreach(output_dir_prop_name ${output_dir_prop_names}) + get_target_property(output_dir ${target_name} "${output_dir_prop_name}") + if(output_dir) + break() + endif() + endforeach() + + # 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) + foreach(output_dir_prop_name ${output_dir_prop_names}) + get_target_property(output_dir_curr_config ${target_name} "${output_dir_prop_name}_${config_type_upper}") + if(output_dir_curr_config) + break() + endif() + endforeach() + + if(output_dir_curr_config) + set(curr_out_dir "${output_dir_curr_config}") + elseif(output_dir) + string(GENEX_STRIP "${output_dir}" output_dir_no_genex) + # Only add config dir if there is no genex in here. See + # https://cmake.org/cmake/help/latest/prop_tgt/RUNTIME_OUTPUT_DIRECTORY.html + # Logic duplicated from _corrosion_set_imported_location_deferred + if(output_dir STREQUAL output_dir_no_genex) + set(curr_out_dir "${output_dir}/${config_type}") + else() + set(curr_out_dir "${output_dir}") + endif() + else() + # Fallback to the default directory. We do not append the configuration directory here + # and instead let CMake do this, since otherwise the resolving of dynamic library + # imported paths may fail. + set(curr_out_dir "${CMAKE_CURRENT_BINARY_DIR}") + endif() + set(multiconfig_out_dir_genex "${multiconfig_out_dir_genex}$<$:${curr_out_dir}>") + endforeach() + + if(COR_IS_MULTI_CONFIG) + set(output_dir "${multiconfig_out_dir_genex}") + else() + if(NOT output_dir) + # Fallback to default directory. + set(output_dir "${CMAKE_CURRENT_BINARY_DIR}") + endif() + endif() + + # Append .exe suffix for executable by-products if the target is windows or if it's a host + # build and the host is Windows. + get_target_property(target_type "${target_name}" TYPE) + if (target_type STREQUAL "EXECUTABLE") + list(LENGTH file_names list_len) + if(NOT list_len EQUAL "1") + message(FATAL_ERROR + "Internal error: Exactly one filename should be passed for executable types.") + endif() + _corrosion_bin_target_suffix(${target_name} "suffix") + if(suffix AND (NOT "${file_names}" MATCHES "\.pdb$")) + # For executable targets we know / checked that only one file will be passed. + string(APPEND file_names "${suffix}") + endif() + endif() + set(src_file_names "${file_names}") + if(Rust_CARGO_TARGET_ENV STREQUAL "gnullvm") + # Workaround for cargo not exposing implibs yet. + list(TRANSFORM src_file_names PREPEND "deps/" REGEX "\.dll\.a$") + endif() + list(TRANSFORM src_file_names PREPEND "${cargo_build_dir}/") + 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() + +# Copy the artifacts generated by cargo to the appropriate destination. +# +# Parameters: +# - target_name: The name of the Rust target +# - output_dir_prop_names: The property name(s) controlling the destination (e.g. +# `LIBRARY_OUTPUT_DIRECTORY` or `PDB_OUTPUT_DIRECTORY;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_names cargo_build_dir file_names) + cmake_language(EVAL CODE " + cmake_language(DEFER + CALL + _corrosion_copy_byproduct_deferred + [[${target_name}]] + [[${output_dir_prop_names}]] + [[${cargo_build_dir}]] + [[${file_names}]] + ) + ") +endfunction() + + +# Add targets for the static and/or shared libraries of the rust target. +# The generated byproduct names are returned via the `OUT__BYPRODUCTS` arguments. +function(_corrosion_add_library_target) + set(OPTIONS "") + set(ONE_VALUE_KEYWORDS + WORKSPACE_MANIFEST_PATH + TARGET_NAME + OUT_ARCHIVE_OUTPUT_BYPRODUCTS + OUT_SHARED_LIB_BYPRODUCTS + OUT_PDB_BYPRODUCT + ) + set(MULTI_VALUE_KEYWORDS LIB_KINDS) + cmake_parse_arguments(PARSE_ARGV 0 CALT "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}") + + if(DEFINED CALT_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Internal error - unexpected arguments: ${CALT_UNPARSED_ARGUMENTS}") + elseif(DEFINED CALT_KEYWORDS_MISSING_VALUES) + message(FATAL_ERROR "Internal error - the following keywords had no associated value(s):" + "${CALT_KEYWORDS_MISSING_VALUES}") + endif() + list(TRANSFORM ONE_VALUE_KEYWORDS PREPEND CALT_ OUTPUT_VARIABLE required_arguments) + foreach(required_argument ${required_arguments} ) + if(NOT DEFINED "${required_argument}") + message(FATAL_ERROR "Internal error: Missing required argument ${required_argument}." + "Complete argument list: ${ARGN}" + ) + endif() + endforeach() + if("staticlib" IN_LIST CALT_LIB_KINDS) + set(has_staticlib TRUE) + endif() + if("cdylib" IN_LIST CALT_LIB_KINDS) + set(has_cdylib TRUE) + endif() + + if(NOT (has_staticlib OR has_cdylib)) + message(FATAL_ERROR "Unknown library type(s): ${CALT_LIB_KINDS}") + endif() + set(workspace_manifest_path "${CALT_WORKSPACE_MANIFEST_PATH}") + set(target_name "${CALT_TARGET_NAME}") + + set(is_windows "") + set(is_windows_gnu "") + set(is_windows_msvc "") + set(is_macos "") + if(Rust_CARGO_TARGET_OS STREQUAL "windows") + set(is_windows TRUE) + if(Rust_CARGO_TARGET_ENV STREQUAL "msvc") + set(is_windows_msvc TRUE) + elseif(Rust_CARGO_TARGET_ENV STREQUAL "gnu" OR Rust_CARGO_TARGET_ENV STREQUAL "gnullvm") + set(is_windows_gnu TRUE) + endif() + elseif(Rust_CARGO_TARGET_OS STREQUAL "darwin") + set(is_macos TRUE) + endif() + + # 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("${CALT_OUT_SHARED_LIB_BYPRODUCTS}" "${dynamic_lib_name}" PARENT_SCOPE) + if(is_windows) + list(APPEND archive_output_byproducts ${implib_name}) + endif() + if(is_windows_msvc) + set("${CALT_OUT_PDB_BYPRODUCT}" "${pdb_name}" PARENT_SCOPE) + endif() + endif() + set("${CALT_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}) + set_target_properties(${target_name}-static PROPERTIES COR_FILE_NAME ${static_lib_name}) + + _corrosion_set_imported_location("${target_name}-static" "IMPORTED_LOCATION" + "ARCHIVE_OUTPUT_DIRECTORY" + "${static_lib_name}") + + # Todo: NO_STD target property? + if(NOT COR_NO_STD) + set_property( + TARGET ${target_name}-static + PROPERTY INTERFACE_LINK_LIBRARIES ${Rust_CARGO_TARGET_LINK_NATIVE_LIBS} + ) + set_property( + TARGET ${target_name}-static + PROPERTY INTERFACE_LINK_OPTIONS ${Rust_CARGO_TARGET_LINK_OPTIONS} + ) + 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}) + set_target_properties(${target_name}-shared PROPERTIES COR_FILE_NAME ${dynamic_lib_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}" + ) + # In the future we would probably prefer to let Rust set the soname for packages >= 1.0. + # This is tracked in issue #333. + set_target_properties(${target_name}-shared PROPERTIES IMPORTED_NO_SONAME TRUE) + + if(is_windows) + _corrosion_set_imported_location("${target_name}-shared" "IMPORTED_IMPLIB" + "ARCHIVE_OUTPUT_DIRECTORY" + "${implib_name}" + ) + set_target_properties(${target_name}-shared PROPERTIES COR_IMPLIB_FILE_NAME ${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() + + 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") + + if(Rust_CARGO_TARGET_ENV STREQUAL "msvc") + set(${out_pdb_byproduct} "${pdb_name}" PARENT_SCOPE) + endif() + + # Potential .exe suffix will be added later, also depending on possible hostbuild + # target property + set(bin_filename "${bin_name}") + set(${out_bin_byproduct} "${bin_filename}" PARENT_SCOPE) + add_dependencies(${bin_name} cargo-build_${bin_name}) + + if(Rust_CARGO_TARGET_OS STREQUAL "darwin") + 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() + + +include(CorrosionGenerator) + +# Note: `cmake_language(GET_MESSAGE_LOG_LEVEL )` requires CMake 3.25, +# so we offer our own option to control verbosity of downstream commands (e.g. cargo build) +if (CORROSION_VERBOSE_OUTPUT) + set(_CORROSION_VERBOSE_OUTPUT_FLAG --verbose CACHE INTERNAL "") +else() + # We want to silence some less important commands by default. + set(_CORROSION_QUIET_OUTPUT_FLAG --quiet CACHE INTERNAL "") +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}") +set(_CORROSION_RUST_CARGO_TARGET_UNDERSCORE "${_CORROSION_RUST_CARGO_TARGET_UNDERSCORE}" CACHE INTERNAL "lowercase target triple with underscores") +string(TOUPPER "${_CORROSION_RUST_CARGO_TARGET_UNDERSCORE}" _CORROSION_TARGET_TRIPLE_UPPER) +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. +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 "") + +# 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 WORKSPACE_MANIFEST_PATH) + set(multi_value_args BYPRODUCTS TARGET_KINDS) + cmake_parse_arguments( + ACB + "${options}" + "${one_value_args}" + "${multi_value_args}" + ${ARGN} + ) + + if(DEFINED ACB_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Internal error - unexpected arguments: " + ${ACB_UNPARSED_ARGUMENTS}) + elseif(DEFINED ACB_KEYWORDS_MISSING_VALUES) + message(FATAL_ERROR "Internal error - missing values for the following arguments: " + ${ACB_KEYWORDS_MISSING_VALUES}) + endif() + + set(package_name "${ACB_PACKAGE}") + set(target_name "${ACB_TARGET}") + set(path_to_toml "${ACB_MANIFEST_PATH}") + set(target_kinds "${ACB_TARGET_KINDS}") + set(workspace_manifest_path "${ACB_WORKSPACE_MANIFEST_PATH}") + set(build_byproducts "${ACB_BYPRODUCTS}") + + unset(cargo_rustc_crate_types) + 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") + if("${Rust_VERSION}" VERSION_GREATER_EQUAL "1.64") + # https://doc.rust-lang.org/1.64.0/cargo/commands/cargo-rustc.html + # `--crate-type` is documented since Rust 1.64 for `cargo rustc`. + # We just unconditionally set it when available, to support overriding the crate type. + # Due to https://github.com/rust-lang/cargo/issues/14498 we can't use one argument and pass a + # comma seperated list. Instead we use multiple arguments. + set(cargo_rustc_crate_types "${target_kinds}") + list(TRANSFORM cargo_rustc_crate_types PREPEND "--crate-type=") + endif() + 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}/$") + elseif(COR_IS_MULTI_CONFIG) + set(build_dir "$") + else() + unset(build_dir) + 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_USES_TERMINAL) + unset(cor_uses_terminal) + else() + set(cor_uses_terminal USES_TERMINAL) + endif() + + set(global_rustflags_target_property "$>") + set(local_rustflags_target_property "$>") + + # todo: this probably should be TARGET_GENEX_EVAL + set(features_target_property "$>") + set(features_genex "$<$:--features=$>>") + + # target property overrides corrosion_import_crate argument + set(all_features_target_property "$>") + set(all_features_arg "$<$:--all-features>") + + set(no_default_features_target_property "$>") + set(no_default_features_arg "$<$:--no-default-features>") + + set(build_env_variable_genex "$>") + set(hostbuild_override "$>") + set(if_not_host_build_condition "$") + + set(corrosion_link_args "$<${if_not_host_build_condition}:${corrosion_link_args}>") + # We always set `--target`, so that cargo always places artifacts into a directory with the + # target triple. + set(cargo_target_option "--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) + _corrosion_strip_target_triple("${_CORROSION_RUST_CARGO_TARGET_UPPER}" stripped_target_triple_upper) + set(target_artifact_dir "$") + + set(flags_genex "$>") + + set(explicit_linker_property "$") + set(explicit_linker_defined "$") + + set(cargo_profile_target_property "$>") + + # Option to override the rustc/cargo binary to something other than the global default + set(rustc_override "$") + set(cargo_override "$") + set(rustc_bin "$,${rustc_override},${_CORROSION_RUSTC}>") + set(cargo_bin "$,${cargo_override},${_CORROSION_CARGO}>") + + + # 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 "$<${hostbuild_override}:LIBRARY_PATH=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib>") + endif() + endif() + + set(cargo_profile_set "$") + # In the default case just specify --release or nothing to stay compatible with + # older rust versions. + set(default_profile_option "$<$,$>>:--release>") + # evaluates to either `--profile=`, `--release` or nothing (for debug). + set(cargo_profile "$") + + # If the profile name is `dev` change the dir name to `debug`. + set(is_dev_profile "$") + set(profile_dir_override "$<${is_dev_profile}:debug>") + set(profile_dir_is_overridden "$") + set(custom_profile_build_type_dir "$") + + set(default_build_type_dir "$,$>,debug,release>") + set(build_type_dir "$") + + # We set a target folder based on the manifest path so if you build multiple workspaces (or standalone projects + # without workspace) they won't collide if they use a common dependency. This would confuse cargo and trigger + # unnecessary rebuilds + cmake_path(GET workspace_manifest_path PARENT_PATH parent_path) + cmake_path(GET parent_path PARENT_PATH grandparent_path) + string(REPLACE "${grandparent_path}/" "" cargo_folder_name "${parent_path}") + string(SHA1 cargo_path_hash ${workspace_manifest_path}) + # Include a hash of the full path in case there are multiple projects with the same folder name + string(SUBSTRING "${cargo_path_hash}" 0 5 cargo_path_hash) + cmake_path(APPEND CMAKE_BINARY_DIR ${build_dir} cargo "${cargo_folder_name}_${cargo_path_hash}" + OUTPUT_VARIABLE cargo_target_dir) + 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(corrosion_cc_rs_flags) + + if(CMAKE_C_COMPILER) + # 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_${stripped_target_triple}=${CMAKE_C_COMPILER}") + endif() + if(CMAKE_CXX_COMPILER) + list(APPEND corrosion_cc_rs_flags "CXX_${stripped_target_triple}=${CMAKE_CXX_COMPILER}") + endif() + # cc-rs doesn't seem to support `llvm-ar` (commandline syntax), wo we might as well just use + # the default AR. + if(CMAKE_AR AND NOT (Rust_CARGO_TARGET_ENV STREQUAL "msvc")) + list(APPEND corrosion_cc_rs_flags "AR_${stripped_target_triple}=${CMAKE_AR}") + endif() + + # Todo: use a cache variable to avoid rechecking + # When using XCode to target iOS / iOSSimulator, `cc` will be a compiler that targets iOS. + # (Presumably this is because XCode modifies PATH). + # This causes linker errors, because Rust compiles build-scripts and proc-macros for the host-platform, and + # assumes `cc` is a valid linker driver for the host platform (but in this case `cc` targets iOS). + # To work around this we explicitly set the linker for the host platform, and use a dummy CMake project + # to determine a suitable C compiler. + unset(cargo_host_target_linker) + if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_NAME STREQUAL "iOS") + message(CHECK_START "Determining linker for host architecture (${Rust_CARGO_HOST_TARGET_CACHED})") + string(TOUPPER Rust_CARGO_HOST_TARGET_CACHED host_target_upper) + string(REPLACE "-" "_" host_target_upper host_target_upper_underscore) + unset(corrosion_host_c_compiler) + _corrosion_determine_host_compiler(corrosion_host_c_compiler cor_error_info) + if(DEFINED corrosion_host_c_compiler) + message(CHECK_PASS "${corrosion_host_c_compiler}") + set(cargo_host_target_linker "CARGO_TARGET_${host_target_upper_underscore}_LINKER=${corrosion_host_c_compiler}") + else() + message(CHECK_FAIL "Failed - ${cor_error_info}") + endif() + 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() + + # Ensure that cc-rs targets same Apple platform version as the CMake build + if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_OSX_DEPLOYMENT_TARGET) + list(APPEND corrosion_cc_rs_flags "MACOSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}") + endif() + + corrosion_add_target_local_rustflags("${target_name}" "$<$:-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 "$") + set(global_rustflags_genex "$<$:RUSTFLAGS=${global_joined_rustflags}>") + set(local_rustflags_delimiter "$<$:-->") + set(local_rustflags_genex "$<$:${local_rustflags_target_property}>") + + set(deps_link_languages_prop "$") + set(deps_link_languages "$") + set(target_uses_cxx "$") + unset(default_linker) + # With the MSVC ABI rustc only supports directly invoking the linker - Invoking cl as the linker driver is not supported. + if(NOT (Rust_CARGO_TARGET_ENV STREQUAL "msvc" OR COR_NO_LINKER_OVERRIDE)) + set(default_linker "$,${CMAKE_CXX_COMPILER},${CMAKE_C_COMPILER}>") + endif() + # Used to set a linker for a specific target-triple. + set(cargo_target_linker_var "CARGO_TARGET_${stripped_target_triple_upper}_LINKER") + set(linker "$") + 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}>") + endif() + + message(DEBUG "TARGET ${target_name} produces byproducts ${build_byproducts}") + message(DEBUG "corrosion_cc_rs_flags: ${corrosion_cc_rs_flags}") + + add_custom_target( + _cargo-build_${target_name} + # Build crate + COMMAND + ${CMAKE_COMMAND} -E env + "${build_env_variable_genex}" + "${global_rustflags_genex}" + "${cargo_target_linker}" + "${cargo_host_target_linker}" + "${corrosion_cc_rs_flags}" + "${cargo_library_path}" + "CORROSION_BUILD_DIR=${CMAKE_CURRENT_BINARY_DIR}" + "CARGO_BUILD_RUSTC=${rustc_bin}" + "${cargo_bin}" + rustc + ${cargo_rustc_filter} + ${cargo_target_option} + ${_CORROSION_VERBOSE_OUTPUT_FLAG} + ${all_features_arg} + ${no_default_features_arg} + ${features_genex} + --package ${package_name} + ${cargo_rustc_crate_types} + --manifest-path "${path_to_toml}" + --target-dir "${cargo_target_dir}" + ${cargo_profile} + ${flags_genex} + # Any arguments to cargo must be placed before this line + ${local_rustflags_delimiter} + ${local_rustflags_genex} + + # Note: `BYPRODUCTS` may not contain **target specific** generator expressions. + # This means we cannot use `${cargo_build_dir}`, since it currently uses `$` + # to determine the correct target directory, depending on if the hostbuild target property is + # set or not. + # BYPRODUCTS "${cargo_build_dir}/${build_byproducts}" + + # Set WORKING_DIRECTORY to the directory containing the manifest, so that configuration files + # such as `.cargo/config.toml` or `toolchain.toml` are applied as expected. Cargo searches for + # configuration files by walking upward from the current directory. + WORKING_DIRECTORY "${workspace_toml_dir}" + ${cor_uses_terminal} + COMMAND_EXPAND_LISTS + VERBATIM + ) + + # User exposed custom target, that depends on the internal target. + # Corrosion post build steps are added on the internal target, which + # ensures that they run before any user defined post build steps on this + # target. + add_custom_target( + cargo-build_${target_name} + ALL + ) + add_dependencies(cargo-build_${target_name} _cargo-build_${target_name}) + + # Add custom target before actual build that user defined custom commands (e.g. code generators) can + # use as a hook to do something before the build. This mainly exists to not expose the `_cargo-build` targets. + add_custom_target(cargo-prebuild_${target_name}) + add_dependencies(_cargo-build_${target_name} cargo-prebuild_${target_name}) + if(NOT TARGET cargo-prebuild) + add_custom_target(cargo-prebuild) + endif() + add_dependencies(cargo-prebuild cargo-prebuild_${target_name}) + + add_custom_target( + cargo-clean_${target_name} + COMMAND + "${cargo_bin}" clean ${cargo_target_option} + -p ${package_name} --manifest-path "${path_to_toml}" + # Set WORKING_DIRECTORY to the directory containing the manifest, so that configuration files + # such as `.cargo/config.toml` or `toolchain.toml` are applied as expected. Cargo searches for + # configuration files by walking upward from the current directory. + WORKING_DIRECTORY "${workspace_toml_dir}" + ${cor_uses_terminal} + ) + + if (NOT TARGET cargo-clean) + add_custom_target(cargo-clean) + endif() + add_dependencies(cargo-clean cargo-clean_${target_name}) +endfunction() + +#[=======================================================================[.md: +ANCHOR: corrosion-import-crate +```cmake +corrosion_import_crate( + MANIFEST_PATH + [ALL_FEATURES] + [NO_DEFAULT_FEATURES] + [NO_STD] + [NO_LINKER_OVERRIDE] + [NO_USES_TERMINAL] + [LOCKED] + [FROZEN] + [PROFILE ] + [IMPORTED_CRATES ] + [CRATE_TYPES ... ] + [OVERRIDE_CRATE_TYPE = ...] + [CRATES ... ] + [FEATURES ... ] + [FLAGS ... ] +) +``` +* **MANIFEST_PATH**: Path to a [Cargo.toml Manifest] file. +* **ALL_FEATURES**: Equivalent to [--all-features] passed to cargo build +* **NO_DEFAULT_FEATURES**: Equivalent to [--no-default-features] passed to cargo build +* **NO_STD**: Disable linking of standard libraries (required for no_std crates). +* **NO_LINKER_OVERRIDE**: Will let Rust/Cargo determine which linker to use instead of corrosion (when linking is invoked by Rust) +* **NO_USES_TERMINAL**: Don't pass the `USES_TERMINAL` flag when creating the custom CMake targets. +* **LOCKED**: Pass [`--locked`] to cargo build and cargo metadata. +* **FROZEN**: Pass [`--frozen`] to cargo build and cargo metadata. +* **PROFILE**: Specify cargo build profile (`dev`/`release` or a [custom profile]; `bench` and `test` are not supported) +* **IMPORTED_CRATES**: Save the list of imported crates into the variable with the provided name in the current scope. +* **CRATE_TYPES**: Only import the specified crate types. Valid values: `staticlib`, `cdylib`, `bin`. +* **OVERRIDE_CRATE_TYPE**: Override the crate-types of a cargo crate with the given comma-separated values. + Internally uses the `rustc` flag [`--crate-type`] to override the crate-type. + Valid values for the crate types are the library types `staticlib` and `cdylib`. +* **CRATES**: Only import the specified crates from a workspace. Values: Crate names. +* **FEATURES**: Enable the specified features. Equivalent to [--features] passed to `cargo build`. +* **FLAGS**: Arbitrary flags to `cargo build`. + +[custom profile]: https://doc.rust-lang.org/cargo/reference/profiles.html#custom-profiles +[--all-features]: https://doc.rust-lang.org/cargo/reference/features.html#command-line-feature-options +[--no-default-features]: https://doc.rust-lang.org/cargo/reference/features.html#command-line-feature-options +[--features]: https://doc.rust-lang.org/cargo/reference/features.html#command-line-feature-options +[`--locked`]: https://doc.rust-lang.org/cargo/commands/cargo.html#manifest-options +[`--frozen`]: https://doc.rust-lang.org/cargo/commands/cargo.html#manifest-options +[`--crate-type`]: https://doc.rust-lang.org/rustc/command-line-arguments.html#--crate-type-a-list-of-types-of-crates-for-the-compiler-to-emit +[Cargo.toml Manifest]: https://doc.rust-lang.org/cargo/appendix/glossary.html#manifest + +ANCHOR_END: corrosion-import-crate +#]=======================================================================] +function(corrosion_import_crate) + set(OPTIONS + ALL_FEATURES + NO_DEFAULT_FEATURES + NO_STD + NO_LINKER_OVERRIDE + NO_USES_TERMINAL + LOCKED + FROZEN) + set(ONE_VALUE_KEYWORDS MANIFEST_PATH PROFILE IMPORTED_CRATES) + set(MULTI_VALUE_KEYWORDS CRATE_TYPES CRATES FEATURES FLAGS OVERRIDE_CRATE_TYPE) + cmake_parse_arguments(COR "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}" ${ARGN}) + list(APPEND CMAKE_MESSAGE_CONTEXT "corrosion_import_crate") + + if(DEFINED COR_UNPARSED_ARGUMENTS) + message(AUTHOR_WARNING "Unexpected arguments: " ${COR_UNPARSED_ARGUMENTS} + "\nCorrosion will ignore these unexpected arguments." + ) + endif() + if(DEFINED COR_KEYWORDS_MISSING_VALUES) + message(DEBUG "Note: the following keywords passed to corrosion_import_crate had no associated value(s): " + ${COR_KEYWORDS_MISSING_VALUES} + ) + endif() + if (NOT DEFINED COR_MANIFEST_PATH) + message(FATAL_ERROR "MANIFEST_PATH is a required keyword to corrosion_add_crate") + endif() + _corrosion_option_passthrough_helper(NO_LINKER_OVERRIDE COR no_linker_override) + _corrosion_option_passthrough_helper(LOCKED COR locked) + _corrosion_option_passthrough_helper(FROZEN COR frozen) + _corrosion_arg_passthrough_helper(CRATES COR crate_allowlist) + _corrosion_arg_passthrough_helper(CRATE_TYPES COR crate_types) + + if(COR_PROFILE) + if(Rust_VERSION VERSION_LESS 1.57.0) + message(FATAL_ERROR "Selecting custom profiles via `PROFILE` requires at least rust 1.57.0, but you " + "have ${Rust_VERSION}." + ) + # The profile name could be part of a Generator expression, so this won't catch all occurences. + # Since it is hard to add an error message for genex, we don't do that here. + elseif("${COR_PROFILE}" STREQUAL "test" OR "${COR_PROFILE}" STREQUAL "bench") + message(FATAL_ERROR "Corrosion does not support building Rust crates with the cargo profiles" + " `test` or `bench`. These profiles add a hash to the output artifact name that we" + " cannot predict. Please consider using a custom cargo profile which inherits from the" + " built-in profile instead." + ) + endif() + endif() + + # intended to be used with foreach(... ZIP_LISTS ...), meaning + # that the crate_types at index i of `override_crate_type_types_list` are + # for the package_name at index i of `override_crate_type_package_name_list`. + # It would really be nice if CMake had structs or dicts. + unset(override_crate_type_package_name_list) + unset(override_crate_type_types_list) + unset(OVERRIDE_CRATE_TYPE_ARGS) + if(DEFINED COR_OVERRIDE_CRATE_TYPE) + string(JOIN " " usage_help + "Each argument to OVERRIDE_CRATE_TYPE must be of the form `=." + "The package_name must be a valid cargo package name and the crate_type must be " + "a comma-seperated list with valid values being `staticlib`, `cdylib` and `bin`" + ) + foreach(entry IN LISTS COR_OVERRIDE_CRATE_TYPE) + string(REPLACE "=" ";" key_val_list ${entry}) + list(LENGTH key_val_list key_val_list_len) + if(NOT key_val_list_len EQUAL "2") + message(FATAL_ERROR "Invalid argument: `${entry}` for parameter OVERRIDE_CRATE_TYPE!\n" + "${usage_help}" + ) + endif() + list(GET key_val_list "0" package_name) + list(GET key_val_list "1" crate_types) + list(APPEND override_crate_type_package_name_list "${package_name}") + list(APPEND override_crate_type_types_list "${crate_types}") + endforeach() + list(LENGTH override_crate_type_package_name_list num_override_packages) + list(LENGTH override_crate_type_types_list num_override_packages2) + if("${Rust_VERSION}" VERSION_LESS "1.64") + message(WARNING "OVERRIDE_CRATE_TYPE requires at Rust 1.64 or newer. Ignoring the option") + elseif(NOT num_override_packages EQUAL num_override_packages2) + message(WARNING "Internal error while parsing OVERRIDE_CRATE_TYPE arguments.\n" + "Corrosion will ignore this argument and continue." + ) + else() + # Pass by ref: we intentionally pass the list names here! + set(override_crate_types_arg "OVERRIDE_CRATE_TYPE_ARGS" "override_crate_type_package_name_list" "override_crate_type_types_list") + endif() + endif() + + if (NOT IS_ABSOLUTE "${COR_MANIFEST_PATH}") + set(COR_MANIFEST_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${COR_MANIFEST_PATH}) + endif() + + set(additional_cargo_flags ${COR_FLAGS}) + + if(COR_LOCKED AND NOT "--locked" IN_LIST additional_cargo_flags) + list(APPEND additional_cargo_flags "--locked") + endif() + if(COR_FROZEN AND NOT "--frozen" IN_LIST additional_cargo_flags) + list(APPEND additional_cargo_flags "--frozen") + endif() + + set(imported_crates "") + + _generator_add_cargo_targets( + MANIFEST_PATH + "${COR_MANIFEST_PATH}" + IMPORTED_CRATES + imported_crates + ${crate_allowlist} + ${crate_types} + ${no_linker_override} + ${override_crate_types_arg} + ) + + # Not target props yet: + # NO_STD + # NO_LINKER_OVERRIDE # We could simply zero INTERFACE_CORROSION_LINKER if this is set. + # LOCKED / FROZEN get merged into FLAGS after cargo metadata. + + # Initialize the target properties with the arguments to corrosion_import_crate. + set_target_properties( + ${imported_crates} + PROPERTIES + "${_CORR_PROP_ALL_FEATURES}" "${COR_ALL_FEATURES}" + "${_CORR_PROP_NO_DEFAULT_FEATURES}" "${COR_NO_DEFAULT_FEATURES}" + "${_CORR_PROP_FEATURES}" "${COR_FEATURES}" + INTERFACE_CORROSION_CARGO_PROFILE "${COR_PROFILE}" + INTERFACE_CORROSION_CARGO_FLAGS "${additional_cargo_flags}" + ) + + # _CORR_PROP_ENV_VARS + if(DEFINED COR_IMPORTED_CRATES) + set(${COR_IMPORTED_CRATES} ${imported_crates} PARENT_SCOPE) + endif() +endfunction() + +function(corrosion_set_linker target_name linker) + if(NOT linker) + message(FATAL_ERROR "The linker passed to `corrosion_set_linker` may not be empty") + elseif(NOT TARGET "${target_name}") + message(FATAL_ERROR "The target `${target_name}` does not exist.") + endif() + if(MSVC) + message(WARNING "Explicitly setting the linker with the MSVC toolchain is currently not supported and ignored") + endif() + + if(TARGET "${target_name}-static" AND NOT TARGET "${target_name}-shared") + message(WARNING "The target ${target_name} builds a static library." + "The linker is never invoked for a static library so specifying a linker has no effect." + ) + endif() + + set_property( + TARGET ${target_name} + PROPERTY INTERFACE_CORROSION_LINKER "${linker}" + ) +endfunction() + +function(corrosion_set_hostbuild target_name) + # Configure the target to be compiled for the Host target and ignore any cross-compile configuration. + set_property( + TARGET ${target_name} + PROPERTY ${_CORR_PROP_HOST_BUILD} 1 + ) +endfunction() + +# Add flags for rustc (RUSTFLAGS) which affect the target and all of it's Rust dependencies +# +# Additional rustflags may be passed as optional parameters after rustflag. +# Please note, that if you import multiple targets from a package or workspace, but set different +# Rustflags via this function, the Rust dependencies will have to be rebuilt when changing targets. +# Consider `corrosion_add_target_local_rustflags()` as an alternative to avoid this. +function(corrosion_add_target_rustflags target_name rustflag) + # Additional rustflags may be passed as optional parameters after rustflag. + set_property( + TARGET ${target_name} + APPEND + PROPERTY INTERFACE_CORROSION_RUSTFLAGS ${rustflag} ${ARGN} + ) +endfunction() + +# Add flags for rustc (RUSTFLAGS) which only affect the target, but none of it's (Rust) dependencies +# +# Additional rustflags may be passed as optional parameters after rustc_flag. +function(corrosion_add_target_local_rustflags target_name rustc_flag) + # Set Rustflags via `cargo rustc` which only affect the current crate, but not dependencies. + set_property( + TARGET ${target_name} + APPEND + PROPERTY INTERFACE_CORROSION_LOCAL_RUSTFLAGS ${rustc_flag} ${ARGN} + ) +endfunction() + +function(corrosion_set_env_vars target_name env_var) + # Additional environment variables may be passed as optional parameters after env_var. + set_property( + TARGET ${target_name} + APPEND + PROPERTY ${_CORR_PROP_ENV_VARS} ${env_var} ${ARGN} + ) +endfunction() + +function(corrosion_set_cargo_flags target_name) + # corrosion_set_cargo_flags( [ ... ]) + + set_property( + TARGET ${target_name} + APPEND + PROPERTY INTERFACE_CORROSION_CARGO_FLAGS ${ARGN} + ) +endfunction() + +function(corrosion_set_features target_name) + # corrosion_set_features( [ALL_FEATURES=Bool] [NO_DEFAULT_FEATURES] [FEATURES ... ]) + set(options NO_DEFAULT_FEATURES) + set(one_value_args ALL_FEATURES) + set(multi_value_args FEATURES) + cmake_parse_arguments( + PARSE_ARGV 1 + SET + "${options}" + "${one_value_args}" + "${multi_value_args}" + ) + + if(DEFINED SET_ALL_FEATURES) + set_property( + TARGET ${target_name} + PROPERTY ${_CORR_PROP_ALL_FEATURES} ${SET_ALL_FEATURES} + ) + endif() + if(SET_NO_DEFAULT_FEATURES) + set_property( + TARGET ${target_name} + PROPERTY ${_CORR_PROP_NO_DEFAULT_FEATURES} 1 + ) + endif() + if(SET_FEATURES) + set_property( + TARGET ${target_name} + APPEND + PROPERTY ${_CORR_PROP_FEATURES} ${SET_FEATURES} + ) + endif() +endfunction() + +function(corrosion_link_libraries target_name) + if(TARGET "${target_name}-static") + message(DEBUG "The target ${target_name} builds a static Rust library." + "Calling `target_link_libraries()` instead." + ) + target_link_libraries("${target_name}-static" INTERFACE ${ARGN}) + if(NOT TARGET "${target_name}-shared") + # Early return, since Rust won't invoke the linker for static libraries + return() + endif() + endif() + foreach(library ${ARGN}) + set_property( + TARGET _cargo-build_${target_name} + APPEND + PROPERTY CARGO_DEPS_LINKER_LANGUAGES + $ + ) + + if (TARGET "${library}") + # This works fine, except when compiling for ios. See https://cmake.org/pipermail/cmake/2016-March/063050.html + # XCODE_EMIT_EFFECTIVE_PLATFORM_NAME=OFF is supposed to prevent emitting EFFECTIVE_PLATFORM_NAME, but even + # with CMake 4.1 and the variable set to off EFFECTIVE_PLATFORM_NAME still leaks into generator expressions, + # and is not correctly replaced at build time + set(linker_dir "$") + # Probably should also affect other apple OSs with a simulator + if(CMAKE_SYSTEM_NAME STREQUAL "iOS") + unset(platform_name) + message(CHECK_START "corrosion_link_libraries: Attempting to replace EFFECTIVE_PLATFORM_NAME") + if(CMAKE_OSX_SYSROOT MATCHES "iphoneos") + set(platform_name "-iphoneos") + elseif(CMAKE_OSX_SYSROOT MATCHES "iphonesimulator") + set(platform_name "-iphonesimulator") + else() + # Todo: CMAKE_OSX_SYSROOT can be not set - how do we handle that? + message(CHECK_FAIL "Failed to determine platform name for iOS target from sysroot ${CMAKE_OSX_SYSROOT}") + endif() + if(DEFINED platform_name) + # This is a hack to fix $EFFECTIVE_PLATFORM_NAME not expanding in TARGET_LINKER_FILE_DIR + set(linker_dir "$${platform_name}>") + message(CHECK_PASS "done") + endif() + endif() + corrosion_add_target_local_rustflags(${target_name} + "-L${linker_dir}" + "-l$" + ) + add_dependencies(_cargo-build_${target_name} ${library}) + elseif(IS_ABSOLUTE "${library}") + # Linking via full path (See https://doc.rust-lang.org/rustc/command-line-arguments.html#linking-modifiers-verbatim) + corrosion_add_target_local_rustflags(${target_name} "-Clink-arg=${library}") + else() + # We have to assume ${library} is a non-CMake library name + corrosion_add_target_local_rustflags(${target_name} "-l${library}") + endif() + endforeach() +endfunction() + +#[=======================================================================[.md: +ANCHOR: corrosion-install +** EXPERIMENTAL **: This function is currently still considered experimental + and is not officially released yet. Feedback and Suggestions are welcome. + +```cmake +corrosion_install(TARGETS ... [EXPORT ] + [[ARCHIVE|LIBRARY|RUNTIME|PUBLIC_HEADER] + [DESTINATION ] + [PERMISSIONS ] + [CONFIGURATIONS [Debug|Release|]] + ] [...]) +``` +* **TARGETS**: Target or targets to install. +* **EXPORT**: Creates an export that can be installed with `install(EXPORT)`. must be globally unique. + Also creates a file at ${CMAKE_BINARY_DIR}/corrosion/Corrosion.cmake that must be included in the installed config file. +* **ARCHIVE**/**LIBRARY**/**RUNTIME**/PUBLIC_HEADER: Designates that the following settings only apply to that specific type of object. +* **DESTINATION**: The subdirectory within the CMAKE_INSTALL_PREFIX that a specific object should be placed. Defaults to values from GNUInstallDirs. +* **PERMISSIONS**: The permissions of files copied into the install prefix. + +Any `PUBLIC` or `INTERFACE` [file sets] will be installed. + +[file sets]: https://cmake.org/cmake/help/latest/command/target_sources.html#file-sets + +ANCHOR_END: corrosion-install +#]=======================================================================] +function(corrosion_install) + # Default install dirs + include(GNUInstallDirs) + + # Parse arguments to corrosion_install + list(GET ARGN 0 INSTALL_TYPE) + list(REMOVE_AT ARGN 0) + + # The different install types that are supported. Some targets may have more than one of these + # types. For example, on Windows, a shared library will have both an ARCHIVE component and a + # RUNTIME component. + set(INSTALL_TARGET_TYPES ARCHIVE LIBRARY RUNTIME PRIVATE_HEADER PUBLIC_HEADER) + + # Arguments to each install target type + set(OPTIONS) + set(ONE_VALUE_ARGS DESTINATION) + set(MULTI_VALUE_ARGS PERMISSIONS CONFIGURATIONS) + set(TARGET_ARGS ${OPTIONS} ${ONE_VALUE_ARGS} ${MULTI_VALUE_ARGS}) + + if (INSTALL_TYPE STREQUAL "TARGETS") + # Extract targets + set(INSTALL_TARGETS) + list(LENGTH ARGN ARGN_LENGTH) + set(DELIMITERS EXPORT ${INSTALL_TARGET_TYPES} ${TARGET_ARGS}) + while(ARGN_LENGTH) + # If we hit another keyword, stop - we've found all the targets + list(GET ARGN 0 FRONT) + if (FRONT IN_LIST DELIMITERS) + break() + endif() + + list(APPEND INSTALL_TARGETS ${FRONT}) + list(REMOVE_AT ARGN 0) + + # Update ARGN_LENGTH + list(LENGTH ARGN ARGN_LENGTH) + endwhile() + + # Check if there are any args left before proceeding + list(LENGTH ARGN ARGN_LENGTH) + if (ARGN_LENGTH) + list(GET ARGN 0 FRONT) + if (FRONT STREQUAL "EXPORT") + list(REMOVE_AT ARGN 0) # Pop "EXPORT" + + list(GET ARGN 0 EXPORT_NAME) + list(REMOVE_AT ARGN 0) # Pop + set(EXTRA_TARGETS_EXPORT_NAME ${EXPORT_NAME}Corrosion.cmake) + set(EXPORT_NAME EXPORT ${EXPORT_NAME}) + set(EXPORT_FILE_PATH "${CMAKE_BINARY_DIR}/corrosion/${EXTRA_TARGETS_EXPORT_NAME}") + # Remove first, since otherwise we will append to the file on every reconfigure. + # Assumes that the corrosion_install will only be called once for a given EXPORT_NAME. + file(REMOVE "${EXPORT_FILE_PATH}") + endif() + else() + # Prevent variable set in user code from interfering + set(EXPORT_NAME) + endif() + + # Loop over all arguments and get options for each install target type + list(LENGTH ARGN ARGN_LENGTH) + while(ARGN_LENGTH) + # Check if we're dealing with arguments for a specific install target type, or with + # default options for all target types. + list(GET ARGN 0 FRONT) + if (FRONT IN_LIST INSTALL_TARGET_TYPES) + set(INSTALL_TARGET_TYPE ${FRONT}) + list(REMOVE_AT ARGN 0) + else() + set(INSTALL_TARGET_TYPE DEFAULT) + endif() + + # Gather the arguments to this install type + set(ARGS) + list(LENGTH ARGN ARGN_LENGTH) + while(ARGN_LENGTH) + # If the next keyword is an install target type, then break - arguments have been + # gathered. + list(GET ARGN 0 FRONT) + if (FRONT IN_LIST INSTALL_TARGET_TYPES) + break() + endif() + + list(APPEND ARGS ${FRONT}) + list(REMOVE_AT ARGN 0) + + list(LENGTH ARGN ARGN_LENGTH) + endwhile() + + # Parse the arguments and register the file install + cmake_parse_arguments( + COR "${OPTIONS}" "${ONE_VALUE_ARGS}" "${MULTI_VALUE_ARGS}" ${ARGS}) + + if (COR_DESTINATION) + set(COR_INSTALL_${INSTALL_TARGET_TYPE}_DESTINATION ${COR_DESTINATION}) + endif() + + if (COR_PERMISSIONS) + set(COR_INSTALL_${INSTALL_TARGET_TYPE}_PERMISSIONS ${COR_PERMISSIONS}) + endif() + + if (COR_CONFIGURATIONS) + set(COR_INSTALL_${INSTALL_TARGET_TYPE}_CONFIGURATIONS ${COR_CONFIGURATIONS}) + endif() + + # Update ARG_LENGTH + list(LENGTH ARGN ARGN_LENGTH) + endwhile() + + # Default permissions for all files + set(DEFAULT_PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) + + # Loop through each install target and register file installations + foreach(INSTALL_TARGET ${INSTALL_TARGETS}) + if(NOT TARGET ${INSTALL_TARGET}) + message(FATAL_ERROR "Install target ${INSTALL_TARGET} is not a valid target") + endif() + # Don't both implementing target type differentiation using generator expressions since + # TYPE cannot change after target creation + get_property( + TARGET_TYPE + TARGET ${INSTALL_TARGET} PROPERTY TYPE + ) + + # Install executable files first + if (TARGET_TYPE STREQUAL "EXECUTABLE") + if (DEFINED COR_INSTALL_RUNTIME_DESTINATION) + set(DESTINATION ${COR_INSTALL_RUNTIME_DESTINATION}) + elseif (DEFINED COR_INSTALL_DEFAULT_DESTINATION) + set(DESTINATION ${COR_INSTALL_DEFAULT_DESTINATION}) + else() + set(DESTINATION ${CMAKE_INSTALL_BINDIR}) + endif() + + if (DEFINED COR_INSTALL_RUNTIME_PERMISSIONS) + set(PERMISSIONS ${COR_INSTALL_RUNTIME_PERMISSIONS}) + elseif (DEFINED COR_INSTALL_DEFAULT_PERMISSIONS) + set(PERMISSIONS ${COR_INSTALL_DEFAULT_PERMISSIONS}) + else() + set( + PERMISSIONS + ${DEFAULT_PERMISSIONS} OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE) + endif() + + if (DEFINED COR_INSTALL_RUNTIME_CONFIGURATIONS) + set(CONFIGURATIONS CONFIGURATIONS ${COR_INSTALL_RUNTIME_CONFIGURATIONS}) + elseif (DEFINED COR_INSTALL_DEFAULT_CONFIGURATIONS) + set(CONFIGURATIONS CONFIGURATIONS ${COR_INSTALL_DEFAULT_CONFIGURATIONS}) + else() + set(CONFIGURATIONS) + endif() + + install( + FILES $ + DESTINATION ${DESTINATION} + PERMISSIONS ${PERMISSIONS} + ${CONFIGURATIONS} + ) + elseif(TARGET_TYPE STREQUAL "INTERFACE_LIBRARY") + if(TARGET ${INSTALL_TARGET}-static) + if (DEFINED COR_INSTALL_ARCHIVE_DESTINATION) + set(DESTINATION ${COR_INSTALL_ARCHIVE_DESTINATION}) + elseif (DEFINED COR_INSTALL_DEFAULT_DESTINATION) + set(DESTINATION ${COR_INSTALL_DEFAULT_DESTINATION}) + else() + set(DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif() + + if (DEFINED COR_INSTALL_ARCHIVE_PERMISSIONS) + set(PERMISSIONS ${COR_INSTALL_ARCHIVE_PERMISSIONS}) + elseif (DEFINED COR_INSTALL_DEFAULT_PERMISSIONS) + set(PERMISSIONS ${COR_INSTALL_DEFAULT_PERMISSIONS}) + else() + set(PERMISSIONS ${DEFAULT_PERMISSIONS}) + endif() + + if (DEFINED COR_INSTALL_ARCHIVE_CONFIGURATIONS) + set(CONFIGURATIONS CONFIGURATIONS ${COR_INSTALL_ARCHIVE_CONFIGURATIONS}) + elseif (DEFINED COR_INSTALL_DEFAULT_CONFIGURATIONS) + set(CONFIGURATIONS CONFIGURATIONS ${COR_INSTALL_DEFAULT_CONFIGURATIONS}) + else() + set(CONFIGURATIONS) + endif() + + install( + FILES $ + DESTINATION ${DESTINATION} + PERMISSIONS ${PERMISSIONS} + ${CONFIGURATIONS} + ) + + if(EXPORT_NAME) + get_target_property(COR_FILE_NAME ${INSTALL_TARGET}-static COR_FILE_NAME) + file(APPEND "${EXPORT_FILE_PATH}" +" +add_library(${INSTALL_TARGET}-static STATIC IMPORTED) +set_target_properties(${INSTALL_TARGET}-static + PROPERTIES + IMPORTED_LOCATION \"\${PACKAGE_PREFIX_DIR}/${DESTINATION}/${COR_FILE_NAME}\" +) +" + ) + endif() + endif() + + if(TARGET ${INSTALL_TARGET}-shared) + if (DEFINED COR_INSTALL_LIBRARY_DESTINATION) + set(DESTINATION ${COR_INSTALL_LIBRARY_DESTINATION}) + elseif (DEFINED COR_INSTALL_DEFAULT_DESTINATION) + set(DESTINATION ${COR_INSTALL_DEFAULT_DESTINATION}) + else() + set(DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif() + + if (DEFINED COR_INSTALL_LIBRARY_PERMISSIONS) + set(PERMISSIONS ${COR_INSTALL_LIBRARY_PERMISSIONS}) + elseif (DEFINED COR_INSTALL_DEFAULT_PERMISSIONS) + set(PERMISSIONS ${COR_INSTALL_DEFAULT_PERMISSIONS}) + else() + set( + PERMISSIONS + ${DEFAULT_PERMISSIONS} OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE + ) + endif() + + if (DEFINED COR_INSTALL_LIBRARY_CONFIGURATIONS) + set(CONFIGURATIONS CONFIGURATIONS ${COR_INSTALL_LIBRARY_CONFIGURATIONS}) + elseif (DEFINED COR_INSTALL_DEFAULT_CONFIGURATIONS) + set(CONFIGURATIONS CONFIGURATIONS ${COR_INSTALL_DEFAULT_CONFIGURATIONS}) + else() + set(CONFIGURATIONS) + endif() + + install( + IMPORTED_RUNTIME_ARTIFACTS ${INSTALL_TARGET}-shared + PERMISSIONS ${PERMISSIONS} + DESTINATION ${DESTINATION} + ${CONFIGURATIONS} + ) + + if(EXPORT_NAME) + get_target_property(COR_FILE_NAME ${INSTALL_TARGET}-shared COR_FILE_NAME) + file(APPEND "${EXPORT_FILE_PATH}" +" +add_library(${INSTALL_TARGET}-shared SHARED IMPORTED) +set_target_properties(${INSTALL_TARGET}-shared + PROPERTIES + IMPORTED_LOCATION \"\${PACKAGE_PREFIX_DIR}/${DESTINATION}/${COR_FILE_NAME}\" +) +" + ) + + get_target_property(COR_IMPLIB_FILE_NAME ${INSTALL_TARGET}-shared COR_IMPLIB_FILE_NAME) + if (NOT COR_IMPLIB_FILE_NAME MATCHES .*-NOTFOUND) + file(APPEND "${EXPORT_FILE_PATH}" +" +set_target_properties(${INSTALL_TARGET}-shared + PROPERTIES + IMPORTED_IMPLIB \"\${PACKAGE_PREFIX_DIR}/${DESTINATION}/${COR_IMPLIB_FILE_NAME}\" +)" + ) + endif() + endif() + endif() + else() + message(FATAL_ERROR "Unknown target type ${TARGET_TYPE} for install target ${INSTALL_TARGET}") + endif() + + # Executables can also have export tables, so they _might_ also need header files + if (DEFINED COR_INSTALL_PUBLIC_HEADER_DESTINATION) + set(DESTINATION ${COR_INSTALL_PUBLIC_HEADER_DESTINATION}) + elseif (DEFINED COR_INSTALL_DEFAULT_DESTINATION) + set(DESTINATION ${COR_INSTALL_DEFAULT_DESTINATION}) + else() + set(DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + endif() + + if (DEFINED COR_INSTALL_PUBLIC_HEADER_PERMISSIONS) + set(PERMISSIONS ${COR_INSTALL_PUBLIC_HEADER_PERMISSIONS}) + elseif (DEFINED COR_INSTALL_DEFAULT_PERMISSIONS) + set(PERMISSIONS ${COR_INSTALL_DEFAULT_PERMISSIONS}) + else() + # Directories need OWNER_EXECUTE in order to be deletable by owner + set(PERMISSIONS ${DEFAULT_PERMISSIONS} OWNER_EXECUTE) + endif() + + if (DEFINED COR_INSTALL_PUBLIC_HEADER_CONFIGURATIONS) + set(CONFIGURATIONS CONFIGURATIONS ${COR_INSTALL_PUBLIC_HEADER_CONFIGURATIONS}) + elseif (DEFINED COR_INSTALL_DEFAULT_CONFIGURATIONS) + set(CONFIGURATIONS CONFIGURATIONS ${COR_INSTALL_DEFAULT_CONFIGURATIONS}) + else() + set(CONFIGURATIONS) + endif() + + get_target_property(FILE_SET ${INSTALL_TARGET} INTERFACE_HEADER_SETS) + if(NOT FILE_SET OR FILE_SET MATCHES .*-NOTFOUND) + set(TARGET_HAS_FILE_SET FALSE) + else() + set(TARGET_HAS_FILE_SET TRUE) + endif() + + if(NOT TARGET_HAS_FILE_SET) + if(EXPORT_NAME) + # We still need to generate a EXPORT but we can't do that with install(DIRECTORY) + install(TARGETS ${INSTALL_TARGET} ${EXPORT_NAME}) + endif() + + set(PUBLIC_HEADER_PROPERTIES INCLUDE_DIRECTORIES PUBLIC_INCLUDE_DIRECTORIES INTERFACE_INCLUDE_DIRECTORIES) + foreach(PUBLIC_HEADER_PROPERTY ${PUBLIC_HEADER_PROPERTIES}) + get_target_property(PUBLIC_HEADER ${INSTALL_TARGET} ${PUBLIC_HEADER_PROPERTY}) + + if(NOT PUBLIC_HEADER MATCHES .*-NOTFOUND) + foreach(INCLUDE_DIRECTORY ${PUBLIC_HEADER}) + install( + DIRECTORY ${INCLUDE_DIRECTORY} + DESTINATION . + FILE_PERMISSIONS ${PERMISSIONS} + DIRECTORY_PERMISSIONS ${PERMISSIONS} + ${CONFIGURATIONS} + ) + endforeach() + endif() + endforeach() + else() + install( + TARGETS ${INSTALL_TARGET} + ${EXPORT_NAME} + FILE_SET HEADERS + DESTINATION ${DESTINATION} + PERMISSIONS ${PERMISSIONS} + ${CONFIGURATIONS} + ) + endif() + endforeach() + + elseif(INSTALL_TYPE STREQUAL "EXPORT") + message(FATAL_ERROR "install(EXPORT ...) not yet implemented") + else() + message(FATAL_ERROR "Unknown arg: ${INSTALL_TYPE}") + endif() +endfunction() + +function(_corrosion_check_cxx_version_helper manifest_dir cxx_name out_required_version) + execute_process(COMMAND ${CMAKE_COMMAND} -E env + "CARGO_BUILD_RUSTC=${_CORROSION_RUSTC}" + ${_CORROSION_CARGO} tree -i "${cxx_name}" + # Usage of `cxx` could be gated behind a feature. Features can use Generator expressions, + # so we can't really know what features we will enable when building at this point. + # Features should be additive though, so simply enabling all-features should work for + # dependency resolution. + --all-features + --target all + --depth=0 + WORKING_DIRECTORY "${manifest_dir}" + RESULT_VARIABLE cxx_version_result + OUTPUT_VARIABLE cxx_version_output + ERROR_VARIABLE cxx_version_error + ) + if(NOT "${cxx_version_result}" EQUAL "0") + message(DEBUG "`cargo tree -i ${cxx_name}` returned an error: ${cxx_version_error}") + set("${out_required_version}" "${cxx_name}-NOTFOUND" PARENT_SCOPE) + return() + endif() + if(cxx_version_output MATCHES "${cxx_name} v([0-9]+.[0-9]+.[0-9]+)") + set("${out_required_version}" "${CMAKE_MATCH_1}" PARENT_SCOPE) + else() + message(DEBUG "Failed to parse `cargo tree -i ${cxx_name}` output: ${cxx_version_output}") + set("${out_required_version}" "${cxx_name}-NOTFOUND" PARENT_SCOPE) + endif() +endfunction() + +function(_corrosion_check_cxx_version manifest_dir out_required_version) + # cxxbridge-cmd is known to be available in lockfiles since cxx 1.0.131. + # We include `cxx` as a fallback to support older versions too. `cxxbridge` should always + # be exactly the same version as `cxx`, so falling back to `cxx` version should not cause issues. + foreach(cxxbridge_name cxxbridge-cmd cxx) + unset(cxx_required_version) + _corrosion_check_cxx_version_helper("${manifest_dir}" + "${cxxbridge_name}" + cxx_required_version) + if(cxx_required_version) + set("${out_required_version}" "${cxx_required_version}" PARENT_SCOPE) + break() + else() + set("${out_required_version}" "cxx-NOTFOUND" PARENT_SCOPE) + endif() + endforeach() + +endfunction() + + + +#[=======================================================================[.md: +** EXPERIMENTAL **: This function is currently still considered experimental + and is not officially released yet. Feedback and Suggestions are welcome. + +ANCHOR: corrosion_add_cxxbridge + +```cmake +corrosion_add_cxxbridge(cxx_target + CRATE + REGEN_TARGET + [FILES ] +) +``` + +Adds build-rules to create C++ bindings using the [cxx] crate. + +### Arguments: +* `cxxtarget`: Name of the C++ library target for the bindings, which corrosion will create. +* **FILES**: Input Rust source file containing #[cxx::bridge]. +* **CRATE**: Name of an imported Rust target. Note: Parameter may be renamed before release +* **REGEN_TARGET**: Name of a custom target that will regenerate the cxx bindings **without** recompiling. Note: Parameter may be renamed before release + +#### Currently missing arguments + +The following arguments to cxxbridge **currently** have no way to be passed by the user: +- `--cfg` +- `--cxx-impl-annotations` +- `--include` + +The created rules approximately do the following: +- Check which version of `cxx` the Rust crate specified by the `CRATE` argument depends on. +- Check if the exact same version of `cxxbridge-cmd` is installed (available in `PATH`) +- If not, create a rule to build the exact same version of `cxxbridge-cmd`. +- Create rules to run `cxxbridge` and generate + - The `rust/cxx.h` header + - A header and source file for each of the files specified in `FILES` +- The generated sources (and header include directories) are added to the `cxxtarget` CMake + library target. + +### Limitations + +We currently require the `CRATE` argument to be a target imported by Corrosion, however, +Corrosion does not import `rlib` only libraries. As a workaround users can add +`staticlib` to their list of crate kinds. In the future this may be solved more properly, +by either adding an option to also import Rlib targets (without build rules) or by +adding a `MANIFEST_PATH` argument to this function, specifying where the crate is. + +### Contributing + +Specifically some more realistic test / demo projects and feedback about limitations would be +welcome. + +[cxx]: https://github.com/dtolnay/cxx + +ANCHOR_END: corrosion_add_cxxbridge +#]=======================================================================] +function(corrosion_add_cxxbridge cxx_target) + set(OPTIONS) + set(ONE_VALUE_KEYWORDS CRATE REGEN_TARGET) + set(MULTI_VALUE_KEYWORDS FILES) + cmake_parse_arguments(PARSE_ARGV 1 _arg "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}") + + set(required_keywords CRATE FILES) + foreach(keyword ${required_keywords}) + if(NOT DEFINED "_arg_${keyword}") + message(FATAL_ERROR "Missing required parameter `${keyword}`.") + elseif("${_arg_${keyword}}" STREQUAL "") + message(FATAL_ERROR "Required parameter `${keyword}` may not be set to an empty string.") + endif() + endforeach() + + if(DEFINED _arg_UNPARSED_ARGUMENTS) + message(AUTHOR_WARNING "corrosion_add_cxxbridge was called with the following unknown arguments: " + "`${_arg_UNPARSED_ARGUMENTS}`\n" + "Unknown arguments will be ignored." + ) + endif() + + get_target_property(manifest_path "${_arg_CRATE}" INTERFACE_COR_PACKAGE_MANIFEST_PATH) + + if(NOT EXISTS "${manifest_path}") + message(FATAL_ERROR "Internal error: No package manifest found at ${manifest_path}") + endif() + + get_filename_component(manifest_dir ${manifest_path} DIRECTORY) + + _corrosion_check_cxx_version("${manifest_dir}" cxx_required_version) + + if(NOT cxx_required_version) + message(FATAL_ERROR + "Failed to find a dependency on `cxxbridge-cmd` / `cxx` for crate ${_arg_CRATE}" + ) + endif() + + # First check if a suitable version of cxxbridge is installed + find_program(INSTALLED_CXXBRIDGE cxxbridge PATHS "$ENV{HOME}/.cargo/bin/") + mark_as_advanced(INSTALLED_CXXBRIDGE) + if(INSTALLED_CXXBRIDGE) + execute_process(COMMAND ${INSTALLED_CXXBRIDGE} --version OUTPUT_VARIABLE cxxbridge_version_output) + if(cxxbridge_version_output MATCHES "cxxbridge ([0-9]+.[0-9]+.[0-9]+)") + set(cxxbridge_version "${CMAKE_MATCH_1}") + else() + set(cxxbridge_version "") + endif() + endif() + + set(cxxbridge "") + if(cxxbridge_version) + if(cxxbridge_version VERSION_EQUAL cxx_required_version) + set(cxxbridge "${INSTALLED_CXXBRIDGE}") + if(NOT TARGET "cxxbridge_v${cxx_required_version}") + # Add an empty target. + add_custom_target("cxxbridge_v${cxx_required_version}" + ) + endif() + endif() + endif() + + # No suitable version of cxxbridge was installed, so use custom target to build correct version. + if(NOT cxxbridge) + if(NOT TARGET "cxxbridge_v${cxx_required_version}") + unset(executable_postfix) + if(Rust_CARGO_HOST_OS STREQUAL "windows") + set(executable_postfix ".exe") + endif() + + add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/corrosion/cxxbridge_v${cxx_required_version}/bin/cxxbridge${executable_postfix}" + COMMAND + ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/corrosion/cxxbridge_v${cxx_required_version}" + COMMAND + ${CMAKE_COMMAND} -E env + "CARGO_BUILD_RUSTC=$CACHE{CORROSION_TOOLS_RUSTC}" + $CACHE{CORROSION_TOOLS_CARGO} install + cxxbridge-cmd + --version "${cxx_required_version}" + --locked + --root "${CMAKE_BINARY_DIR}/corrosion/cxxbridge_v${cxx_required_version}" + --quiet + # todo: use --target-dir to potentially reuse artifacts + COMMENT "Building cxxbridge (version ${cxx_required_version}) with Rust toolchain $CACHE{CORROSION_TOOLS_RUST_TOOLCHAIN}" + ) + add_custom_target("cxxbridge_v${cxx_required_version}" + DEPENDS "${CMAKE_BINARY_DIR}/corrosion/cxxbridge_v${cxx_required_version}/bin/cxxbridge${executable_postfix}" + ) + endif() + set(cxxbridge "${CMAKE_BINARY_DIR}/corrosion/cxxbridge_v${cxx_required_version}/bin/cxxbridge${executable_postfix}") + endif() + + + # The generated folder structure will be of the following form + # + # CMAKE_CURRENT_BINARY_DIR + # corrosion_generated + # cxxbridge + # + # include + # + # + # rust + # cxx.h + # src + # + # cbindgen + # ... + # other + # ... + + set(corrosion_generated_dir "${CMAKE_CURRENT_BINARY_DIR}/corrosion_generated") + set(generated_dir "${corrosion_generated_dir}/cxxbridge/${cxx_target}") + set(header_placement_dir "${generated_dir}/include/${cxx_target}") + set(source_placement_dir "${generated_dir}/src") + + add_library(${cxx_target} STATIC) + target_include_directories(${cxx_target} + PUBLIC + $ + $ + ) + + # cxx generated code is using c++11 features in headers, so propagate c++11 as minimal requirement + target_compile_features(${cxx_target} PUBLIC cxx_std_11) + + if (TARGET "${_arg_CRATE}-static") + target_link_libraries(${cxx_target} PRIVATE "${_arg_CRATE}-static") + target_link_libraries("${_arg_CRATE}-static" INTERFACE ${cxx_target}) + endif() + if (TARGET "${_arg_CRATE}-shared") + target_link_libraries(${cxx_target} PRIVATE "${_arg_CRATE}-shared") + target_link_libraries("${_arg_CRATE}-shared" INTERFACE ${cxx_target}) + endif() + + file(MAKE_DIRECTORY "${generated_dir}/include/rust") + add_custom_command( + OUTPUT "${generated_dir}/include/rust/cxx.h" + COMMAND + ${cxxbridge} --header --output "${generated_dir}/include/rust/cxx.h" + DEPENDS "cxxbridge_v${cxx_required_version}" + COMMENT "Generating rust/cxx.h header" + ) + + set(GENERATED_SOURCES "") + set(GENERATED_HEADERS "${generated_dir}/include/rust/cxx.h") + + foreach(filepath ${_arg_FILES}) + get_filename_component(filename ${filepath} NAME_WE) + get_filename_component(directory ${filepath} DIRECTORY) + set(directory_component "") + if(directory) + set(directory_component "${directory}/") + endif() + # todo: convert potentially absolute paths to relative paths.. + set(cxx_header ${directory_component}${filename}.h) + set(cxx_source ${directory_component}${filename}.cpp) + + # todo: not all projects may use the `src` directory. + set(rust_source_path "${manifest_dir}/src/${filepath}") + + file(MAKE_DIRECTORY "${header_placement_dir}/${directory}" "${source_placement_dir}/${directory}") + + add_custom_command( + OUTPUT + "${header_placement_dir}/${cxx_header}" + "${source_placement_dir}/${cxx_source}" + COMMAND + ${cxxbridge} ${rust_source_path} --header --output "${header_placement_dir}/${cxx_header}" + COMMAND + ${cxxbridge} ${rust_source_path} + --output "${source_placement_dir}/${cxx_source}" + --include "${cxx_target}/${cxx_header}" + DEPENDS "cxxbridge_v${cxx_required_version}" "${rust_source_path}" + COMMENT "Generating cxx bindings for crate ${_arg_CRATE} and file src/${filepath}" + ) + + list(APPEND GENERATED_SOURCES "${source_placement_dir}/${cxx_source}") + list(APPEND GENERATED_HEADERS "${header_placement_dir}/${cxx_header}") + endforeach() + target_sources(${cxx_target} PRIVATE ${GENERATED_SOURCES}) + # Make sure to export the headers with PUBLIC. + # This ensures that any target that depends on cxx_target also has these files as a dependency + # CMake will then make sure to generate the files before building either target, which is important + # in the presence of circular dependencies + target_sources(${cxx_target} PUBLIC ${GENERATED_HEADERS}) + + if(DEFINED _arg_REGEN_TARGET) + # Add only the headers to the regen target, as the sources are actually not needed + # For the IDE to pick everything up + add_custom_target(${_arg_REGEN_TARGET} + DEPENDS ${GENERATED_HEADERS} + COMMENT "Generated cxx bindings for crate ${_arg_CRATE}") + endif() + +endfunction() + +#[=======================================================================[.md: +ANCHOR: corrosion_cbindgen + +A helper function which uses [cbindgen] to generate C/C++ bindings for a Rust crate. +If `cbindgen` is not in `PATH` the helper function will automatically try to download +`cbindgen` and place the built binary into `CMAKE_BINARY_DIR`. The binary is shared +between multiple invocations of this function. + +The function comes with two different signatures. It's recommended to use the `TARGET` based signature when possible. + +### Auto mode (With a Rust target imported by corrosion) +```cmake +corrosion_experimental_cbindgen( + TARGET + HEADER_NAME + [CBINDGEN_VERSION ] + [FLAGS ... ] +) +``` + +### Auto-mode specific Arguments + + +* **TARGET**: The name of an imported Rust library target, for which bindings should be generated. + If the target is not imported by Corrosion, because the crate only produces an + `rlib`, you can instead use the second signature and manually pass `MANIFEST_DIRECTORY`, + `CARGO_PACKAGE` and `BINDINGS_TARGET` + +### Manual mode (Without a Rust target imported by corrosion) +```cmake +corrosion_experimental_cbindgen( + MANIFEST_DIRECTORY + CARGO_PACKAGE + BINDINGS_TARGET + [TARGET_TRIPLE ] + HEADER_NAME + [CBINDGEN_VERSION ] + [FLAGS ... ] +) +``` + +### Manual-mode specific Arguments + +* **MANIFEST_DIRECTORY**: Manual mode only. + Directory of the package defining the library crate bindings should be generated for. + If you want to avoid specifying `MANIFEST_DIRECTORY` you could add a `staticlib` target to your package + manifest as a workaround to make corrosion import the crate. + +* **CARGO_PACKAGE**: Manual mode only. + The name of the cargo package that bindings should be generated for. + Note: This corresponds to the `cbindgen` `--crate` option, which actually wants a package name. + +* **BINDINGS_TARGET**: Manual mode only. + Name of an `INTERFACE` CMake target that the generated bindings should be attached to. + In auto mode, the generated headers will be attached to the imported rust CMake crate, + and corrosion will take care of adding the necessary build dependencies. + In manual mode, this target likely doesn't exist, so the user needs to specify an INTERFACE CMake + target, which the header files should be attached to. The user must create this target themselves and + ensure to add any necessary dependencies (e.g. via `add_dependencies()`) to ensure that consumers of the + `INTERFACE` library are not linked before the Rust library has been built. + +* **TARGET_TRIPLE**: Manual mode only. + Rust target triple (e.g. `x86_64-unknown-linux-gnu`) that cbindgen should use when generating the bindings. + Defaults to target triple that corrosion was confiured to compile for. + +### Common Arguments + +* **HEADER_NAME**: The name of the generated header file. This will be the name which you include in your C/C++ code + (e.g. `#include "myproject/myheader.h" if you specify `HEADER_NAME "myproject/myheader.h"`. +* **CBINDGEN_VERSION**: Version requirement for cbindgen. Exact semantics to be specified. Currently not implemented. +* **FLAGS**: Arbitrary other flags for `cbindgen`. Run `cbindgen --help` to see the possible flags. + +[cbindgen]: https://github.com/mozilla/cbindgen + +### Current limitations + +- Cbindgens (optional) macro expansion feature internally actually builds the crate / runs the build script. + For this to work as expected in all cases, we probably need to set all the same environment variables + as when corrosion builds the crate. However the crate is a **library**, so we would need to figure out which + target builds it - and if there are multiple, potentially generate bindings per-target? + Alternatively we could add support of setting some environment variables on rlibs, and pulling that + information in when building the actual corrosion targets + Alternatively we could restrict corrosions support of this feature to actual imported staticlib/cdylib targets. +ANCHOR_END: corrosion_cbindgen +#]=======================================================================] +function(corrosion_experimental_cbindgen) + set(OPTIONS "") + set(ONE_VALUE_KEYWORDS + TARGET + MANIFEST_DIRECTORY + CARGO_PACKAGE + BINDINGS_TARGET + TARGET_TRIPLE + HEADER_NAME + CBINDGEN_VERSION + ) + set(MULTI_VALUE_KEYWORDS "FLAGS") + cmake_parse_arguments(PARSE_ARGV 0 CCN "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}") + + set(required_keywords HEADER_NAME) + foreach(keyword ${required_keywords}) + if(NOT DEFINED "CCN_${keyword}") + message(FATAL_ERROR "Missing required parameter `${keyword}`.") + elseif("${CCN_${keyword}}" STREQUAL "") + message(FATAL_ERROR "Required parameter `${keyword}` may not be set to an empty string.") + endif() + endforeach() + if(NOT (DEFINED CCN_TARGET + OR (DEFINED CCN_MANIFEST_DIRECTORY AND DEFINED CCN_BINDINGS_TARGET + AND DEFINED CCN_BINDINGS_TARGET) + ) + ) + message(FATAL_ERROR "Unknown signature for corrosion_experimental_cbindgen.\n" + "Either the `TARGET` or the `MANIFEST_DIRECTORY` based signature must be chosen.\n" + "Please view the documentation for details on the function signature.\n" + "Passed arguments where: `${ARGV}`" + ) + endif() + + if(DEFINED CCN_UNPARSED_ARGUMENTS) + message(AUTHOR_WARNING "corrosion_experimental_cbindgen was called with the following unknown arguments: " + "`${CCN_UNPARSED_ARGUMENTS}`\n" + "Unknown arguments will be ignored." + ) + endif() + unset(package_manifest_dir) + + + if(TARGET "${CCN_TARGET}") + set(cbindgen_bindings_target "${CCN_TARGET}") + set(hostbuild_override "$>") + set(cbindgen_target_triple "$") + + get_target_property(package_manifest_path "${CCN_TARGET}" INTERFACE_COR_PACKAGE_MANIFEST_PATH) + if(NOT EXISTS "${package_manifest_path}") + message(FATAL_ERROR "Internal error: No package manifest found at ${package_manifest_path}") + endif() + get_filename_component(package_manifest_dir "${package_manifest_path}" DIRECTORY) + get_target_property(rust_cargo_package "${CCN_TARGET}" COR_CARGO_PACKAGE_NAME ) + if(NOT rust_cargo_package) + message(FATAL_ERROR "Internal Error: Could not determine cargo package name for cbindgen. ") + endif() + # todo: as an optimization we could cache the cargo metadata output (but --no-deps makes that slightly more complicated) + else() + if(NOT DEFINED CCN_MANIFEST_DIRECTORY) + message(FATAL_ERROR + "Internal error: There should have been a fatal error already if neither TARGET or " + "MANIFEST_DIRECTORY are specfied.") + endif() + cmake_path(ABSOLUTE_PATH CCN_MANIFEST_DIRECTORY NORMALIZE OUTPUT_VARIABLE package_manifest_dir) + if(DEFINED CCN_TARGET_TRIPLE) + set(cbindgen_target_triple "${CCN_TARGET_TRIPLE}") + else() + set(cbindgen_target_triple "${Rust_CARGO_TARGET}") + endif() + set(rust_cargo_package "${CCN_CARGO_PACKAGE}") + set(cbindgen_bindings_target "${CCN_BINDINGS_TARGET}") + get_target_property(type "${cbindgen_bindings_target}" TYPE) + if(NOT ${type} STREQUAL "INTERFACE_LIBRARY") + message(AUTHOR_WARNING "The CMake target for the cbindgen generated files is expected to be" + " an `INTERFACE` library, but was `${type}` instead." + ) + endif() + endif() + + message(STATUS "Using package `${rust_cargo_package}` as crate for cbindgen") + + set(output_header_name "${CCN_HEADER_NAME}") + + find_program(installed_cbindgen cbindgen) + + # Install the newest cbindgen version into our build tree. + if(installed_cbindgen) + set(cbindgen "${installed_cbindgen}") + else() + set(local_cbindgen_install_dir "${CMAKE_BINARY_DIR}/corrosion/cbindgen") + unset(executable_postfix) + if(Rust_CARGO_HOST_OS STREQUAL "windows") + set(executable_postfix ".exe") + endif() + set(cbindgen "${local_cbindgen_install_dir}/bin/cbindgen${executable_postfix}") + + if(NOT TARGET "_corrosion_cbindgen") + file(MAKE_DIRECTORY "${local_cbindgen_install_dir}") + + add_custom_command(OUTPUT "${cbindgen}" + COMMAND ${CMAKE_COMMAND} + -E env + "CARGO_BUILD_RUSTC=$CACHE{CORROSION_TOOLS_RUSTC}" + $CACHE{CORROSION_TOOLS_CARGO} install + cbindgen + --locked + --root "${local_cbindgen_install_dir}" + ${_CORROSION_QUIET_OUTPUT_FLAG} + COMMENT "Building cbindgen with Rust toolchain $CACHE{CORROSION_TOOLS_RUST_TOOLCHAIN}" + VERBATIM + ) + add_custom_target("_corrosion_cbindgen" + DEPENDS "${cbindgen}" + ) + endif() + endif() + + set(corrosion_generated_dir "${CMAKE_CURRENT_BINARY_DIR}/corrosion_generated") + set(generated_dir "${corrosion_generated_dir}/cbindgen/${cbindgen_bindings_target}") + set(header_placement_dir "${generated_dir}/include") + set(depfile_placement_dir "${generated_dir}/depfile") + set(generated_depfile "${depfile_placement_dir}/${output_header_name}.d") + set(generated_header "${header_placement_dir}/${output_header_name}") + + if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.23") + target_sources(${cbindgen_bindings_target} + INTERFACE + FILE_SET HEADERS + BASE_DIRS "${header_placement_dir}" + FILES "${header_placement_dir}/${output_header_name}" + ) + else() + # Note: not clear to me how install would best work before CMake 3.23 + target_include_directories(${cbindgen_bindings_target} + INTERFACE + $ + $ + ) + endif() + + # This may be different from $header_placement_dir since the user specified HEADER_NAME may contain + # relative directories. + get_filename_component(generated_header_dir "${generated_header}" DIRECTORY) + file(MAKE_DIRECTORY "${generated_header_dir}") + + unset(depfile_cbindgen_arg) + get_filename_component(generated_depfile_dir "${generated_depfile}" DIRECTORY) + file(MAKE_DIRECTORY "${generated_depfile_dir}") + set(depfile_cbindgen_arg "--depfile=${generated_depfile}") + + add_custom_command( + OUTPUT + "${generated_header}" + COMMAND + "${CMAKE_COMMAND}" -E env + TARGET="${cbindgen_target_triple}" + # cbindgen invokes cargo-metadata and checks the CARGO environment variable + CARGO="${_CORROSION_CARGO}" + RUSTC="${_CORROSION_RUSTC}" + "${cbindgen}" + --output "${generated_header}" + --crate "${rust_cargo_package}" + ${depfile_cbindgen_arg} + ${CCN_FLAGS} + COMMENT "Generate cbindgen bindings for package ${rust_cargo_package} and output header ${generated_header}" + DEPFILE "${generated_depfile}" + COMMAND_EXPAND_LISTS + WORKING_DIRECTORY "${package_manifest_dir}" + ) + + if(NOT installed_cbindgen) + add_custom_command( + OUTPUT "${generated_header}" + APPEND + DEPENDS _corrosion_cbindgen + ) + endif() + + if(NOT TARGET "_corrosion_cbindgen_${cbindgen_bindings_target}_bindings") + add_custom_target(_corrosion_cbindgen_${cbindgen_bindings_target}_bindings + COMMENT "Generate cbindgen bindings for package ${rust_cargo_package}" + ) + endif() + # Users might want to call cbindgen multiple times, e.g. to generate separate C++ and C header files. + string(MAKE_C_IDENTIFIER "${output_header_name}" header_identifier ) + add_custom_target("_corrosion_cbindgen_${cbindgen_bindings_target}_bindings_${header_identifier}" + DEPENDS "${generated_header}" + COMMENT "Generate ${generated_header} for ${cbindgen_bindings_target}" + ) + add_dependencies("_corrosion_cbindgen_${cbindgen_bindings_target}_bindings" "_corrosion_cbindgen_${cbindgen_bindings_target}_bindings_${header_identifier}") + add_dependencies(${cbindgen_bindings_target} "_corrosion_cbindgen_${cbindgen_bindings_target}_bindings") + if(TARGET "${CCN_TARGET}") + add_dependencies(cargo-build_${CCN_TARGET} "_corrosion_cbindgen_${cbindgen_bindings_target}_bindings") + endif() +endfunction() + +# Parse the version of a Rust package from it's package manifest (Cargo.toml) +function(corrosion_parse_package_version package_manifest_path out_package_version) + if(NOT EXISTS "${package_manifest_path}") + message(FATAL_ERROR "Package manifest `${package_manifest_path}` does not exist.") + endif() + + file(READ "${package_manifest_path}" package_manifest) + + # Find the package table. It may contain arrays, so match until \n\[, which should mark the next + # table. Note: backslashes must be doubled to escape the backslash for the bracket. LF is single + # backslash however. On windows the line also ends in \n, so matching against \n\[ is sufficient + # to detect an opening bracket on a new line. + set(package_table_regex "\\[package\\](.*)\n\\[") + + string(REGEX MATCH "${package_table_regex}" _package_table "${package_manifest}") + + if(CMAKE_MATCH_COUNT EQUAL "1") + set(package_table "${CMAKE_MATCH_1}") + else() + message(DEBUG + "Failed to find `[package]` table in package manifest `${package_manifest_path}`.\n" + "Matches: ${CMAKE_MATCH_COUNT}\n" + ) + set(${out_package_version} + "NOTFOUND" + PARENT_SCOPE + ) + endif() + # Match `version = "0.3.2"`, `"version" = "0.3.2" Contains one matching group for the version + set(version_regex "[\r]?\n[\"']?version[\"']?[ \t]*=[ \t]*[\"']([0-9\.]+)[\"']") + + string(REGEX MATCH "${version_regex}" _version "${package_table}") + + if("${package_table}" MATCHES "${version_regex}") + set(${out_package_version} + "${CMAKE_MATCH_1}" + PARENT_SCOPE + ) + else() + message(DEBUG "Failed to extract package version from manifest `${package_manifest_path}`.") + set(${out_package_version} + "NOTFOUND" + PARENT_SCOPE + ) + endif() +endfunction() + +function(_corrosion_determine_host_compiler host_c_compiler_out error_out) + # Create minimal CMakeLists.txt to be generated for the host. + set(package_dir "${CMAKE_BINARY_DIR}/corrosion/host_compiler") + file(REMOVE_RECURSE "${package_dir}") + file(MAKE_DIRECTORY "${package_dir}") + set(lists "cmake_minimum_required(VERSION 3.10)\n") + string(APPEND lists "project(CorrosionDetermineHostCompiler LANGUAGES C)\n") + # We add a `:` after the compiler so we can easily match the end, since `:` is + # invalid in filenames. + string(APPEND lists "message(STATUS \"HOST_C_COMPILER=\${CMAKE_C_COMPILER}:\")\n") + file(WRITE "${package_dir}/CMakeLists.txt" "${lists}") + + # Generate the CMake project. + execute_process( + COMMAND ${CMAKE_COMMAND} + -DCMAKE_CROSSCOMPILING=OFF + "${package_dir}" + WORKING_DIRECTORY "${package_dir}" + OUTPUT_VARIABLE host_detection_output + ERROR_VARIABLE host_detection_error + RESULT_VARIABLE host_detection_result + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_STRIP_TRAILING_WHITESPACE + ) + + # Check if configuring the dummy CMake project failed. + if(NOT host_detection_result EQUAL 0) + message(WARNING "Failed to detect host compiler. Result: ${host_detection_result}\n" + "Output: ${host_detection_output}\n" + "Error: ${host_detection_result}") + return() + endif() + + # Extract C compiler from the output. + string(REGEX MATCH "HOST_C_COMPILER=([^:\r\n]*):" host_c_compiler_match "${host_detection_output}") + if(host_c_compiler_match) + set("${host_c_compiler_out}" "${CMAKE_MATCH_1}" PARENT_SCOPE) + else() + set("${error_out}" "Regex match failure: ${host_detection_output}") + endif() +endfunction() + +function(_corrosion_initialize_properties target_name) + # Initialize the `_OUTPUT_DIRECTORY` properties based on `CMAKE__OUTPUT_DIRECTORY`. + foreach(output_var RUNTIME_OUTPUT_DIRECTORY ARCHIVE_OUTPUT_DIRECTORY LIBRARY_OUTPUT_DIRECTORY PDB_OUTPUT_DIRECTORY) + if (DEFINED "CMAKE_${output_var}") + set_property(TARGET ${target_name} PROPERTY "${output_var}" "${CMAKE_${output_var}}") + endif() + + foreach(config_type ${CMAKE_CONFIGURATION_TYPES}) + string(TOUPPER "${config_type}" config_type_upper) + if (DEFINED "CMAKE_${output_var}_${config_type_upper}") + set_property(TARGET ${target_name} PROPERTY "${output_var}_${config_type_upper}" "${CMAKE_${output_var}_${config_type_upper}}") + endif() + endforeach() + endforeach() +endfunction() + +# Helper macro to pass through an optional `OPTION` argument parsed via `cmake_parse_arguments` +# to another function that takes the same OPTION. +# If the option was set, then the variable will be set to the same option name again, +# otherwise will be unset. +macro(_corrosion_option_passthrough_helper option_name prefix var_name) + if(${${prefix}_${option_name}}) + set("${var_name}" "${option_name}") + else() + unset("${var_name}") + endif() +endmacro() + +# Helper macro to pass through an optional argument with value(s), parsed via `cmake_parse_arguments`, +# to another function that takes the same keyword + associated values. +# If the argument was given, then the variable will be a list of the argument name and the values, +# which will be expanded, when calling the function (assuming no quotes). +macro(_corrosion_arg_passthrough_helper arg_name prefix var_name) + if(DEFINED "${prefix}_${arg_name}") + set("${var_name}" "${arg_name}" "${${prefix}_${arg_name}}") + else() + unset("${var_name}") + endif() +endmacro() + +list(POP_BACK CMAKE_MESSAGE_CONTEXT) diff --git a/libs/3rdparty/corrosion/cmake/CorrosionConfig.cmake.in b/libs/3rdparty/corrosion/cmake/CorrosionConfig.cmake.in new file mode 100644 index 00000000000..f8f4de3a6d7 --- /dev/null +++ b/libs/3rdparty/corrosion/cmake/CorrosionConfig.cmake.in @@ -0,0 +1,9 @@ +@PACKAGE_INIT@ + +if (Corrosion_FOUND) + return() +endif() + +list(APPEND CMAKE_MODULE_PATH "${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_DATADIR@/cmake") + +include(Corrosion) diff --git a/libs/3rdparty/corrosion/cmake/CorrosionGenerator.cmake b/libs/3rdparty/corrosion/cmake/CorrosionGenerator.cmake new file mode 100644 index 00000000000..471483215e7 --- /dev/null +++ b/libs/3rdparty/corrosion/cmake/CorrosionGenerator.cmake @@ -0,0 +1,344 @@ +function(_cargo_metadata out manifest) + set(OPTIONS LOCKED FROZEN) + set(ONE_VALUE_KEYWORDS "") + set(MULTI_VALUE_KEYWORDS "") + cmake_parse_arguments(PARSE_ARGV 2 CM "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}") + + list(APPEND CMAKE_MESSAGE_CONTEXT "_cargo_metadata") + + if(DEFINED CM_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Internal error - unexpected arguments: ${CM_UNPARSED_ARGUMENTS}") + elseif(DEFINED CM_KEYWORDS_MISSING_VALUES) + message(FATAL_ERROR "Internal error - the following keywords had no associated value(s):" + "${CM_KEYWORDS_MISSING_VALUES}") + endif() + + set(cargo_locked "") + set(cargo_frozen "") + if(LOCKED) + set(cargo_locked "--locked") + endif() + if(FROZEN) + set(cargo_frozen "--frozen") + endif() + + get_filename_component(workspace_toml_dir "${manifest}" DIRECTORY) + + execute_process( + COMMAND + ${CMAKE_COMMAND} -E env + "CARGO_BUILD_RUSTC=${_CORROSION_RUSTC}" + "${_CORROSION_CARGO}" + metadata + --manifest-path "${manifest}" + --format-version 1 + # We don't care about non-workspace dependencies + --no-deps + ${cargo_locked} + ${cargo_frozen} + # Set WORKING_DIRECTORY to the directory containing the manifest, so that configuration files + # such as `.cargo/config.toml` or `toolchain.toml` are applied as expected. Cargo searches for + # configuration files by walking upward from the current directory. + WORKING_DIRECTORY "${workspace_toml_dir}" + OUTPUT_VARIABLE json + COMMAND_ERROR_IS_FATAL ANY + ) + + set(${out} "${json}" PARENT_SCOPE) +endfunction() + +# Add targets (crates) of one package +function(_generator_add_package_targets) + set(OPTIONS NO_LINKER_OVERRIDE) + set(ONE_VALUE_KEYWORDS + WORKSPACE_MANIFEST_PATH + PACKAGE_MANIFEST_PATH + PACKAGE_NAME + PACKAGE_VERSION + TARGETS_JSON + OUT_CREATED_TARGETS) + set(MULTI_VALUE_KEYWORDS CRATE_TYPES OVERRIDE_CRATE_TYPE_ARGS) + cmake_parse_arguments(PARSE_ARGV 0 GAPT "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}") + + if(DEFINED GAPT_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Internal error - unexpected arguments: ${GAPT_UNPARSED_ARGUMENTS}") + elseif(DEFINED GAPT_KEYWORDS_MISSING_VALUES) + message(FATAL_ERROR "Internal error - the following keywords had no associated value(s):" + "${GAPT_KEYWORDS_MISSING_VALUES}") + endif() + + _corrosion_option_passthrough_helper(NO_LINKER_OVERRIDE GAPT no_linker_override) + + set(workspace_manifest_path "${GAPT_WORKSPACE_MANIFEST_PATH}") + set(package_manifest_path "${GAPT_PACKAGE_MANIFEST_PATH}") + set(package_name "${GAPT_PACKAGE_NAME}") + set(package_version "${GAPT_PACKAGE_VERSION}") + set(targets "${GAPT_TARGETS_JSON}") + set(out_created_targets "${GAPT_OUT_CREATED_TARGETS}") + set(crate_types "${GAPT_CRATE_TYPES}") + if(DEFINED GAPT_OVERRIDE_CRATE_TYPE_ARGS) + list(GET GAPT_OVERRIDE_CRATE_TYPE_ARGS 0 override_crate_name_list_ref) + list(GET GAPT_OVERRIDE_CRATE_TYPE_ARGS 1 override_crate_types_list_ref) + endif() + + set(corrosion_targets "") + + file(TO_CMAKE_PATH "${package_manifest_path}" manifest_path) + + string(JSON targets_len LENGTH "${targets}") + math(EXPR targets_len-1 "${targets_len} - 1") + + message(DEBUG "Found ${targets_len} targets in package ${package_name}") + + foreach(ix RANGE ${targets_len-1}) + string(JSON target GET "${targets}" ${ix}) + string(JSON target_name GET "${target}" "name") + string(JSON target_kind GET "${target}" "kind") + string(JSON target_kind_len LENGTH "${target_kind}") + + math(EXPR target_kind_len-1 "${target_kind_len} - 1") + set(kinds) + unset(override_package_crate_type) + # OVERRIDE_CRATE_TYPE is more specific than the CRATE_TYPES argument to corrosion_import_crate, and thus takes + # priority. + if(DEFINED GAPT_OVERRIDE_CRATE_TYPE_ARGS) + foreach(override_crate_name override_crate_types IN ZIP_LISTS ${override_crate_name_list_ref} ${override_crate_types_list_ref}) + if("${override_crate_name}" STREQUAL "${target_name}") + message(DEBUG "Forcing crate ${target_name} to crate-type(s): ${override_crate_types}.") + # Convert to CMake list + string(REPLACE "," ";" kinds "${override_crate_types}") + break() + endif() + endforeach() + else() + foreach(ix RANGE ${target_kind_len-1}) + string(JSON kind GET "${target_kind}" ${ix}) + if(NOT crate_types OR ${kind} IN_LIST crate_types) + list(APPEND kinds ${kind}) + endif() + endforeach() + endif() + if(TARGET "${target_name}" + AND ("staticlib" IN_LIST kinds OR "cdylib" IN_LIST kinds OR "bin" IN_LIST kinds) + ) + message(WARNING "Failed to import Rust crate ${target_name} (kind: `${target_kind}`) because a target " + "with the same name already exists. Skipping this target.\n" + "Help: If you are importing a package which exposes both a `lib` and " + "a `bin` target, please consider explicitly naming the targets in your `Cargo.toml` manifest.\n" + "Note: If you have multiple different packages which have targets with the same name, please note that " + "this is currently not supported by Corrosion. Feel free to open an issue on Github to request " + "supporting this scenario." + ) + # Skip this target to prevent a hard error. + continue() + endif() + + if("staticlib" IN_LIST kinds OR "cdylib" IN_LIST kinds) + # Explicitly set library names have always been forbidden from using dashes (by cargo). + # Starting with Rust 1.79, names inherited from the package name will have dashes replaced + # by underscores too. Corrosion will thus replace dashes with underscores, to make the target + # name consistent independent of the Rust version. `bin` target names are not affected. + # See https://github.com/corrosion-rs/corrosion/issues/501 for more details. + string(REPLACE "\-" "_" target_name "${target_name}") + + set(archive_byproducts "") + set(shared_lib_byproduct "") + set(pdb_byproduct "") + + add_library(${target_name} INTERFACE) + _corrosion_initialize_properties(${target_name}) + _corrosion_add_library_target( + WORKSPACE_MANIFEST_PATH "${workspace_manifest_path}" + TARGET_NAME "${target_name}" + LIB_KINDS ${kinds} + OUT_ARCHIVE_OUTPUT_BYPRODUCTS archive_byproducts + OUT_SHARED_LIB_BYPRODUCTS shared_lib_byproduct + OUT_PDB_BYPRODUCT pdb_byproduct + ) + + set(byproducts "") + list(APPEND byproducts "${archive_byproducts}" "${shared_lib_byproduct}" "${pdb_byproduct}") + + set(cargo_build_out_dir "") + _add_cargo_build( + cargo_build_out_dir + PACKAGE ${package_name} + TARGET ${target_name} + MANIFEST_PATH "${manifest_path}" + WORKSPACE_MANIFEST_PATH "${workspace_manifest_path}" + TARGET_KINDS "${kinds}" + BYPRODUCTS "${byproducts}" + # Optional + ${no_linker_override} + ) + if(archive_byproducts) + _corrosion_copy_byproducts( + ${target_name} ARCHIVE_OUTPUT_DIRECTORY "${cargo_build_out_dir}" "${archive_byproducts}" + ) + endif() + if(shared_lib_byproduct) + _corrosion_copy_byproducts( + ${target_name} LIBRARY_OUTPUT_DIRECTORY "${cargo_build_out_dir}" "${shared_lib_byproduct}" + ) + endif() + if(pdb_byproduct) + _corrosion_copy_byproducts( + ${target_name} "PDB_OUTPUT_DIRECTORY;LIBRARY_OUTPUT_DIRECTORY" "${cargo_build_out_dir}" "${pdb_byproduct}" + ) + endif() + list(APPEND corrosion_targets ${target_name}) + set_property(TARGET "${target_name}" PROPERTY COR_CARGO_PACKAGE_NAME "${package_name}" ) + # Note: "bin" is mutually exclusive with "staticlib/cdylib", since `bin`s are seperate crates from libraries. + elseif("bin" IN_LIST kinds) + set(bin_byproduct "") + set(pdb_byproduct "") + add_executable(${target_name} IMPORTED GLOBAL) + _corrosion_initialize_properties(${target_name}) + _corrosion_add_bin_target("${workspace_manifest_path}" "${target_name}" + "bin_byproduct" "pdb_byproduct" + ) + + set(byproducts "") + list(APPEND byproducts "${bin_byproduct}" "${pdb_byproduct}") + + set(cargo_build_out_dir "") + _add_cargo_build( + cargo_build_out_dir + PACKAGE "${package_name}" + TARGET "${target_name}" + MANIFEST_PATH "${manifest_path}" + WORKSPACE_MANIFEST_PATH "${workspace_manifest_path}" + TARGET_KINDS "bin" + BYPRODUCTS "${byproducts}" + # Optional + ${no_linker_override} + ) + _corrosion_copy_byproducts( + ${target_name} RUNTIME_OUTPUT_DIRECTORY "${cargo_build_out_dir}" "${bin_byproduct}" + ) + if(pdb_byproduct) + _corrosion_copy_byproducts( + ${target_name} "PDB_OUTPUT_DIRECTORY;RUNTIME_OUTPUT_DIRECTORY" "${cargo_build_out_dir}" "${pdb_byproduct}" + ) + endif() + list(APPEND corrosion_targets ${target_name}) + set_property(TARGET "${target_name}" PROPERTY COR_CARGO_PACKAGE_NAME "${package_name}" ) + else() + # ignore other kinds (like examples, tests, build scripts, ...) + endif() + endforeach() + + if(NOT corrosion_targets) + message(DEBUG "No relevant targets found in package ${package_name} - Ignoring") + else() + set_target_properties(${corrosion_targets} PROPERTIES INTERFACE_COR_PACKAGE_MANIFEST_PATH "${package_manifest_path}") + endif() + set(${out_created_targets} "${corrosion_targets}" PARENT_SCOPE) + +endfunction() + +# Add all cargo targets defined in the packages defined in the Cargo.toml manifest at +# `MANIFEST_PATH`. +function(_generator_add_cargo_targets) + set(options NO_LINKER_OVERRIDE) + set(one_value_args MANIFEST_PATH IMPORTED_CRATES) + set(multi_value_args CRATES CRATE_TYPES OVERRIDE_CRATE_TYPE_ARGS) + cmake_parse_arguments( + GGC + "${options}" + "${one_value_args}" + "${multi_value_args}" + ${ARGN} + ) + list(APPEND CMAKE_MESSAGE_CONTEXT "_add_cargo_targets") + + _corrosion_option_passthrough_helper(NO_LINKER_OVERRIDE GGC no_linker_override) + _corrosion_arg_passthrough_helper(CRATE_TYPES GGC crate_types) + _corrosion_arg_passthrough_helper(OVERRIDE_CRATE_TYPE_ARGS GGC override_crate_types) + + _cargo_metadata(json "${GGC_MANIFEST_PATH}") + string(JSON packages GET "${json}" "packages") + string(JSON workspace_members GET "${json}" "workspace_members") + + string(JSON pkgs_len LENGTH "${packages}") + math(EXPR pkgs_len-1 "${pkgs_len} - 1") + + string(JSON ws_mems_len LENGTH ${workspace_members}) + math(EXPR ws_mems_len-1 "${ws_mems_len} - 1") + + set(created_targets "") + set(available_package_names "") + foreach(ix RANGE ${pkgs_len-1}) + string(JSON pkg GET "${packages}" ${ix}) + string(JSON pkg_id GET "${pkg}" "id") + string(JSON pkg_name GET "${pkg}" "name") + string(JSON pkg_manifest_path GET "${pkg}" "manifest_path") + string(JSON pkg_version GET "${pkg}" "version") + list(APPEND available_package_names "${pkg_name}") + + if(DEFINED GGC_CRATES) + if(NOT pkg_name IN_LIST GGC_CRATES) + continue() + endif() + endif() + + # probably this loop is not necessary at all, since when using --no-deps, the + # contents of packages should already be only workspace members! + unset(pkg_is_ws_member) + foreach(ix RANGE ${ws_mems_len-1}) + string(JSON ws_mem GET "${workspace_members}" ${ix}) + if(ws_mem STREQUAL pkg_id) + set(pkg_is_ws_member YES) + break() + endif() + endforeach() + + if(NOT DEFINED pkg_is_ws_member) + # Since we pass `--no-deps` to cargo metadata now, I think this situation can't happen, but lets check for + # it anyway, just to discover any potential issues. + # If nobody complains for a while, it should be safe to remove this check and the previous loop, which + # should speed up the configuration process. + message(WARNING "The package `${pkg_name}` unexpectedly is not part of the workspace." + "Please open an issue at corrosion with some background information on the package" + ) + endif() + + string(JSON targets GET "${pkg}" "targets") + + _generator_add_package_targets( + WORKSPACE_MANIFEST_PATH "${GGC_MANIFEST_PATH}" + PACKAGE_MANIFEST_PATH "${pkg_manifest_path}" + PACKAGE_NAME "${pkg_name}" + PACKAGE_VERSION "${pkg_version}" + TARGETS_JSON "${targets}" + OUT_CREATED_TARGETS curr_created_targets + ${no_linker_override} + ${crate_types} + ${override_crate_types} + ) + list(APPEND created_targets "${curr_created_targets}") + endforeach() + + if(NOT created_targets) + set(crates_error_message "") + if(DEFINED GGC_CRATES) + set(crates_error_message "\n`corrosion_import_crate()` was called with the `CRATES` " + "parameter set to `${GGC_CRATES}`. Corrosion will only attempt to import packages matching " + "names from this list." + ) + endif() + message(FATAL_ERROR + "Found no targets in ${pkgs_len} packages." + ${crates_error_message}. + "\nPlease keep in mind that corrosion will only import Rust `bin` targets or" + "`staticlib` or `cdylib` library targets." + "The following packages were found in the Manifest: ${available_package_names}" + ) + else() + message(DEBUG "Corrosion created the following CMake targets: ${created_targets}") + endif() + + if(GGC_IMPORTED_CRATES) + set(${GGC_IMPORTED_CRATES} "${created_targets}" PARENT_SCOPE) + endif() +endfunction() diff --git a/libs/3rdparty/corrosion/cmake/FindRust.cmake b/libs/3rdparty/corrosion/cmake/FindRust.cmake new file mode 100644 index 00000000000..413645adb8d --- /dev/null +++ b/libs/3rdparty/corrosion/cmake/FindRust.cmake @@ -0,0 +1,904 @@ +#[=======================================================================[.rst: +FindRust +-------- + +Find Rust + +This module finds an installed rustc compiler and the cargo build tool. If Rust +is managed by rustup it determines the available toolchains and returns a +concrete Rust version, not a rustup proxy. + +#]=======================================================================] + +cmake_minimum_required(VERSION 3.12) + +option( + Rust_RUSTUP_INSTALL_MISSING_TARGET + "Use Rustup to automatically install missing targets instead of giving up" + OFF +) + +# search for Cargo here and set up a bunch of cool flags and stuff +include(FindPackageHandleStandardArgs) + +list(APPEND CMAKE_MESSAGE_CONTEXT "FindRust") + +# Print error message and return. Should not be used from inside functions +macro(_findrust_failed) + if("${Rust_FIND_REQUIRED}") + message(FATAL_ERROR ${ARGN}) + elseif(NOT "${Rust_FIND_QUIETLY}") + message(WARNING ${ARGN}) + endif() + set(Rust_FOUND "") + return() +endmacro() + +# Checks if the actual version of a Rust toolchain matches the VERSION requirements specified in find_package. +function(_findrust_version_ok ACTUAL_VERSION OUT_IS_OK) + if(DEFINED Rust_FIND_VERSION_RANGE) + if(Rust_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE") + set(COMPARSION_OPERATOR "VERSION_LESS_EQUAL") + elseif(Rust_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE") + set(COMPARSION_OPERATOR "VERSION_LESS") + else() + message(FATAL_ERROR "Unexpected value in `_FIND_VERSION_RANGE_MAX`: " + "`${Rust_FIND_VERSION_RANGE_MAX}`.") + endif() + if(("${ACTUAL_VERSION}" VERSION_GREATER_EQUAL "${Rust_FIND_VERSION_RANGE_MIN}") + AND + ( "${ACTUAL_VERSION}" ${COMPARSION_OPERATOR} "${Rust_FIND_VERSION_RANGE_MAX}" ) + ) + set("${OUT_IS_OK}" TRUE PARENT_SCOPE) + else() + set("${OUT_IS_OK}" FALSE PARENT_SCOPE) + endif() + elseif(DEFINED Rust_FIND_VERSION) + if(Rust_VERSION_EXACT) + set(COMPARISON_OPERATOR VERSION_EQUAL) + else() + set(COMPARISON_OPERATOR VERSION_GREATER_EQUAL) + endif() + if(_TOOLCHAIN_${_TOOLCHAIN_SELECTED}_VERSION "${COMPARISON_OPERATOR}" Rust_FIND_VERSION) + set("${OUT_IS_OK}" TRUE PARENT_SCOPE) + else() + set("${OUT_IS_OK}" FALSE PARENT_SCOPE) + endif() + else() + # if no VERSION requirement was specified, the version is always okay. + set("${OUT_IS_OK}" TRUE PARENT_SCOPE) + 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() + +function(_corrosion_parse_target_triple target_triple out_arch out_vendor out_os out_env) + _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[a-z0-9]*" # espressif, e.g. riscv32imc-esp-espidf or xtensa-esp32s3-none-elf + "fortanix" + "kmc" + "pc" + "nintendo" + "nvidia" + "openwrt" + "alpine" + "chimera" + "unikraft" + "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 determines some information about the output artifacts based on OS " + "specified in the Rust target-triple.\n" + "Currently this is relevant for windows and darwin (mac) targets, since file " + "extensions differ.\n" + "Note: If you are targeting a different OS you can suppress this warning by" + " setting the CMake cache variable " + "`CORROSION_NO_WARN_PARSE_TARGET_TRIPLE_FAILED`." + "Please consider opening an issue on github if you you need to add a new vendor to the list." + ) + endif() + + message(DEBUG "Parsed Target triple: arch: ${CMAKE_MATCH_1}, vendor: ${CMAKE_MATCH_3}, " + "OS: ${CMAKE_MATCH_4}, env: ${CMAKE_MATCH_6}") + + set("${out_arch}" "${CMAKE_MATCH_1}" PARENT_SCOPE) + set("${out_vendor}" "${CMAKE_MATCH_3}" PARENT_SCOPE) + set("${out_os}" "${CMAKE_MATCH_4}" PARENT_SCOPE) + set("${out_env}" "${CMAKE_MATCH_6}" PARENT_SCOPE) +endfunction() + +function(_corrosion_determine_libs_new target_triple out_libs out_flags) + set(package_dir "${CMAKE_BINARY_DIR}/corrosion/required_libs") + # Cleanup on reconfigure to get a cleans state (in case we change something in the future) + file(REMOVE_RECURSE "${package_dir}") + file(MAKE_DIRECTORY "${package_dir}") + set(manifest "[package]\nname = \"required_libs\"\nedition = \"2018\"\nversion = \"0.1.0\"\n") + string(APPEND manifest "\n[lib]\ncrate-type=[\"staticlib\"]\npath = \"lib.rs\"\n") + string(APPEND manifest "\n[workspace]\n") + file(WRITE "${package_dir}/Cargo.toml" "${manifest}") + file(WRITE "${package_dir}/lib.rs" "pub fn add(left: usize, right: usize) -> usize {left + right}\n") + + execute_process( + COMMAND ${CMAKE_COMMAND} -E env + "CARGO_BUILD_RUSTC=${Rust_COMPILER_CACHED}" + ${Rust_CARGO_CACHED} rustc --verbose --color never --target=${target_triple} -- --print=native-static-libs + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/corrosion/required_libs" + RESULT_VARIABLE cargo_build_result + ERROR_VARIABLE cargo_build_error_message + ) + if(cargo_build_result) + message(DEBUG "Determining required native libraries - failed: ${cargo_build_result}.") + message(TRACE "The cargo build error was: ${cargo_build_error_message}") + message(DEBUG "Note: This is expected for Rust targets without std support") + return() + else() + # The pattern starts with `native-static-libs:` and goes to the end of the line. + if(cargo_build_error_message MATCHES "native-static-libs: ([^\r\n]+)\r?\n") + string(REPLACE " " ";" "libs_list" "${CMAKE_MATCH_1}") + set(stripped_lib_list "") + set(flag_list "") + + set(was_last_framework OFF) + foreach(lib ${libs_list}) + # merge -framework;lib -> "-framework lib" as CMake does de-duplication of link libraries, and -framework prefix is required + if (lib STREQUAL "-framework") + set(was_last_framework ON) + continue() + endif() + if (was_last_framework) + list(APPEND stripped_lib_list "-framework ${lib}") + set(was_last_framework OFF) + continue() + endif() + + # Flags start with / for MSVC + if (lib MATCHES "^/" AND ${target_triple} MATCHES "msvc$") + # Windows GNU uses the compiler to invoke the linker, so -Wl, prefix is needed + # https://gitlab.kitware.com/cmake/cmake/-/blob/9bed4f4d817f139f0c2e050d7420e1e247949fe4/Modules/Platform/Windows-GNU.cmake#L156 + if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU") + list(APPEND flag_list "-Wl,${lib}") + else() + list(APPEND flag_list "${lib}") + endif() + else() + # Strip leading `-l` (unix) and potential .lib suffix (windows) + string(REGEX REPLACE "^-l" "" "stripped_lib" "${lib}") + string(REGEX REPLACE "\.lib$" "" "stripped_lib" "${stripped_lib}") + list(APPEND stripped_lib_list "${stripped_lib}") + endif() + endforeach() + set(libs_list "${stripped_lib_list}") + # We leave it up to the C/C++ executable that links in the Rust static-library + # to determine which version of the msvc runtime library it should select. + list(FILTER libs_list EXCLUDE REGEX "^msvcrtd?") + list(FILTER flag_list EXCLUDE REGEX "^(-Wl,)?/defaultlib:msvcrtd?") + else() + message(DEBUG "Determining required native libraries - failed: Regex match failure.") + message(DEBUG "`native-static-libs` not found in: `${cargo_build_error_message}`") + return() + endif() + endif() + set("${out_libs}" "${libs_list}" PARENT_SCOPE) + set("${out_flags}" "${flag_list}" PARENT_SCOPE) +endfunction() + +if (NOT "${Rust_TOOLCHAIN}" STREQUAL "$CACHE{Rust_TOOLCHAIN}") + # Promote Rust_TOOLCHAIN to a cache variable if it is not already a cache variable + set(Rust_TOOLCHAIN ${Rust_TOOLCHAIN} CACHE STRING "Requested rustup toolchain" FORCE) +endif() + +set(_RESOLVE_RUSTUP_TOOLCHAINS_DESC "Indicates whether to descend into the toolchain pointed to by rustup") +set(Rust_RESOLVE_RUSTUP_TOOLCHAINS ON CACHE BOOL ${_RESOLVE_RUSTUP_TOOLCHAINS_DESC}) + +# This block checks to see if we're prioritizing a rustup-managed toolchain. +if (DEFINED Rust_TOOLCHAIN) + # If the user specifies `Rust_TOOLCHAIN`, then look for `rustup` first, rather than `rustc`. + find_program(Rust_RUSTUP rustup PATHS "$ENV{HOME}/.cargo/bin") + if(NOT Rust_RUSTUP) + if(NOT "${Rust_FIND_QUIETLY}") + message( + WARNING "CMake variable `Rust_TOOLCHAIN` specified, but `rustup` was not found. " + "Ignoring toolchain and looking for a Rust toolchain not managed by rustup.") + endif() + endif() +else() + # If we aren't definitely using a rustup toolchain, look for rustc first - the user may have + # a toolchain installed via a method other than rustup higher in the PATH, which should be + # preferred. However, if the first-found rustc is a rustup proxy, then we'll revert to + # finding the preferred toolchain via rustup. + + # Uses `Rust_COMPILER` to let user-specified `rustc` win. But we will still "override" the + # user's setting if it is pointing to `rustup`. Default rustup install path is provided as a + # backup if a toolchain cannot be found in the user's PATH. + + if (DEFINED Rust_COMPILER) + set(_Rust_COMPILER_TEST "${Rust_COMPILER}") + set(_USER_SPECIFIED_RUSTC ON) + if(NOT (EXISTS "${_Rust_COMPILER_TEST}" AND NOT IS_DIRECTORY "${_Rust_COMPILER_TEST}")) + set(_ERROR_MESSAGE "Rust_COMPILER was set to `${Rust_COMPILER}`, but this file does " + "not exist." + ) + _findrust_failed(${_ERROR_MESSAGE}) + return() + endif() + else() + find_program(_Rust_COMPILER_TEST rustc PATHS "$ENV{HOME}/.cargo/bin") + if(NOT EXISTS "${_Rust_COMPILER_TEST}") + cmake_path(CONVERT "$ENV{HOME}/.cargo/bin" TO_CMAKE_PATH_LIST _cargo_bin_dir) + set(_ERROR_MESSAGE "`rustc` not found in PATH or `${_cargo_bin_dir}`.\n" + "Hint: Check if `rustc` is in PATH or manually specify the location " + "by setting `Rust_COMPILER` to the path to `rustc`.") + _findrust_failed(${_ERROR_MESSAGE}) + endif() + endif() + + # Check if the discovered rustc is actually a "rustup" proxy. + execute_process( + COMMAND + ${CMAKE_COMMAND} -E env + RUSTUP_FORCE_ARG0=rustup + "${_Rust_COMPILER_TEST}" --version + OUTPUT_VARIABLE _RUSTC_VERSION_RAW + ERROR_VARIABLE _RUSTC_VERSION_STDERR + RESULT_VARIABLE _RUSTC_VERSION_RESULT + ) + + if(NOT (_RUSTC_VERSION_RESULT EQUAL "0")) + _findrust_failed("`${_Rust_COMPILER_TEST} --version` failed with ${_RUSTC_VERSION_RESULT}\n" + "rustc stderr:\n${_RUSTC_VERSION_STDERR}" + ) + endif() + + if (_RUSTC_VERSION_RAW MATCHES "rustup [0-9\\.]+") + if (_USER_SPECIFIED_RUSTC) + message( + WARNING "User-specified Rust_COMPILER pointed to rustup's rustc proxy. Corrosion's " + "FindRust will always try to evaluate to an actual Rust toolchain, and so the " + "user-specified Rust_COMPILER will be discarded in favor of the default " + "rustup-managed toolchain." + ) + + unset(Rust_COMPILER) + unset(Rust_COMPILER CACHE) + endif() + + # Get `rustup` next to the `rustc` proxy + get_filename_component(_RUST_PROXIES_PATH "${_Rust_COMPILER_TEST}" DIRECTORY) + find_program(Rust_RUSTUP rustup HINTS "${_RUST_PROXIES_PATH}" NO_DEFAULT_PATH) + endif() + + unset(_Rust_COMPILER_TEST CACHE) +endif() + +# At this point, the only thing we should have evaluated is a path to `rustup` _if that's what the +# best source for a Rust toolchain was determined to be_. +if (NOT Rust_RUSTUP) + set(Rust_RESOLVE_RUSTUP_TOOLCHAINS OFF CACHE BOOL ${_RESOLVE_RUSTUP_TOOLCHAINS_DESC} FORCE) +endif() + +# List of user variables that will override any toolchain-provided setting +set(_Rust_USER_VARS Rust_COMPILER Rust_CARGO Rust_CARGO_TARGET Rust_CARGO_HOST_TARGET) +foreach(_VAR ${_Rust_USER_VARS}) + if (DEFINED "${_VAR}") + set(${_VAR}_CACHED "${${_VAR}}" CACHE INTERNAL "Internal cache of ${_VAR}") + else() + unset(${_VAR}_CACHED CACHE) + endif() +endforeach() + +# Discover what toolchains are installed by rustup, if the discovered `rustc` is a proxy from +# `rustup` and the user hasn't explicitly requested to override this behavior, then select either +# the default toolchain, or the requested toolchain Rust_TOOLCHAIN +if (Rust_RESOLVE_RUSTUP_TOOLCHAINS) + execute_process( + COMMAND + "${Rust_RUSTUP}" toolchain list --verbose + OUTPUT_VARIABLE _TOOLCHAINS_RAW + ) + + string(REPLACE "\n" ";" _TOOLCHAINS_RAW "${_TOOLCHAINS_RAW}") + set(_DISCOVERED_TOOLCHAINS "") + set(_DISCOVERED_TOOLCHAINS_RUSTC_PATH "") + set(_DISCOVERED_TOOLCHAINS_CARGO_PATH "") + set(_DISCOVERED_TOOLCHAINS_VERSION "") + + foreach(_TOOLCHAIN_RAW ${_TOOLCHAINS_RAW}) + if (_TOOLCHAIN_RAW MATCHES "([a-zA-Z0-9\\._\\-]+)[ \t\r\n]?(\\(active\\)|\\(active, default\\)|\\(default\\) \\(override\\)|\\(default\\)|\\(override\\))?[ \t\r\n]+(.+)") + set(_TOOLCHAIN "${CMAKE_MATCH_1}") + set(_TOOLCHAIN_TYPE "${CMAKE_MATCH_2}") + + set(_TOOLCHAIN_PATH "${CMAKE_MATCH_3}") + set(_TOOLCHAIN_${_TOOLCHAIN}_PATH "${CMAKE_MATCH_3}") + + if (_TOOLCHAIN_TYPE MATCHES ".*\\((active, )?default\\).*") + set(_TOOLCHAIN_DEFAULT "${_TOOLCHAIN}") + endif() + + if (_TOOLCHAIN_TYPE MATCHES ".*\\((active|override)\\).*") + set(_TOOLCHAIN_OVERRIDE "${_TOOLCHAIN}") + endif() + + execute_process( + COMMAND + "${_TOOLCHAIN_PATH}/bin/rustc" --version + OUTPUT_VARIABLE _TOOLCHAIN_RAW_VERSION + ) + if (_TOOLCHAIN_RAW_VERSION MATCHES "rustc ([0-9]+)\\.([0-9]+)\\.([0-9]+)(-nightly)?") + list(APPEND _DISCOVERED_TOOLCHAINS "${_TOOLCHAIN}") + list(APPEND _DISCOVERED_TOOLCHAINS_RUSTC_PATH "${_TOOLCHAIN_PATH}/bin/rustc") + list(APPEND _DISCOVERED_TOOLCHAINS_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}") + + # We need this variable to determine the default toolchain, since `foreach(... IN ZIP_LISTS ...)` + # requires CMake 3.17. As a workaround we define this variable to lookup the version when iterating + # through the `_DISCOVERED_TOOLCHAINS` lists. + set(_TOOLCHAIN_${_TOOLCHAIN}_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}") + if(CMAKE_MATCH_4) + set(_TOOLCHAIN_${_TOOLCHAIN}_IS_NIGHTLY "TRUE") + else() + set(_TOOLCHAIN_${_TOOLCHAIN}_IS_NIGHTLY "FALSE") + endif() + set(_suffix "") + if(CMAKE_HOST_WIN32) + set(_suffix ".exe") + endif() + if(EXISTS "${_TOOLCHAIN_PATH}/bin/cargo${_suffix}") + list(APPEND _DISCOVERED_TOOLCHAINS_CARGO_PATH "${_TOOLCHAIN_PATH}/bin/cargo") + else() + list(APPEND _DISCOVERED_TOOLCHAINS_CARGO_PATH "NOTFOUND") + endif() + else() + message(AUTHOR_WARNING "Unexpected output from `rustc --version` for Toolchain `${_TOOLCHAIN}`: " + "`${_TOOLCHAIN_RAW_VERSION}`.\n" + "Ignoring this toolchain (Path: `${_TOOLCHAIN_PATH}`)." + ) + endif() + else() + message(AUTHOR_WARNING "Didn't recognize toolchain: ${_TOOLCHAIN_RAW}. Ignoring this toolchain.\n" + "Rustup toolchain list output( `${Rust_RUSTUP} toolchain list --verbose`):\n" + "${_TOOLCHAINS_RAW}" + ) + endif() + endforeach() + + # Expose a list of available rustup toolchains. + list(LENGTH _DISCOVERED_TOOLCHAINS _toolchain_len) + list(LENGTH _DISCOVERED_TOOLCHAINS_RUSTC_PATH _toolchain_rustc_len) + list(LENGTH _DISCOVERED_TOOLCHAINS_CARGO_PATH _toolchain_cargo_len) + list(LENGTH _DISCOVERED_TOOLCHAINS_VERSION _toolchain_version_len) + if(NOT + (_toolchain_len EQUAL _toolchain_rustc_len + AND _toolchain_cargo_len EQUAL _toolchain_version_len + AND _toolchain_len EQUAL _toolchain_cargo_len) + ) + message(FATAL_ERROR "Internal error - list length mismatch." + "List lengths: ${_toolchain_len} toolchains, ${_toolchain_rustc_len} rustc, ${_toolchain_cargo_len} cargo," + " ${_toolchain_version_len} version. The lengths should be the same." + ) + endif() + + set(Rust_RUSTUP_TOOLCHAINS "${_DISCOVERED_TOOLCHAINS}" CACHE INTERNAL "List of available Rustup toolchains") + set(Rust_RUSTUP_TOOLCHAINS_RUSTC_PATH "${_DISCOVERED_TOOLCHAINS_RUSTC_PATH}" + CACHE INTERNAL + "List of the rustc paths corresponding to the toolchain at the same index in `Rust_RUSTUP_TOOLCHAINS`." + ) + set(Rust_RUSTUP_TOOLCHAINS_CARGO_PATH "${_DISCOVERED_TOOLCHAINS_CARGO_PATH}" + CACHE INTERNAL + "List of the cargo paths corresponding to the toolchain at the same index in `Rust_RUSTUP_TOOLCHAINS`. \ + May also be `NOTFOUND` if the toolchain does not have a cargo executable." + ) + set(Rust_RUSTUP_TOOLCHAINS_VERSION "${_DISCOVERED_TOOLCHAINS_VERSION}" + CACHE INTERNAL + "List of the rust toolchain version corresponding to the toolchain at the same index in \ + `Rust_RUSTUP_TOOLCHAINS`." + ) + + # Rust_TOOLCHAIN is preferred over a requested version if it is set. + if (NOT DEFINED Rust_TOOLCHAIN) + if (NOT DEFINED _TOOLCHAIN_OVERRIDE) + set(_TOOLCHAIN_SELECTED "${_TOOLCHAIN_DEFAULT}") + else() + set(_TOOLCHAIN_SELECTED "${_TOOLCHAIN_OVERRIDE}") + endif() + # Check default toolchain first. + _findrust_version_ok("_TOOLCHAIN_${_TOOLCHAIN_SELECTED}_VERSION" _VERSION_OK) + if(NOT "${_VERSION_OK}") + foreach(_TOOLCHAIN "${_DISCOVERED_TOOLCHAINS}") + _findrust_version_ok("_TOOLCHAIN_${_TOOLCHAIN}_VERSION" _VERSION_OK) + if("${_VERSION_OK}") + set(_TOOLCHAIN_SELECTED "${_TOOLCHAIN}") + break() + endif() + endforeach() + # Check if we found a suitable version in the for loop. + if(NOT "${_VERSION_OK}") + string(REPLACE ";" "\n" _DISCOVERED_TOOLCHAINS "${_DISCOVERED_TOOLCHAINS}") + _findrust_failed("Failed to find a Rust toolchain matching the version requirements of " + "${Rust_FIND_VERSION}. Available toolchains: ${_DISCOVERED_TOOLCHAINS}") + endif() + endif() + endif() + + set(Rust_TOOLCHAIN "${_TOOLCHAIN_SELECTED}" CACHE STRING "The rustup toolchain to use") + set_property(CACHE Rust_TOOLCHAIN PROPERTY STRINGS "${_DISCOVERED_TOOLCHAINS}") + + if(NOT Rust_FIND_QUIETLY) + message(STATUS "Rust Toolchain: ${Rust_TOOLCHAIN}") + endif() + + if (NOT Rust_TOOLCHAIN IN_LIST _DISCOVERED_TOOLCHAINS) + # If the precise toolchain wasn't found, try appending the default host + execute_process( + COMMAND + "${Rust_RUSTUP}" show + RESULT_VARIABLE _SHOW_RESULT + OUTPUT_VARIABLE _SHOW_RAW + ) + if(NOT "${_SHOW_RESULT}" EQUAL "0") + _findrust_failed("Command `${Rust_RUSTUP} show` failed") + endif() + + if (_SHOW_RAW MATCHES "Default host: ([a-zA-Z0-9_\\-]*)\n") + set(_DEFAULT_HOST "${CMAKE_MATCH_1}") + else() + _findrust_failed("Failed to parse \"Default host\" from `${Rust_RUSTUP} show`. Got: ${_SHOW_RAW}") + endif() + + if (NOT "${Rust_TOOLCHAIN}-${_DEFAULT_HOST}" IN_LIST _DISCOVERED_TOOLCHAINS) + set(_NOT_FOUND_MESSAGE "Could not find toolchain '${Rust_TOOLCHAIN}'\n" + "Available toolchains:\n" + ) + foreach(_TOOLCHAIN ${_DISCOVERED_TOOLCHAINS}) + list(APPEND _NOT_FOUND_MESSAGE " `${_TOOLCHAIN}`\n") + endforeach() + _findrust_failed(${_NOT_FOUND_MESSAGE}) + endif() + + set(_RUSTUP_TOOLCHAIN_FULL "${Rust_TOOLCHAIN}-${_DEFAULT_HOST}") + else() + set(_RUSTUP_TOOLCHAIN_FULL "${Rust_TOOLCHAIN}") + endif() + + set(_RUST_TOOLCHAIN_PATH "${_TOOLCHAIN_${_RUSTUP_TOOLCHAIN_FULL}_PATH}") + if(NOT "${Rust_FIND_QUIETLY}") + message(VERBOSE "Rust toolchain ${_RUSTUP_TOOLCHAIN_FULL}") + message(VERBOSE "Rust toolchain path ${_RUST_TOOLCHAIN_PATH}") + endif() + + # Is overridden if the user specifies `Rust_COMPILER` explicitly. + find_program( + Rust_COMPILER_CACHED + rustc + HINTS "${_RUST_TOOLCHAIN_PATH}/bin" + NO_DEFAULT_PATH) +else() + message(DEBUG "Rust_RESOLVE_RUSTUP_TOOLCHAINS=OFF and Rust_RUSTUP=${Rust_RUSTUP}") + if(Rust_RUSTUP) + get_filename_component(_RUSTUP_DIR "${Rust_RUSTUP}" DIRECTORY) + find_program(Rust_COMPILER_CACHED rustc HINTS "${_RUSTUP_DIR}") + else() + find_program(Rust_COMPILER_CACHED rustc) + endif() + message(DEBUG "find_program rustc: ${Rust_COMPILER_CACHED}") + if (EXISTS "${Rust_COMPILER_CACHED}") + # rustc is expected to be at `/bin/rustc`. + get_filename_component(_RUST_TOOLCHAIN_PATH "${Rust_COMPILER_CACHED}" DIRECTORY) + get_filename_component(_RUST_TOOLCHAIN_PATH "${_RUST_TOOLCHAIN_PATH}" DIRECTORY) + endif() +endif() + +if (NOT EXISTS "${Rust_COMPILER_CACHED}") + set(_NOT_FOUND_MESSAGE "The rustc executable was not found. " + "Rust not installed or ~/.cargo/bin not added to path?\n" + "Hint: Consider setting `Rust_COMPILER` to the absolute path of `rustc`." + ) + _findrust_failed(${_NOT_FOUND_MESSAGE}) +endif() + +if (Rust_RESOLVE_RUSTUP_TOOLCHAINS) + set(_NOT_FOUND_MESSAGE "Rust was detected to be managed by rustup, but failed to find `cargo` " + "next to `rustc` in `${_RUST_TOOLCHAIN_PATH}/bin`. This can happen for custom toolchains, " + "if cargo was not built. " + "Please manually specify the path to a compatible `cargo` by setting `Rust_CARGO`." + ) + find_program( + Rust_CARGO_CACHED + cargo + HINTS "${_RUST_TOOLCHAIN_PATH}/bin" + NO_DEFAULT_PATH + ) + # note: maybe can use find_package_handle_standard_args here, if we remove the _CACHED postfix. + # not sure why that is here... + if(NOT EXISTS "${Rust_CARGO_CACHED}") + _findrust_failed(${_NOT_FOUND_MESSAGE}) + endif() + set(Rust_TOOLCHAIN_IS_RUSTUP_MANAGED TRUE CACHE INTERNAL "" FORCE) +else() + set(_NOT_FOUND_MESSAGE "Failed to find `cargo` in PATH and `${_RUST_TOOLCHAIN_PATH}/bin`.\n" + "Please ensure cargo is in PATH or manually specify the path to a compatible `cargo` by " + "setting `Rust_CARGO`." + ) + # On some systems (e.g. NixOS) cargo is not managed by rustup and also not next to rustc. + find_program( + Rust_CARGO_CACHED + cargo + HINTS "${_RUST_TOOLCHAIN_PATH}/bin" + ) + # note: maybe can use find_package_handle_standard_args here, if we remove the _CACHED postfix. + # not sure why that is here... + if(NOT EXISTS "${Rust_CARGO_CACHED}") + _findrust_failed(${_NOT_FOUND_MESSAGE}) + endif() +endif() + +execute_process( + COMMAND "${Rust_CARGO_CACHED}" --version --verbose + OUTPUT_VARIABLE _CARGO_VERSION_RAW + RESULT_VARIABLE _CARGO_VERSION_RESULT +) +# todo: check if cargo is a required component! +if(NOT ( "${_CARGO_VERSION_RESULT}" EQUAL "0" )) + _findrust_failed("Failed to get cargo version.\n" + "`${Rust_CARGO_CACHED} --version` failed with error: `${_CARGO_VERSION_RESULT}" +) +endif() + +# todo: don't set cache variables here, but let find_package_handle_standard_args do the promotion +# later. +if (_CARGO_VERSION_RAW MATCHES "cargo ([0-9]+)\\.([0-9]+)\\.([0-9]+)") + set(Rust_CARGO_VERSION_MAJOR "${CMAKE_MATCH_1}" CACHE INTERNAL "" FORCE) + set(Rust_CARGO_VERSION_MINOR "${CMAKE_MATCH_2}" CACHE INTERNAL "" FORCE) + set(Rust_CARGO_VERSION_PATCH "${CMAKE_MATCH_3}" CACHE INTERNAL "" FORCE) + set(Rust_CARGO_VERSION "${Rust_CARGO_VERSION_MAJOR}.${Rust_CARGO_VERSION_MINOR}.${Rust_CARGO_VERSION_PATCH}" CACHE INTERNAL "" FORCE) +# Workaround for the version strings where the `cargo ` prefix is missing. +elseif(_CARGO_VERSION_RAW MATCHES "([0-9]+)\\.([0-9]+)\\.([0-9]+)") + set(Rust_CARGO_VERSION_MAJOR "${CMAKE_MATCH_1}" CACHE INTERNAL "" FORCE) + set(Rust_CARGO_VERSION_MINOR "${CMAKE_MATCH_2}" CACHE INTERNAL "" FORCE) + set(Rust_CARGO_VERSION_PATCH "${CMAKE_MATCH_3}" CACHE INTERNAL "" FORCE) + set(Rust_CARGO_VERSION "${Rust_CARGO_VERSION_MAJOR}.${Rust_CARGO_VERSION_MINOR}.${Rust_CARGO_VERSION_PATCH}" CACHE INTERNAL "" FORCE) +else() + _findrust_failed( + "Failed to parse cargo version. `cargo --version` evaluated to (${_CARGO_VERSION_RAW}). " + "Expected a .. version triple." + ) +endif() + +execute_process( + COMMAND "${Rust_COMPILER_CACHED}" --version --verbose + OUTPUT_VARIABLE _RUSTC_VERSION_RAW + RESULT_VARIABLE _RUSTC_VERSION_RESULT +) + +if(NOT ( "${_RUSTC_VERSION_RESULT}" EQUAL "0" )) + _findrust_failed("Failed to get rustc version.\n" + "${Rust_COMPILER_CACHED} --version failed with error: `${_RUSTC_VERSION_RESULT}`") +endif() + +if (_RUSTC_VERSION_RAW MATCHES "rustc ([0-9]+)\\.([0-9]+)\\.([0-9]+)(-nightly)?") + set(Rust_VERSION_MAJOR "${CMAKE_MATCH_1}" CACHE INTERNAL "" FORCE) + set(Rust_VERSION_MINOR "${CMAKE_MATCH_2}" CACHE INTERNAL "" FORCE) + set(Rust_VERSION_PATCH "${CMAKE_MATCH_3}" CACHE INTERNAL "" FORCE) + set(Rust_VERSION "${Rust_VERSION_MAJOR}.${Rust_VERSION_MINOR}.${Rust_VERSION_PATCH}" CACHE INTERNAL "" FORCE) + if(CMAKE_MATCH_4) + set(Rust_IS_NIGHTLY 1 CACHE INTERNAL "" FORCE) + else() + set(Rust_IS_NIGHTLY 0 CACHE INTERNAL "" FORCE) + endif() +else() + _findrust_failed("Failed to parse rustc version. `${Rust_COMPILER_CACHED} --version --verbose` " + "evaluated to:\n`${_RUSTC_VERSION_RAW}`" + ) +endif() + +if (_RUSTC_VERSION_RAW MATCHES "host: ([a-zA-Z0-9_\\-]*)\n") + set(Rust_DEFAULT_HOST_TARGET "${CMAKE_MATCH_1}") + set(Rust_CARGO_HOST_TARGET_CACHED "${Rust_DEFAULT_HOST_TARGET}" CACHE STRING "Host triple") +else() + _findrust_failed( + "Failed to parse rustc host target. `rustc --version --verbose` evaluated to:\n${_RUSTC_VERSION_RAW}" + ) +endif() + +if (_RUSTC_VERSION_RAW MATCHES "LLVM version: ([0-9]+)\\.([0-9]+)(\\.([0-9]+))?") + set(Rust_LLVM_VERSION_MAJOR "${CMAKE_MATCH_1}" CACHE INTERNAL "" FORCE) + set(Rust_LLVM_VERSION_MINOR "${CMAKE_MATCH_2}" CACHE INTERNAL "" FORCE) + # With the Rust toolchain 1.44.1 the reported LLVM version is 9.0, i.e. without a patch version. + # Since cmake regex does not support non-capturing groups, just ignore Match 3. + set(Rust_LLVM_VERSION_PATCH "${CMAKE_MATCH_4}" CACHE INTERNAL "" FORCE) + set(Rust_LLVM_VERSION "${Rust_LLVM_VERSION_MAJOR}.${Rust_LLVM_VERSION_MINOR}.${Rust_LLVM_VERSION_PATCH}" CACHE INTERNAL "" FORCE) +elseif(NOT Rust_FIND_QUIETLY) + message( + WARNING + "Failed to parse rustc LLVM version. `rustc --version --verbose` evaluated to:\n${_RUSTC_VERSION_RAW}" + ) +endif() + +if (NOT Rust_CARGO_TARGET_CACHED) + unset(_CARGO_ARCH) + unset(_CARGO_ABI) + if (WIN32) + if (CMAKE_VS_PLATFORM_NAME) + string(TOLOWER "${CMAKE_VS_PLATFORM_NAME}" LOWER_VS_PLATFORM_NAME) + if ("${LOWER_VS_PLATFORM_NAME}" STREQUAL "win32") + set(_CARGO_ARCH i686) + elseif("${LOWER_VS_PLATFORM_NAME}" STREQUAL "x64") + set(_CARGO_ARCH x86_64) + elseif("${LOWER_VS_PLATFORM_NAME}" STREQUAL "arm64") + set(_CARGO_ARCH aarch64) + else() + message(WARNING "VS Platform '${CMAKE_VS_PLATFORM_NAME}' not recognized") + endif() + endif() + # Fallback path + if(NOT DEFINED _CARGO_ARCH) + # Possible values for windows when not cross-compiling taken from here: + # https://learn.microsoft.com/en-us/windows/win32/winprog64/wow64-implementation-details + # When cross-compiling the user is expected to supply the value, so we match more variants. + if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(AMD64|amd64|x86_64)$") + set(_CARGO_ARCH x86_64) + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(ARM64|arm64|aarch64)$") + set(_CARGO_ARCH aarch64) + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(X86|x86|i686)$") + set(_CARGO_ARCH i686) + elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "i586") + set(_CARGO_ARCH i586) + elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "IA64") + message(FATAL_ERROR "No rust target for Intel Itanium.") + elseif(NOT "${CMAKE_SYSTEM_PROCESSOR}") + message(WARNING "Failed to detect target architecture. Please set `CMAKE_SYSTEM_PROCESSOR`" + " to your target architecture or set `Rust_CARGO_TARGET` to your cargo target triple." + ) + else() + message(WARNING "Failed to detect target architecture. Please set " + "`Rust_CARGO_TARGET` to your cargo target triple." + ) + endif() + endif() + + set(_CARGO_VENDOR "pc-windows") + + # The MSVC Generators will always target the msvc ABI. + # For other generators we check the compiler ID and compiler target (if present) + # If no compiler is set and we are not cross-compiling then we just choose the + # default rust host target. + if(DEFINED MSVC + OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" + OR "${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC" + OR "${CMAKE_CXX_COMPILER_TARGET}" MATCHES "-msvc$" + OR "${CMAKE_C_COMPILER_TARGET}" MATCHES "-msvc$" + ) + set(_CARGO_ABI msvc) + elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" + OR "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" + OR (NOT CMAKE_CROSSCOMPILING + AND NOT DEFINED CMAKE_CXX_COMPILER_ID + AND NOT DEFINED CMAKE_C_COMPILER_ID + AND "${Rust_DEFAULT_HOST_TARGET}" MATCHES "-gnu$" + ) + ) + set(_CARGO_ABI gnu) + elseif(("${CMAKE_C_COMPILER_ID}" MATCHES "Clang$" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang$") + AND ("${CMAKE_CXX_COMPILER_TARGET}" MATCHES "-gnu(llvm)?$" + OR "${CMAKE_C_COMPILER_TARGET}" MATCHES "-gnu(llvm)?$") + ) + if("${Rust_VERSION}" VERSION_GREATER_EQUAL "1.79") + set(_CARGO_ABI gnullvm) + else() + message(WARNING "Your selected C/C++ compilers suggest you want to use the -gnullvm" + " rust targets, however your Rust compiler version is ${Rust_VERSION}, which is" + " before the promotion of the gnullvm target to tier2." + " Please either use a more recent rust compiler or manually choose a target " + " triple by specifying `Rust_CARGO_TARGET` manually." + ) + endif() + elseif(NOT "${CMAKE_CROSSCOMPILING}" AND "${Rust_DEFAULT_HOST_TARGET}" MATCHES "-msvc$") + # We first check if the gnu branches match to ensure this fallback is only used + # if no compiler is enabled. + set(_CARGO_ABI msvc) + else() + message(WARNING "Could not determine the target ABI. Please specify `Rust_CARGO_TARGET` manually.") + endif() + + if(DEFINED _CARGO_ARCH AND DEFINED _CARGO_VENDOR AND DEFINED _CARGO_ABI) + set(Rust_CARGO_TARGET_CACHED "${_CARGO_ARCH}-${_CARGO_VENDOR}-${_CARGO_ABI}" + CACHE STRING "Target triple") + endif() + elseif (ANDROID) + if (CMAKE_ANDROID_ARCH_ABI STREQUAL armeabi-v7a) + if (CMAKE_ANDROID_ARM_MODE) + set(_Rust_ANDROID_TARGET armv7-linux-androideabi) + else () + set(_Rust_ANDROID_TARGET thumbv7neon-linux-androideabi) + endif() + elseif (CMAKE_ANDROID_ARCH_ABI STREQUAL arm64-v8a) + set(_Rust_ANDROID_TARGET aarch64-linux-android) + elseif (CMAKE_ANDROID_ARCH_ABI STREQUAL x86) + set(_Rust_ANDROID_TARGET i686-linux-android) + elseif (CMAKE_ANDROID_ARCH_ABI STREQUAL x86_64) + set(_Rust_ANDROID_TARGET x86_64-linux-android) + endif() + + if (_Rust_ANDROID_TARGET) + set(Rust_CARGO_TARGET_CACHED "${_Rust_ANDROID_TARGET}" CACHE STRING "Target triple") + endif() + elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "OHOS") + if(CMAKE_OHOS_ARCH_ABI STREQUAL arm64-v8a) + set(_RUST_OHOS_TARGET aarch64-unknown-linux-ohos) + elseif(CMAKE_OHOS_ARCH_ABI STREQUAL armeabi-v7a) + set(_RUST_OHOS_TARGET armv7-unknown-linux-ohos) + elseif(CMAKE_OHOS_ARCH_ABI STREQUAL x86_64) + set(_RUST_OHOS_TARGET x86_64-unknown-linux-ohos) + else() + message(WARNING "unrecognized OHOS architecture: ${OHOS_ARCH}") + endif() + if(_RUST_OHOS_TARGET) + set(Rust_CARGO_TARGET_CACHED "${_RUST_OHOS_TARGET}" CACHE STRING "Target triple") + endif() + endif() + # Fallback to the default host target + if(NOT Rust_CARGO_TARGET_CACHED) + if(CMAKE_CROSSCOMPILING) + message(WARNING "CMake is in cross-compiling mode, but the cargo target-triple could not be inferred." + "Falling back to the default host target. Please consider manually setting `Rust_CARGO_TARGET`." + ) + endif() + set(Rust_CARGO_TARGET_CACHED "${Rust_DEFAULT_HOST_TARGET}" CACHE STRING "Target triple") + endif() + + message(STATUS "Rust Target: ${Rust_CARGO_TARGET_CACHED}") +endif() + + +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_CACHED}" 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_CACHED}" IN_LIST INSTALLED_TARGETS)) + if(Rust_RUSTUP_INSTALL_MISSING_TARGET) + message(STATUS "Cargo target ${Rust_CARGO_TARGET_CACHED} is not installed. Installing via rustup.") + execute_process(COMMAND "${Rust_RUSTUP}" target add + --toolchain ${Rust_TOOLCHAIN} + ${Rust_CARGO_TARGET_CACHED} + RESULT_VARIABLE target_add_result + ) + if(NOT "${target_add_result}" EQUAL "0") + message(FATAL_ERROR "Target ${Rust_CARGO_TARGET_CACHED} is not installed for toolchain " + "${Rust_TOOLCHAIN} and automatically installing failed with ${target_add_result}.\n" + "You can try to manually install by running\n" + "`rustup target add --toolchain ${Rust_TOOLCHAIN} ${Rust_CARGO_TARGET}`." + ) + endif() + message(STATUS "Installed target ${Rust_CARGO_TARGET_CACHED} successfully.") + else() + message(FATAL_ERROR "Target ${Rust_CARGO_TARGET_CACHED} is not installed for toolchain ${Rust_TOOLCHAIN}.\n" + "Help: Run `rustup target add --toolchain ${Rust_TOOLCHAIN} ${Rust_CARGO_TARGET_CACHED}` to install " + "the missing target or configure corrosion with `Rust_RUSTUP_INSTALL_MISSING_TARGET=ON`." + ) + endif() + endif() + endif() +endif() + +if(Rust_CARGO_TARGET_CACHED STREQUAL Rust_DEFAULT_HOST_TARGET) + set(Rust_CROSSCOMPILING FALSE CACHE INTERNAL "Rust is configured for cross-compiling") +else() + set(Rust_CROSSCOMPILING TRUE CACHE INTERNAL "Rust is configured for cross-compiling") +endif() + +_corrosion_parse_target_triple("${Rust_CARGO_TARGET_CACHED}" rust_arch rust_vendor rust_os rust_env) +_corrosion_parse_target_triple("${Rust_CARGO_HOST_TARGET_CACHED}" rust_host_arch rust_host_vendor rust_host_os rust_host_env) + +set(Rust_CARGO_TARGET_ARCH "${rust_arch}" CACHE INTERNAL "Target architecture") +set(Rust_CARGO_TARGET_VENDOR "${rust_vendor}" CACHE INTERNAL "Target vendor") +set(Rust_CARGO_TARGET_OS "${rust_os}" CACHE INTERNAL "Target Operating System") +set(Rust_CARGO_TARGET_ENV "${rust_env}" CACHE INTERNAL "Target environment") + +set(Rust_CARGO_HOST_ARCH "${rust_host_arch}" CACHE INTERNAL "Host architecture") +set(Rust_CARGO_HOST_VENDOR "${rust_host_vendor}" CACHE INTERNAL "Host vendor") +set(Rust_CARGO_HOST_OS "${rust_host_os}" CACHE INTERNAL "Host Operating System") +set(Rust_CARGO_HOST_ENV "${rust_host_env}" CACHE INTERNAL "Host environment") + +if(NOT DEFINED CACHE{Rust_CARGO_TARGET_LINK_NATIVE_LIBS}) + message(STATUS "Determining required link libraries for target ${Rust_CARGO_TARGET_CACHED}") + unset(required_native_libs) + _corrosion_determine_libs_new("${Rust_CARGO_TARGET_CACHED}" required_native_libs required_link_flags) + if(DEFINED required_native_libs) + message(STATUS "Required static libs for target ${Rust_CARGO_TARGET_CACHED}: ${required_native_libs}" ) + endif() + if(DEFINED required_link_flags) + message(STATUS "Required link flags for target ${Rust_CARGO_TARGET_CACHED}: ${required_link_flags}" ) + endif() + # In very recent corrosion versions it is possible to override the rust compiler version + # per target, so to be totally correct we would need to determine the libraries for + # every installed Rust version, that the user could choose from. + # In practice there aren't likely going to be any major differences, so we just do it once + # for the target and once for the host target (if cross-compiling). + set(Rust_CARGO_TARGET_LINK_NATIVE_LIBS "${required_native_libs}" CACHE INTERNAL + "Required native libraries when linking Rust static libraries") + set(Rust_CARGO_TARGET_LINK_OPTIONS "${required_link_flags}" CACHE INTERNAL + "Required link flags when linking Rust static libraries") +endif() + +if(Rust_CROSSCOMPILING AND NOT DEFINED CACHE{Rust_CARGO_HOST_TARGET_LINK_NATIVE_LIBS}) + message(STATUS "Determining required link libraries for target ${Rust_CARGO_HOST_TARGET_CACHED}") + unset(host_libs) + _corrosion_determine_libs_new("${Rust_CARGO_HOST_TARGET_CACHED}" host_libs host_flags) + if(DEFINED host_libs) + message(STATUS "Required static libs for host target ${Rust_CARGO_HOST_TARGET_CACHED}: ${host_libs}" ) + endif() + set(Rust_CARGO_HOST_TARGET_LINK_NATIVE_LIBS "${host_libs}" CACHE INTERNAL + "Required native libraries when linking Rust static libraries for the host target") + set(Rust_CARGO_HOST_TARGET_LINK_OPTIONS "${host_flags}" CACHE INTERNAL + "Required linker flags when linking Rust static libraries for the host target") +endif() + +# Set the input variables as non-cache variables so that the variables are available after +# `find_package`, even if the values were evaluated to defaults. +foreach(_VAR ${_Rust_USER_VARS}) + set(${_VAR} "${${_VAR}_CACHED}") + # Ensure cached variables have type INTERNAL + set(${_VAR}_CACHED "${${_VAR}_CACHED}" CACHE INTERNAL "Internal cache of ${_VAR}") +endforeach() + +find_package_handle_standard_args( + Rust + REQUIRED_VARS Rust_COMPILER Rust_VERSION Rust_CARGO Rust_CARGO_VERSION Rust_CARGO_TARGET Rust_CARGO_HOST_TARGET + VERSION_VAR Rust_VERSION +) + + +if(NOT TARGET Rust::Rustc) + add_executable(Rust::Rustc IMPORTED GLOBAL) + set_property( + TARGET Rust::Rustc + PROPERTY IMPORTED_LOCATION "${Rust_COMPILER_CACHED}" + ) + + add_executable(Rust::Cargo IMPORTED GLOBAL) + set_property( + TARGET Rust::Cargo + PROPERTY IMPORTED_LOCATION "${Rust_CARGO_CACHED}" + ) + set(Rust_FOUND true) +endif() + +list(POP_BACK CMAKE_MESSAGE_CONTEXT) diff --git a/libs/3rdparty/corrosion/doc/.gitignore b/libs/3rdparty/corrosion/doc/.gitignore new file mode 100644 index 00000000000..7585238efed --- /dev/null +++ b/libs/3rdparty/corrosion/doc/.gitignore @@ -0,0 +1 @@ +book diff --git a/libs/3rdparty/corrosion/doc/book.toml b/libs/3rdparty/corrosion/doc/book.toml new file mode 100644 index 00000000000..7930b4d0a94 --- /dev/null +++ b/libs/3rdparty/corrosion/doc/book.toml @@ -0,0 +1,5 @@ +[book] +language = "en" +multilingual = false +src = "src" +title = "Corrosion documentation" diff --git a/libs/3rdparty/corrosion/doc/src/SUMMARY.md b/libs/3rdparty/corrosion/doc/src/SUMMARY.md new file mode 100644 index 00000000000..9f877b92803 --- /dev/null +++ b/libs/3rdparty/corrosion/doc/src/SUMMARY.md @@ -0,0 +1,9 @@ +# Summary + +- [Introduction](./introduction.md) +- [Quick Start](./quick_start.md) +- [Setup Corrosion](./setup_corrosion.md) +- [Usage](./usage.md) +- [Advanced](./advanced.md) +- [FFI binding integrations](./ffi_bindings.md) +- [Common Issues](./common_issues.md) diff --git a/libs/3rdparty/corrosion/doc/src/advanced.md b/libs/3rdparty/corrosion/doc/src/advanced.md new file mode 100644 index 00000000000..203c48bf1dc --- /dev/null +++ b/libs/3rdparty/corrosion/doc/src/advanced.md @@ -0,0 +1,100 @@ +## What does corrosion do? + +The specifics of what corrosion does should be regarded as an implementation detail and not relied on +when writing user code. However, a basic understanding of what corrosion does may be helpful when investigating +issues. + +### FindRust + +Corrosion maintains a CMake module `FindRust` which is executed when Corrosion is loaded, i.e. at the time +of `find_package(corrosion)`, `FetchContent_MakeAvailable(corrosion)` or `add_subdirectory(corrosion)` depending +on the method used to include Corrosion. + +`FindRust` will search for installed rust toolchains, respecting the options prefixed with `Rust_` documented in +the [Usage](usage.md#corrosion-options) chapter. +It will select _one_ Rust toolchain to be used for the compilation of Rust code. Toolchains managed by `rustup` +will be resolved and corrosion will always select a specific toolchain, not a `rustup` proxy. + + +### Importing Rust crates + +Corrosion's main function is `corrosion_import_crate`, which internally will call `cargo metadata` to provide +structured information based on the `Cargo.toml` manifest. +Corrosion will then iterate over all workspace and/or package members and find all rust crates that are either +a static (`staticlib`) or shared (`cdylib`) library or a `bin` target and create CMake targets matching the +crate name. Additionally, a build target is created for each imported target, containing the required build +command to create the imported artifact. This build command can be influenced by various arguments to +`corrosion_import_crate` as well as corrosion specific target properties which are documented int the +[Usage](usage.md) chapter. +Corrosion adds the necessary dependencies and also copies the target artifacts out of the cargo build tree +to standard CMake locations, even respecting `OUTPUT_DIRECTORY` target properties if set. + +### Linking + +Depending on the type of the crate the linker will either be invoked by CMake or by `rustc`. +Rust `staticlib`s are linked into C/C++ code via `target_link_libraries()` and the linker is +invoked by CMake. +For rust `cdylib`s and `bin`s, the linker is invoked via `rustc` and CMake just gets the final artifact. + +#### CMake invokes the linker + +When CMake invokes the linker, everything is as usual. CMake will call the linker with +the compiler as the linker driver and users can just use the regular CMake functions to +modify linking behaviour. `corrosion_set_linker()` has **no effect**. +As a convenience, `corrosion_link_libraries()` will forward its arguments to `target_link_libraries()`. + +#### Rustc invokes the linker + +Rust `cdylib`s and `bin`s are linked via `rustc`. Corrosion provides several helper functions +to influence the linker invocation for such targets. + +`corrosion_link_libraries()` is a limited version of `target_link_libraries()` +for rust `cdylib` or `bin` targets. +Under the hood this function passes `-l` and `-L` flags to the linker invocation and +ensures the linked libraries are built first. +Much of the advanced functionality available in `target_link_libraries()` is not implemented yet, +but pull-requests are welcome! In the meantime, users may want to use +`corrosion_add_target_local_rustflags()` to pass customized linking flags. + +`corrosion_set_linker()` can be used to specify a custom linker, in case the default one +chosen by corrosion is not what you want. +Corrosion currently instructs `rustc` to use the C/C++ compiler as the linker driver. +This is done because: +- For C++ code we must link with `libstdc++` or `libc++` (depending on the compiler), so we must + either specify the library on the link line or use a `c++` compiler as the linker driver. +- `Rustc`s default linker selection currently is not so great. For a number of platforms + `rustc` will fallback to `cc` as the linker driver. When cross-compiling, this leads + to linking failures, since the linker driver is for the host architecture. + Corrosion avoids this by specifying the C/C++ compiler as the linker driver. + + +In some cases, especially in older rust versions (pre 1.68), the linker flavor detection +of `rustc` is also not correct, so when setting a custom linker you may want to pass the +[`-C linker-flavor`](https://doc.rust-lang.org/rustc/codegen-options/index.html#linker-flavor) +rustflag via `corrosion_add_target_local_rustflags()`. + +## FFI bindings + +For interaction between Rust and other languages there need to be some FFI bindings of some sort. +For simple cases manually defining the interfaces may be sufficient, but in many cases users +wish to use tools like [bindgen], [cbindgen], [cxx] or [autocxx] to automate the generating of +bindings. + +In principle there are two different ways to generate the bindings: +- use a `build.rs` script to generate the bindings when cargo is invoked, using + library versions of the tools to generate the bindings. +- use the cli versions of the tools and setup custom CMake targets/commands to + generate the bindings. This approach should be preferred if the bindings are needed + by the C/C++ side. + +Corrosion currently provides 2 experimental functions to integrate cbindgen and cxx into +the build process. They are not 100% production ready yet, but should work well as a +template on how to integrate generating bindings into your build process. + +Todo: expand this documentation and link to other resources. + +[bindgen]: https://rust-lang.github.io/rust-bindgen/ +[cbindgen]: https://github.com/eqrion/cbindgen +[cxx]: https://cxx.rs/ +[autocxx]: https://google.github.io/autocxx/index.html + \ No newline at end of file diff --git a/libs/3rdparty/corrosion/doc/src/common_issues.md b/libs/3rdparty/corrosion/doc/src/common_issues.md new file mode 100644 index 00000000000..c7af9a0b9dd --- /dev/null +++ b/libs/3rdparty/corrosion/doc/src/common_issues.md @@ -0,0 +1,122 @@ +# Commonly encountered (Non-Corrosion) Issues + +## Table of Contents + +- [Linking Debug C/C++ libraries into Rust fails on Windows MSVC targets](#linking-debug-cc-libraries-into-rust-fails-on-windows-msvc-targets) +- [Linking Rust static libraries into Debug C/C++ binaries fails on Windows MSVC targets](#linking-rust-static-libraries-into-debug-cc-binaries-fails-on-windows-msvc-targets) +- [Missing `soname` on Linux for `cdylibs`](#missing-soname-on-linux-for-cdylibs) +- [Missing `install_name` on MacOS for `ccdylibs` / Hardcoded references to the build-directory](#missing-installname-on-macos-for-ccdylibs--hardcoded-references-to-the-build-directory) +- [CMake Error (target_link_libraries): Cannot find source file](#cmake-error-target_link_libraries-cannot-find-source-file) + +## Linking Debug C/C++ libraries into Rust fails on Windows MSVC targets + +`rustc` always links against the non-debug Windows runtime on `*-msvc` targets. +This is tracked [in this issue](https://github.com/rust-lang/rust/issues/39016) +and could be fixed upstream. + +A typical error message for this issue is: + +``` + Compiling rust_bin v0.1.0 (D:\a\corrosion\corrosion\test\cxxbridge\cxxbridge_cpp2rust\rust) +error: linking with `link.exe` failed: exit code: 1319 +[ redacted ] + = note: cxxbridge-cpp.lib(lib.cpp.obj) : error LNK2038: mismatch detected for '_ITERATOR_DEBUG_LEVEL': value '2' doesn't match value '0' in libcxx-bafec361a1a30317.rlib(cxx.o) + + cxxbridge-cpp.lib(lib.cpp.obj) : error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MDd_DynamicDebug' doesn't match value 'MD_DynamicRelease' in libcxx-bafec361a1a30317.rlib(cxx.o) + + cpp_lib.lib(cpplib.cpp.obj) : error LNK2038: mismatch detected for '_ITERATOR_DEBUG_LEVEL': value '2' doesn't match value '0' in libcxx-bafec361a1a30317.rlib(cxx.o) + + cpp_lib.lib(cpplib.cpp.obj) : error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MDd_DynamicDebug' doesn't match value 'MD_DynamicRelease' in libcxx-bafec361a1a30317.rlib(cxx.o) + + msvcrt.lib(initializers.obj) : warning LNK4098: defaultlib 'msvcrtd.lib' conflicts with use of other libs; use /NODEFAULTLIB:library +``` + +### Solutions + +One solution is to also use the non-debug version when building the C/C++ libraries. +You can set the [MSVC_RUNTIME_LIBRARY] target properties of your C/C++ libraries to the non-debug variants. +By default you will probably want to select the `MultiThreadedDLL` variant, unless you specified +[`-Ctarget-feature=+crt-static`](https://rust-lang.github.io/rfcs/1721-crt-static.html) in your +`RUSTFLAGS`. + + +[MSVC_RUNTIME_LIBRARY]: https://cmake.org/cmake/help/latest/prop_tgt/MSVC_RUNTIME_LIBRARY.html#prop_tgt:MSVC_RUNTIME_LIBRARY + +## Linking Rust static libraries into Debug C/C++ binaries fails on Windows MSVC targets + +This issue is quite similar to the previous one, except that this time it's a Rust library being linked +into a C/C++ target. If it's 100% only Rust code you likely won't even have any issues. +However, if somewhere in the dependency graph C/C++ code is built and linked into your Rust library, +you will likely encounter this issue. Please note, that using [cxx] counts as using C++ code and will +lead to this issue. + +The previous solution should also work for this case, but additionally you [may also +have success](https://github.com/rust-lang/rust/issues/39016#issuecomment-853964918) by using +`corrosion_set_env_vars(your_rust_lib "CFLAGS=-MDd" "CXXFLAGS=-MDd")` (or `-MTd` for a statically linked +runtime). +For debug builds, this is likely to be the preferable solution. It assumes that downstream C/C++ code +is built by the `cc` crate, which respects the `CFLAGS` and `CXXFLAGS` environment variables. + +[cxx]: https://github.com/dtolnay/cxx + + +## Missing `soname` on Linux for `cdylibs` + +Cargo doesn't support setting the `soname` field for cdylib, which may cause issues. +You can set the soname manually by passing a linker-flag such as `-Clink-arg=-Wl,-soname,libyour_crate.so` +to the linker via `corrosion_add_target_local_rustflags()` and additionally seting the `IMPORTED_SONAME` +property on the import CMake target: +``` +set_target_properties(your_crate-shared PROPERTIES IMPORTED_SONAME libyour_crate.so) +``` +Replace `your_crate` with the name of your shared library as defined in the `[lib]` section of your Cargo.toml +Manifest file. + +Attention: The Linux section may not be entirely correct, maybe `$ORIGIN` needs to be added to the linker arguments. +Feel free to open a pull-request with corrections. + +## Missing `install_name` on MacOS for `ccdylibs` / Hardcoded references to the build-directory + +The solution here is essentially the same as in the previous section. +``` +corrosion_add_target_local_rustflags(your_crate -Clink-arg=-Wl,-install_name,@rpath/libyour_crate.dylib,-current_version,${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR},-compatibility_version,${PROJECT_VERSION_MAJOR}.0) +set_target_properties(your_crate-shared PROPERTIES IMPORTED_NO_SONAME 0) +set_target_properties(your_crate-shared PROPERTIES IMPORTED_SONAME libyour_crate.dylib) +``` +When building binaries using this shared library, you should set the build rpath to the output directory of +your shared library, e.g. by setting `set(CMAKE_BUILD_RPATH ${YOUR_CUSTOM_OUTPUT_DIRECTORY})` before adding +executables. +For a practical example, you may look at [Slint PR 2455](https://github.com/slint-ui/slint/pull/2455). + +## CMake Error (target_link_libraries): Cannot find source file + +When using `corrosion_add_cxxbridge`, you may encounter an error similar to this in targets that depend on the cxxbridge target: + +```diff +- CMake Error at ...../CMakeLists.txt:61 (target_link_libraries): +- Cannot find source file: +- +- ...../corrosion_generated/..../somefile.h +- +- Tried extensions .c .C .c++ .cc .cpp .cxx .cu .mpp .m .M .mm .ixx .cppm +- .ccm .cxxm .c++m .h .hh .h++ .hm .hpp .hxx .in .txx .f .F .for .f77 .f90 +- .f95 .f03 .hip .ispc +``` + +Where `somefile.h` should be generated by CXX via `corrosion_add_cxxbridge`. +In theory, CMake should already know that this is a generated file and just generate it when needed. + +However, in older versions of CMake the `GENERATED` property isn't correctly propagated. +See also: [https://gitlab.kitware.com/cmake/cmake/-/issues/18399](https://gitlab.kitware.com/cmake/cmake/-/issues/18399) + +This has since been fixed with CMake 3.20: [https://cmake.org/cmake/help/v3.20/policy/CMP0118.html](https://cmake.org/cmake/help/latest/command/cmake_policy.html#version) +However, the CMake policy CMP0118 must be enabled **in any dependent CMakeLists.txt** for the fix to work. + +The best fix is to call: +```cmake +cmake_minimium_required(VERSION 3.20 FATAL_ERROR) +# (or any other version above 3.20) +``` +As described [here](https://cmake.org/cmake/help/latest/command/cmake_policy.html#version), this implies a call to `cmake_policy` which enables CMP0118. + +Unfortunately this must be done in all (transitive) downstream dependencies that link to the bridge target, so cannot be done from within corrosion automatically. diff --git a/libs/3rdparty/corrosion/doc/src/ffi_bindings.md b/libs/3rdparty/corrosion/doc/src/ffi_bindings.md new file mode 100644 index 00000000000..58077a1437b --- /dev/null +++ b/libs/3rdparty/corrosion/doc/src/ffi_bindings.md @@ -0,0 +1,38 @@ +# Integrating Automatically Generated FFI Bindings + +There are a number of tools to automatically generate bindings between Rust and different +foreign languages. + +1. [bindgen](#bindgen) +2. [cbindgen](#cbindgen-integration) +3. [cxx](#cxx-integration) + +## bindgen + +[bindgen] is a tool to automatically generate Rust bindings from C headers. +As such, integrating bindgen [via a build-script](https://rust-lang.github.io/rust-bindgen/library-usage.html) +works well and their doesn't seem to be a need to create CMake rules for +generating the bindings. + +[bindgen]: https://github.com/rust-lang/rust-bindgen + +## cbindgen integration + +⚠️⚠️⚠️ **EXPERIMENTAL** ⚠️⚠️⚠️ + +[cbindgen] is a tool that generates C/C++ headers from Rust code. When compiling C/C++ +code that `#include`s such generated headers the buildsystem must be aware of the dependencies. +Generating the headers via a build-script is possible, but Corrosion offers no guidance here. + +Instead, Corrosion offers an experimental function to add CMake rules using cbindgen to generate +the headers. +This is not available on a stable released version yet, and the details are subject to change. +{{#include ../../cmake/Corrosion.cmake:corrosion_cbindgen}} + +## cxx integration + +⚠️⚠️⚠️ **EXPERIMENTAL** ⚠️⚠️⚠️ + +[cxx] is a tool which generates bindings for C++/Rust interop. + +{{#include ../../cmake/Corrosion.cmake:corrosion_add_cxxbridge}} diff --git a/libs/3rdparty/corrosion/doc/src/introduction.md b/libs/3rdparty/corrosion/doc/src/introduction.md new file mode 100644 index 00000000000..ad133b9d4f8 --- /dev/null +++ b/libs/3rdparty/corrosion/doc/src/introduction.md @@ -0,0 +1,19 @@ +## About Corrosion + +Corrosion, formerly known as cmake-cargo, is a tool for integrating Rust into an existing CMake +project. Corrosion is capable of automatically importing executables, static libraries, and +dynamic libraries from a Rust package or workspace as CMake targets. + +The imported static and dynamic library types can be linked into C/C++ CMake targets using the usual +CMake functions such as [`target_link_libraries()`]. +For rust executables and dynamic libraries corrosion provides a `corrosion_link_libraries` +helper function to conveniently add the necessary flags to link C/C++ libraries into +the rust target. + +## Requirements + +- The latest release (v0.6) of Corrosion currently requires CMake 3.22 or newer. +- The previous v0.5 release supports CMake 3.15 or newer. If you are using the v0.5 release, please + view [the documentation here](./v0.5/introduction.md). + +[`target_link_libraries()`]: https://cmake.org/cmake/help/latest/command/target_link_libraries.html diff --git a/libs/3rdparty/corrosion/doc/src/quick_start.md b/libs/3rdparty/corrosion/doc/src/quick_start.md new file mode 100644 index 00000000000..e571163c4fb --- /dev/null +++ b/libs/3rdparty/corrosion/doc/src/quick_start.md @@ -0,0 +1,37 @@ +# Quick Start + +You can add corrosion to your project via the `FetchContent` CMake module or one of the other methods +described in the [Setup chapter](setup_corrosion.md). +Afterwards you can import Rust targets defined in a `Cargo.toml` manifest file by using +`corrosion_import_crate`. This will add CMake targets with names matching the crate names defined +in the Cargo.toml manifest. These targets can then subsequently be used, e.g. to link the imported +target into a regular C/C++ target. + +The example below shows how to add Corrosion to your project via `FetchContent` +and how to import a rust library and link it into a regular C/C++ CMake target. + +```cmake +include(FetchContent) + +FetchContent_Declare( + Corrosion + GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git + GIT_TAG v0.6 # Optionally specify a commit hash, version tag or branch here +) +# Set any global configuration variables such as `Rust_TOOLCHAIN` before this line! +FetchContent_MakeAvailable(Corrosion) + +# Import targets defined in a package or workspace manifest `Cargo.toml` file +corrosion_import_crate(MANIFEST_PATH rust-lib/Cargo.toml) + +add_executable(your_cool_cpp_bin main.cpp) + +# In this example the the `Cargo.toml` file passed to `corrosion_import_crate` is assumed to have +# defined a static (`staticlib`) or shared (`cdylib`) rust library with the name "rust-lib". +# A target with the same name is now available in CMake and you can use it to link the rust library into +# your C/C++ CMake target(s). +target_link_libraries(your_cool_cpp_bin PUBLIC rust-lib) +``` + + +Please see the [Usage chapter](usage.md) for a complete discussion of possible configuration options. diff --git a/libs/3rdparty/corrosion/doc/src/setup_corrosion.md b/libs/3rdparty/corrosion/doc/src/setup_corrosion.md new file mode 100644 index 00000000000..8d3795b0407 --- /dev/null +++ b/libs/3rdparty/corrosion/doc/src/setup_corrosion.md @@ -0,0 +1,91 @@ +# Adding Corrosion to your project + +There are two fundamental installation methods that are supported by Corrosion - installation as a +CMake package or using it as a subdirectory in an existing CMake project. For CMake versions below +3.19 Corrosion strongly recommends installing the package, either via a package manager or manually +using CMake's installation facilities. +If you have CMake 3.19 or newer, we recommend to use either the [FetchContent](#fetchcontent) or the +[Subdirectory](#subdirectory) method to integrate Corrosion. + +## FetchContent +If you are using CMake >= 3.19 or installation is difficult or not feasible in +your environment, you can use the +[FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html) module to include +Corrosion. This will download Corrosion and use it as if it were a subdirectory at configure time. + +In your CMakeLists.txt: +```cmake +include(FetchContent) + +FetchContent_Declare( + Corrosion + GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git + # v0.6 will be updated to point to the latest patch version. + # Use v0.6. or the commit hash to prevent such auto updates. + GIT_TAG v0.6 +) +# Set any global configuration variables such as `Rust_TOOLCHAIN` before this line! +FetchContent_MakeAvailable(Corrosion) +``` + +## Subdirectory +Corrosion can also be used directly as a subdirectory. This solution may work well for small +projects, but it's discouraged for large projects with many dependencies, especially those which may +themselves use Corrosion. Either copy the Corrosion library into your source tree, being sure to +preserve the `LICENSE` file, or add this repository as a git submodule: +```bash +git submodule add https://github.com/corrosion-rs/corrosion.git +``` + +From there, using Corrosion is easy. In your CMakeLists.txt: +```cmake +add_subdirectory(path/to/corrosion) +``` + +## Installation + + +Installation will pre-build all of Corrosion's native tooling (required only for CMake versions +below 3.19) and install it together with Corrosions CMake files into a standard location. +On CMake >= 3.19 installing Corrosion does not offer any speed advantages, unless the native +tooling option is explicitly enabled. + +### Install from source + +First, download and install Corrosion: +```bash +git clone https://github.com/corrosion-rs/corrosion.git +# Optionally, specify -DCMAKE_INSTALL_PREFIX= to specify a +# custom installation directory +cmake -Scorrosion -Bbuild -DCMAKE_BUILD_TYPE=Release +cmake --build build --config Release +# This next step may require sudo or admin privileges if you're installing to a system location, +# which is the default. +cmake --install build --config Release +``` + +You'll want to ensure that the install directory is available in your `PATH` or `CMAKE_PREFIX_PATH` +environment variable. This is likely to already be the case by default on a Unix system, but on +Windows it will install to `C:\Program Files (x86)\Corrosion` by default, which will not be in your +`PATH` or `CMAKE_PREFIX_PATH` by default. + +Once Corrosion is installed, and you've ensured the package is available in your `PATH`, you +can use it from your own project like any other package from your CMakeLists.txt: +```cmake +find_package(Corrosion REQUIRED) +``` + +### Package Manager + +#### Homebrew (unofficial) + +Corrosion is available via Homebrew and can be installed via + +```bash +brew install corrosion +``` + +Please note that this package is community maintained. Please also keep in mind that Corrosion follows +semantic versioning and minor version bumps (i.e. `0.3` -> `0.4`) may contain breaking changes, while +Corrosion is still pre `1.0`. +Please read the release notes when upgrading Corrosion. diff --git a/libs/3rdparty/corrosion/doc/src/usage.md b/libs/3rdparty/corrosion/doc/src/usage.md new file mode 100644 index 00000000000..625413500a4 --- /dev/null +++ b/libs/3rdparty/corrosion/doc/src/usage.md @@ -0,0 +1,412 @@ +## Usage + +### Automatically import crate targets with `corrosion_import_crate` + +In order to integrate a Rust crate into CMake, you first need to import Rust crates from +a [package] or [workspace]. Corrosion provides `corrosion_import_crate()` to automatically import +crates defined in a Cargo.toml Manifest file: + +{{#include ../../cmake/Corrosion.cmake:corrosion-import-crate}} + +Corrosion will use `cargo metadata` to add a cmake target for each crate defined in the Manifest file +and add the necessary rules to build the targets. +For Rust executables an [`IMPORTED`] executable target is created with the same name as defined in the `[[bin]]` +section of the Manifest corresponding to this target. +If no such name was defined the target name defaults to the Rust package name. +For Rust library targets an [`INTERFACE`] library target is created with the same name as defined in the `[lib]` +section of the Manifest. This `INTERFACE` library links an internal corrosion target, which is either a +`SHARED` or `STATIC` `IMPORTED` library, depending on the Rust crate type (`cdylib` vs `staticlib`). + +The created library targets can be linked into other CMake targets by simply using [target_link_libraries]. + +Corrosion will by default copy the produced Rust artifacts into `${CMAKE_CURRENT_BINARY_DIR}`. The target location +can be changed by setting the CMake `OUTPUT_DIRECTORY` target properties on the imported Rust targets. +See the [OUTPUT_DIRECTORY](#cmake-output_directory-target-properties-and-imported_location) section for more details. + +Many of the options available for `corrosion_import_crate` can also be individually set per +target, see [Per Target options](#per-target-options) for details. + +[package]: https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html +[workspace]: https://doc.rust-lang.org/cargo/reference/workspaces.html +[`IMPORTED`]: https://cmake.org/cmake/help/latest/prop_tgt/IMPORTED.html +[`INTERFACE`]: https://cmake.org/cmake/help/latest/command/add_library.html#interface-libraries +[target_link_libraries]: https://cmake.org/cmake/help/latest/command/target_link_libraries.html + +### Experimental: Install crate and headers with `corrosion_install` + +The default CMake [install commands] do not work correctly with the targets exported from `corrosion_import_crate()`. +Corrosion provides `corrosion_install` to automatically install relevant files: + +{{#include ../../cmake/Corrosion.cmake:corrosion-install}} + +The example below shows how to import a rust library and make it available for install through CMake. + +```cmake +include(FetchContent) + +FetchContent_Declare( + Corrosion + GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git + # v0.6 will be updated to point to the latest patch version. + # Use v0.6. or the commit hash to prevent such auto updates. + GIT_TAG v0.6 +) +# Set any global configuration variables such as `Rust_TOOLCHAIN` before this line! +FetchContent_MakeAvailable(Corrosion) + +# Import targets defined in a package or workspace manifest `Cargo.toml` file +corrosion_import_crate(MANIFEST_PATH rust-lib/Cargo.toml) + +# Add a manually written header file which will be exported +# Requires CMake >=3.23 +target_sources(rust-lib INTERFACE + FILE_SET HEADERS + BASE_DIRS include + FILES + include/rust-lib/rust-lib.h +) + +# OR for CMake <= 3.23 +target_include_directories(is_odd INTERFACE + $ + $ +) +target_sources(is_odd + INTERFACE + $ + $ +) + +# Rust libraries must be installed using `corrosion_install`. +corrosion_install(TARGETS rust-lib EXPORT RustLibTargets) + +# Installs the main target +install( + EXPORT RustLibTargets + NAMESPACE RustLib:: + DESTINATION lib/cmake/RustLib +) + +# Necessary for packaging helper commands +include(CMakePackageConfigHelpers) +# Create a file for checking version compatibility +# Optional +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/RustLibConfigVersion.cmake" + VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}" + COMPATIBILITY AnyNewerVersion +) + +# Configures the main config file that cmake loads +configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/RustLibConfig.cmake" + INSTALL_DESTINATION lib/cmake/RustLib + NO_SET_AND_CHECK_MACRO + NO_CHECK_REQUIRED_COMPONENTS_MACRO +) +# Config.cmake.in contains +# @PACKAGE_INIT@ +# +# include(${CMAKE_CURRENT_LIST_DIR}/RustLibTargetsCorrosion.cmake) +# include(${CMAKE_CURRENT_LIST_DIR}/RustLibTargets.cmake) + +# Install all generated files +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/RustLibConfigVersion.cmake + ${CMAKE_CURRENT_BINARY_DIR}/RustLibConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/corrosion/RustLibTargetsCorrosion.cmake + DESTINATION lib/cmake/RustLib +) +``` + +[install commands]: https://cmake.org/cmake/help/latest/command/install.html + +### Per Target options + +Some configuration options can be specified individually for each target. You can set them via the +`corrosion_set_xxx()` functions specified below: + +- `corrosion_set_env_vars( [... ])`: Define environment variables + that should be set during the invocation of `cargo build` for the specified target. Please note that + the environment variable will only be set for direct builds of the target via cmake, and not for any + build where cargo built the crate in question as a dependency for another target. + The environment variables may contain generator expressions. +- `corrosion_add_target_rustflags( [... ])`: When building the target, + the `RUSTFLAGS` environment variable will contain the flags added via this function. Please note that any + dependencies (built by cargo) will also see these flags. See also: `corrosion_add_target_local_rustflags`. +- `corrosion_add_target_local_rustflags(target_name rustc_flag [more_flags ...])`: Support setting + rustflags for only the main target (crate) and none of its dependencies. + This is useful in cases where you only need rustflags on the main-crate, but need to set different + flags for different targets. Without "local" Rustflags this would require rebuilds of the + dependencies when switching targets. +- `corrosion_set_hostbuild()`: The target should be compiled for the Host target and ignore any + cross-compile configuration. +- `corrosion_set_features( [ALL_FEATURES ] [NO_DEFAULT_FEATURES] [FEATURES ... ])`: + For a given target, enable specific features via `FEATURES`, toggle `ALL_FEATURES` on or off or disable all features + via `NO_DEFAULT_FEATURES`. For more information on features, please see also the + [cargo reference](https://doc.rust-lang.org/cargo/reference/features.html). +- `corrosion_set_cargo_flags( ...])`: + For a given target, add options and flags at the end of `cargo build` invocation. This will be appended after any + arguments passed through the `FLAGS` during the crate import. +- `corrosion_set_linker(target_name linker)`: Use `linker` to link the target. + Please note that this only has an effect for targets where the final linker invocation is done + by cargo, i.e. targets where foreign code is linked into rust code and not the other way around. + Please also note that if you are cross-compiling and specify a linker such as `clang`, you are + responsible for also adding a rustflag which adds the necessary `--target=` argument for the + linker. + + +### Global Corrosion Options + +#### Selecting the Rust toolchain and target triple + +The following variables are evaluated automatically in most cases. In typical cases you +shouldn't need to alter any of these. If you do want to specify them manually, make sure to set +them **before** `find_package(Corrosion REQUIRED)`. + +- `Rust_TOOLCHAIN:STRING` - Specify a named rustup toolchain to use. Changes to this variable + resets all other options. Default: If the first-found `rustc` is a `rustup` proxy, then the default + rustup toolchain (see `rustup show`) is used. Otherwise, the variable is unset by default. +- `Rust_COMPILER:STRING` - Path to `rustc`, which should be used for compiling or for toolchain + detection (if it is a `rustup` proxy). Default: The `rustc` in the first-found toolchain, either + from `rustup`, or from a toolchain available in the user's `PATH`. +- `Rust_RESOLVE_RUSTUP_TOOLCHAINS:BOOL` - If the found `rustc` is a `rustup` proxy, resolve a + concrete path to a specific toolchain managed by `rustup`, according to the `rustup` toolchain + selection rules and other options detailed here. If this option is turned off, the found `rustc` + will be used as-is to compile, even if it is a `rustup` proxy, which might increase compilation + time. Default: `ON` if the found `rustc` is a rustup proxy or a `rustup` managed toolchain was + requested, `OFF` otherwise. Forced `OFF` if `rustup` was not found. +- `Rust_CARGO:STRING` - Path to `cargo`. Default: the `cargo` installed next to `${Rust_COMPILER}`. +- `Rust_CARGO_TARGET:STRING` - The default target triple to build for. Alter for cross-compiling. + Default: On Visual Studio Generator, the matching triple for `CMAKE_VS_PLATFORM_NAME`. Otherwise, + the default target triple reported by `${Rust_COMPILER} --version --verbose`. +- `CORROSION_TOOLS_RUST_TOOLCHAIN:STRING`: Specify a different toolchain (e.g. `stable`) to use for compiling helper + tools such as `cbindgen` or `cxxbridge`. This can be useful when you want to compile your project with an + older rust version (e.g. for checking the MSRV), but you can build build-tools with a newer installed rust version. + +#### Enable Convenience Options + +The following options are off by default, but may increase convenience: + +- `Rust_RUSTUP_INSTALL_MISSING_TARGET:BOOL`: Automatically install a missing target via `rustup` instead of failing. + + +#### Developer/Maintainer Options +These options are not used in the course of normal Corrosion usage, but are used to configure how +Corrosion is built and installed. Only applies to Corrosion builds and subdirectory uses. + +- `CORROSION_BUILD_TESTS:BOOL` - Build the Corrosion tests. Default: `Off` if Corrosion is a + subdirectory, `ON` if it is the top-level project + + +### Information provided by Corrosion + +For your convenience, Corrosion sets a number of variables which contain information about the version of the rust +toolchain. You can use the CMake version comparison operators +(e.g. [`VERSION_GREATER_EQUAL`](https://cmake.org/cmake/help/latest/command/if.html#version-comparisons)) on the main +variable (e.g. `if(Rust_VERSION VERSION_GREATER_EQUAL "1.57.0")`), or you can inspect the major, minor and patch +versions individually. +- `Rust_VERSION<_MAJOR|_MINOR|_PATCH>` - The version of rustc. +- `Rust_CARGO_VERSION<_MAJOR|_MINOR|_PATCH>` - The cargo version. +- `Rust_LLVM_VERSION<_MAJOR|_MINOR|_PATCH>` - The LLVM version used by rustc. +- `Rust_IS_NIGHTLY` - 1 if a nightly toolchain is used, otherwise 0. Useful for selecting an unstable feature for a + crate, that is only available on nightly toolchains. +- `Rust_RUSTUP_TOOLCHAINS`, `Rust_RUSTUP_TOOLCHAINS_RUSTC_PATH`, `Rust_RUSTUP_TOOLCHAINS_CARGO_PATH` + and `Rust_RUSTUP_TOOLCHAINS_VERSION`: These variables are lists, which should be iterated over with + CMakes `foreach(var IN ZIP_LISTS list1 list2 ...)` iterator. They provide a list of installed rustup managed toolchains and + the associated rustc and cargo paths as well as the corresponding rustc version. +- Cache variables containing information based on the target triple for the selected target + as well as the default host target: + - `Rust_CARGO_TARGET_ARCH`, `Rust_CARGO_HOST_ARCH`: e.g. `x86_64` or `aarch64` + - `Rust_CARGO_TARGET_VENDOR`, `Rust_CARGO_HOST_VENDOR`: e.g. `apple`, `pc`, `unknown` etc. + - `Rust_CARGO_TARGET_OS`, `Rust_CARGO_HOST_OS`: e.g. `darwin`, `linux`, `windows`, `none` + - `Rust_CARGO_TARGET_ENV`, `Rust_CARGO_HOST_ENV`: e.g. `gnu`, `musl` + + + + +### Selecting a custom cargo profile + +[Rust 1.57](https://blog.rust-lang.org/2021/12/02/Rust-1.57.0.html) stabilized the support for custom +[profiles](https://doc.rust-lang.org/cargo/reference/profiles.html). If you are using a sufficiently new rust toolchain, +you may select a custom profile by adding the optional argument `PROFILE ` to +`corrosion_import_crate()`. If you do not specify a profile, or you use an older toolchain, corrosion will select +the standard `dev` profile if the CMake config is either `Debug` or unspecified. In all other cases the `release` +profile is chosen for cargo. + +### Importing C-Style Libraries Written in Rust +Corrosion makes it completely trivial to import a crate into an existing CMake project. Consider +a project called [rust2cpp](test/rust2cpp/rust2cpp) with the following file structure: +``` +rust2cpp/ + rust/ + src/ + lib.rs + Cargo.lock + Cargo.toml + CMakeLists.txt + main.cpp +``` + +This project defines a simple Rust lib crate, like so, in [`rust2cpp/rust/Cargo.toml`](test/rust2cpp/rust2cpp/rust/Cargo.toml): +```toml +[package] +name = "rust-lib" +version = "0.1.0" +authors = ["Andrew Gaspar "] +license = "MIT" +edition = "2018" + +[dependencies] + +[lib] +crate-type=["staticlib"] +``` + +In addition to `"staticlib"`, you can also use `"cdylib"`. In fact, you can define both with a +single crate and switch between which is used using the standard +[`BUILD_SHARED_LIBS`](https://cmake.org/cmake/help/latest/variable/BUILD_SHARED_LIBS.html) variable. + +This crate defines a simple crate called `rust-lib`. Importing this crate into your +[CMakeLists.txt](test/rust2cpp/CMakeLists.txt) is trivial: +```cmake +# Note: you must have already included Corrosion for `corrosion_import_crate` to be available. See # the `Installation` section above. + +corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml) +``` + +Now that you've imported the crate into CMake, all of the executables, static libraries, and dynamic +libraries defined in the Rust can be directly referenced. So, merely define your C++ executable as +normal in CMake and add your crate's library using target_link_libraries: +```cmake +add_executable(cpp-exe main.cpp) +target_link_libraries(cpp-exe PUBLIC rust-lib) +``` + +That's it! You're now linking your Rust library to your C++ library. + +#### Generate Bindings to Rust Library Automatically + +Currently, you must manually declare bindings in your C or C++ program to the exported routines and +types in your Rust project. You can see boths sides of this in +[the Rust code](test/rust2cpp/rust2cpp/rust/src/lib.rs) and in [the C++ code](test/rust2cpp/rust2cpp/main.cpp). + +Integration with [cbindgen](https://github.com/eqrion/cbindgen) is +planned for the future. + +### Importing Libraries Written in C and C++ Into Rust + +The rust targets can be imported with `corrosion_import_crate()` into CMake. +For targets where the linker should be invoked by Rust corrosion provides +`corrosion_link_libraries()` to link your C/C++ libraries with the Rust target. +For additional linker flags you may use `corrosion_add_target_local_rustflags()` +and pass linker arguments via the `-Clink-args` flag to rustc. These flags will +only be passed to the final rustc invocation and not affect any rust dependencies. + +C bindings can be generated via [bindgen](https://github.com/rust-lang/rust-bindgen). +Corrosion does not offer any direct integration yet, but you can either generate the +bindings in the build-script of your crate, or generate the bindings as a CMake build step +(e.g. a custom target) and add a dependency from `cargo-prebuild_` to your +custom target for generating the bindings. + +Example: + +```cmake +# Import your Rust targets +corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml) +# Link C/C++ libraries with your Rust target +corrosion_link_libraries(target_name c_library) +# Optionally explicitly define which linker to use. +corrosion_set_linker(target_name your_custom_linker) +# Optionally set linker arguments +corrosion_add_target_local_rustflags(target_name "-Clink-args=") +# Optionally tell CMake that the rust crate depends on another target (e.g. a code generator) +add_dependencies(cargo-prebuild_ custom_bindings_target) +``` + +### Cross Compiling +Corrosion attempts to support cross-compiling as generally as possible, though not all +configurations are tested. Cross-compiling is explicitly supported in the following scenarios. + +In all cases, you will need to install the standard library for the Rust target triple. When using +Rustup, you can use it to install the target standard library: + +```bash +rustup target add +``` + +If the target triple is automatically derived, Corrosion will print the target during configuration. +For example: + +``` +-- Rust Target: aarch64-linux-android +``` + +#### Windows-to-Windows +Corrosion supports cross-compiling between arbitrary Windows architectures using the Visual Studio +Generator. For example, to cross-compile for ARM64 from any platform, simply set the `-A` +architecture flag: + +```bash +cmake -S. -Bbuild-arm64 -A ARM64 +cmake --build build-arm64 +``` + +Please note that for projects containing a build-script at least Rust 1.54 is required due to a bug +in previous cargo versions, which causes the build-script to incorrectly be built for the target +platform. + +#### Linux-to-Linux +In order to cross-compile on Linux, you will need to install a cross-compiler. For example, on +Ubuntu, to cross compile for 64-bit Little-Endian PowerPC Little-Endian, install +`g++-powerpc64le-linux-gnu` from apt-get: + +```bash +sudo apt install g++-powerpc64le-linux-gnu +``` + +Currently, Corrosion does not automatically determine the target triple while cross-compiling on +Linux, so you'll need to specify a matching `Rust_CARGO_TARGET`. + +```bash +cmake -S. -Bbuild-ppc64le -DRust_CARGO_TARGET=powerpc64le-unknown-linux-gnu -DCMAKE_CXX_COMPILER=powerpc64le-linux-gnu-g++ +cmake --build build-ppc64le +``` + +#### Android + +Cross-compiling for Android is supported on all platforms with the Makefile and Ninja generators, +and the Rust target triple will automatically be selected. The CMake +[cross-compiling instructions for Android](https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-android) +apply here. For example, to build for ARM64: + +```bash +cmake -S. -Bbuild-android-arm64 -GNinja -DCMAKE_SYSTEM_NAME=Android \ + -DCMAKE_ANDROID_NDK=/path/to/android-ndk-rxxd -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a +``` + +**Important note:** The Android SDK ships with CMake 3.10 at newest, which Android Studio will +prefer over any CMake you've installed locally. CMake 3.10 is insufficient for using Corrosion, +which requires a minimum of CMake 3.22. If you're using Android Studio to build your project, +follow the instructions in the Android Studio documentation for +[using a specific version of CMake](https://developer.android.com/studio/projects/install-ndk#vanilla_cmake). + + +### CMake `OUTPUT_DIRECTORY` target properties and `IMPORTED_LOCATION` + +Corrosion respects the following `OUTPUT_DIRECTORY` target properties: +- [ARCHIVE_OUTPUT_DIRECTORY](https://cmake.org/cmake/help/latest/prop_tgt/ARCHIVE_OUTPUT_DIRECTORY.html) +- [LIBRARY_OUTPUT_DIRECTORY](https://cmake.org/cmake/help/latest/prop_tgt/LIBRARY_OUTPUT_DIRECTORY.html) +- [RUNTIME_OUTPUT_DIRECTORY](https://cmake.org/cmake/help/latest/prop_tgt/RUNTIME_OUTPUT_DIRECTORY.html) +- [PDB_OUTPUT_DIRECTORY](https://cmake.org/cmake/help/latest/prop_tgt/PDB_OUTPUT_DIRECTORY.html) + +If the target property is set (e.g. by defining the `CMAKE_XYZ_OUTPUT_DIRECTORY` variable before calling +`corrosion_import_crate()`), corrosion will copy the built rust artifacts to the location defined in the +target property. +Due to limitations in CMake these target properties are evaluated in a deferred manner, to +support the user setting the target properties after the call to `corrosion_import_crate()`. +This has the side effect that the `IMPORTED_LOCATION` property will be set late, and users should not +use `get_property` to read `IMPORTED_LOCATION` at configure time. Instead, generator expressions +should be used to get the location of the target artifact. +If `IMPORTED_LOCATION` is needed at configure time users may use `cmake_language(DEFER CALL ...)` to defer +evaluation to after the `IMPORTED_LOCATION` property is set. diff --git a/libs/3rdparty/corrosion/test/CMakeLists.txt b/libs/3rdparty/corrosion/test/CMakeLists.txt new file mode 100644 index 00000000000..ac0d1aa52e2 --- /dev/null +++ b/libs/3rdparty/corrosion/test/CMakeLists.txt @@ -0,0 +1,192 @@ +# This option is currently used to prevent recursion +option(CORROSION_TESTS "Enable Corrosion tests" ON) +mark_as_advanced(CORROSION_TESTS) +if(NOT CORROSION_TESTS) + return() +endif() + +option(CORROSION_TESTS_CXXBRIDGE + "Build cxxbridge tests which requires cxxbridge executable being available" + OFF) +option(CORROSION_TESTS_KEEP_BUILDDIRS + "By default corrosion tests will cleanup after themselves. This option limits the cleaning up to the + target directories and will keep the build directories, which may be useful for caching." + OFF) +mark_as_advanced(CORROSION_TESTS_NO_CLEANUP) + +set(test_install_path "${CMAKE_CURRENT_BINARY_DIR}/test-install-corrosion") +file(REAL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/.." corrosion_source_dir) +set(test_header_contents + "option(CORROSION_TESTS_FIND_CORROSION \"Use Corrosion as a subdirectory\" OFF)" + "if (CORROSION_TESTS_FIND_CORROSION)" + " set(CMAKE_PREFIX_PATH \"${test_install_path}\" CACHE INTERNAL \"\" FORCE)" + " find_package(Corrosion REQUIRED PATHS \"${test_install_path}\" NO_CMAKE_SYSTEM_PATH)" + "else()" + " add_subdirectory(\"${corrosion_source_dir}\" corrosion)" + "endif()" +) + +string(REPLACE ";" "\n" test_header_contents "${test_header_contents}") + +file(WRITE test_header.cmake "${test_header_contents}") + +option(CORROSION_TESTS_INSTALL_CORROSION + "Install Corrosion to a test directory and let tests use the installed Corrosion" + OFF) +if(CORROSION_TESTS_INSTALL_CORROSION) + add_test(NAME "install_corrosion_configure" + COMMAND + ${CMAKE_COMMAND} + -S "${CMAKE_CURRENT_SOURCE_DIR}/.." + -B "${CMAKE_CURRENT_BINARY_DIR}/build-corrosion" + -DCORROSION_VERBOSE_OUTPUT=ON + -DCORROSION_TESTS=OFF + -DCMAKE_BUILD_TYPE=Release + -G${CMAKE_GENERATOR} + "-DCMAKE_INSTALL_PREFIX=${test_install_path}" + ) + add_test(NAME "install_corrosion_build" + COMMAND + ${CMAKE_COMMAND} --build "${CMAKE_CURRENT_BINARY_DIR}/build-corrosion" --config Release + ) + add_test(NAME "install_corrosion_install" + COMMAND + ${CMAKE_COMMAND} --install "${CMAKE_CURRENT_BINARY_DIR}/build-corrosion" --config Release + ) + set_tests_properties("install_corrosion_configure" PROPERTIES FIXTURES_SETUP "fixture_corrosion_configure") + set_tests_properties("install_corrosion_build" PROPERTIES FIXTURES_SETUP "fixture_corrosion_build") + set_tests_properties("install_corrosion_build" PROPERTIES FIXTURES_REQUIRED "fixture_corrosion_configure") + set_tests_properties("install_corrosion_install" PROPERTIES FIXTURES_REQUIRED "fixture_corrosion_build") + set_tests_properties("install_corrosion_install" PROPERTIES FIXTURES_SETUP "fixture_corrosion_install") + + add_test(NAME "install_corrosion_build_cleanup" COMMAND "${CMAKE_COMMAND}" -E remove_directory "${CMAKE_CURRENT_BINARY_DIR}/build-corrosion") + set_tests_properties("install_corrosion_build_cleanup" PROPERTIES + FIXTURES_CLEANUP + "fixture_corrosion_configure;fixture_corrosion_build" + ) + + add_test(NAME "install_corrosion_cleanup" COMMAND "${CMAKE_COMMAND}" -E remove_directory "${test_install_path}") + set_tests_properties("install_corrosion_cleanup" PROPERTIES + FIXTURES_CLEANUP + "fixture_corrosion_configure;fixture_corrosion_build;fixture_corrosion_install" + ) +endif() + +function(corrosion_tests_add_test test_name bin_names) + set(options "IS_HOSTBUILD") + set(one_value_kewords "TEST_SRC_DIR") + set(multi_value_keywords "") + cmake_parse_arguments(PARSE_ARGV 2 TST "${options}" "${one_value_kewords}" "${multi_value_keywords}") + set(pass_through_arguments "${TST_UNPARSED_ARGUMENTS}") + +# In the future we could add multiple tests here for different configurations (generator, build mode, rust version ...) +# which would allow us to simplify the github job matrix + if(TST_TEST_SRC_DIR) + set(test_dir "${TST_TEST_SRC_DIR}") + else() + set(test_dir "${test_name}") + endif() + + set(configure_cmake_args) + if(CMAKE_C_COMPILER) + list(APPEND configure_cmake_args "C_COMPILER" "${CMAKE_C_COMPILER}") + endif() + if(CMAKE_CXX_COMPILER) + list(APPEND configure_cmake_args "CXX_COMPILER" "${CMAKE_CXX_COMPILER}") + endif() + if(CMAKE_C_COMPILER_TARGET) + list(APPEND configure_cmake_args "C_COMPILER_TARGET" "${CMAKE_C_COMPILER_TARGET}") + endif() + if(CMAKE_CXX_COMPILER_TARGET) + list(APPEND configure_cmake_args "CXX_COMPILER_TARGET" "${CMAKE_CXX_COMPILER_TARGET}") + endif() + if(CMAKE_GENERATOR_PLATFORM) + list(APPEND configure_cmake_args "GENERATOR_PLATFORM" "${CMAKE_GENERATOR_PLATFORM}") + endif() + if(CMAKE_CROSSCOMPILING) + list(APPEND configure_cmake_args SYSTEM_NAME "${CMAKE_SYSTEM_NAME}") + endif() + if(CMAKE_OSX_ARCHITECTURES) + list(APPEND configure_cmake_args OSX_ARCHITECTURES "${CMAKE_OSX_ARCHITECTURES}") + endif() + if(CMAKE_TOOLCHAIN_FILE) + list(APPEND configure_cmake_args TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}") + endif() + + add_test(NAME "${test_name}_build" + COMMAND + ${CMAKE_COMMAND} + -P "${CMAKE_SOURCE_DIR}/test/ConfigureAndBuild.cmake" + SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/${test_dir}" + BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/build-${test_name}" + GENERATOR "${CMAKE_GENERATOR}" + RUST_TOOLCHAIN "${Rust_TOOLCHAIN}" + CARGO_TARGET "${Rust_CARGO_TARGET}" + ${configure_cmake_args} + ${pass_through_arguments} + + COMMAND_EXPAND_LISTS + ) + set_tests_properties("${test_name}_build" PROPERTIES FIXTURES_SETUP "build_fixture_${test_name}") + if(CORROSION_TESTS_INSTALL_CORROSION) + set_tests_properties("${test_name}_build" PROPERTIES FIXTURES_REQUIRED "fixture_corrosion_install") + endif() + foreach(bin ${bin_names}) + if(WIN32) + set(bin_filename "${bin}.exe") + else() + set(bin_filename "${bin}") + endif() + add_test(NAME "${test_name}_run_${bin}" COMMAND "${CMAKE_CURRENT_BINARY_DIR}/build-${test_name}/${bin_filename}") + set_tests_properties("${test_name}_run_${bin}" PROPERTIES FIXTURES_REQUIRED "build_fixture_${test_name}") + # CMAKE_CROSSCOMPILING is not set when cross-compiling with VS (via -A flag). + # Todo: We could run x86 binaries on x64 hosts. + if((CMAKE_CROSSCOMPILING OR CMAKE_VS_PLATFORM_NAME) AND NOT "${TST_IS_HOSTBUILD}") + # Todo: In the future we could potentially run some tests with qemu. + set_tests_properties("${test_name}_run_${bin}" PROPERTIES DISABLED TRUE) + endif() + endforeach() + + if(CORROSION_TESTS_KEEP_BUILDDIRS) + add_test(NAME "${test_name}_cleanup_artifacts" + COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_CURRENT_BINARY_DIR}/build-${test_name}" --target clean + ) + add_test(NAME "${test_name}_cleanup_cargo" + COMMAND "${CMAKE_COMMAND}" -E remove_directory "${CMAKE_CURRENT_BINARY_DIR}/build-${test_name}/cargo" + ) + set_tests_properties("${test_name}_cleanup_artifacts" PROPERTIES FIXTURES_CLEANUP "build_fixture_${test_name}") + set_tests_properties("${test_name}_cleanup_cargo" PROPERTIES FIXTURES_CLEANUP "build_fixture_${test_name}") + else() + add_test(NAME "${test_name}_cleanup" COMMAND "${CMAKE_COMMAND}" -E remove_directory "${CMAKE_CURRENT_BINARY_DIR}/build-${test_name}") + set_tests_properties("${test_name}_cleanup" PROPERTIES FIXTURES_CLEANUP "build_fixture_${test_name}") + endif() +endfunction() + +# Please keep this in alphabetical order. +add_subdirectory(config_discovery) +add_subdirectory(cargo_flags) +add_subdirectory(cpp2rust) +if(Rust_VERSION VERSION_GREATER_EQUAL "1.64.0") + # Flag `--crate-type` is only supported since Rust 1.64.0 + add_subdirectory(crate_type) + add_subdirectory(override_crate_type) +endif() +add_subdirectory(custom_profiles) +if(NOT Rust_CROSSCOMPILING AND Rust_VERSION VERSION_GREATER_EQUAL "1.60.0") + add_subdirectory(custom_target) +endif() +add_subdirectory(cbindgen) +add_subdirectory(corrosion_install) +add_subdirectory(cxxbridge) +add_subdirectory(envvar) +add_subdirectory(features) +add_subdirectory(find_rust) +add_subdirectory(gensource) +add_subdirectory(hostbuild) +add_subdirectory(multitarget) +add_subdirectory(nostd) +add_subdirectory("output directory") +add_subdirectory(parse_target_triple) +add_subdirectory(rust2cpp) +add_subdirectory(rustflags) +add_subdirectory(workspace) diff --git a/libs/3rdparty/corrosion/test/ConfigureAndBuild.cmake b/libs/3rdparty/corrosion/test/ConfigureAndBuild.cmake new file mode 100644 index 00000000000..c3017074fea --- /dev/null +++ b/libs/3rdparty/corrosion/test/ConfigureAndBuild.cmake @@ -0,0 +1,118 @@ +# CMake script to configure and build a test project + +set(TEST_ARG_LIST) + +# Expect actual arguments to start at index 3 (cmake -P ) +foreach(ARG_INDEX RANGE 3 ${CMAKE_ARGC}) + list(APPEND TEST_ARG_LIST "${CMAKE_ARGV${ARG_INDEX}}") +endforeach() + +set(options "USE_INSTALLED_CORROSION") +set(oneValueArgs + SOURCE_DIR + BINARY_DIR + GENERATOR + GENERATOR_PLATFORM + RUST_TOOLCHAIN + CARGO_TARGET + C_COMPILER + CXX_COMPILER + C_COMPILER_TARGET + CXX_COMPILER_TARGET + SYSTEM_NAME + CARGO_PROFILE + OSX_ARCHITECTURES + TOOLCHAIN_FILE +) +set(multiValueArgs "PASS_THROUGH_ARGS") +cmake_parse_arguments(TEST "${options}" "${oneValueArgs}" + "${multiValueArgs}" ${TEST_ARG_LIST} ) + +set(configure_args "") +if(TEST_CARGO_TARGET) + list(APPEND configure_args "-DRust_CARGO_TARGET=${TEST_CARGO_TARGET}") +endif() +if(TEST_USE_INSTALLED_CORROSION) + list(APPEND configure_args "-DCORROSION_TESTS_FIND_CORROSION=ON") +endif() +if(TEST_GENERATOR_PLATFORM) + list(APPEND configure_args "-A${TEST_GENERATOR_PLATFORM}") +endif() +if(TEST_C_COMPILER) + list(APPEND configure_args "-DCMAKE_C_COMPILER=${TEST_C_COMPILER}") +endif() +if(TEST_CXX_COMPILER) + list(APPEND configure_args "-DCMAKE_CXX_COMPILER=${TEST_CXX_COMPILER}") +endif() +if(TEST_C_COMPILER_TARGET) + list(APPEND configure_args "-DCMAKE_C_COMPILER_TARGET=${TEST_C_COMPILER_TARGET}") +endif() +if(TEST_CXX_COMPILER_TARGET) + list(APPEND configure_args "-DCMAKE_CXX_COMPILER_TARGET=${TEST_CXX_COMPILER_TARGET}") +endif() +if(TEST_SYSTEM_NAME) + list(APPEND configure_args "-DCMAKE_SYSTEM_NAME=${TEST_SYSTEM_NAME}") +endif() +if(TEST_OSX_ARCHITECTURES) + list(APPEND configure_args "-DCMAKE_OSX_ARCHITECTURES=${TEST_OSX_ARCHITECTURES}") +endif() +if(TEST_TOOLCHAIN_FILE) + list(APPEND configure_args "-DCMAKE_TOOLCHAIN_FILE=${TEST_TOOLCHAIN_FILE}") +endif() +if(TEST_CARGO_PROFILE) + list(APPEND configure_args "-DCARGO_PROFILE=${TEST_CARGO_PROFILE}") +endif() + +# Remove old binary directory +file(REMOVE_RECURSE "${TEST_BINARY_DIR}") + +file(MAKE_DIRECTORY "${TEST_BINARY_DIR}") + +message(STATUS "TEST_BINARY_DIRECTORY: ${TEST_BINARY_DIR}") + +execute_process( + COMMAND + "${CMAKE_COMMAND}" + "-G${TEST_GENERATOR}" + "-DRust_TOOLCHAIN=${TEST_RUST_TOOLCHAIN}" + --log-level Debug + ${configure_args} + ${TEST_PASS_THROUGH_ARGS} + -S "${TEST_SOURCE_DIR}" + -B "${TEST_BINARY_DIR}" + COMMAND_ECHO STDOUT + RESULT_VARIABLE EXIT_CODE +) + +if (NOT "${EXIT_CODE}" EQUAL 0) + message(FATAL_ERROR "Configure step failed. Exit code: `${EXIT_CODE}`") +endif() + +if ("${TEST_GENERATOR}" STREQUAL "Ninja Multi-Config" + OR "${TEST_GENERATOR}" MATCHES "Visual Studio" + ) + foreach(config Debug Release RelWithDebInfo) + execute_process( + COMMAND "${CMAKE_COMMAND}" + --build "${TEST_BINARY_DIR}" + --config "${config}" + COMMAND_ECHO STDOUT + RESULT_VARIABLE EXIT_CODE + ) + if (NOT "${EXIT_CODE}" EQUAL 0) + message(FATAL_ERROR "Build step failed for config `${config}`. " + "Exit code: `${EXIT_CODE}`") + endif() + endforeach() +else() + execute_process( + COMMAND "${CMAKE_COMMAND}" --build "${TEST_BINARY_DIR}" + COMMAND_ECHO STDOUT + RESULT_VARIABLE EXIT_CODE + ) + if (NOT "${EXIT_CODE}" EQUAL 0) + message(FATAL_ERROR "Build step failed. Exit code: `${EXIT_CODE}`") + endif() +endif() + + diff --git a/libs/3rdparty/corrosion/test/README.md b/libs/3rdparty/corrosion/test/README.md new file mode 100644 index 00000000000..df48158801f --- /dev/null +++ b/libs/3rdparty/corrosion/test/README.md @@ -0,0 +1,7 @@ +# Corrosion Tests + +Corrosions tests are run via ctest. The tests themselves utilize CMake script mode +to configure and build a test project, which allows for great flexibility. +Using ctest properties such as `PASS_REGULAR_EXPRESSION` or `FAIL_REGULAR_EXPRESSION` +can be used to confirm that built executable targets run as expected, but can also +be used to fail tests if Corrosion warnings appear in the configure output. \ No newline at end of file diff --git a/libs/3rdparty/corrosion/test/TestFileExists.cmake b/libs/3rdparty/corrosion/test/TestFileExists.cmake new file mode 100644 index 00000000000..a69f49a0a70 --- /dev/null +++ b/libs/3rdparty/corrosion/test/TestFileExists.cmake @@ -0,0 +1,27 @@ +# CMake script to test if a file exists. Errors if the file does not exist. +# Expect actual arguments to start at index 3 (cmake -P ) + +# Expect one argument +if(NOT (CMAKE_ARGC EQUAL "4")) + message(FATAL_ERROR "Test Internal Error: Unexpected ARGC Value: ${CMAKE_ARGC}.") +endif() + +set(FILE_PATH "${CMAKE_ARGV3}") + +if(NOT ( EXISTS "${FILE_PATH}" )) + set(error_details "File `${FILE_PATH}` does not exist!\n") + set(PARENT_TREE "${FILE_PATH}") + cmake_path(HAS_PARENT_PATH PARENT_TREE has_parent) + while(has_parent) + cmake_path(GET PARENT_TREE PARENT_PATH PARENT_TREE) + cmake_path(HAS_PARENT_PATH PARENT_TREE has_parent) + if(EXISTS "${PARENT_TREE}") + file(GLOB dir_contents LIST_DIRECTORIES true "${PARENT_TREE}/*") + list(APPEND error_details "Found Parent directory `${PARENT_TREE}` exists and contains:\n" ${dir_contents}) + break() + else() + list(APPEND error_details "Parent directory `${PARENT_TREE}` also does not exist!") + endif() + endwhile() + message(FATAL_ERROR "Test failed: ${error_details}") +endif() diff --git a/libs/3rdparty/corrosion/test/cargo_flags/CMakeLists.txt b/libs/3rdparty/corrosion/test/cargo_flags/CMakeLists.txt new file mode 100644 index 00000000000..0707f3a54cf --- /dev/null +++ b/libs/3rdparty/corrosion/test/cargo_flags/CMakeLists.txt @@ -0,0 +1,3 @@ +corrosion_tests_add_test(cargo_flags "flags-exe") + +set_tests_properties("cargo_flags_run_flags-exe" PROPERTIES PASS_REGULAR_EXPRESSION [[Hello, Cxx! I am Rust!]]) diff --git a/libs/3rdparty/corrosion/test/cargo_flags/cargo_flags/CMakeLists.txt b/libs/3rdparty/corrosion/test/cargo_flags/cargo_flags/CMakeLists.txt new file mode 100644 index 00000000000..8c4d0784ccd --- /dev/null +++ b/libs/3rdparty/corrosion/test/cargo_flags/cargo_flags/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0) +include(../../test_header.cmake) + +corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml FLAGS --features one) + +add_executable(flags-exe main.cpp) +target_link_libraries(flags-exe PUBLIC flags_lib) +corrosion_set_cargo_flags(flags_lib --features two) +corrosion_set_cargo_flags(flags_lib $) + +set_property( + TARGET flags_lib + APPEND + PROPERTY more_flags --features three +) diff --git a/libs/3rdparty/corrosion/test/cargo_flags/cargo_flags/main.cpp b/libs/3rdparty/corrosion/test/cargo_flags/cargo_flags/main.cpp new file mode 100644 index 00000000000..b5fde3cf777 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cargo_flags/cargo_flags/main.cpp @@ -0,0 +1,6 @@ +extern "C" void rust_function(char const *name); + + +int main(int argc, char **argv) { + rust_function("Cxx"); +} diff --git a/libs/3rdparty/corrosion/test/cargo_flags/cargo_flags/rust/Cargo.lock b/libs/3rdparty/corrosion/test/cargo_flags/cargo_flags/rust/Cargo.lock new file mode 100644 index 00000000000..17c6b44904e --- /dev/null +++ b/libs/3rdparty/corrosion/test/cargo_flags/cargo_flags/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "flags-lib" +version = "0.1.0" diff --git a/libs/3rdparty/corrosion/test/cargo_flags/cargo_flags/rust/Cargo.toml b/libs/3rdparty/corrosion/test/cargo_flags/cargo_flags/rust/Cargo.toml new file mode 100644 index 00000000000..479ff413fad --- /dev/null +++ b/libs/3rdparty/corrosion/test/cargo_flags/cargo_flags/rust/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "flags-lib" +version = "0.1.0" +edition = "2018" + +[lib] +crate-type=["staticlib"] + +[features] + +one = [] +two = [] +three = [] diff --git a/libs/3rdparty/corrosion/test/cargo_flags/cargo_flags/rust/src/lib.rs b/libs/3rdparty/corrosion/test/cargo_flags/cargo_flags/rust/src/lib.rs new file mode 100644 index 00000000000..7afea31a08c --- /dev/null +++ b/libs/3rdparty/corrosion/test/cargo_flags/cargo_flags/rust/src/lib.rs @@ -0,0 +1,14 @@ +use std::os::raw::c_char; + +#[no_mangle] +pub extern "C" fn rust_function(name: *const c_char) { + let name = unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() }; + println!("Hello, {}! I am Rust!", name); + + #[cfg(not(feature = "one"))] + compile_error!("Feature one is not enabled"); + #[cfg(not(feature = "two"))] + compile_error!("Feature two is not enabled"); + #[cfg(not(feature = "three"))] + compile_error!("Feature three is not enabled"); +} diff --git a/libs/3rdparty/corrosion/test/cbindgen/CMakeLists.txt b/libs/3rdparty/corrosion/test/cbindgen/CMakeLists.txt new file mode 100644 index 00000000000..b91120d3046 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cbindgen/CMakeLists.txt @@ -0,0 +1,53 @@ +corrosion_tests_add_test(cbindgen_rust2cpp_auto "cpp-exe" TEST_SRC_DIR auto) +corrosion_tests_add_test(cbindgen_manual "cpp-exe" TEST_SRC_DIR manual) + +set_tests_properties(cbindgen_rust2cpp_auto_run_cpp-exe cbindgen_manual_run_cpp-exe + PROPERTIES PASS_REGULAR_EXPRESSION + "^add_point Result: Point { x: 100, y: 100 }\r?\n$" +) + +add_test(NAME "cbindgen_install_configure" + COMMAND + ${CMAKE_COMMAND} + -S "${CMAKE_CURRENT_SOURCE_DIR}/install_lib" + -B "${CMAKE_CURRENT_BINARY_DIR}/build_install_lib" + "-G${CMAKE_GENERATOR}" + --install-prefix "${CMAKE_CURRENT_BINARY_DIR}/build_install_lib/test_install_lib_install_dir" + + COMMAND_EXPAND_LISTS +) + +add_test(NAME "cbindgen_install" + COMMAND + ${CMAKE_COMMAND} + --build "${CMAKE_CURRENT_BINARY_DIR}/build_install_lib" + --target install + --config Debug +) + +add_test(NAME cbindgen_install_check_header_installed + COMMAND + "${CMAKE_COMMAND}" + -P "${CMAKE_CURRENT_SOURCE_DIR}/../TestFileExists.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/build_install_lib/test_install_lib_install_dir/include/rust-lib.h" +) + +add_test(NAME cbindgen_install_clean + COMMAND + "${CMAKE_COMMAND}" + -E remove_directory "${CMAKE_CURRENT_BINARY_DIR}/build_install_lib/" +) +set_tests_properties("cbindgen_install_configure" PROPERTIES FIXTURES_SETUP "configure_fixture_cbindgen_install") +set_tests_properties("cbindgen_install" PROPERTIES FIXTURES_REQUIRED "configure_fixture_cbindgen_install") + +set_tests_properties("cbindgen_install" PROPERTIES FIXTURES_SETUP "install_fixture_cbindgen_install") +set_tests_properties("cbindgen_install_check_header_installed" PROPERTIES FIXTURES_REQUIRED "install_fixture_cbindgen_install") +set_tests_properties("cbindgen_install_check_header_installed" PROPERTIES FIXTURES_SETUP "fx_check_header_installed") +set_tests_properties(cbindgen_install_clean PROPERTIES FIXTURES_CLEANUP "configure_fixture_cbindgen_install;install_fixture_cbindgen_install;fx_check_header_installed") + +# Todo: We also should add a cpp2rust test with the following setup: +# - A rust lib that is used by a rust executable +# - cbindgen creates bindings for the rust-lib +# - c++ code uses the rust lib and is used in turn by the rust bin. + +# todo: add a test for the DEPFILE and correct regenerating if the sources are touched. diff --git a/libs/3rdparty/corrosion/test/cbindgen/auto/CMakeLists.txt b/libs/3rdparty/corrosion/test/cbindgen/auto/CMakeLists.txt new file mode 100644 index 00000000000..b316a04831d --- /dev/null +++ b/libs/3rdparty/corrosion/test/cbindgen/auto/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0) + +set(CORROSION_TOOLS_RUST_TOOLCHAIN "stable") +include(../../test_header.cmake) +corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml) +corrosion_experimental_cbindgen(TARGET the_rust_lib_crate_name HEADER_NAME "rust-lib.h") + +add_executable(cpp-exe main.cpp) +set_property(TARGET cpp-exe PROPERTY CXX_STANDARD 11) +target_link_libraries(cpp-exe PUBLIC the_rust_lib_crate_name) diff --git a/libs/3rdparty/corrosion/test/cbindgen/auto/main.cpp b/libs/3rdparty/corrosion/test/cbindgen/auto/main.cpp new file mode 100644 index 00000000000..7ad201fca56 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cbindgen/auto/main.cpp @@ -0,0 +1,22 @@ +#include "rust-lib.h" +#include + +int main(int argc, char **argv) { + assert(is_magic_number(MAGIC_NUMBER)); + struct Point p1, p2; + p1.x = 54; + p2.x = 46; + p1.y = 34; + p2.y = 66; + add_point(&p1, &p2); + assert(p1.x == 100); + assert(p2.x == 46); + assert(p1.y == 100); + assert(p2.y == 66); + add_point(&p1, NULL); + assert(p1.x == 100); + assert(p1.y == 100); + + assert(OTHER_MOD_MAGIC_NUMBER == 192312312); + assert(FFI_MAGIC_NUMBER == 0xFDA00184); +} diff --git a/libs/3rdparty/corrosion/test/cbindgen/auto/rust/Cargo.toml b/libs/3rdparty/corrosion/test/cbindgen/auto/rust/Cargo.toml new file mode 100644 index 00000000000..ff8d58fec9f --- /dev/null +++ b/libs/3rdparty/corrosion/test/cbindgen/auto/rust/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "the_rust_package_name" +version = "0.1.0" +license = "MIT" +edition = "2018" + +[dependencies] + +[lib] +crate-type=["staticlib"] +name = "the_rust_lib_crate_name" diff --git a/libs/3rdparty/corrosion/test/cbindgen/auto/rust/cbindgen.toml b/libs/3rdparty/corrosion/test/cbindgen/auto/rust/cbindgen.toml new file mode 100644 index 00000000000..86b1a9ae829 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cbindgen/auto/rust/cbindgen.toml @@ -0,0 +1,4 @@ +language = "C++" +include_version = true + + diff --git a/libs/3rdparty/corrosion/test/cbindgen/auto/rust/src/ffi.rs b/libs/3rdparty/corrosion/test/cbindgen/auto/rust/src/ffi.rs new file mode 100644 index 00000000000..01ad181cb14 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cbindgen/auto/rust/src/ffi.rs @@ -0,0 +1,3 @@ +//! Just a module that contains some entries that should be parsed by cbindgen. + +pub const FFI_MAGIC_NUMBER: u64 = 0xFDA0_0184; diff --git a/libs/3rdparty/corrosion/test/cbindgen/auto/rust/src/lib.rs b/libs/3rdparty/corrosion/test/cbindgen/auto/rust/src/lib.rs new file mode 100644 index 00000000000..0ad5c8f8af5 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cbindgen/auto/rust/src/lib.rs @@ -0,0 +1,33 @@ +pub const MAGIC_NUMBER: u64 = 0xABCD_EFAB; + +pub mod ffi; +pub mod other_mod; + +#[derive(Debug)] +#[repr(C)] +pub struct Point { + x: u64, + y: u64, +} + +impl Point { + pub(crate) fn add(&mut self, rhs: &Point) { + self.x = self.x.wrapping_add(rhs.x); + self.y = self.y.wrapping_add(rhs.y); + } +} + +#[no_mangle] +pub extern "C" fn add_point(lhs: Option<&mut Point>, rhs: Option<&Point>) { + if let (Some(p1), Some(p2)) = (lhs, rhs) { + p1.add(p2); + // Print something so we can let Ctest assert the output. + println!("add_point Result: {:?}", p1); + } +} + +// simple test if the constant was exported by cbindgen correctly +#[no_mangle] +pub extern "C" fn is_magic_number(num: u64) -> bool { + num == MAGIC_NUMBER +} diff --git a/libs/3rdparty/corrosion/test/cbindgen/auto/rust/src/other_mod/mod.rs b/libs/3rdparty/corrosion/test/cbindgen/auto/rust/src/other_mod/mod.rs new file mode 100644 index 00000000000..ca34458b0d3 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cbindgen/auto/rust/src/other_mod/mod.rs @@ -0,0 +1 @@ +pub const OTHER_MOD_MAGIC_NUMBER: u32 = 192312312; diff --git a/libs/3rdparty/corrosion/test/cbindgen/install_lib/CMakeLists.txt b/libs/3rdparty/corrosion/test/cbindgen/install_lib/CMakeLists.txt new file mode 100644 index 00000000000..66bb81aa1fc --- /dev/null +++ b/libs/3rdparty/corrosion/test/cbindgen/install_lib/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0) + +set(CORROSION_TOOLS_RUST_TOOLCHAIN "stable") +include(../../test_header.cmake) + +corrosion_import_crate(MANIFEST_PATH rust_lib/Cargo.toml) + +if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") + corrosion_add_target_local_rustflags(rust_lib "-Clink-arg=-Wl,-soname,librust_lib.so") + set_target_properties(rust_lib-shared PROPERTIES IMPORTED_SONAME librust_lib.so) +elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin") + corrosion_add_target_local_rustflags(rust_lib -Clink-arg=-Wl,-install_name,@rpath/librust_lib.dylib,-current_version,1.0,-compatibility_version,1.0) + set_target_properties(rust_lib-shared PROPERTIES IMPORTED_NO_SONAME 0) + set_target_properties(rust_lib-shared PROPERTIES IMPORTED_SONAME librust_lib.dylib) +endif() + +corrosion_experimental_cbindgen(TARGET rust_lib HEADER_NAME "rust-lib.h") + +corrosion_install(TARGETS rust_lib LIBRARY PUBLIC_HEADER) diff --git a/libs/3rdparty/corrosion/test/cbindgen/install_lib/rust_lib/Cargo.toml b/libs/3rdparty/corrosion/test/cbindgen/install_lib/rust_lib/Cargo.toml new file mode 100644 index 00000000000..eb4a0752167 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cbindgen/install_lib/rust_lib/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "rust_lib" +version = "0.1.0" +edition = "2018" + +[dependencies] + +[lib] +crate-type = ["staticlib", "cdylib"] diff --git a/libs/3rdparty/corrosion/test/cbindgen/install_lib/rust_lib/src/lib.rs b/libs/3rdparty/corrosion/test/cbindgen/install_lib/rust_lib/src/lib.rs new file mode 100644 index 00000000000..76d40c6c0a1 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cbindgen/install_lib/rust_lib/src/lib.rs @@ -0,0 +1,5 @@ + +#[no_mangle] +pub extern "C" fn add(left: u64, right: u64) -> u64 { + left + right +} diff --git a/libs/3rdparty/corrosion/test/cbindgen/manual/CMakeLists.txt b/libs/3rdparty/corrosion/test/cbindgen/manual/CMakeLists.txt new file mode 100644 index 00000000000..da7b0193076 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cbindgen/manual/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0) + +set(CORROSION_TOOLS_RUST_TOOLCHAIN "stable") +include(../../test_header.cmake) +corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml) + +add_library(cbindgen_rust_lib INTERFACE) +corrosion_experimental_cbindgen(MANIFEST_DIRECTORY rust + CARGO_PACKAGE the-rust-lib-package-name + BINDINGS_TARGET cbindgen_rust_lib + HEADER_NAME "rust-lib.h") + +# The interface library for the generated headers should link to the actual rust library +target_link_libraries(cbindgen_rust_lib INTERFACE the_actual_library_crate_name) + +add_executable(cpp-exe main.cpp) +set_property(TARGET cpp-exe PROPERTY CXX_STANDARD 11) +# The C/C++ bin needs to link to the cbindgen library with the generated sources. +target_link_libraries(cpp-exe PUBLIC cbindgen_rust_lib) +#add_dependencies(cpp-exe cbindgen_rust_lib) diff --git a/libs/3rdparty/corrosion/test/cbindgen/manual/main.cpp b/libs/3rdparty/corrosion/test/cbindgen/manual/main.cpp new file mode 100644 index 00000000000..7ad201fca56 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cbindgen/manual/main.cpp @@ -0,0 +1,22 @@ +#include "rust-lib.h" +#include + +int main(int argc, char **argv) { + assert(is_magic_number(MAGIC_NUMBER)); + struct Point p1, p2; + p1.x = 54; + p2.x = 46; + p1.y = 34; + p2.y = 66; + add_point(&p1, &p2); + assert(p1.x == 100); + assert(p2.x == 46); + assert(p1.y == 100); + assert(p2.y == 66); + add_point(&p1, NULL); + assert(p1.x == 100); + assert(p1.y == 100); + + assert(OTHER_MOD_MAGIC_NUMBER == 192312312); + assert(FFI_MAGIC_NUMBER == 0xFDA00184); +} diff --git a/libs/3rdparty/corrosion/test/cbindgen/manual/rust/Cargo.toml b/libs/3rdparty/corrosion/test/cbindgen/manual/rust/Cargo.toml new file mode 100644 index 00000000000..604d712763a --- /dev/null +++ b/libs/3rdparty/corrosion/test/cbindgen/manual/rust/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "the-rust-lib-package-name" +version = "0.1.0" +license = "MIT" +edition = "2018" + +[dependencies] + +[lib] +crate-type=["staticlib"] +name = "the_actual_library_crate_name" diff --git a/libs/3rdparty/corrosion/test/cbindgen/manual/rust/cbindgen.toml b/libs/3rdparty/corrosion/test/cbindgen/manual/rust/cbindgen.toml new file mode 100644 index 00000000000..86b1a9ae829 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cbindgen/manual/rust/cbindgen.toml @@ -0,0 +1,4 @@ +language = "C++" +include_version = true + + diff --git a/libs/3rdparty/corrosion/test/cbindgen/manual/rust/src/ffi.rs b/libs/3rdparty/corrosion/test/cbindgen/manual/rust/src/ffi.rs new file mode 100644 index 00000000000..01ad181cb14 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cbindgen/manual/rust/src/ffi.rs @@ -0,0 +1,3 @@ +//! Just a module that contains some entries that should be parsed by cbindgen. + +pub const FFI_MAGIC_NUMBER: u64 = 0xFDA0_0184; diff --git a/libs/3rdparty/corrosion/test/cbindgen/manual/rust/src/lib.rs b/libs/3rdparty/corrosion/test/cbindgen/manual/rust/src/lib.rs new file mode 100644 index 00000000000..0ad5c8f8af5 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cbindgen/manual/rust/src/lib.rs @@ -0,0 +1,33 @@ +pub const MAGIC_NUMBER: u64 = 0xABCD_EFAB; + +pub mod ffi; +pub mod other_mod; + +#[derive(Debug)] +#[repr(C)] +pub struct Point { + x: u64, + y: u64, +} + +impl Point { + pub(crate) fn add(&mut self, rhs: &Point) { + self.x = self.x.wrapping_add(rhs.x); + self.y = self.y.wrapping_add(rhs.y); + } +} + +#[no_mangle] +pub extern "C" fn add_point(lhs: Option<&mut Point>, rhs: Option<&Point>) { + if let (Some(p1), Some(p2)) = (lhs, rhs) { + p1.add(p2); + // Print something so we can let Ctest assert the output. + println!("add_point Result: {:?}", p1); + } +} + +// simple test if the constant was exported by cbindgen correctly +#[no_mangle] +pub extern "C" fn is_magic_number(num: u64) -> bool { + num == MAGIC_NUMBER +} diff --git a/libs/3rdparty/corrosion/test/cbindgen/manual/rust/src/other_mod/mod.rs b/libs/3rdparty/corrosion/test/cbindgen/manual/rust/src/other_mod/mod.rs new file mode 100644 index 00000000000..ca34458b0d3 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cbindgen/manual/rust/src/other_mod/mod.rs @@ -0,0 +1 @@ +pub const OTHER_MOD_MAGIC_NUMBER: u32 = 192312312; diff --git a/libs/3rdparty/corrosion/test/config_discovery/CMakeLists.txt b/libs/3rdparty/corrosion/test/config_discovery/CMakeLists.txt new file mode 100644 index 00000000000..89bac08eb9c --- /dev/null +++ b/libs/3rdparty/corrosion/test/config_discovery/CMakeLists.txt @@ -0,0 +1,13 @@ +# The `.cargo/config.toml` file registers the `my-registry` index. If Cargo fails to +# discover the config file, the build will fail with: +# "registry index was not found in any configuration: `my-registry`" +corrosion_tests_add_test(config_discovery "config_discovery") + +# Run the `cargo-clean` target to verify `.cargo/config.toml` discovery. +add_test(NAME "config_discovery_run_cargo_clean" + COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_CURRENT_BINARY_DIR}/build-config_discovery" --target cargo-clean +) +set_tests_properties("config_discovery_run_cargo_clean" PROPERTIES + FIXTURES_REQUIRED "build_fixture_config_discovery" + DEPENDS "config_discovery_run_config_discovery" +) diff --git a/libs/3rdparty/corrosion/test/config_discovery/README.md b/libs/3rdparty/corrosion/test/config_discovery/README.md new file mode 100644 index 00000000000..896edbbdda3 --- /dev/null +++ b/libs/3rdparty/corrosion/test/config_discovery/README.md @@ -0,0 +1,13 @@ +# Cargo Configuration Discovery Test + +This test verifies that `cargo` correctly discovers configuration files such as `.cargo/config.toml` and `toolchain.toml` in the source tree. + +## What's Being Tested + +Cargo discovers configuration files by searching the current working directory and its parent directories. Therefore, Corrosion must set the correct `WORKING_DIRECTORY` for all `cargo` invocations. + +## How the Test Works + +The test uses a `.cargo/config.toml` that defines a custom registry alias `my-registry`. A dependency in `Cargo.toml` references this alias via `registry = "my-registry"`. + +If `cargo` does not find `.cargo/config.toml`, the `registry = "my-registry"` entry will cause an error during manifest parsing. diff --git a/libs/3rdparty/corrosion/test/config_discovery/config_discovery/.cargo/config.toml b/libs/3rdparty/corrosion/test/config_discovery/config_discovery/.cargo/config.toml new file mode 100644 index 00000000000..504655bc8ec --- /dev/null +++ b/libs/3rdparty/corrosion/test/config_discovery/config_discovery/.cargo/config.toml @@ -0,0 +1,4 @@ +# Defines registry alias `my-registry` pointing to crates.io. +# If not discovered cargo errors: "registry `my-registry` not found" +[registries.my-registry] +index = "https://github.com/rust-lang/crates.io-index" diff --git a/libs/3rdparty/corrosion/test/config_discovery/config_discovery/CMakeLists.txt b/libs/3rdparty/corrosion/test/config_discovery/config_discovery/CMakeLists.txt new file mode 100644 index 00000000000..4aca2c26794 --- /dev/null +++ b/libs/3rdparty/corrosion/test/config_discovery/config_discovery/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0) +include(../../test_header.cmake) + +corrosion_import_crate(MANIFEST_PATH Cargo.toml) diff --git a/libs/3rdparty/corrosion/test/config_discovery/config_discovery/Cargo.lock b/libs/3rdparty/corrosion/test/config_discovery/config_discovery/Cargo.lock new file mode 100644 index 00000000000..c7686973d6c --- /dev/null +++ b/libs/3rdparty/corrosion/test/config_discovery/config_discovery/Cargo.lock @@ -0,0 +1,16 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "config_discovery" +version = "0.1.0" +dependencies = [ + "bitflags", +] diff --git a/libs/3rdparty/corrosion/test/config_discovery/config_discovery/Cargo.toml b/libs/3rdparty/corrosion/test/config_discovery/config_discovery/Cargo.toml new file mode 100644 index 00000000000..f7e161fccac --- /dev/null +++ b/libs/3rdparty/corrosion/test/config_discovery/config_discovery/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "config_discovery" +version = "0.1.0" +edition = "2018" + +[dependencies] +# Uses registry alias `my-registry`. If `.cargo/config.toml` is not discovered, the test will +# fail wit the error: "registry `my-registry` not found" +bitflags = { version = "1.3", registry = "my-registry" } diff --git a/libs/3rdparty/corrosion/test/config_discovery/config_discovery/src/main.rs b/libs/3rdparty/corrosion/test/config_discovery/config_discovery/src/main.rs new file mode 100644 index 00000000000..322d4464f8b --- /dev/null +++ b/libs/3rdparty/corrosion/test/config_discovery/config_discovery/src/main.rs @@ -0,0 +1,12 @@ +use bitflags::bitflags; + +bitflags! { + struct TestFlags: u32 { + const VALUE = 0b00000001; + } +} + +fn main() { + let flags = TestFlags::VALUE; + println!("Flag value: {}", flags.bits()); +} diff --git a/libs/3rdparty/corrosion/test/corrosion_install/CMakeLists.txt b/libs/3rdparty/corrosion/test/corrosion_install/CMakeLists.txt new file mode 100644 index 00000000000..82ed76f2a34 --- /dev/null +++ b/libs/3rdparty/corrosion/test/corrosion_install/CMakeLists.txt @@ -0,0 +1,27 @@ +if(NOT (CMAKE_CROSSCOMPILING AND MSVC)) + # When using MSVC the cmake build via ExternalProject seems to inherit the target architecture, + # which breaks the test. Since we practically don't care about this, and we just want to ensure + # that installing an executable works, skipping this test when cross-compiling is fine. + corrosion_tests_add_test(install_rust_bin "generated_from_installed_bin") + + set_tests_properties("install_rust_bin_run_generated_from_installed_bin" + PROPERTIES PASS_REGULAR_EXPRESSION + "Hello World! I'm generated code" + ) +endif() + +# Todo: Fix and re-enable tests on Windows +if(NOT CMAKE_CROSSCOMPILING AND NOT WIN32) + corrosion_tests_add_test(install_lib "main-static;main-shared") + + set_tests_properties("install_lib_run_main-static" "install_lib_run_main-shared" + PROPERTIES PASS_REGULAR_EXPRESSION + "The sum is 11" + ) +endif() + +# Further tests we should add: +# - Test installing a Rust executable, that requires a (C/C++) shared library at runtime. +# Note: We should delete the build directory of the subproject +# before running the installed rust executable, to insure the shared library is loaded from the +# installed location and not from the build dir. \ No newline at end of file diff --git a/libs/3rdparty/corrosion/test/corrosion_install/install_lib/CMakeLists.txt b/libs/3rdparty/corrosion/test/corrosion_install/install_lib/CMakeLists.txt new file mode 100644 index 00000000000..4587ec839e6 --- /dev/null +++ b/libs/3rdparty/corrosion/test/corrosion_install/install_lib/CMakeLists.txt @@ -0,0 +1,44 @@ +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0) +include(ExternalProject) + +add_library(static_lib STATIC IMPORTED) +add_library(shared_lib SHARED IMPORTED) +set(install_prefix "${CMAKE_CURRENT_BINARY_DIR}/rust_lib") +set(static_lib_install_path "${install_prefix}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}rust_lib${CMAKE_STATIC_LIBRARY_SUFFIX}") +set(shared_lib_install_path "${install_prefix}/lib/${CMAKE_SHARED_LIBRARY_PREFIX}rust_lib${CMAKE_SHARED_LIBRARY_SUFFIX}") + + +set_target_properties(static_lib PROPERTIES + IMPORTED_LOCATION + "${static_lib_install_path}") + +set_target_properties(shared_lib PROPERTIES + IMPORTED_LOCATION + "${shared_lib_install_path}") + +add_executable(main-static main.cpp) +target_link_libraries(main-static PRIVATE static_lib) + +ExternalProject_Add( + rust_lib + PREFIX "${CMAKE_CURRENT_BINARY_DIR}/rust_lib" + SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/rust_lib" + CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=${install_prefix}" + # INSTALL_BYPRODUCTS "${static_lib_install_path}" +) + +# Dummy target since INSTALL_BYPRODUCTS requires CMake 3.26 +add_custom_target(build_rust_project_dummy + COMMAND echo dummy + BYPRODUCTS "${static_lib_install_path}" "${shared_lib_install_path}" + DEPENDS rust_lib) + +add_dependencies(main-static build_rust_project_dummy) + +set(CMAKE_BUILD_RPATH ${install_prefix}/lib) +add_executable(main-shared main.cpp) +target_link_libraries(main-shared + PUBLIC shared_lib) + +add_dependencies(main-shared build_rust_project_dummy) diff --git a/libs/3rdparty/corrosion/test/corrosion_install/install_lib/main.cpp b/libs/3rdparty/corrosion/test/corrosion_install/install_lib/main.cpp new file mode 100644 index 00000000000..ff1602b2f39 --- /dev/null +++ b/libs/3rdparty/corrosion/test/corrosion_install/install_lib/main.cpp @@ -0,0 +1,11 @@ +#include +#include +#include + +extern "C" uint64_t add(uint64_t a, uint64_t b); + +int main(int argc, char **argv) { + uint64_t sum = add(5, 6); + assert(sum == 11); + std::cout << "The sum is " << sum << std::endl; +} diff --git a/libs/3rdparty/corrosion/test/corrosion_install/install_lib/rust_lib/CMakeLists.txt b/libs/3rdparty/corrosion/test/corrosion_install/install_lib/rust_lib/CMakeLists.txt new file mode 100644 index 00000000000..3e39de83c35 --- /dev/null +++ b/libs/3rdparty/corrosion/test/corrosion_install/install_lib/rust_lib/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0) +include(../../../test_header.cmake) + +corrosion_import_crate(MANIFEST_PATH Cargo.toml) + +if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") + corrosion_add_target_local_rustflags(rust_lib "-Clink-arg=-Wl,-soname,librust_lib.so") + set_target_properties(rust_lib-shared PROPERTIES IMPORTED_SONAME librust_lib.so) +elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin") + corrosion_add_target_local_rustflags(rust_lib -Clink-arg=-Wl,-install_name,@rpath/librust_lib.dylib,-current_version,1.0,-compatibility_version,1.0) + set_target_properties(rust_lib-shared PROPERTIES IMPORTED_NO_SONAME 0) + set_target_properties(rust_lib-shared PROPERTIES IMPORTED_SONAME librust_lib.dylib) +endif() + +target_sources(rust_lib INTERFACE include/rust_lib/rust_lib.hpp) + +corrosion_install(TARGETS rust_lib) diff --git a/libs/3rdparty/corrosion/test/corrosion_install/install_lib/rust_lib/Cargo.lock b/libs/3rdparty/corrosion/test/corrosion_install/install_lib/rust_lib/Cargo.lock new file mode 100644 index 00000000000..ecfa244376d --- /dev/null +++ b/libs/3rdparty/corrosion/test/corrosion_install/install_lib/rust_lib/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust_lib" +version = "0.1.0" diff --git a/libs/3rdparty/corrosion/test/corrosion_install/install_lib/rust_lib/Cargo.toml b/libs/3rdparty/corrosion/test/corrosion_install/install_lib/rust_lib/Cargo.toml new file mode 100644 index 00000000000..eb4a0752167 --- /dev/null +++ b/libs/3rdparty/corrosion/test/corrosion_install/install_lib/rust_lib/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "rust_lib" +version = "0.1.0" +edition = "2018" + +[dependencies] + +[lib] +crate-type = ["staticlib", "cdylib"] diff --git a/libs/3rdparty/corrosion/test/corrosion_install/install_lib/rust_lib/include/rust_lib/rust_lib.hpp b/libs/3rdparty/corrosion/test/corrosion_install/install_lib/rust_lib/include/rust_lib/rust_lib.hpp new file mode 100644 index 00000000000..827ae6e5761 --- /dev/null +++ b/libs/3rdparty/corrosion/test/corrosion_install/install_lib/rust_lib/include/rust_lib/rust_lib.hpp @@ -0,0 +1,3 @@ +#include + +extern "C" uint64_t add(uint64_t left, uint64_t right); diff --git a/libs/3rdparty/corrosion/test/corrosion_install/install_lib/rust_lib/src/lib.rs b/libs/3rdparty/corrosion/test/corrosion_install/install_lib/rust_lib/src/lib.rs new file mode 100644 index 00000000000..76d40c6c0a1 --- /dev/null +++ b/libs/3rdparty/corrosion/test/corrosion_install/install_lib/rust_lib/src/lib.rs @@ -0,0 +1,5 @@ + +#[no_mangle] +pub extern "C" fn add(left: u64, right: u64) -> u64 { + left + right +} diff --git a/libs/3rdparty/corrosion/test/corrosion_install/install_rust_bin/CMakeLists.txt b/libs/3rdparty/corrosion/test/corrosion_install/install_rust_bin/CMakeLists.txt new file mode 100644 index 00000000000..275a00fd37d --- /dev/null +++ b/libs/3rdparty/corrosion/test/corrosion_install/install_rust_bin/CMakeLists.txt @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 3.22) +project(test_project VERSION 0.1.0) + +# Note: Corrosion supports `hostbuild`, so building a Rust binary in a subproject +# like this doesn't offer any benefit over using the hostbuild option. +# However, this is a reasonable way to test that installing Rust binaries via +# corrosion_install works as expected. +include(ExternalProject) + +set(bin_suffix "") +if(CMAKE_HOST_WIN32) + set(bin_suffix ".exe") +endif() +set(generator_bin_path "${CMAKE_CURRENT_BINARY_DIR}/rust_bin/bin/my_rust_bin${bin_suffix}") + +ExternalProject_Add( + rust_bin + PREFIX "${CMAKE_CURRENT_BINARY_DIR}/rust_bin" + SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/rust_bin" + CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/rust_bin" +) + +# This custom command is the main part of the test: +# We test that corrosion (in the CMake of the ExternalProject) properly installed +# a Rust executable to the location we specified by running the executable, which generates some cpp code. +add_custom_command( + OUTPUT generated_main.cpp + COMMAND "${generator_bin_path}" > "${CMAKE_CURRENT_BINARY_DIR}/generated_main.cpp" + DEPENDS rust_bin +) + +add_executable(generated_from_installed_bin ${CMAKE_CURRENT_BINARY_DIR}/generated_main.cpp) diff --git a/libs/3rdparty/corrosion/test/corrosion_install/install_rust_bin/rust_bin/CMakeLists.txt b/libs/3rdparty/corrosion/test/corrosion_install/install_rust_bin/rust_bin/CMakeLists.txt new file mode 100644 index 00000000000..4061560f021 --- /dev/null +++ b/libs/3rdparty/corrosion/test/corrosion_install/install_rust_bin/rust_bin/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.22) +project(test_rust_bin VERSION 0.1.0) +include(../../../test_header.cmake) +include(GNUInstallDirs) + +corrosion_import_crate(MANIFEST_PATH Cargo.toml) +corrosion_install(TARGETS my_rust_bin) diff --git a/libs/3rdparty/corrosion/test/corrosion_install/install_rust_bin/rust_bin/Cargo.lock b/libs/3rdparty/corrosion/test/corrosion_install/install_rust_bin/rust_bin/Cargo.lock new file mode 100644 index 00000000000..492a67d8e24 --- /dev/null +++ b/libs/3rdparty/corrosion/test/corrosion_install/install_rust_bin/rust_bin/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "my_rust_bin" +version = "0.1.0" diff --git a/libs/3rdparty/corrosion/test/corrosion_install/install_rust_bin/rust_bin/Cargo.toml b/libs/3rdparty/corrosion/test/corrosion_install/install_rust_bin/rust_bin/Cargo.toml new file mode 100644 index 00000000000..5442fb263b8 --- /dev/null +++ b/libs/3rdparty/corrosion/test/corrosion_install/install_rust_bin/rust_bin/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "my_rust_bin" +version = "0.1.0" +edition = "2018" +license = "MIT" + +[dependencies] diff --git a/libs/3rdparty/corrosion/test/corrosion_install/install_rust_bin/rust_bin/src/main.rs b/libs/3rdparty/corrosion/test/corrosion_install/install_rust_bin/rust_bin/src/main.rs new file mode 100644 index 00000000000..08ce8be69fb --- /dev/null +++ b/libs/3rdparty/corrosion/test/corrosion_install/install_rust_bin/rust_bin/src/main.rs @@ -0,0 +1,9 @@ +fn main() { + println!( +"#include +int main() {{ + std::cout << \"Hello World! I'm generated code\"; + return 0; +}}" + ); +} diff --git a/libs/3rdparty/corrosion/test/cpp2rust/CMakeLists.txt b/libs/3rdparty/corrosion/test/cpp2rust/CMakeLists.txt new file mode 100644 index 00000000000..5b4cb46d6aa --- /dev/null +++ b/libs/3rdparty/corrosion/test/cpp2rust/CMakeLists.txt @@ -0,0 +1,5 @@ +corrosion_tests_add_test(cpp2rust "rust-exe") + +set_tests_properties("cpp2rust_run_rust-exe" PROPERTIES PASS_REGULAR_EXPRESSION + "Hello, Rust! I am Cpp!\r?\nHello, Rust! I am Cpp library Number 2!\r?\nHello, Rust! I am Cpp library Number 3!" + ) diff --git a/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/CMakeLists.txt b/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/CMakeLists.txt new file mode 100644 index 00000000000..2a6fe134ed0 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/CMakeLists.txt @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0) +include(../../test_header.cmake) + +corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml) + +add_library(cpp-lib lib.cpp) +target_compile_features(cpp-lib PRIVATE cxx_std_14) +set_target_properties( + cpp-lib + PROPERTIES + POSITION_INDEPENDENT_CODE ON +) + +add_library(cpp-lib2 lib2.cpp) +target_compile_features(cpp-lib2 PRIVATE cxx_std_14) +set_target_properties( + cpp-lib2 + PROPERTIES + POSITION_INDEPENDENT_CODE ON + OUTPUT_NAME cpp-lib-renamed +) + +add_library(cpp-lib3 "path with space/lib3.cpp" ) +target_compile_features(cpp-lib3 PRIVATE cxx_std_14) +set_target_properties( + cpp-lib3 + PROPERTIES + POSITION_INDEPENDENT_CODE ON +) + +corrosion_link_libraries(rust-exe cpp-lib cpp-lib2 cpp-lib3) diff --git a/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/lib.cpp b/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/lib.cpp new file mode 100644 index 00000000000..df7642d2cdf --- /dev/null +++ b/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/lib.cpp @@ -0,0 +1,5 @@ +#include + +extern "C" void cpp_function(char const *name) { + std::cout << "Hello, " << name << "! I am Cpp!\n"; +} diff --git a/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/lib2.cpp b/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/lib2.cpp new file mode 100644 index 00000000000..63a335183b6 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/lib2.cpp @@ -0,0 +1,11 @@ +#include +#include + +extern "C" void cpp_function2(char const *name) { + std::cout << "Hello, " << name << "! I am Cpp library Number 2!\n"; +} + +extern "C" uint32_t get_42() { + uint32_t v = 42; + return v; +} diff --git a/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/path with space/lib3.cpp b/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/path with space/lib3.cpp new file mode 100644 index 00000000000..d09ddc878fa --- /dev/null +++ b/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/path with space/lib3.cpp @@ -0,0 +1,8 @@ +// Check that libraries located at a path containing a space can also be linked. + +#include + +extern "C" void cpp_function3(char const *name) { + std::cout << "Hello, " << name << "! I am Cpp library Number 3!\n"; +} + diff --git a/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/rust/Cargo.lock b/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/rust/Cargo.lock new file mode 100644 index 00000000000..be17c9ceef5 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/rust/Cargo.lock @@ -0,0 +1,14 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust-dependency" +version = "0.1.0" + +[[package]] +name = "rust-exe" +version = "0.1.0" +dependencies = [ + "rust-dependency", +] diff --git a/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/rust/Cargo.toml b/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/rust/Cargo.toml new file mode 100644 index 00000000000..21bfb64fce2 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/rust/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "rust-exe" +version = "0.1.0" +authors = ["Andrew Gaspar "] +license = "MIT" +edition = "2018" + +[dependencies] +rust-dependency = { path = "rust_dependency" } diff --git a/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/rust/build.rs b/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/rust/build.rs new file mode 100644 index 00000000000..9dfeaa0be1e --- /dev/null +++ b/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/rust/build.rs @@ -0,0 +1,4 @@ +// Build-scripts also need to be linked, so just add a dummy buildscript ensuring this works. +fn main() { + println!("Build-script is running.") +} diff --git a/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/rust/rust_dependency/Cargo.toml b/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/rust/rust_dependency/Cargo.toml new file mode 100644 index 00000000000..89acbbeab89 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/rust/rust_dependency/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "rust-dependency" +version = "0.1.0" +license = "MIT" +edition = "2018" + +[dependencies] + diff --git a/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/rust/rust_dependency/src/lib.rs b/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/rust/rust_dependency/src/lib.rs new file mode 100644 index 00000000000..304cfb9001b --- /dev/null +++ b/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/rust/rust_dependency/src/lib.rs @@ -0,0 +1,8 @@ + +extern "C" { + fn get_42() -> u32; +} +pub fn calls_ffi() { + let res = unsafe { get_42()}; + assert_eq!(res, 42); +} diff --git a/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/rust/src/bin/rust-exe.rs b/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/rust/src/bin/rust-exe.rs new file mode 100644 index 00000000000..43950e7ec83 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cpp2rust/cpp2rust/rust/src/bin/rust-exe.rs @@ -0,0 +1,27 @@ +use std::os::raw::c_char; + +extern "C" { + fn cpp_function(name: *const c_char); + fn cpp_function2(name: *const c_char); + fn cpp_function3(name: *const c_char); + +} + +fn greeting(name: &str) { + let name = std::ffi::CString::new(name).unwrap(); + unsafe { + cpp_function(name.as_ptr()); + cpp_function2(name.as_ptr()); + cpp_function3(name.as_ptr()); + } +} + +fn main() { + let args = std::env::args().skip(1).collect::>(); + if args.len() >= 1 { + greeting(&args[0]); + } else { + greeting("Rust"); + } + rust_dependency::calls_ffi(); +} diff --git a/libs/3rdparty/corrosion/test/crate_type/CMakeLists.txt b/libs/3rdparty/corrosion/test/crate_type/CMakeLists.txt new file mode 100644 index 00000000000..771cc19765f --- /dev/null +++ b/libs/3rdparty/corrosion/test/crate_type/CMakeLists.txt @@ -0,0 +1,6 @@ +corrosion_tests_add_test(crate_type "cpp-exe") + + +set_tests_properties("crate_type_run_cpp-exe" PROPERTIES PASS_REGULAR_EXPRESSION + "Hello from lib 1!\r?\nHello from lib 2!" + ) diff --git a/libs/3rdparty/corrosion/test/crate_type/crate_type/CMakeLists.txt b/libs/3rdparty/corrosion/test/crate_type/crate_type/CMakeLists.txt new file mode 100644 index 00000000000..281d5c4f700 --- /dev/null +++ b/libs/3rdparty/corrosion/test/crate_type/crate_type/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0) +include(../../test_header.cmake) + +# Add --crate-type to ensure that only the specified type of library is built and no error is thrown +corrosion_import_crate(MANIFEST_PATH proj1/Cargo.toml CRATE_TYPES staticlib FLAGS --crate-type=staticlib) +corrosion_import_crate(MANIFEST_PATH proj2/Cargo.toml CRATE_TYPES cdylib FLAGS --crate-type=cdylib) + +add_executable(cpp-exe main.cpp) +target_link_libraries(cpp-exe proj1) +target_link_libraries(cpp-exe proj2) diff --git a/libs/3rdparty/corrosion/test/crate_type/crate_type/main.cpp b/libs/3rdparty/corrosion/test/crate_type/crate_type/main.cpp new file mode 100644 index 00000000000..65113193ae9 --- /dev/null +++ b/libs/3rdparty/corrosion/test/crate_type/crate_type/main.cpp @@ -0,0 +1,8 @@ +extern "C" void rust_function1(); +extern "C" void rust_function2(); + +int main() { + rust_function1(); + rust_function2(); + return 0; +} diff --git a/libs/3rdparty/corrosion/test/crate_type/crate_type/proj1/Cargo.lock b/libs/3rdparty/corrosion/test/crate_type/crate_type/proj1/Cargo.lock new file mode 100644 index 00000000000..dfcd813dc79 --- /dev/null +++ b/libs/3rdparty/corrosion/test/crate_type/crate_type/proj1/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "proj1" +version = "0.1.0" diff --git a/libs/3rdparty/corrosion/test/crate_type/crate_type/proj1/Cargo.toml b/libs/3rdparty/corrosion/test/crate_type/crate_type/proj1/Cargo.toml new file mode 100644 index 00000000000..81ad88ffe35 --- /dev/null +++ b/libs/3rdparty/corrosion/test/crate_type/crate_type/proj1/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "proj1" +version = "0.1.0" +edition = "2018" + +[dependencies] + +[lib] +crate-type=["staticlib", "cdylib"] + diff --git a/libs/3rdparty/corrosion/test/crate_type/crate_type/proj1/src/lib.rs b/libs/3rdparty/corrosion/test/crate_type/crate_type/proj1/src/lib.rs new file mode 100644 index 00000000000..433521903a0 --- /dev/null +++ b/libs/3rdparty/corrosion/test/crate_type/crate_type/proj1/src/lib.rs @@ -0,0 +1,4 @@ +#[no_mangle] +pub extern "C" fn rust_function1() { + println!("Hello from lib 1!"); +} diff --git a/libs/3rdparty/corrosion/test/crate_type/crate_type/proj2/Cargo.lock b/libs/3rdparty/corrosion/test/crate_type/crate_type/proj2/Cargo.lock new file mode 100644 index 00000000000..780ef1f499d --- /dev/null +++ b/libs/3rdparty/corrosion/test/crate_type/crate_type/proj2/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "proj2" +version = "0.1.0" diff --git a/libs/3rdparty/corrosion/test/crate_type/crate_type/proj2/Cargo.toml b/libs/3rdparty/corrosion/test/crate_type/crate_type/proj2/Cargo.toml new file mode 100644 index 00000000000..74c7d61750b --- /dev/null +++ b/libs/3rdparty/corrosion/test/crate_type/crate_type/proj2/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "proj2" +version = "0.1.0" +edition = "2018" + +[dependencies] + +[lib] +crate-type=["staticlib", "cdylib"] diff --git a/libs/3rdparty/corrosion/test/crate_type/crate_type/proj2/src/lib.rs b/libs/3rdparty/corrosion/test/crate_type/crate_type/proj2/src/lib.rs new file mode 100644 index 00000000000..23048680cd5 --- /dev/null +++ b/libs/3rdparty/corrosion/test/crate_type/crate_type/proj2/src/lib.rs @@ -0,0 +1,4 @@ +#[no_mangle] +pub extern "C" fn rust_function2() { + println!("Hello from lib 2!"); +} diff --git a/libs/3rdparty/corrosion/test/custom_profiles/CMakeLists.txt b/libs/3rdparty/corrosion/test/custom_profiles/CMakeLists.txt new file mode 100644 index 00000000000..e0d76d8930c --- /dev/null +++ b/libs/3rdparty/corrosion/test/custom_profiles/CMakeLists.txt @@ -0,0 +1,27 @@ +# The tests in this folder test specifying the cargo profile name via the --profile option. +# The built-in `test` and `bench` profiles are _not_ supported, because they output +# artifacts to a different location and add a hash to the artifact name. +if(Rust_VERSION VERSION_GREATER_EQUAL 1.57.0) + + corrosion_tests_add_test(custom_profiles_global "custom-profile-exe" TEST_SRC_DIR custom_profiles) + corrosion_tests_add_test(custom_profiles_target_specific "custom-profile-exe" + TEST_SRC_DIR custom_profiles + PASS_THROUGH_ARGS -DCORROSION_TEST_USE_TARGET_SPECIFIC_OVERRIDE=ON + ) + corrosion_tests_add_test(dev_profile "dev_bin" TEST_SRC_DIR basic_profiles CARGO_PROFILE dev) + corrosion_tests_add_test(release_profile "release_bin" TEST_SRC_DIR basic_profiles CARGO_PROFILE release) + + set_tests_properties("custom_profiles_global_run_custom-profile-exe" PROPERTIES PASS_REGULAR_EXPRESSION + "^Hello, Cpp! I'm Rust!\r?\n$" + ) + set_tests_properties("custom_profiles_target_specific_run_custom-profile-exe" PROPERTIES PASS_REGULAR_EXPRESSION + "^Hello, Cpp! I'm Rust!\r?\n$" + ) + set_tests_properties("dev_profile_run_dev_bin" PROPERTIES PASS_REGULAR_EXPRESSION + "^Hello, Cpp! I'm Rust!\r?\n$" + ) + set_tests_properties("release_profile_run_release_bin" PROPERTIES PASS_REGULAR_EXPRESSION + "^Hello, Cpp! I'm Rust!\r?\n$" + ) + +endif() diff --git a/libs/3rdparty/corrosion/test/custom_profiles/basic_profiles/CMakeLists.txt b/libs/3rdparty/corrosion/test/custom_profiles/basic_profiles/CMakeLists.txt new file mode 100644 index 00000000000..d020df4f950 --- /dev/null +++ b/libs/3rdparty/corrosion/test/custom_profiles/basic_profiles/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0) +include(../../test_header.cmake) + +if(NOT DEFINED CARGO_PROFILE) + message(FATAL_ERROR "Test internal error. The test should be called with the CARGO_PROFILE parameter.") +endif() + +corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml PROFILE ${CARGO_PROFILE}) + +add_executable(${CARGO_PROFILE}_bin main.cpp) +target_link_libraries(${CARGO_PROFILE}_bin PUBLIC cargo_profiles_lib) diff --git a/libs/3rdparty/corrosion/test/custom_profiles/basic_profiles/main.cpp b/libs/3rdparty/corrosion/test/custom_profiles/basic_profiles/main.cpp new file mode 100644 index 00000000000..b714e76ee4b --- /dev/null +++ b/libs/3rdparty/corrosion/test/custom_profiles/basic_profiles/main.cpp @@ -0,0 +1,6 @@ +extern "C" void rust_function(char const *name); + + +int main(int argc, char **argv) { + rust_function("Cpp"); +} diff --git a/libs/3rdparty/corrosion/test/custom_profiles/basic_profiles/rust/Cargo.lock b/libs/3rdparty/corrosion/test/custom_profiles/basic_profiles/rust/Cargo.lock new file mode 100644 index 00000000000..9b747a8a408 --- /dev/null +++ b/libs/3rdparty/corrosion/test/custom_profiles/basic_profiles/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cargo-profiles-lib" +version = "0.1.0" diff --git a/libs/3rdparty/corrosion/test/custom_profiles/basic_profiles/rust/Cargo.toml b/libs/3rdparty/corrosion/test/custom_profiles/basic_profiles/rust/Cargo.toml new file mode 100644 index 00000000000..282029f4256 --- /dev/null +++ b/libs/3rdparty/corrosion/test/custom_profiles/basic_profiles/rust/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "cargo-profiles-lib" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type=["staticlib"] diff --git a/libs/3rdparty/corrosion/test/custom_profiles/basic_profiles/rust/src/lib.rs b/libs/3rdparty/corrosion/test/custom_profiles/basic_profiles/rust/src/lib.rs new file mode 100644 index 00000000000..1a51950abcc --- /dev/null +++ b/libs/3rdparty/corrosion/test/custom_profiles/basic_profiles/rust/src/lib.rs @@ -0,0 +1,8 @@ +use std::os::raw::c_char; + +#[no_mangle] +pub extern "C" fn rust_function(name: *const c_char) { + let name = unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() }; + println!("Hello, {}! I'm Rust!", name); +} + diff --git a/libs/3rdparty/corrosion/test/custom_profiles/custom_profiles/CMakeLists.txt b/libs/3rdparty/corrosion/test/custom_profiles/custom_profiles/CMakeLists.txt new file mode 100644 index 00000000000..c9b5cd2e185 --- /dev/null +++ b/libs/3rdparty/corrosion/test/custom_profiles/custom_profiles/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0) +include(../../test_header.cmake) + +set(_release_profile $,release-without-dbg,custom-without-dbg>) +set(custom_profile $,dev-without-dbg,${_release_profile}>) + +if(CORROSION_TEST_USE_TARGET_SPECIFIC_OVERRIDE) + # Select "wrong" profile here on purpose. + corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml PROFILE dev) + set_target_properties(custom_profiles_lib + PROPERTIES + INTERFACE_CORROSION_CARGO_PROFILE "${custom_profile}" + ) +else() + corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml PROFILE ${custom_profile}) +endif() + +add_executable(custom-profile-exe main.cpp) +target_link_libraries(custom-profile-exe PUBLIC custom_profiles_lib) diff --git a/libs/3rdparty/corrosion/test/custom_profiles/custom_profiles/main.cpp b/libs/3rdparty/corrosion/test/custom_profiles/custom_profiles/main.cpp new file mode 100644 index 00000000000..b714e76ee4b --- /dev/null +++ b/libs/3rdparty/corrosion/test/custom_profiles/custom_profiles/main.cpp @@ -0,0 +1,6 @@ +extern "C" void rust_function(char const *name); + + +int main(int argc, char **argv) { + rust_function("Cpp"); +} diff --git a/libs/3rdparty/corrosion/test/custom_profiles/custom_profiles/rust/Cargo.lock b/libs/3rdparty/corrosion/test/custom_profiles/custom_profiles/rust/Cargo.lock new file mode 100644 index 00000000000..6c1abd7f5e6 --- /dev/null +++ b/libs/3rdparty/corrosion/test/custom_profiles/custom_profiles/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "custom-profiles-lib" +version = "0.1.0" diff --git a/libs/3rdparty/corrosion/test/custom_profiles/custom_profiles/rust/Cargo.toml b/libs/3rdparty/corrosion/test/custom_profiles/custom_profiles/rust/Cargo.toml new file mode 100644 index 00000000000..93e3c7592a6 --- /dev/null +++ b/libs/3rdparty/corrosion/test/custom_profiles/custom_profiles/rust/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "custom-profiles-lib" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type=["staticlib"] + +# Test if neither release or debug where selected by only disabling debug-assertions in the inherited profile. +[profile.release] +debug-assertions = true + +[profile.dev-without-dbg] +inherits = "dev" +debug-assertions = false + +[profile.release-without-dbg] +inherits = "release" +debug-assertions = false + +[profile.custom-without-dbg] +inherits = "release" +opt-level = 1 +debug-assertions = false diff --git a/libs/3rdparty/corrosion/test/custom_profiles/custom_profiles/rust/src/lib.rs b/libs/3rdparty/corrosion/test/custom_profiles/custom_profiles/rust/src/lib.rs new file mode 100644 index 00000000000..ee3f4b01631 --- /dev/null +++ b/libs/3rdparty/corrosion/test/custom_profiles/custom_profiles/rust/src/lib.rs @@ -0,0 +1,11 @@ +use std::os::raw::c_char; + +#[no_mangle] +pub extern "C" fn rust_function(name: *const c_char) { + let name = unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() }; + println!("Hello, {}! I'm Rust!", name); +} + + +#[cfg(debug_assertions)] +const _: () = assert!(false, "Debug assertions where not disabled via custom profile!"); diff --git a/libs/3rdparty/corrosion/test/custom_target/CMakeLists.txt b/libs/3rdparty/corrosion/test/custom_target/CMakeLists.txt new file mode 100644 index 00000000000..8b1c45502ce --- /dev/null +++ b/libs/3rdparty/corrosion/test/custom_target/CMakeLists.txt @@ -0,0 +1,21 @@ +# Create a custom target triple, by taking the default host triple target spec. +# This way we don't actually need to cross-compile and just check if we can handle +# custom json target triples. +# Note: dashes and not underscore is important, at least if cc-rs is used by dependencies, +# since cc-rs will attempt to parse the target triple. +# A real-world toolchain .json file should be named the same as the corresponding c/c++ compiler target, +# in order for cc-rs to choose the correct target by default. +set(target_spec_file "${CMAKE_CURRENT_BINARY_DIR}/custom-target-triple.json") +execute_process(COMMAND + ${CMAKE_COMMAND} -E env RUSTC_BOOTSTRAP=1 + ${_CORROSION_RUSTC} -Z unstable-options --print target-spec-json + OUTPUT_FILE "${target_spec_file}" + COMMAND_ERROR_IS_FATAL ANY +) + +set(Rust_CARGO_TARGET "${target_spec_file}") +corrosion_tests_add_test(custom_target "test-exe;rust-bin") + +set_tests_properties("custom_target_run_test-exe" PROPERTIES PASS_REGULAR_EXPRESSION [[Hello, Cxx! I am Rust!]]) +set_tests_properties("custom_target_run_rust-bin" PROPERTIES PASS_REGULAR_EXPRESSION [[The answer is 42]]) + diff --git a/libs/3rdparty/corrosion/test/custom_target/custom_target/CMakeLists.txt b/libs/3rdparty/corrosion/test/custom_target/custom_target/CMakeLists.txt new file mode 100644 index 00000000000..d6396bcfc93 --- /dev/null +++ b/libs/3rdparty/corrosion/test/custom_target/custom_target/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0 LANGUAGES C CXX) +# The outer test driver gives the file a useless name +# Supress the warning, since we don't rely on this information anyway. +set(CORROSION_NO_WARN_PARSE_TARGET_TRIPLE_FAILED ON) +include(../../test_header.cmake) + +if(NOT "${Rust_CARGO_TARGET}" MATCHES ".json") + message(FATAL_ERROR "This test project expects to be configured with a custom rust target!" + "Actual target: ${Rust_CARGO_TARGET}" + ) +endif() + +corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml) +corrosion_set_cargo_flags(rust_lib "-Zbuild-std") +# custom target triples require nightly features +corrosion_set_env_vars(rust_lib RUSTC_BOOTSTRAP=1) + +corrosion_set_cargo_flags(rust-bin "-Zbuild-std") +corrosion_set_env_vars(rust-bin RUSTC_BOOTSTRAP=1) + +add_executable(test-exe main.cpp) +target_link_libraries(test-exe PUBLIC rust_lib) diff --git a/libs/3rdparty/corrosion/test/custom_target/custom_target/main.cpp b/libs/3rdparty/corrosion/test/custom_target/custom_target/main.cpp new file mode 100644 index 00000000000..b5fde3cf777 --- /dev/null +++ b/libs/3rdparty/corrosion/test/custom_target/custom_target/main.cpp @@ -0,0 +1,6 @@ +extern "C" void rust_function(char const *name); + + +int main(int argc, char **argv) { + rust_function("Cxx"); +} diff --git a/libs/3rdparty/corrosion/test/custom_target/custom_target/rust/Cargo.lock b/libs/3rdparty/corrosion/test/custom_target/custom_target/rust/Cargo.lock new file mode 100644 index 00000000000..7299895a3cf --- /dev/null +++ b/libs/3rdparty/corrosion/test/custom_target/custom_target/rust/Cargo.lock @@ -0,0 +1,16 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cc" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7db2f146208d7e0fbee761b09cd65a7f51ccc38705d4e7262dad4d73b12a76b1" + +[[package]] +name = "rust-lib" +version = "0.1.0" +dependencies = [ + "cc", +] diff --git a/libs/3rdparty/corrosion/test/custom_target/custom_target/rust/Cargo.toml b/libs/3rdparty/corrosion/test/custom_target/custom_target/rust/Cargo.toml new file mode 100644 index 00000000000..8977e313b9a --- /dev/null +++ b/libs/3rdparty/corrosion/test/custom_target/custom_target/rust/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "rust-lib" +version = "0.1.0" +edition = "2018" + +[lib] +crate-type=["staticlib", "lib"] + +[[bin]] +name = "rust-bin" +path = "src/bin.rs" + +[build-dependencies] +cc = "1" diff --git a/libs/3rdparty/corrosion/test/custom_target/custom_target/rust/build.rs b/libs/3rdparty/corrosion/test/custom_target/custom_target/rust/build.rs new file mode 100644 index 00000000000..a12b8d81595 --- /dev/null +++ b/libs/3rdparty/corrosion/test/custom_target/custom_target/rust/build.rs @@ -0,0 +1,10 @@ +fn main() { + let mut builder = cc::Build::new(); + // We override the target here, purely to make the testcase simpler. + // In a real-world project, the custom rust .json target triple file + // should have a filename matching the target-triple the c-compiler understands + // (if the c/c++ toolchain is llvm based) + builder.target(&std::env::var("HOST").unwrap()); + + builder.file("c_lib.c").compile("custom_target"); +} \ No newline at end of file diff --git a/libs/3rdparty/corrosion/test/custom_target/custom_target/rust/c_lib.c b/libs/3rdparty/corrosion/test/custom_target/custom_target/rust/c_lib.c new file mode 100644 index 00000000000..df162481e89 --- /dev/null +++ b/libs/3rdparty/corrosion/test/custom_target/custom_target/rust/c_lib.c @@ -0,0 +1,5 @@ +#include + +uint32_t calculate_42(void) { + return 42; +} \ No newline at end of file diff --git a/libs/3rdparty/corrosion/test/custom_target/custom_target/rust/src/bin.rs b/libs/3rdparty/corrosion/test/custom_target/custom_target/rust/src/bin.rs new file mode 100644 index 00000000000..0a64cec5b22 --- /dev/null +++ b/libs/3rdparty/corrosion/test/custom_target/custom_target/rust/src/bin.rs @@ -0,0 +1,6 @@ +use rust_lib::calculate_42; + +fn main() { + let answer = unsafe { calculate_42() } ; + println!("The answer is {}", answer); +} diff --git a/libs/3rdparty/corrosion/test/custom_target/custom_target/rust/src/lib.rs b/libs/3rdparty/corrosion/test/custom_target/custom_target/rust/src/lib.rs new file mode 100644 index 00000000000..0a1c5381015 --- /dev/null +++ b/libs/3rdparty/corrosion/test/custom_target/custom_target/rust/src/lib.rs @@ -0,0 +1,13 @@ +use std::os::raw::c_char; + +extern "C" { + pub fn calculate_42() -> u32; +} + +#[no_mangle] +pub extern "C" fn rust_function(name: *const c_char) { + let name = unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() }; + let res = unsafe { calculate_42() }; + assert_eq!(res, 42); + println!("Hello, {}! I am Rust!", name); +} diff --git a/libs/3rdparty/corrosion/test/cxxbridge/CMakeLists.txt b/libs/3rdparty/corrosion/test/cxxbridge/CMakeLists.txt new file mode 100644 index 00000000000..fb8f880291d --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/CMakeLists.txt @@ -0,0 +1,38 @@ +if(CORROSION_TESTS_CXXBRIDGE) + corrosion_tests_add_test(cxxbridge_cpp2rust_1 "rust_bin" + TEST_SRC_DIR cxxbridge_cpp2rust + PASS_THROUGH_ARGS -DTEST_CXXBRIDGE_VARIANT1=ON + ) + corrosion_tests_add_test(cxxbridge_cpp2rust_2 "rust_bin" + TEST_SRC_DIR cxxbridge_cpp2rust + PASS_THROUGH_ARGS -DTEST_CXXBRIDGE_VARIANT2=ON + ) + corrosion_tests_add_test(cxxbridge_rust2cpp "cxxbridge-exe") + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0" AND CMAKE_LINK_GROUP_USING_RESCAN_SUPPORTED) + corrosion_tests_add_test(cxxbridge_circular_link_group "cpp_bin" + TEST_SRC_DIR cxxbridge_circular + PASS_THROUGH_ARGS -DTEST_CXXBRIDGE_VARIANT1=ON + ) + endif() + corrosion_tests_add_test(cxxbridge_circular_mutual_link "cpp_bin" + TEST_SRC_DIR cxxbridge_circular + PASS_THROUGH_ARGS -DTEST_CXXBRIDGE_VARIANT2=ON + ) + + set_tests_properties("cxxbridge_cpp2rust_1_run_rust_bin" + PROPERTIES PASS_REGULAR_EXPRESSION + "main function" + ) + set_tests_properties("cxxbridge_rust2cpp_run_cxxbridge-exe" + PROPERTIES PASS_REGULAR_EXPRESSION + "Hello cxxbridge from lib.rs! \\[4, 5, 6\\]\r?\nHello cxxbridge from foo/mod.rs! \\[4, 5, 6\\]" + ) + + if(NOT WIN32) + corrosion_tests_add_test(cxxbridge_exported_impls "test_main") + set_tests_properties("cxxbridge_exported_impls_run_test_main" + PROPERTIES PASS_REGULAR_EXPRESSION + "main function" + ) + endif() +endif() diff --git a/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_circular/CMakeLists.txt b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_circular/CMakeLists.txt new file mode 100644 index 00000000000..1944f36d8f4 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_circular/CMakeLists.txt @@ -0,0 +1,47 @@ +# This CMake project tests the setup for circular dependencies that involve a CXX bridge +# While circular dependencies are usually discouraged, with CXX they are reasonbly natural, +# as ideally, Rust should be able to call C++ freely and vice-versa. +# +# The way this project is set up, the rust_lib target acts as the one target that includes +# the mixed C++ and Rust code with the cpp_lib and cxxbridge targets as implementation details, +# which shouldn't be used individually. +cmake_minimum_required(VERSION 3.24) +project(test_project VERSION 0.1.0 LANGUAGES CXX) +include(../../test_header.cmake) +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED 1) + +corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml) +corrosion_add_cxxbridge(cxxbridge CRATE rust_lib FILES lib.rs) + +if(MSVC) + set_target_properties(cxxbridge PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreadedDLL") +endif() + +add_library(cpp_lib STATIC cpplib.cpp) +target_include_directories(cpp_lib PUBLIC "${CMAKE_CURRENT_LIST_DIR}/include") + +# Make sure the cpp library can access the headers from the bridge and vice-versa +target_link_libraries(cpp_lib PUBLIC cxxbridge) +target_link_libraries(cxxbridge PRIVATE cpp_lib) + +# The 3 libraries (rust, cpp, cxx) have a circular dependency, set this up in the linker +# so that the rust_lib target links to everything and circular references are resolved. +if(TEST_CXXBRIDGE_VARIANT1) + if (NOT CMAKE_LINK_GROUP_USING_RESCAN_SUPPORTED) + message(FATAL_ERROR "Cannot run this test case without Cmake 3.24 or higher") + endif() + target_link_libraries(rust_lib INTERFACE + "$") +elseif(TEST_CXXBRIDGE_VARIANT2) + target_link_libraries(rust_lib INTERFACE cxxbridge cpp_lib) +endif() + +add_executable(cpp_bin main.cpp) +target_link_libraries(cpp_bin cpp_lib) + +if(MSVC) + set_target_properties(cpp_lib PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreadedDLL") + set_target_properties(cxxbridge PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreadedDLL") + set_target_properties(cpp_bin PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreadedDLL") +endif() diff --git a/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_circular/cpplib.cpp b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_circular/cpplib.cpp new file mode 100644 index 00000000000..15549a4267a --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_circular/cpplib.cpp @@ -0,0 +1,18 @@ +#include "cpplib.h" +#include "cxxbridge/lib.h" +#include "rust/cxx.h" +#include + +RsImage read_image(rust::Str path) { + std::cout << "read_image called" << std::endl; + std::cout << path << std::endl; + Rgba c = {1.0, 2.0, 3.0, 4.0}; + RsImage v = {1, 1, c}; + return v; +} + +void assert_equality() { + if (!read_image("dummy_path").equal_to("dummy path")) { + throw std::runtime_error("equality_check failed"); + } +} diff --git a/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_circular/include/cpplib.h b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_circular/include/cpplib.h new file mode 100644 index 00000000000..cf3427d6580 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_circular/include/cpplib.h @@ -0,0 +1,6 @@ +#pragma once +#include "cxxbridge/lib.h" + +::RsImage read_image(::rust::Str path); + +void assert_equality(); diff --git a/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_circular/main.cpp b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_circular/main.cpp new file mode 100644 index 00000000000..023e5a91149 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_circular/main.cpp @@ -0,0 +1,17 @@ +#include "cpplib.h" + +#include + +int main(void) { + std::cout << "Testing roundtrip..." << std::endl; + + try { + assert_equality(); + } catch (const std::exception &e) { + std::cerr << "Error: " << e.what() << std::endl; + return 1; + } + + std::cout << "Roundtrip successful!"; + return 0; +} diff --git a/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_circular/rust/Cargo.lock b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_circular/rust/Cargo.lock new file mode 100644 index 00000000000..aadd14c8665 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_circular/rust/Cargo.lock @@ -0,0 +1,89 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cc" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" + +[[package]] +name = "cxx" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d1075c37807dcf850c379432f0df05ba52cc30f279c5cfc43cc221ce7f8579" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61b50bc93ba22c27b0d31128d2d130a0a6b3d267ae27ef7e4fae2167dfe8781c" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e61fda7e62115119469c7b3591fd913ecca96fb766cfd3f2e2502ab7bc87a5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "link-cplusplus" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +dependencies = [ + "cc", +] + +[[package]] +name = "proc-macro2" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rust_lib" +version = "0.1.0" +dependencies = [ + "cxx", +] + +[[package]] +name = "syn" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" diff --git a/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_circular/rust/Cargo.toml b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_circular/rust/Cargo.toml new file mode 100644 index 00000000000..d5fca1eaec0 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_circular/rust/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "rust_lib" +version = "0.1.0" +edition = "2018" + +[lib] +name = "rust_lib" +crate-type = ["staticlib"] + +[dependencies] +cxx = "1.0" diff --git a/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_circular/rust/src/lib.rs b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_circular/rust/src/lib.rs new file mode 100644 index 00000000000..024e6eaef43 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_circular/rust/src/lib.rs @@ -0,0 +1,34 @@ +#[cxx::bridge] +pub mod ffi { + #[derive(Debug, PartialEq)] + pub struct Rgba { + r: f32, + g: f32, + b: f32, + a: f32, + } + + #[derive(Debug, PartialEq)] + pub struct RsImage { + width: usize, + height: usize, + raster: Rgba, + } + unsafe extern "C++" { + include!("cpplib.h"); + pub fn read_image(path: &str) -> RsImage; + } + + extern "Rust" { + pub fn equal_to(self: &RsImage, other: &str) -> bool; + } +} + +use ffi::*; + +impl RsImage { + pub fn equal_to(&self, path: &str) -> bool { + println!("equal_to"); + *self == read_image(path) + } +} diff --git a/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_cpp2rust/CMakeLists.txt b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_cpp2rust/CMakeLists.txt new file mode 100644 index 00000000000..b063b17345b --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_cpp2rust/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0 LANGUAGES CXX) +include(../../test_header.cmake) +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED 1) + +corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml) +corrosion_add_cxxbridge(cxxbridge-cpp CRATE rust_bin FILES lib.rs) +target_include_directories(cxxbridge-cpp PRIVATE "include") + +if(CMAKE_SYSTEM_NAME STREQUAL "Linux" + OR (CMAKE_SYSTEM_NAME STREQUAL "Windows" + AND (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + ) +) + corrosion_add_target_local_rustflags(rust_bin "-Clink-arg=-fuse-ld=lld") +endif() + +if(MSVC) + set_target_properties(cxxbridge-cpp PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreadedDLL") +endif() + +if(TEST_CXXBRIDGE_VARIANT1) + # Variant 1: Merge the C++ User sources into the generated library target. + target_sources(cxxbridge-cpp PRIVATE cpplib.cpp) + corrosion_link_libraries(rust_bin cxxbridge-cpp) +elseif(TEST_CXXBRIDGE_VARIANT2) + # Variant 2: Create a separate C++ library and link both the User library and + # the generated library into rust + add_library(cpp_lib STATIC cpplib.cpp) + target_include_directories(cpp_lib PUBLIC "${CMAKE_CURRENT_LIST_DIR}/include") + target_link_libraries(cpp_lib PUBLIC cxxbridge-cpp) + corrosion_link_libraries(rust_bin cpp_lib cxxbridge-cpp) + if(MSVC) + set_target_properties(cpp_lib PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreadedDLL") + endif() +else() + message(FATAL_ERROR "Internal test error - required option not defined") +endif() diff --git a/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_cpp2rust/cpplib.cpp b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_cpp2rust/cpplib.cpp new file mode 100644 index 00000000000..14dd49fc07e --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_cpp2rust/cpplib.cpp @@ -0,0 +1,15 @@ +#include +#include "cpplib.h" +#include "cxxbridge-cpp/lib.h" +#include "rust/cxx.h" + +RsImage read_image(rust::Str path) { + std::cout << "read_image called" << std::endl; + std::cout << path << std::endl; + Rgba c = { 1.0, 2.0, 3.0, 4.0}; + RsImage v = { 1, 1, c}; + return v; +} +void write_image(::rust::Str path, ::RsImage const & image) { + +} diff --git a/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_cpp2rust/include/cpplib.h b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_cpp2rust/include/cpplib.h new file mode 100644 index 00000000000..3e96dffc1b9 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_cpp2rust/include/cpplib.h @@ -0,0 +1,5 @@ +#pragma once +#include "cxxbridge-cpp/lib.h" + +::RsImage read_image(::rust::Str path); +void write_image(::rust::Str path, ::RsImage const & image); diff --git a/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_cpp2rust/rust/Cargo.lock b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_cpp2rust/rust/Cargo.lock new file mode 100644 index 00000000000..4c72e50f721 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_cpp2rust/rust/Cargo.lock @@ -0,0 +1,89 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cc" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" + +[[package]] +name = "cxx" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d1075c37807dcf850c379432f0df05ba52cc30f279c5cfc43cc221ce7f8579" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61b50bc93ba22c27b0d31128d2d130a0a6b3d267ae27ef7e4fae2167dfe8781c" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e61fda7e62115119469c7b3591fd913ecca96fb766cfd3f2e2502ab7bc87a5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "link-cplusplus" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +dependencies = [ + "cc", +] + +[[package]] +name = "proc-macro2" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rust_bin" +version = "0.1.0" +dependencies = [ + "cxx", +] + +[[package]] +name = "syn" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" diff --git a/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_cpp2rust/rust/Cargo.toml b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_cpp2rust/rust/Cargo.toml new file mode 100644 index 00000000000..d2cf479dcca --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_cpp2rust/rust/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "rust_bin" +version = "0.1.0" +edition = "2018" + +[lib] +name = "cxxbridge_lib" + +[dependencies] +cxx = "1.0" diff --git a/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_cpp2rust/rust/src/lib.rs b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_cpp2rust/rust/src/lib.rs new file mode 100644 index 00000000000..db946caf539 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_cpp2rust/rust/src/lib.rs @@ -0,0 +1,26 @@ +#[cxx::bridge] +pub mod ffi +{ + #[derive(Debug, PartialEq)] + pub struct Rgba + { + r: f32, + g: f32, + b: f32, + a: f32, + } + + #[derive(Debug,PartialEq)] + pub struct RsImage + { + width: usize, + height: usize, + raster: Rgba, + } + unsafe extern "C++" + { + include!("cpplib.h"); + pub fn read_image(path: &str) -> RsImage; + fn write_image(path: &str, image: &RsImage); + } +} \ No newline at end of file diff --git a/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_cpp2rust/rust/src/main.rs b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_cpp2rust/rust/src/main.rs new file mode 100644 index 00000000000..f9ae26e6de1 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_cpp2rust/rust/src/main.rs @@ -0,0 +1,14 @@ +use cxxbridge_lib::ffi::{RsImage,Rgba,read_image}; + +fn main() { + println!("main function"); + let expected = RsImage { width: 1, height: 1, raster: Rgba { + r: 1.0, + g: 2.0, + b: 3.0, + a: 4.0, + }}; + let actual = read_image("dummy path"); + println!("returned from C++"); + assert_eq!(actual, expected) +} \ No newline at end of file diff --git a/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_exported_impls/CMakeLists.txt b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_exported_impls/CMakeLists.txt new file mode 100644 index 00000000000..9491452f4c4 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_exported_impls/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.24) +project(test_project VERSION 0.1.0 LANGUAGES CXX) +include(../../test_header.cmake) +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED 1) + +corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml) +corrosion_add_cxxbridge(cxxbridge + CRATE rust_lib + FILES + bridge_a.rs + bridge_b.rs + lib.rs +) + +if(MSVC) + set_target_properties(cxxbridge PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreadedDLL") +endif() + +add_executable(test_main + main.cpp +) + +target_link_libraries(test_main + cxxbridge +) \ No newline at end of file diff --git a/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_exported_impls/main.cpp b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_exported_impls/main.cpp new file mode 100644 index 00000000000..d0e867f0b34 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_exported_impls/main.cpp @@ -0,0 +1,14 @@ +#include "cxxbridge/lib.h" + +#include + +int main() +{ + auto result = make_result(); + + std::cout << static_cast(result.ok->message) << std::endl; + + std::cout << "main function" << std::endl; + + return 0; +} \ No newline at end of file diff --git a/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_exported_impls/rust/Cargo.lock b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_exported_impls/rust/Cargo.lock new file mode 100644 index 00000000000..0943eea27ab --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_exported_impls/rust/Cargo.lock @@ -0,0 +1,297 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "anstyle" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" + +[[package]] +name = "cc" +version = "1.2.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1354349954c6fc9cb0deab020f27f783cf0b604e8bb754dc4658ecf0d29c35f" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "clap" +version = "4.5.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" +dependencies = [ + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_lex" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" + +[[package]] +name = "codespan-reporting" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" +dependencies = [ + "serde", + "termcolor", + "unicode-width", +] + +[[package]] +name = "cxx" +version = "1.0.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e9c4fe7f2f5dc5c62871a1b43992d197da6fa1394656a94276ac2894a90a6fe" +dependencies = [ + "cc", + "cxx-build", + "cxxbridge-cmd", + "cxxbridge-flags", + "cxxbridge-macro", + "foldhash", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5cf2909d37d80633ddd208676fc27c2608a7f035fff69c882421168038b26dd" +dependencies = [ + "cc", + "codespan-reporting", + "indexmap", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-cmd" +version = "1.0.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "077f5ee3d3bfd8d27f83208fdaa96ddd50af7f096c77077cc4b94da10bfacefd" +dependencies = [ + "clap", + "codespan-reporting", + "indexmap", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0108748615125b9f2e915dfafdffcbdabbca9b15102834f6d7e9a768f2f2864" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e896681ef9b8dc462cfa6961d61909704bde0984b30bcb4082fe102b478890" +dependencies = [ + "indexmap", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "find-msvc-tools" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + +[[package]] +name = "indexmap" +version = "2.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "link-cplusplus" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f78c730aaa7d0b9336a299029ea49f9ee53b0ed06e9202e8cb7db9bae7b8c82" +dependencies = [ + "cc", +] + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rust_lib" +version = "0.1.0" +dependencies = [ + "cxx", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "scratch" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d68f2ec51b097e4c1a75b681a8bec621909b5e91f15bb7b840c4f2f7b01148b2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "unicode-width" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + +[[package]] +name = "windows-sys" +version = "0.61.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" +dependencies = [ + "windows-link", +] diff --git a/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_exported_impls/rust/Cargo.toml b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_exported_impls/rust/Cargo.toml new file mode 100644 index 00000000000..d5fca1eaec0 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_exported_impls/rust/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "rust_lib" +version = "0.1.0" +edition = "2018" + +[lib] +name = "rust_lib" +crate-type = ["staticlib"] + +[dependencies] +cxx = "1.0" diff --git a/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_exported_impls/rust/src/bridge_a.rs b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_exported_impls/rust/src/bridge_a.rs new file mode 100644 index 00000000000..3faad612657 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_exported_impls/rust/src/bridge_a.rs @@ -0,0 +1,24 @@ +#[cxx::bridge] +pub mod ffi { + pub struct OkResult { + pub value: bool, + pub message: String, + } + + pub struct TestResult { + pub ok: SharedPtr, + } + + impl SharedPtr {} + + extern "Rust" { + fn make_result() -> Result; + } +} + +pub fn make_result() -> Result { + let now = std::time::Instant::now(); + let ok = ffi::OkResult { value: true, message: format!("{:#?}", now)}; + Ok(ffi::TestResult { ok: cxx::SharedPtr::new(ok)} ) +} + diff --git a/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_exported_impls/rust/src/bridge_b.rs b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_exported_impls/rust/src/bridge_b.rs new file mode 100644 index 00000000000..6373bfa2f5a --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_exported_impls/rust/src/bridge_b.rs @@ -0,0 +1,21 @@ +#[cxx::bridge] +pub mod ffi { + + #[derive(Clone)] + pub struct NewVal { + pub value: bool, + pub message: String, + } + + impl SharedPtr {} + + extern "Rust" { + fn make_new_val() -> SharedPtr; + } +} + +pub fn make_new_val() -> cxx::SharedPtr { + let now = std::time::Instant::now(); + let ok = ffi::NewVal { value: true, message: format!("{:#?}", now)}; + cxx::SharedPtr::new(ok) +} \ No newline at end of file diff --git a/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_exported_impls/rust/src/lib.rs b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_exported_impls/rust/src/lib.rs new file mode 100644 index 00000000000..18dbc6ca5e2 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_exported_impls/rust/src/lib.rs @@ -0,0 +1,30 @@ +pub mod bridge_a; +pub mod bridge_b; +// pub use bridge_a::combine_result; + +#[cxx::bridge] +pub mod ffi { + + extern "C++" { + include!("cxxbridge/bridge_a.h"); + include!("cxxbridge/bridge_b.h"); + + type TestResult = crate::bridge_a::ffi::TestResult; + type NewVal = crate::bridge_b::ffi::NewVal; + } + + extern "Rust" { + fn combine_result(other: SharedPtr) -> Result; + } + +} + +pub fn combine_result(other: cxx::SharedPtr) -> Result { + if let Some(crate::bridge_b::ffi::NewVal { value, message }) = other.as_ref().cloned() { + let result = crate::bridge_a::ffi::TestResult { ok: cxx::SharedPtr::new(crate::bridge_a::ffi::OkResult { value, message }) }; + Ok(result) + } + else { + crate::bridge_a::make_result() + } +} \ No newline at end of file diff --git a/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_rust2cpp/CMakeLists.txt b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_rust2cpp/CMakeLists.txt new file mode 100644 index 00000000000..0111d5466b7 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_rust2cpp/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0) +include(../../test_header.cmake) +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED 1) + +corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml) +corrosion_add_cxxbridge(cxxbridge-cpp CRATE cxxbridge_crate FILES lib.rs foo/mod.rs) + +add_executable(cxxbridge-exe main.cpp) +target_link_libraries(cxxbridge-exe PUBLIC cxxbridge-cpp) + +if(MSVC) + # Note: This is required because we use `cxx` which uses `cc` to compile and link C++ code. + corrosion_set_env_vars(cxxbridge_crate "CFLAGS=-MDd" "CXXFLAGS=-MDd") +endif() diff --git a/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_rust2cpp/main.cpp b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_rust2cpp/main.cpp new file mode 100644 index 00000000000..e512ce44a70 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_rust2cpp/main.cpp @@ -0,0 +1,11 @@ +#include +#include +#include + +int main(int argc, char **argv) +{ + std::vector input = { 4, 5, 6}; + rust::Slice slice{input.data(), input.size()}; + lib::print(slice); + foo::print(slice); +} diff --git a/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_rust2cpp/rust/Cargo.lock b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_rust2cpp/rust/Cargo.lock new file mode 100644 index 00000000000..ff091252ff5 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_rust2cpp/rust/Cargo.lock @@ -0,0 +1,89 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cc" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" + +[[package]] +name = "cxx" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d1075c37807dcf850c379432f0df05ba52cc30f279c5cfc43cc221ce7f8579" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxxbridge-crate" +version = "0.1.0" +dependencies = [ + "cxx", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61b50bc93ba22c27b0d31128d2d130a0a6b3d267ae27ef7e4fae2167dfe8781c" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e61fda7e62115119469c7b3591fd913ecca96fb766cfd3f2e2502ab7bc87a5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "link-cplusplus" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +dependencies = [ + "cc", +] + +[[package]] +name = "proc-macro2" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" diff --git a/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_rust2cpp/rust/Cargo.toml b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_rust2cpp/rust/Cargo.toml new file mode 100644 index 00000000000..3c53c25eb73 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_rust2cpp/rust/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "cxxbridge-crate" +version = "0.1.0" +edition = "2018" + +[lib] +crate-type = ["staticlib"] + +[dependencies] +cxx = "1.0" diff --git a/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_rust2cpp/rust/src/foo/mod.rs b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_rust2cpp/rust/src/foo/mod.rs new file mode 100644 index 00000000000..cbeae92dd42 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_rust2cpp/rust/src/foo/mod.rs @@ -0,0 +1,10 @@ +#[cxx::bridge(namespace = "foo")] +mod bridge { + extern "Rust" { + fn print(slice: &[u64]); + } +} + +fn print(slice: &[u64]) { + println!("Hello cxxbridge from foo/mod.rs! {:?}", slice); +} diff --git a/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_rust2cpp/rust/src/lib.rs b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_rust2cpp/rust/src/lib.rs new file mode 100644 index 00000000000..0a2f4103133 --- /dev/null +++ b/libs/3rdparty/corrosion/test/cxxbridge/cxxbridge_rust2cpp/rust/src/lib.rs @@ -0,0 +1,12 @@ +mod foo; + +#[cxx::bridge(namespace = "lib")] +mod bridge { + extern "Rust" { + fn print(slice: &[u64]); + } +} + +fn print(slice: &[u64]) { + println!("Hello cxxbridge from lib.rs! {:?}", slice); +} diff --git a/libs/3rdparty/corrosion/test/envvar/CMakeLists.txt b/libs/3rdparty/corrosion/test/envvar/CMakeLists.txt new file mode 100644 index 00000000000..8762eda625b --- /dev/null +++ b/libs/3rdparty/corrosion/test/envvar/CMakeLists.txt @@ -0,0 +1,5 @@ +corrosion_tests_add_test(envvar "program_requiring_rust_lib_with_envvar") + +set_tests_properties("envvar_run_program_requiring_rust_lib_with_envvar" PROPERTIES PASS_REGULAR_EXPRESSION + "Ok" + ) diff --git a/libs/3rdparty/corrosion/test/envvar/envvar/.cargo/config.toml b/libs/3rdparty/corrosion/test/envvar/envvar/.cargo/config.toml new file mode 100644 index 00000000000..0d9ab8c814b --- /dev/null +++ b/libs/3rdparty/corrosion/test/envvar/envvar/.cargo/config.toml @@ -0,0 +1,2 @@ +[env] +COR_CONFIG_TOML_ENV_VAR = "EnvVariableSetViaConfig.toml" diff --git a/libs/3rdparty/corrosion/test/envvar/envvar/CMakeLists.txt b/libs/3rdparty/corrosion/test/envvar/envvar/CMakeLists.txt new file mode 100644 index 00000000000..2e0eeabdde1 --- /dev/null +++ b/libs/3rdparty/corrosion/test/envvar/envvar/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0) +include(../../test_header.cmake) + +corrosion_import_crate(MANIFEST_PATH Cargo.toml) + +corrosion_set_env_vars(rust_lib_requiring_envvar + "ANOTHER_VARIABLE=ANOTHER_VALUE" + "$" + "COR_CARGO_VERSION_MAJOR=${Rust_CARGO_VERSION_MAJOR}" + "COR_CARGO_VERSION_MINOR=${Rust_CARGO_VERSION_MINOR}" +) + +add_executable(program_requiring_rust_lib_with_envvar main.cpp) + +set_property( + TARGET program_requiring_rust_lib_with_envvar + APPEND + PROPERTY INDIRECT_VAR_TEST + "REQUIRED_VARIABLE=EXPECTED_VALUE" +) + +target_link_libraries(program_requiring_rust_lib_with_envvar PUBLIC rust_lib_requiring_envvar) diff --git a/libs/3rdparty/corrosion/test/envvar/envvar/Cargo.lock b/libs/3rdparty/corrosion/test/envvar/envvar/Cargo.lock new file mode 100644 index 00000000000..c079aa709c2 --- /dev/null +++ b/libs/3rdparty/corrosion/test/envvar/envvar/Cargo.lock @@ -0,0 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "rust-lib-requiring-envvar" +version = "0.1.0" diff --git a/libs/3rdparty/corrosion/test/envvar/envvar/Cargo.toml b/libs/3rdparty/corrosion/test/envvar/envvar/Cargo.toml new file mode 100644 index 00000000000..e74e08bf4a1 --- /dev/null +++ b/libs/3rdparty/corrosion/test/envvar/envvar/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "rust-lib-requiring-envvar" +version = "0.1.0" +authors = ["Olivier Goffart "] +edition = "2018" +build = "build.rs" + +[lib] +crate-type = [ "lib", "cdylib" ] diff --git a/libs/3rdparty/corrosion/test/envvar/envvar/build.rs b/libs/3rdparty/corrosion/test/envvar/envvar/build.rs new file mode 100644 index 00000000000..4c173db3631 --- /dev/null +++ b/libs/3rdparty/corrosion/test/envvar/envvar/build.rs @@ -0,0 +1,18 @@ +fn main() { + assert_eq!(env!("REQUIRED_VARIABLE"), "EXPECTED_VALUE"); + assert_eq!(std::env::var("ANOTHER_VARIABLE").unwrap(), "ANOTHER_VALUE"); + let cargo_major = env!("COR_CARGO_VERSION_MAJOR") + .parse::() + .expect("Invalid Major version"); + let cargo_minor = env!("COR_CARGO_VERSION_MINOR") + .parse::() + .expect("Invalid Minor version"); + + // The `[env]` section in `.cargo/config.toml` was added in version 1.56. + if cargo_major > 1 || (cargo_major == 1 && cargo_minor >= 56) { + // Check if cargo picks up the config.toml, which sets this additional env variable. + let env_value = option_env!("COR_CONFIG_TOML_ENV_VAR") + .expect("Test failure! Cargo >= 1.56.0 should set this environment variable"); + assert_eq!(env_value, "EnvVariableSetViaConfig.toml"); + } +} diff --git a/libs/3rdparty/corrosion/test/envvar/envvar/main.cpp b/libs/3rdparty/corrosion/test/envvar/envvar/main.cpp new file mode 100644 index 00000000000..5af4054446d --- /dev/null +++ b/libs/3rdparty/corrosion/test/envvar/envvar/main.cpp @@ -0,0 +1,5 @@ +#include + +int main() { + std::cout << "Ok"; +} diff --git a/libs/3rdparty/corrosion/test/envvar/envvar/src/lib.rs b/libs/3rdparty/corrosion/test/envvar/envvar/src/lib.rs new file mode 100644 index 00000000000..31e1bb209f9 --- /dev/null +++ b/libs/3rdparty/corrosion/test/envvar/envvar/src/lib.rs @@ -0,0 +1,7 @@ +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} diff --git a/libs/3rdparty/corrosion/test/features/CMakeLists.txt b/libs/3rdparty/corrosion/test/features/CMakeLists.txt new file mode 100644 index 00000000000..d1d0a7a050c --- /dev/null +++ b/libs/3rdparty/corrosion/test/features/CMakeLists.txt @@ -0,0 +1,5 @@ +corrosion_tests_add_test(features "features-cpp-exe") + +set_tests_properties("features_run_features-cpp-exe" PROPERTIES PASS_REGULAR_EXPRESSION + "Hello, Cpp! I'm Rust!\r?\nHello, Cpp again! I'm Rust again!\r?\nHello, Cpp again! I'm Rust again, third time the charm!" + ) diff --git a/libs/3rdparty/corrosion/test/features/features/CMakeLists.txt b/libs/3rdparty/corrosion/test/features/features/CMakeLists.txt new file mode 100644 index 00000000000..7b3767950dd --- /dev/null +++ b/libs/3rdparty/corrosion/test/features/features/CMakeLists.txt @@ -0,0 +1,27 @@ +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0) +include(../../test_header.cmake) + +corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml FEATURES thirdfeature ALL_FEATURES) + +add_executable(features-cpp-exe main.cpp) +target_link_libraries(features-cpp-exe PUBLIC rust_feature_lib) + +corrosion_set_features(rust_feature_lib + ALL_FEATURES OFF + NO_DEFAULT_FEATURES + FEATURES + $ +) + +set_property( + TARGET features-cpp-exe + APPEND + PROPERTY app_features myfeature +) +set_property( + TARGET features-cpp-exe + APPEND + PROPERTY app_features secondfeature +) + diff --git a/libs/3rdparty/corrosion/test/features/features/main.cpp b/libs/3rdparty/corrosion/test/features/features/main.cpp new file mode 100644 index 00000000000..0b9b1b92ac2 --- /dev/null +++ b/libs/3rdparty/corrosion/test/features/features/main.cpp @@ -0,0 +1,13 @@ +extern "C" void rust_function(char const *name); +extern "C" void rust_second_function(char const *name); +extern "C" void rust_third_function(char const *name); + +int main(int argc, char **argv) { + if (argc < 2) { + rust_function("Cpp"); + rust_second_function("Cpp again"); + rust_third_function("Cpp again"); + } else { + rust_function(argv[1]); + } +} diff --git a/libs/3rdparty/corrosion/test/features/features/rust/Cargo.lock b/libs/3rdparty/corrosion/test/features/features/rust/Cargo.lock new file mode 100644 index 00000000000..5cbbeb2708a --- /dev/null +++ b/libs/3rdparty/corrosion/test/features/features/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust-feature-lib" +version = "0.1.0" diff --git a/libs/3rdparty/corrosion/test/features/features/rust/Cargo.toml b/libs/3rdparty/corrosion/test/features/features/rust/Cargo.toml new file mode 100644 index 00000000000..977dc534d69 --- /dev/null +++ b/libs/3rdparty/corrosion/test/features/features/rust/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "rust-feature-lib" +version = "0.1.0" +authors = ["Andrew Gaspar "] +license = "MIT" +edition = "2018" + +[dependencies] + +[lib] +crate-type=["staticlib"] + +[features] +default = ["compile-breakage"] +myfeature = [] +secondfeature = [] +thirdfeature = [] +compile-breakage = [] \ No newline at end of file diff --git a/libs/3rdparty/corrosion/test/features/features/rust/src/lib.rs b/libs/3rdparty/corrosion/test/features/features/rust/src/lib.rs new file mode 100644 index 00000000000..7c5c6d64866 --- /dev/null +++ b/libs/3rdparty/corrosion/test/features/features/rust/src/lib.rs @@ -0,0 +1,26 @@ +#[cfg(feature = "myfeature")] +use std::os::raw::c_char; + +#[no_mangle] +#[cfg(feature = "myfeature")] +pub extern "C" fn rust_function(name: *const c_char) { + let name = unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() }; + println!("Hello, {}! I'm Rust!", name); +} + +#[no_mangle] +#[cfg(feature = "secondfeature")] +pub extern "C" fn rust_second_function(name: *const c_char) { + let name = unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() }; + println!("Hello, {}! I'm Rust again!", name); +} + +#[no_mangle] +#[cfg(feature = "thirdfeature")] +pub extern "C" fn rust_third_function(name: *const c_char) { + let name = unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() }; + println!("Hello, {}! I'm Rust again, third time the charm!", name); +} + +#[cfg(feature = "compile-breakage")] +const _: [(); 1] = [(); 2]; // Trigger a compile error to make sure that we succeeded in de-activating this feature diff --git a/libs/3rdparty/corrosion/test/find_rust/CMakeLists.txt b/libs/3rdparty/corrosion/test/find_rust/CMakeLists.txt new file mode 100644 index 00000000000..482e5aef674 --- /dev/null +++ b/libs/3rdparty/corrosion/test/find_rust/CMakeLists.txt @@ -0,0 +1,7 @@ +corrosion_tests_add_test(find_rust "") +corrosion_tests_add_test(rustup_proxy "") + +find_program(rustup rustup) +if(NOT rustup) + set_tests_properties(rustup_proxy_build rustup_proxy_cleanup PROPERTIES DISABLED 1) +endif() diff --git a/libs/3rdparty/corrosion/test/find_rust/find_rust/CMakeLists.txt b/libs/3rdparty/corrosion/test/find_rust/find_rust/CMakeLists.txt new file mode 100644 index 00000000000..bdd0cb7ee5c --- /dev/null +++ b/libs/3rdparty/corrosion/test/find_rust/find_rust/CMakeLists.txt @@ -0,0 +1,9 @@ + +cmake_minimum_required(VERSION 3.15) +project(FindRust LANGUAGES CXX) + +set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/../../../cmake" ${CMAKE_MODULE_PATH}) + +# make sure find_package(Rust) can be used more than once +find_package(Rust REQUIRED) +find_package(Rust REQUIRED) diff --git a/libs/3rdparty/corrosion/test/find_rust/rustup_proxy/CMakeLists.txt b/libs/3rdparty/corrosion/test/find_rust/rustup_proxy/CMakeLists.txt new file mode 100644 index 00000000000..7d0440f4fee --- /dev/null +++ b/libs/3rdparty/corrosion/test/find_rust/rustup_proxy/CMakeLists.txt @@ -0,0 +1,47 @@ +cmake_minimum_required(VERSION 3.15) +project(RustupProxy LANGUAGES CXX) + +set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/../../../cmake" ${CMAKE_MODULE_PATH}) + +function(_assert_is_rustup_proxy executable_path) + execute_process( + COMMAND + ${CMAKE_COMMAND} -E env + RUSTUP_FORCE_ARG0=rustup + "${executable_path}" --version + OUTPUT_VARIABLE _VERSION_RAW + ERROR_VARIABLE _VERSION_STDERR + RESULT_VARIABLE _VERSION_RESULT + ) + + if(NOT _VERSION_RESULT EQUAL "0") + message(FATAL_ERROR "`${executable_path} --version` failed with ${_VERSION_RESULT}\n" + "stderr:\n${_VERSION_STDERR}" + ) + endif() + + if (NOT _VERSION_RAW MATCHES "rustup [0-9\\.]+") + message(FATAL_ERROR "`${executable_path} --version` output does not match rustup: ${_VERSION_RAW}\n") + endif() +endfunction() + +set(Rust_RESOLVE_RUSTUP_TOOLCHAINS OFF CACHE BOOL "" FORCE) +find_package(Rust REQUIRED) + +if (NOT Rust_FOUND) + message(FATAL_ERROR "Rustup not found") +endif() + +get_property( + RUSTC_EXECUTABLE + TARGET Rust::Rustc PROPERTY IMPORTED_LOCATION +) + +_assert_is_rustup_proxy(${RUSTC_EXECUTABLE}) + +get_property( + CARGO_EXECUTABLE + TARGET Rust::Cargo PROPERTY IMPORTED_LOCATION +) + +_assert_is_rustup_proxy(${CARGO_EXECUTABLE}) diff --git a/libs/3rdparty/corrosion/test/gensource/CMakeLists.txt b/libs/3rdparty/corrosion/test/gensource/CMakeLists.txt new file mode 100644 index 00000000000..b38a9877623 --- /dev/null +++ b/libs/3rdparty/corrosion/test/gensource/CMakeLists.txt @@ -0,0 +1,5 @@ +corrosion_tests_add_test(gensource "") + +#set_tests_properties("features_run_features-cpp-exe" PROPERTIES PASS_REGULAR_EXPRESSION +# "Hello, Cpp! I'm Rust!\r?\nHello, Cpp again! I'm Rust again!\r?\nHello, Cpp again! I'm Rust again, third time the charm!" +# ) \ No newline at end of file diff --git a/libs/3rdparty/corrosion/test/gensource/gensource/.gitignore b/libs/3rdparty/corrosion/test/gensource/gensource/.gitignore new file mode 100644 index 00000000000..b4878a28e06 --- /dev/null +++ b/libs/3rdparty/corrosion/test/gensource/gensource/.gitignore @@ -0,0 +1 @@ +src/foo.rs diff --git a/libs/3rdparty/corrosion/test/gensource/gensource/CMakeLists.txt b/libs/3rdparty/corrosion/test/gensource/gensource/CMakeLists.txt new file mode 100644 index 00000000000..ea348d25327 --- /dev/null +++ b/libs/3rdparty/corrosion/test/gensource/gensource/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0) +include(../../test_header.cmake) + +add_subdirectory(generator) + +add_custom_command( + OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/src/foo.rs" + DEPENDS $ + COMMAND $ "${CMAKE_CURRENT_SOURCE_DIR}/src/foo.rs" +) + +add_custom_target(after_generation DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/foo.rs") +add_custom_target(genexdebug COMMAND ${CMAKE_COMMAND} -E echo "Config DEBUG: $ Config Release: $ IMPORTED_LOCATION: $") + +corrosion_import_crate(MANIFEST_PATH ${CMAKE_CURRENT_SOURCE_DIR}/Cargo.toml) +add_dependencies(cargo-prebuild_generated after_generation) + +# Simple test for corrosion_parse_package_version +corrosion_parse_package_version("${CMAKE_CURRENT_SOURCE_DIR}/Cargo.toml" srcgen_version) +if (NOT "${srcgen_version}" VERSION_EQUAL "0.1.0") + message(FATAL_ERROR "Test failed to parse expected version") +endif() diff --git a/libs/3rdparty/corrosion/test/gensource/gensource/Cargo.lock b/libs/3rdparty/corrosion/test/gensource/gensource/Cargo.lock new file mode 100644 index 00000000000..e22568e8f51 --- /dev/null +++ b/libs/3rdparty/corrosion/test/gensource/gensource/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "generated" +version = "0.1.0" diff --git a/libs/3rdparty/corrosion/test/gensource/gensource/Cargo.toml b/libs/3rdparty/corrosion/test/gensource/gensource/Cargo.toml new file mode 100644 index 00000000000..f4c72d391c8 --- /dev/null +++ b/libs/3rdparty/corrosion/test/gensource/gensource/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "generated" +version = "0.1.0" +edition = "2018" + +[lib] +crate-type = ["lib", "cdylib"] +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/libs/3rdparty/corrosion/test/gensource/gensource/generator/CMakeLists.txt b/libs/3rdparty/corrosion/test/gensource/gensource/generator/CMakeLists.txt new file mode 100644 index 00000000000..40ab3a72da2 --- /dev/null +++ b/libs/3rdparty/corrosion/test/gensource/gensource/generator/CMakeLists.txt @@ -0,0 +1,2 @@ +corrosion_import_crate(MANIFEST_PATH Cargo.toml) +corrosion_set_hostbuild(srcgen) diff --git a/libs/3rdparty/corrosion/test/gensource/gensource/generator/Cargo.lock b/libs/3rdparty/corrosion/test/gensource/gensource/generator/Cargo.lock new file mode 100644 index 00000000000..6ad6f0d2aed --- /dev/null +++ b/libs/3rdparty/corrosion/test/gensource/gensource/generator/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "srcgen" +version = "0.1.0" diff --git a/libs/3rdparty/corrosion/test/gensource/gensource/generator/Cargo.toml b/libs/3rdparty/corrosion/test/gensource/gensource/generator/Cargo.toml new file mode 100644 index 00000000000..8712fea43ee --- /dev/null +++ b/libs/3rdparty/corrosion/test/gensource/gensource/generator/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "srcgen" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/libs/3rdparty/corrosion/test/gensource/gensource/generator/src/main.rs b/libs/3rdparty/corrosion/test/gensource/gensource/generator/src/main.rs new file mode 100644 index 00000000000..84eef8c7bf5 --- /dev/null +++ b/libs/3rdparty/corrosion/test/gensource/gensource/generator/src/main.rs @@ -0,0 +1,6 @@ +use std::io::Write; +fn main() -> Result<(), std::io::Error> { + let out_name = std::env::args().skip(1).next().unwrap(); + let mut out_file = std::fs::File::create(out_name)?; + Ok(write!(out_file, "const _: () = ();")?) +} diff --git a/libs/3rdparty/corrosion/test/gensource/gensource/src/lib.rs b/libs/3rdparty/corrosion/test/gensource/gensource/src/lib.rs new file mode 100644 index 00000000000..b624d3c7c10 --- /dev/null +++ b/libs/3rdparty/corrosion/test/gensource/gensource/src/lib.rs @@ -0,0 +1,10 @@ +mod foo; + +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + let result = 2 + 2; + assert_eq!(result, 4); + } +} diff --git a/libs/3rdparty/corrosion/test/hostbuild/CMakeLists.txt b/libs/3rdparty/corrosion/test/hostbuild/CMakeLists.txt new file mode 100644 index 00000000000..0d1c831c356 --- /dev/null +++ b/libs/3rdparty/corrosion/test/hostbuild/CMakeLists.txt @@ -0,0 +1,6 @@ +corrosion_tests_add_test(hostbuild "rust-host-program" IS_HOSTBUILD) + +set_tests_properties("hostbuild_run_rust-host-program" PROPERTIES PASS_REGULAR_EXPRESSION + "^ok\r?\nHello Rust Hostbuild, I am an external C function" + ) + diff --git a/libs/3rdparty/corrosion/test/hostbuild/hostbuild/CMakeLists.txt b/libs/3rdparty/corrosion/test/hostbuild/hostbuild/CMakeLists.txt new file mode 100644 index 00000000000..1e60ff31c89 --- /dev/null +++ b/libs/3rdparty/corrosion/test/hostbuild/hostbuild/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0) +include(../../test_header.cmake) + +corrosion_import_crate(MANIFEST_PATH ${CMAKE_CURRENT_SOURCE_DIR}/Cargo.toml) + +corrosion_set_hostbuild(rust-host-program) diff --git a/libs/3rdparty/corrosion/test/hostbuild/hostbuild/Cargo.lock b/libs/3rdparty/corrosion/test/hostbuild/hostbuild/Cargo.lock new file mode 100644 index 00000000000..aea4063d55a --- /dev/null +++ b/libs/3rdparty/corrosion/test/hostbuild/hostbuild/Cargo.lock @@ -0,0 +1,16 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "rust-host-program" +version = "0.1.0" +dependencies = [ + "cc", +] diff --git a/libs/3rdparty/corrosion/test/hostbuild/hostbuild/Cargo.toml b/libs/3rdparty/corrosion/test/hostbuild/hostbuild/Cargo.toml new file mode 100644 index 00000000000..935757af063 --- /dev/null +++ b/libs/3rdparty/corrosion/test/hostbuild/hostbuild/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "rust-host-program" +version = "0.1.0" +authors = ["Olivier Goffart "] +edition = "2018" + +[build-dependencies] +cc = "1.0" diff --git a/libs/3rdparty/corrosion/test/hostbuild/hostbuild/build.rs b/libs/3rdparty/corrosion/test/hostbuild/hostbuild/build.rs new file mode 100644 index 00000000000..aa725cf5a13 --- /dev/null +++ b/libs/3rdparty/corrosion/test/hostbuild/hostbuild/build.rs @@ -0,0 +1,10 @@ +fn main() { + let out_dir = std::env::var("OUT_DIR").unwrap(); + cc::Build::new() + .file("src/lib.c") + .compile("hello"); + + println!("cargo:rustc-link-search=native={}", out_dir); + println!("cargo:rustc-link-lib=hello"); + println!("cargo:rerun-if-changed=src/lib.c"); +} \ No newline at end of file diff --git a/libs/3rdparty/corrosion/test/hostbuild/hostbuild/src/lib.c b/libs/3rdparty/corrosion/test/hostbuild/hostbuild/src/lib.c new file mode 100644 index 00000000000..4739e9c55f9 --- /dev/null +++ b/libs/3rdparty/corrosion/test/hostbuild/hostbuild/src/lib.c @@ -0,0 +1,5 @@ +#include + +void c_function(char const *name) { + printf("Hello %s, I am an external C function\n", name); +} diff --git a/libs/3rdparty/corrosion/test/hostbuild/hostbuild/src/main.rs b/libs/3rdparty/corrosion/test/hostbuild/hostbuild/src/main.rs new file mode 100644 index 00000000000..d4ec7cb7987 --- /dev/null +++ b/libs/3rdparty/corrosion/test/hostbuild/hostbuild/src/main.rs @@ -0,0 +1,13 @@ +use std::os::raw::c_char; + +extern "C" { + fn c_function(name: *const c_char); +} + +fn main() { + println!("ok"); + let name = b"Rust Hostbuild\0"; + unsafe { + c_function(name.as_ptr() as _); + } +} diff --git a/libs/3rdparty/corrosion/test/multitarget/CMakeLists.txt b/libs/3rdparty/corrosion/test/multitarget/CMakeLists.txt new file mode 100644 index 00000000000..8f016ec269b --- /dev/null +++ b/libs/3rdparty/corrosion/test/multitarget/CMakeLists.txt @@ -0,0 +1,22 @@ +corrosion_tests_add_test(multitarget "bin1;bin2;bin3") + +# Don't run this test in parallel with others, since the target directory size may cause issues. +set_tests_properties("multitarget_build" PROPERTIES RUN_SERIAL TRUE) + +set_tests_properties("multitarget_run_bin1" PROPERTIES PASS_REGULAR_EXPRESSION + "Hello, world!\r?\nHello, bin1! I'm Cpp!" + RUN_SERIAL + TRUE + ) + +set_tests_properties("multitarget_run_bin2" PROPERTIES PASS_REGULAR_EXPRESSION + "Hello, world!\r?\nHello, bin2! I'm Cpp!" + RUN_SERIAL + TRUE + ) + +set_tests_properties("multitarget_run_bin3" PROPERTIES PASS_REGULAR_EXPRESSION + "Hello, world!\r?\nHello, bin3! I'm Cpp!" + RUN_SERIAL + TRUE + ) diff --git a/libs/3rdparty/corrosion/test/multitarget/multitarget/CMakeLists.txt b/libs/3rdparty/corrosion/test/multitarget/multitarget/CMakeLists.txt new file mode 100644 index 00000000000..0d7a4102b8d --- /dev/null +++ b/libs/3rdparty/corrosion/test/multitarget/multitarget/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0) +include(../../test_header.cmake) + +corrosion_import_crate(MANIFEST_PATH Cargo.toml) + +add_library(cpp-lib4 lib.cpp) +target_compile_features(cpp-lib4 PRIVATE cxx_std_14) +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) diff --git a/libs/3rdparty/corrosion/test/multitarget/multitarget/Cargo.lock b/libs/3rdparty/corrosion/test/multitarget/multitarget/Cargo.lock new file mode 100644 index 00000000000..348e15f3bc0 --- /dev/null +++ b/libs/3rdparty/corrosion/test/multitarget/multitarget/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "multitarget-crate" +version = "0.1.0" diff --git a/libs/3rdparty/corrosion/test/multitarget/multitarget/Cargo.toml b/libs/3rdparty/corrosion/test/multitarget/multitarget/Cargo.toml new file mode 100644 index 00000000000..406e1d004da --- /dev/null +++ b/libs/3rdparty/corrosion/test/multitarget/multitarget/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "multitarget-crate" +version = "0.1.0" +edition = "2018" + +[dependencies] + +[lib] +name = "multitarget_lib" +crate-type=["lib", "staticlib", "cdylib"] + +[[bin]] +name = "bin1" + +[[bin]] +name = "bin2" + +[[bin]] +name = "bin3" diff --git a/libs/3rdparty/corrosion/test/multitarget/multitarget/lib.cpp b/libs/3rdparty/corrosion/test/multitarget/multitarget/lib.cpp new file mode 100644 index 00000000000..549964a673a --- /dev/null +++ b/libs/3rdparty/corrosion/test/multitarget/multitarget/lib.cpp @@ -0,0 +1,5 @@ +#include + +extern "C" void cpp_function(char const *name) { + std::cout << "Hello, " << name << "! I'm Cpp!\n"; +} diff --git a/libs/3rdparty/corrosion/test/multitarget/multitarget/src/bin/bin1.rs b/libs/3rdparty/corrosion/test/multitarget/multitarget/src/bin/bin1.rs new file mode 100644 index 00000000000..6284966fcef --- /dev/null +++ b/libs/3rdparty/corrosion/test/multitarget/multitarget/src/bin/bin1.rs @@ -0,0 +1,8 @@ +use multitarget_lib::hello_world; + +fn main() { + hello_world(); + unsafe { + multitarget_lib::cpp_function("bin1\0".as_ptr() as *const _); + } +} diff --git a/libs/3rdparty/corrosion/test/multitarget/multitarget/src/bin/bin2.rs b/libs/3rdparty/corrosion/test/multitarget/multitarget/src/bin/bin2.rs new file mode 100644 index 00000000000..05ddbdb013b --- /dev/null +++ b/libs/3rdparty/corrosion/test/multitarget/multitarget/src/bin/bin2.rs @@ -0,0 +1,8 @@ +use multitarget_lib::hello_world; + +fn main() { + hello_world(); + unsafe { + multitarget_lib::cpp_function("bin2\0".as_ptr() as *const _); + } +} diff --git a/libs/3rdparty/corrosion/test/multitarget/multitarget/src/bin/bin3.rs b/libs/3rdparty/corrosion/test/multitarget/multitarget/src/bin/bin3.rs new file mode 100644 index 00000000000..238e8b97e0c --- /dev/null +++ b/libs/3rdparty/corrosion/test/multitarget/multitarget/src/bin/bin3.rs @@ -0,0 +1,8 @@ +use multitarget_lib::hello_world; + +fn main() { + hello_world(); + unsafe { + multitarget_lib::cpp_function("bin3\0".as_ptr() as *const _); + } +} diff --git a/libs/3rdparty/corrosion/test/multitarget/multitarget/src/lib.rs b/libs/3rdparty/corrosion/test/multitarget/multitarget/src/lib.rs new file mode 100644 index 00000000000..1da2d248521 --- /dev/null +++ b/libs/3rdparty/corrosion/test/multitarget/multitarget/src/lib.rs @@ -0,0 +1,9 @@ +use std::os::raw::c_char; + +pub fn hello_world() { + println!("Hello, world!"); +} + +extern "C" { + pub fn cpp_function(name: *const c_char); +} diff --git a/libs/3rdparty/corrosion/test/nostd/CMakeLists.txt b/libs/3rdparty/corrosion/test/nostd/CMakeLists.txt new file mode 100644 index 00000000000..be700caa2e8 --- /dev/null +++ b/libs/3rdparty/corrosion/test/nostd/CMakeLists.txt @@ -0,0 +1 @@ +corrosion_tests_add_test(nostd "") diff --git a/libs/3rdparty/corrosion/test/nostd/nostd/CMakeLists.txt b/libs/3rdparty/corrosion/test/nostd/nostd/CMakeLists.txt new file mode 100644 index 00000000000..a533d79a324 --- /dev/null +++ b/libs/3rdparty/corrosion/test/nostd/nostd/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0) +include(../../test_header.cmake) + +corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml NO_STD) + +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -nostdlib") +list(REMOVE_ITEM CMAKE_CXX_IMPLICIT_LINK_LIBRARIES stdc++) + +add_library(nostd-cpp-lib STATIC main.cpp) +target_link_libraries(nostd-cpp-lib PUBLIC rust-nostd-lib) diff --git a/libs/3rdparty/corrosion/test/nostd/nostd/main.cpp b/libs/3rdparty/corrosion/test/nostd/nostd/main.cpp new file mode 100644 index 00000000000..3cede3a8e5e --- /dev/null +++ b/libs/3rdparty/corrosion/test/nostd/nostd/main.cpp @@ -0,0 +1,6 @@ +extern "C" void rust_function(); + +extern "C" void cpp_function() { + // Fail on linking issues + rust_function(); +} \ No newline at end of file diff --git a/libs/3rdparty/corrosion/test/nostd/nostd/rust/Cargo.lock b/libs/3rdparty/corrosion/test/nostd/nostd/rust/Cargo.lock new file mode 100644 index 00000000000..0216008de81 --- /dev/null +++ b/libs/3rdparty/corrosion/test/nostd/nostd/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust-nostd-lib" +version = "0.1.0" diff --git a/libs/3rdparty/corrosion/test/nostd/nostd/rust/Cargo.toml b/libs/3rdparty/corrosion/test/nostd/nostd/rust/Cargo.toml new file mode 100644 index 00000000000..e16f8fe8310 --- /dev/null +++ b/libs/3rdparty/corrosion/test/nostd/nostd/rust/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "rust-nostd-lib" +version = "0.1.0" +edition = "2015" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +[lib] +crate-type=["staticlib"] + +[profile.release] +panic = "abort" + +[profile.dev] +panic = "abort" diff --git a/libs/3rdparty/corrosion/test/nostd/nostd/rust/src/lib.rs b/libs/3rdparty/corrosion/test/nostd/nostd/rust/src/lib.rs new file mode 100644 index 00000000000..81443752cbd --- /dev/null +++ b/libs/3rdparty/corrosion/test/nostd/nostd/rust/src/lib.rs @@ -0,0 +1,10 @@ +#![no_std] +use core::panic::PanicInfo; + +#[no_mangle] +pub extern "C" fn rust_function() {} + +#[panic_handler] +fn panic(_panic: &PanicInfo<'_>) -> ! { + loop {} +} \ No newline at end of file diff --git a/libs/3rdparty/corrosion/test/output directory/CMakeLists.txt b/libs/3rdparty/corrosion/test/output directory/CMakeLists.txt new file mode 100644 index 00000000000..ff5b279c784 --- /dev/null +++ b/libs/3rdparty/corrosion/test/output directory/CMakeLists.txt @@ -0,0 +1,171 @@ +set(configure_cmake_args) +if(CMAKE_C_COMPILER) + list(APPEND configure_cmake_args "C_COMPILER" "${CMAKE_C_COMPILER}") +endif() +if(CMAKE_CXX_COMPILER) + list(APPEND configure_cmake_args "CXX_COMPILER" "${CMAKE_CXX_COMPILER}") +endif() +if(CMAKE_C_COMPILER_TARGET) + list(APPEND configure_cmake_args "C_COMPILER_TARGET" "${CMAKE_C_COMPILER_TARGET}") +endif() +if(CMAKE_CXX_COMPILER_TARGET) + list(APPEND configure_cmake_args "CXX_COMPILER_TARGET" "${CMAKE_CXX_COMPILER_TARGET}") +endif() +if(CMAKE_GENERATOR_PLATFORM) + list(APPEND configure_cmake_args "GENERATOR_PLATFORM" "${CMAKE_GENERATOR_PLATFORM}") +endif() +if(CMAKE_OSX_ARCHITECTURES) + list(APPEND configure_cmake_args OSX_ARCHITECTURES "${CMAKE_OSX_ARCHITECTURES}") +endif() +if(CMAKE_TOOLCHAIN_FILE) + list(APPEND configure_cmake_args TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}") +endif() + +add_test(NAME "output_directory_build" + COMMAND + ${CMAKE_COMMAND} + -P "${CMAKE_SOURCE_DIR}/test/ConfigureAndBuild.cmake" + SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/output directory" + BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/build" + GENERATOR "${CMAKE_GENERATOR}" + RUST_TOOLCHAIN "${Rust_TOOLCHAIN}" + CARGO_TARGET "${Rust_CARGO_TARGET}" + SYSTEM_NAME "${CMAKE_SYSTEM_NAME}" + ${configure_cmake_args} + COMMAND_EXPAND_LISTS +) +set_tests_properties("output_directory_build" PROPERTIES FIXTURES_SETUP "build_fixture_output_directory") +if(CORROSION_TESTS_INSTALL_CORROSION) + set_tests_properties("output_directory_build" PROPERTIES FIXTURES_REQUIRED "fixture_corrosion_install") +endif() + +get_cmake_property(IS_MULTI_CONFIG GENERATOR_IS_MULTI_CONFIG) + +if (IS_MULTI_CONFIG) + set(config_path_str "$/") +else() + set(config_path_str "") +endif() + +foreach(output_approach targetprop var targetprop_pdb_fallback) + if(output_approach STREQUAL "targetprop") + set(rust_proj_suffix "1") + elseif(output_approach STREQUAL "var") + set(rust_proj_suffix "2") + elseif(output_approach STREQUAL "targetprop_pdb_fallback") + set(rust_proj_suffix "3") + else() + message(FATAL_ERROR "specify rust project suffix for new output approach ${output_approach}") + endif() + + set(bin_name "rust_bin${rust_proj_suffix}${CMAKE_EXECUTABLE_SUFFIX}") + + add_test(NAME output_directory_bin_${output_approach} + COMMAND + "${CMAKE_COMMAND}" + -P "${CMAKE_CURRENT_SOURCE_DIR}/../TestFileExists.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/build/custom_bin_${output_approach}/${config_path_str}${bin_name}" + ) + set_tests_properties("output_directory_bin_${output_approach}" PROPERTIES FIXTURES_REQUIRED "build_fixture_output_directory") + + set(lib_name "rust_lib${rust_proj_suffix}") + + set(static_lib_name "${CMAKE_STATIC_LIBRARY_PREFIX}${lib_name}${CMAKE_STATIC_LIBRARY_SUFFIX}") + + add_test(NAME output_directory_staticlib_${output_approach} + COMMAND + "${CMAKE_COMMAND}" + -P "${CMAKE_CURRENT_SOURCE_DIR}/../TestFileExists.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/build/custom_archive_${output_approach}/${config_path_str}${static_lib_name}" + ) + set_tests_properties("output_directory_staticlib_${output_approach}" PROPERTIES FIXTURES_REQUIRED "build_fixture_output_directory") + + if(MINGW) + # Windows-GNU defines "lib" as prefix for DLLs, but cargo creates foo.dll instead of libfoo.dll + set(dynamic_lib_prefix "") + else() + set(dynamic_lib_prefix "${CMAKE_SHARED_LIBRARY_PREFIX}") + endif() + set(dynamic_lib_name "${dynamic_lib_prefix}${lib_name}${CMAKE_SHARED_LIBRARY_SUFFIX}") + + add_test(NAME output_directory_cdylib_${output_approach} + COMMAND + "${CMAKE_COMMAND}" + -P "${CMAKE_CURRENT_SOURCE_DIR}/../TestFileExists.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/build/custom_lib_${output_approach}/${config_path_str}${dynamic_lib_name}" + ) + set_tests_properties("output_directory_cdylib_${output_approach}" PROPERTIES FIXTURES_REQUIRED "build_fixture_output_directory") + + if(WIN32) + set(implib_name ${CMAKE_IMPORT_LIBRARY_PREFIX}${lib_name}${CMAKE_IMPORT_LIBRARY_SUFFIX}) + + add_test(NAME output_directory_implib_${output_approach} + COMMAND + "${CMAKE_COMMAND}" + -P "${CMAKE_CURRENT_SOURCE_DIR}/../TestFileExists.cmake" + # Implib is an ARCHIVE artifact, see: + # https://cmake.org/cmake/help/v3.25/manual/cmake-buildsystem.7.html#archive-output-artifacts + "${CMAKE_CURRENT_BINARY_DIR}/build/custom_archive_${output_approach}/${config_path_str}${implib_name}" + ) + set_tests_properties("output_directory_implib_${output_approach}" PROPERTIES FIXTURES_REQUIRED "build_fixture_output_directory") + + if(MSVC) + if(output_approach STREQUAL "targetprop") + set(expected_lib_pdb_path "custom_lib_pdb_targetprop") + set(expected_bin_pdb_path "custom_bin_pdb_targetprop") + elseif(output_approach STREQUAL "var") + # When using a CMAKE_ variable instead of a target property, both targets + # end up in the same directory. + set(expected_lib_pdb_path "custom_binlib_pdb_var") + set(expected_bin_pdb_path "custom_binlib_pdb_var") + elseif(output_approach STREQUAL "targetprop_pdb_fallback") + set(expected_lib_pdb_path "custom_lib_targetprop_pdb_fallback") + set(expected_bin_pdb_path "custom_bin_targetprop_pdb_fallback") + else() + message(FATAL_ERROR "specify rust project suffix for new output approach ${output_approach}") + endif() + + set(lib_pdb_name "${lib_name}.pdb") + add_test(NAME output_directory_cdylib_pdb_${output_approach} + COMMAND + "${CMAKE_COMMAND}" + -P "${CMAKE_CURRENT_SOURCE_DIR}/../TestFileExists.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/build/${expected_lib_pdb_path}/${config_path_str}${lib_pdb_name}" + ) + set_tests_properties("output_directory_cdylib_pdb_${output_approach}" PROPERTIES FIXTURES_REQUIRED "build_fixture_output_directory") + + set(bin_pdb_name "rust_bin${rust_proj_suffix}.pdb") + add_test(NAME output_directory_bin_pdb_${output_approach} + COMMAND + "${CMAKE_COMMAND}" + -P "${CMAKE_CURRENT_SOURCE_DIR}/../TestFileExists.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/build/${expected_bin_pdb_path}/${config_path_str}${bin_pdb_name}" + ) + set_tests_properties("output_directory_bin_pdb_${output_approach}" PROPERTIES FIXTURES_REQUIRED "build_fixture_output_directory") + endif() + endif() + +endforeach() + +add_test(NAME postbuild_custom_command + COMMAND + "${CMAKE_COMMAND}" + -P "${CMAKE_CURRENT_SOURCE_DIR}/../TestFileExists.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/build/another_dir/moved_bin" + ) +set_tests_properties("postbuild_custom_command" PROPERTIES FIXTURES_REQUIRED "build_fixture_output_directory") + +add_test(NAME "output_directory_cleanup" COMMAND "${CMAKE_COMMAND}" -E remove_directory "${CMAKE_CURRENT_BINARY_DIR}/build") +set_tests_properties("output_directory_cleanup" PROPERTIES FIXTURES_CLEANUP "build_fixture_output_directory") + +#################################### +# output_directory_config +#################################### + + + corrosion_tests_add_test(output_directory_config "consumer") + + set_tests_properties("output_directory_config_run_consumer" PROPERTIES PASS_REGULAR_EXPRESSION + "^Hello from output_directory_config_test_executable" + ) + diff --git a/libs/3rdparty/corrosion/test/output directory/output directory/CMakeLists.txt b/libs/3rdparty/corrosion/test/output directory/output directory/CMakeLists.txt new file mode 100644 index 00000000000..e0d29a3d8e7 --- /dev/null +++ b/libs/3rdparty/corrosion/test/output directory/output directory/CMakeLists.txt @@ -0,0 +1,58 @@ +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0) +include(../../test_header.cmake) + +corrosion_import_crate(MANIFEST_PATH proj1/Cargo.toml) + +# Note: The output directories defined here must be manually kept in sync with the expected test location. +set_target_properties(rust_bin1 + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/custom_bin_targetprop" + PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/custom_bin_pdb_targetprop" + +) +set_target_properties(rust_lib1 PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/custom_archive_targetprop") +set_target_properties(rust_lib1 + PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/custom_lib_targetprop" + PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/custom_lib_pdb_targetprop" +) + +add_custom_command(TARGET cargo-build_rust_bin1 POST_BUILD + COMMAND + ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/another_dir" + COMMAND + ${CMAKE_COMMAND} -E copy_if_different "$>" "${CMAKE_CURRENT_BINARY_DIR}/another_dir/moved_bin" + ) + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/custom_bin_var") +set(CMAKE_PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/custom_binlib_pdb_var") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/custom_archive_var") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/custom_lib_var") + +corrosion_import_crate(MANIFEST_PATH proj2/Cargo.toml) + +unset(CMAKE_RUNTIME_OUTPUT_DIRECTORY) +unset(CMAKE_PDB_OUTPUT_DIRECTORY) +unset(CMAKE_ARCHIVE_OUTPUT_DIRECTORY) +unset(CMAKE_LIBRARY_OUTPUT_DIRECTORY) +unset(CMAKE_PDB_OUTPUT_DIRECTORY) + +add_executable(consumer consumer.cpp) +add_dependencies(consumer cargo-build_rust_lib1 cargo-build_rust_lib2) + +target_link_libraries(consumer rust_lib1 rust_lib2) + + +corrosion_import_crate(MANIFEST_PATH proj3/Cargo.toml) + +# Note: The output directories defined here must be manually kept in sync with the expected test location. +set_target_properties(rust_bin3 + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/custom_bin_targetprop_pdb_fallback" +) +set_target_properties(rust_lib3 + PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/custom_archive_targetprop_pdb_fallback" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/custom_lib_targetprop_pdb_fallback" +) diff --git a/libs/3rdparty/corrosion/test/output directory/output directory/consumer.cpp b/libs/3rdparty/corrosion/test/output directory/output directory/consumer.cpp new file mode 100644 index 00000000000..fa943ba6557 --- /dev/null +++ b/libs/3rdparty/corrosion/test/output directory/output directory/consumer.cpp @@ -0,0 +1,16 @@ +#include +#include + +extern "C" unsigned int ret_12(); + + +int main(int argc, char *argv[]) +{ + std::cout << "HI\n"; + unsigned int a = ret_12(); + if (a != 12) { + return -1; + } + + return 0; +} diff --git a/libs/3rdparty/corrosion/test/output directory/output directory/proj1/Cargo.lock b/libs/3rdparty/corrosion/test/output directory/output directory/proj1/Cargo.lock new file mode 100644 index 00000000000..07e006c26b1 --- /dev/null +++ b/libs/3rdparty/corrosion/test/output directory/output directory/proj1/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust_package1" +version = "0.1.0" diff --git a/libs/3rdparty/corrosion/test/output directory/output directory/proj1/Cargo.toml b/libs/3rdparty/corrosion/test/output directory/output directory/proj1/Cargo.toml new file mode 100644 index 00000000000..0f3bc1bcca9 --- /dev/null +++ b/libs/3rdparty/corrosion/test/output directory/output directory/proj1/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "rust_package1" +version = "0.1.0" +edition = "2018" + +[lib] +name = "rust_lib1" +crate-type=["staticlib", "cdylib"] + +[[bin]] +name = "rust_bin1" diff --git a/libs/3rdparty/corrosion/test/output directory/output directory/proj1/src/bin/rust_bin1.rs b/libs/3rdparty/corrosion/test/output directory/output directory/proj1/src/bin/rust_bin1.rs new file mode 100644 index 00000000000..11c0291c8fe --- /dev/null +++ b/libs/3rdparty/corrosion/test/output directory/output directory/proj1/src/bin/rust_bin1.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world from test rust binary"); +} diff --git a/libs/3rdparty/corrosion/test/output directory/output directory/proj1/src/lib.rs b/libs/3rdparty/corrosion/test/output directory/output directory/proj1/src/lib.rs new file mode 100644 index 00000000000..cfadd0f9428 --- /dev/null +++ b/libs/3rdparty/corrosion/test/output directory/output directory/proj1/src/lib.rs @@ -0,0 +1,4 @@ +#[no_mangle] +pub extern "C" fn ret_12() -> u32 { + 12 +} diff --git a/libs/3rdparty/corrosion/test/output directory/output directory/proj2/Cargo.lock b/libs/3rdparty/corrosion/test/output directory/output directory/proj2/Cargo.lock new file mode 100644 index 00000000000..892d964165c --- /dev/null +++ b/libs/3rdparty/corrosion/test/output directory/output directory/proj2/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust_package2" +version = "0.1.0" diff --git a/libs/3rdparty/corrosion/test/output directory/output directory/proj2/Cargo.toml b/libs/3rdparty/corrosion/test/output directory/output directory/proj2/Cargo.toml new file mode 100644 index 00000000000..63df8d5ea78 --- /dev/null +++ b/libs/3rdparty/corrosion/test/output directory/output directory/proj2/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "rust_package2" +version = "0.1.0" +edition = "2018" + +[lib] +name = "rust_lib2" +crate-type=["staticlib", "cdylib"] + +[[bin]] +name = "rust_bin2" diff --git a/libs/3rdparty/corrosion/test/output directory/output directory/proj2/src/bin/rust_bin2.rs b/libs/3rdparty/corrosion/test/output directory/output directory/proj2/src/bin/rust_bin2.rs new file mode 100644 index 00000000000..11c0291c8fe --- /dev/null +++ b/libs/3rdparty/corrosion/test/output directory/output directory/proj2/src/bin/rust_bin2.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world from test rust binary"); +} diff --git a/libs/3rdparty/corrosion/test/output directory/output directory/proj2/src/lib.rs b/libs/3rdparty/corrosion/test/output directory/output directory/proj2/src/lib.rs new file mode 100644 index 00000000000..cfadd0f9428 --- /dev/null +++ b/libs/3rdparty/corrosion/test/output directory/output directory/proj2/src/lib.rs @@ -0,0 +1,4 @@ +#[no_mangle] +pub extern "C" fn ret_12() -> u32 { + 12 +} diff --git a/libs/3rdparty/corrosion/test/output directory/output directory/proj3/Cargo.lock b/libs/3rdparty/corrosion/test/output directory/output directory/proj3/Cargo.lock new file mode 100644 index 00000000000..b7a53967fa1 --- /dev/null +++ b/libs/3rdparty/corrosion/test/output directory/output directory/proj3/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust_package3" +version = "0.1.0" diff --git a/libs/3rdparty/corrosion/test/output directory/output directory/proj3/Cargo.toml b/libs/3rdparty/corrosion/test/output directory/output directory/proj3/Cargo.toml new file mode 100644 index 00000000000..79509fc9107 --- /dev/null +++ b/libs/3rdparty/corrosion/test/output directory/output directory/proj3/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "rust_package3" +version = "0.1.0" +edition = "2018" + +[lib] +name = "rust_lib3" +crate-type=["staticlib", "cdylib"] + +[[bin]] +name = "rust_bin3" diff --git a/libs/3rdparty/corrosion/test/output directory/output directory/proj3/src/bin/rust_bin3.rs b/libs/3rdparty/corrosion/test/output directory/output directory/proj3/src/bin/rust_bin3.rs new file mode 100644 index 00000000000..11c0291c8fe --- /dev/null +++ b/libs/3rdparty/corrosion/test/output directory/output directory/proj3/src/bin/rust_bin3.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world from test rust binary"); +} diff --git a/libs/3rdparty/corrosion/test/output directory/output directory/proj3/src/lib.rs b/libs/3rdparty/corrosion/test/output directory/output directory/proj3/src/lib.rs new file mode 100644 index 00000000000..cfadd0f9428 --- /dev/null +++ b/libs/3rdparty/corrosion/test/output directory/output directory/proj3/src/lib.rs @@ -0,0 +1,4 @@ +#[no_mangle] +pub extern "C" fn ret_12() -> u32 { + 12 +} diff --git a/libs/3rdparty/corrosion/test/output directory/output_directory_config/CMakeLists.txt b/libs/3rdparty/corrosion/test/output directory/output_directory_config/CMakeLists.txt new file mode 100644 index 00000000000..db44ba6dd8f --- /dev/null +++ b/libs/3rdparty/corrosion/test/output directory/output_directory_config/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0) +include(../../test_header.cmake) + +corrosion_import_crate(MANIFEST_PATH proj1/Cargo.toml) + +# Note: The output directories defined here must be manually kept in sync with the expected test location. +set_target_properties(rust_bin1 + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$/bin" + PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$/bin" +) + +set_target_properties(rust_lib1 PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$/lib") +set_target_properties(rust_lib1 + PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$/lib" + PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$/lib" +) + +add_executable(consumer consumer.cpp) +add_dependencies(consumer cargo-build_rust_lib1) +target_link_libraries(consumer rust_lib1) diff --git a/libs/3rdparty/corrosion/test/output directory/output_directory_config/consumer.cpp b/libs/3rdparty/corrosion/test/output directory/output_directory_config/consumer.cpp new file mode 100644 index 00000000000..b70f1534423 --- /dev/null +++ b/libs/3rdparty/corrosion/test/output directory/output_directory_config/consumer.cpp @@ -0,0 +1,16 @@ +#include +#include + +extern "C" unsigned int ret_12(); + + +int main(int argc, char *argv[]) +{ + std::cout << "Hello from output_directory_config_test_executable\n"; + unsigned int a = ret_12(); + if (a != 12) { + return -1; + } + + return 0; +} diff --git a/libs/3rdparty/corrosion/test/output directory/output_directory_config/proj1/Cargo.lock b/libs/3rdparty/corrosion/test/output directory/output_directory_config/proj1/Cargo.lock new file mode 100644 index 00000000000..07e006c26b1 --- /dev/null +++ b/libs/3rdparty/corrosion/test/output directory/output_directory_config/proj1/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust_package1" +version = "0.1.0" diff --git a/libs/3rdparty/corrosion/test/output directory/output_directory_config/proj1/Cargo.toml b/libs/3rdparty/corrosion/test/output directory/output_directory_config/proj1/Cargo.toml new file mode 100644 index 00000000000..0f3bc1bcca9 --- /dev/null +++ b/libs/3rdparty/corrosion/test/output directory/output_directory_config/proj1/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "rust_package1" +version = "0.1.0" +edition = "2018" + +[lib] +name = "rust_lib1" +crate-type=["staticlib", "cdylib"] + +[[bin]] +name = "rust_bin1" diff --git a/libs/3rdparty/corrosion/test/output directory/output_directory_config/proj1/src/bin/rust_bin1.rs b/libs/3rdparty/corrosion/test/output directory/output_directory_config/proj1/src/bin/rust_bin1.rs new file mode 100644 index 00000000000..11c0291c8fe --- /dev/null +++ b/libs/3rdparty/corrosion/test/output directory/output_directory_config/proj1/src/bin/rust_bin1.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world from test rust binary"); +} diff --git a/libs/3rdparty/corrosion/test/output directory/output_directory_config/proj1/src/lib.rs b/libs/3rdparty/corrosion/test/output directory/output_directory_config/proj1/src/lib.rs new file mode 100644 index 00000000000..cfadd0f9428 --- /dev/null +++ b/libs/3rdparty/corrosion/test/output directory/output_directory_config/proj1/src/lib.rs @@ -0,0 +1,4 @@ +#[no_mangle] +pub extern "C" fn ret_12() -> u32 { + 12 +} diff --git a/libs/3rdparty/corrosion/test/override_crate_type/CMakeLists.txt b/libs/3rdparty/corrosion/test/override_crate_type/CMakeLists.txt new file mode 100644 index 00000000000..c246f77e1fb --- /dev/null +++ b/libs/3rdparty/corrosion/test/override_crate_type/CMakeLists.txt @@ -0,0 +1,9 @@ +corrosion_tests_add_test(override_crate_type "cpp-exe;cpp-exe-shared") + +set_tests_properties("override_crate_type_run_cpp-exe" PROPERTIES PASS_REGULAR_EXPRESSION + "^Hello, Cpp! I'm Rust!\r?\n$" + ) + +set_tests_properties("override_crate_type_run_cpp-exe-shared" PROPERTIES PASS_REGULAR_EXPRESSION + "^Hello, Cpp! I'm Rust!\r?\n$" + ) diff --git a/libs/3rdparty/corrosion/test/override_crate_type/override_crate_type/CMakeLists.txt b/libs/3rdparty/corrosion/test/override_crate_type/override_crate_type/CMakeLists.txt new file mode 100644 index 00000000000..8a465ab9a3d --- /dev/null +++ b/libs/3rdparty/corrosion/test/override_crate_type/override_crate_type/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0) +include(../../test_header.cmake) + +corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml OVERRIDE_CRATE_TYPE my_rust_lib=staticlib,cdylib) + +add_executable(cpp-exe main.cpp) +target_link_libraries(cpp-exe PUBLIC my_rust_lib) + +add_executable(cpp-exe-shared main.cpp) +target_link_libraries(cpp-exe-shared + PUBLIC my_rust_lib-shared) diff --git a/libs/3rdparty/corrosion/test/override_crate_type/override_crate_type/main.cpp b/libs/3rdparty/corrosion/test/override_crate_type/override_crate_type/main.cpp new file mode 100644 index 00000000000..785c0bc3aeb --- /dev/null +++ b/libs/3rdparty/corrosion/test/override_crate_type/override_crate_type/main.cpp @@ -0,0 +1,9 @@ +extern "C" void rust_function(char const *name); + +int main(int argc, char **argv) { + if (argc < 2) { + rust_function("Cpp"); + } else { + rust_function(argv[1]); + } +} diff --git a/libs/3rdparty/corrosion/test/override_crate_type/override_crate_type/rust/Cargo.lock b/libs/3rdparty/corrosion/test/override_crate_type/override_crate_type/rust/Cargo.lock new file mode 100644 index 00000000000..5dc1732e203 --- /dev/null +++ b/libs/3rdparty/corrosion/test/override_crate_type/override_crate_type/rust/Cargo.lock @@ -0,0 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "rust-lib" +version = "0.1.0" diff --git a/libs/3rdparty/corrosion/test/override_crate_type/override_crate_type/rust/Cargo.toml b/libs/3rdparty/corrosion/test/override_crate_type/override_crate_type/rust/Cargo.toml new file mode 100644 index 00000000000..d53defba740 --- /dev/null +++ b/libs/3rdparty/corrosion/test/override_crate_type/override_crate_type/rust/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "rust-lib" +version = "0.1.0" +authors = ["Andrew Gaspar "] +license = "MIT" +edition = "2018" + + +[lib] +name = "my_rust_lib" diff --git a/libs/3rdparty/corrosion/test/override_crate_type/override_crate_type/rust/build.rs b/libs/3rdparty/corrosion/test/override_crate_type/override_crate_type/rust/build.rs new file mode 100644 index 00000000000..9dfeaa0be1e --- /dev/null +++ b/libs/3rdparty/corrosion/test/override_crate_type/override_crate_type/rust/build.rs @@ -0,0 +1,4 @@ +// Build-scripts also need to be linked, so just add a dummy buildscript ensuring this works. +fn main() { + println!("Build-script is running.") +} diff --git a/libs/3rdparty/corrosion/test/override_crate_type/override_crate_type/rust/src/lib.rs b/libs/3rdparty/corrosion/test/override_crate_type/override_crate_type/rust/src/lib.rs new file mode 100644 index 00000000000..194e56507a2 --- /dev/null +++ b/libs/3rdparty/corrosion/test/override_crate_type/override_crate_type/rust/src/lib.rs @@ -0,0 +1,7 @@ +use std::os::raw::c_char; + +#[no_mangle] +pub extern "C" fn rust_function(name: *const c_char) { + let name = unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() }; + println!("Hello, {}! I'm Rust!", name); +} diff --git a/libs/3rdparty/corrosion/test/parse_target_triple/CMakeLists.txt b/libs/3rdparty/corrosion/test/parse_target_triple/CMakeLists.txt new file mode 100644 index 00000000000..f9924242f9e --- /dev/null +++ b/libs/3rdparty/corrosion/test/parse_target_triple/CMakeLists.txt @@ -0,0 +1,10 @@ +corrosion_tests_add_test(parse_target_triple "") +corrosion_tests_add_test(parse_target_triple_should_fail "") + +set_tests_properties("parse_target_triple_build" PROPERTIES FAIL_REGULAR_EXPRESSION + "CMake Warning at [^\r\n]*FindRust\.cmake:.*(\r)?\n[ \t]*Failed to parse target-triple `" + ) + +set_tests_properties("parse_target_triple_should_fail_build" PROPERTIES PASS_REGULAR_EXPRESSION + "CMake Warning at [^\r\n]*FindRust\.cmake:.*(\r)?\n[ \t]*Failed to parse target-triple `" + ) diff --git a/libs/3rdparty/corrosion/test/parse_target_triple/parse_target_triple/CMakeLists.txt b/libs/3rdparty/corrosion/test/parse_target_triple/parse_target_triple/CMakeLists.txt new file mode 100644 index 00000000000..25e9159b2cc --- /dev/null +++ b/libs/3rdparty/corrosion/test/parse_target_triple/parse_target_triple/CMakeLists.txt @@ -0,0 +1,106 @@ +# This test is supposed to ensure that the regex in _corrosion_parse_platform works as expected. +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0) +include(../../test_header.cmake) + +# Todo: Test if the output matches expectations. +_corrosion_parse_target_triple("../../blah/x86_64-unknown-custom-gnu.json" arch vendor os env) +_corrosion_parse_target_triple("x86_64-unknown-custom-gnu.json" arch vendor os env) +_corrosion_parse_target_triple("/path/to/x86_64-unknown-custom-musl.json" arch vendor os env) +_corrosion_parse_target_triple("../../blah/x86_64-custom_os.json" arch vendor os env) + +# List of builtin targets aquired via `rustup target list` with rust 1.64 on Linux. +set(rustup_shipped_targets + "aarch64-apple-darwin" + "aarch64-apple-ios" + "aarch64-apple-ios-sim" + "aarch64-fuchsia" + "aarch64-linux-android" + "aarch64-pc-windows-msvc" + "aarch64-unknown-linux-gnu" + "aarch64-unknown-linux-musl" + "aarch64-unknown-none" + "aarch64-unknown-none-softfloat" + "arm-linux-androideabi" + "arm-unknown-linux-gnueabi" + "arm-unknown-linux-gnueabihf" + "arm-unknown-linux-musleabi" + "arm-unknown-linux-musleabihf" + "armebv7r-none-eabi" + "armebv7r-none-eabihf" + "armv5te-unknown-linux-gnueabi" + "armv5te-unknown-linux-musleabi" + "armv7-linux-androideabi" + "armv7-unknown-linux-gnueabi" + "armv7-unknown-linux-gnueabihf" + "armv7-unknown-linux-musleabi" + "armv7-unknown-linux-musleabihf" + "armv7a-none-eabi" + "armv7r-none-eabi" + "armv7r-none-eabihf" + "asmjs-unknown-emscripten" + "i586-pc-windows-msvc" + "i586-unknown-linux-gnu" + "i586-unknown-linux-musl" + "i686-linux-android" + "i686-pc-windows-gnu" + "i686-pc-windows-msvc" + "i686-unknown-freebsd" + "i686-unknown-linux-gnu" + "i686-unknown-linux-musl" + "mips-unknown-linux-gnu" + "mips-unknown-linux-musl" + "mips64-unknown-linux-gnuabi64" + "mips64-unknown-linux-muslabi64" + "mips64el-unknown-linux-gnuabi64" + "mips64el-unknown-linux-muslabi64" + "mipsel-unknown-linux-gnu" + "mipsel-unknown-linux-musl" + "nvptx64-nvidia-cuda" + "powerpc-unknown-linux-gnu" + "powerpc64-unknown-linux-gnu" + "powerpc64le-unknown-linux-gnu" + "riscv32i-unknown-none-elf" + "riscv32imac-unknown-none-elf" + "riscv32imc-unknown-none-elf" + "riscv64gc-unknown-linux-gnu" + "riscv64gc-unknown-none-elf" + "riscv64imac-unknown-none-elf" + "s390x-unknown-linux-gnu" + "sparc64-unknown-linux-gnu" + "sparcv9-sun-solaris" + "thumbv6m-none-eabi" + "thumbv7em-none-eabi" + "thumbv7em-none-eabihf" + "thumbv7m-none-eabi" + "thumbv7neon-linux-androideabi" + "thumbv7neon-unknown-linux-gnueabihf" + "thumbv8m.base-none-eabi" + "thumbv8m.main-none-eabi" + "thumbv8m.main-none-eabihf" + "wasm32-unknown-emscripten" + "wasm32-unknown-unknown" + "wasm32-wasi" + "x86_64-apple-darwin" + "x86_64-apple-ios" + "x86_64-fortanix-unknown-sgx" + "x86_64-fuchsia" + "x86_64-linux-android" + "x86_64-pc-solaris" + "x86_64-pc-windows-gnu" + "x86_64-pc-windows-msvc" + "x86_64-sun-solaris" + "x86_64-unknown-freebsd" + "x86_64-unknown-illumos" + "x86_64-unknown-linux-gnu" + "x86_64-unknown-linux-gnux32" + "x86_64-unknown-linux-musl" + "x86_64-unknown-netbsd" + "x86_64-unknown-none" + "x86_64-unknown-redox" +) +set(other_targets riscv32imc-esp-espidf xtensa-esp32s3-none-elf) + +foreach(target ${rustup_shipped_targets} ${other_targets}) + _corrosion_parse_target_triple("${target}" arch vendor os env) +endforeach() diff --git a/libs/3rdparty/corrosion/test/parse_target_triple/parse_target_triple_should_fail/CMakeLists.txt b/libs/3rdparty/corrosion/test/parse_target_triple/parse_target_triple_should_fail/CMakeLists.txt new file mode 100644 index 00000000000..59d90e80058 --- /dev/null +++ b/libs/3rdparty/corrosion/test/parse_target_triple/parse_target_triple_should_fail/CMakeLists.txt @@ -0,0 +1,6 @@ +# This test is supposed to ensure that the regex in _corrosion_parse_platform works as expected. +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0) +include(../../test_header.cmake) + +_corrosion_parse_target_triple("x86_64-unknown-linux-gnu-toomuch" arch vendor os env) diff --git a/libs/3rdparty/corrosion/test/rust2cpp/CMakeLists.txt b/libs/3rdparty/corrosion/test/rust2cpp/CMakeLists.txt new file mode 100644 index 00000000000..4df9b288cd8 --- /dev/null +++ b/libs/3rdparty/corrosion/test/rust2cpp/CMakeLists.txt @@ -0,0 +1,9 @@ +corrosion_tests_add_test(rust2cpp "cpp-exe;cpp-exe-shared") + +set_tests_properties("rust2cpp_run_cpp-exe" PROPERTIES PASS_REGULAR_EXPRESSION + "^Hello, Cpp! I'm Rust!\r?\n$" + ) + +set_tests_properties("rust2cpp_run_cpp-exe-shared" PROPERTIES PASS_REGULAR_EXPRESSION + "^Hello, Cpp! I'm Rust!\r?\n$" + ) diff --git a/libs/3rdparty/corrosion/test/rust2cpp/rust2cpp/CMakeLists.txt b/libs/3rdparty/corrosion/test/rust2cpp/rust2cpp/CMakeLists.txt new file mode 100644 index 00000000000..e14de93a91b --- /dev/null +++ b/libs/3rdparty/corrosion/test/rust2cpp/rust2cpp/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0) +include(../../test_header.cmake) + +corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml) + +add_executable(cpp-exe main.cpp) +target_link_libraries(cpp-exe PUBLIC rust_lib) + +add_executable(cpp-exe-shared main.cpp) +target_link_libraries(cpp-exe-shared + PUBLIC rust_lib-shared) diff --git a/libs/3rdparty/corrosion/test/rust2cpp/rust2cpp/main.cpp b/libs/3rdparty/corrosion/test/rust2cpp/rust2cpp/main.cpp new file mode 100644 index 00000000000..785c0bc3aeb --- /dev/null +++ b/libs/3rdparty/corrosion/test/rust2cpp/rust2cpp/main.cpp @@ -0,0 +1,9 @@ +extern "C" void rust_function(char const *name); + +int main(int argc, char **argv) { + if (argc < 2) { + rust_function("Cpp"); + } else { + rust_function(argv[1]); + } +} diff --git a/libs/3rdparty/corrosion/test/rust2cpp/rust2cpp/rust/Cargo.lock b/libs/3rdparty/corrosion/test/rust2cpp/rust2cpp/rust/Cargo.lock new file mode 100644 index 00000000000..5dc1732e203 --- /dev/null +++ b/libs/3rdparty/corrosion/test/rust2cpp/rust2cpp/rust/Cargo.lock @@ -0,0 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "rust-lib" +version = "0.1.0" diff --git a/libs/3rdparty/corrosion/test/rust2cpp/rust2cpp/rust/Cargo.toml b/libs/3rdparty/corrosion/test/rust2cpp/rust2cpp/rust/Cargo.toml new file mode 100644 index 00000000000..ab91e62049e --- /dev/null +++ b/libs/3rdparty/corrosion/test/rust2cpp/rust2cpp/rust/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "rust-lib" +version = "0.1.0" +authors = ["Andrew Gaspar "] +license = "MIT" +edition = "2018" + +[dependencies] + +[lib] +crate-type=["staticlib", "cdylib"] diff --git a/libs/3rdparty/corrosion/test/rust2cpp/rust2cpp/rust/build.rs b/libs/3rdparty/corrosion/test/rust2cpp/rust2cpp/rust/build.rs new file mode 100644 index 00000000000..9dfeaa0be1e --- /dev/null +++ b/libs/3rdparty/corrosion/test/rust2cpp/rust2cpp/rust/build.rs @@ -0,0 +1,4 @@ +// Build-scripts also need to be linked, so just add a dummy buildscript ensuring this works. +fn main() { + println!("Build-script is running.") +} diff --git a/libs/3rdparty/corrosion/test/rust2cpp/rust2cpp/rust/src/lib.rs b/libs/3rdparty/corrosion/test/rust2cpp/rust2cpp/rust/src/lib.rs new file mode 100644 index 00000000000..194e56507a2 --- /dev/null +++ b/libs/3rdparty/corrosion/test/rust2cpp/rust2cpp/rust/src/lib.rs @@ -0,0 +1,7 @@ +use std::os::raw::c_char; + +#[no_mangle] +pub extern "C" fn rust_function(name: *const c_char) { + let name = unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() }; + println!("Hello, {}! I'm Rust!", name); +} diff --git a/libs/3rdparty/corrosion/test/rustflags/CMakeLists.txt b/libs/3rdparty/corrosion/test/rustflags/CMakeLists.txt new file mode 100644 index 00000000000..fd2ea529749 --- /dev/null +++ b/libs/3rdparty/corrosion/test/rustflags/CMakeLists.txt @@ -0,0 +1,7 @@ +corrosion_tests_add_test(rustflags "rustflags-cpp-exe") + +set_tests_properties("rustflags_run_rustflags-cpp-exe" PROPERTIES PASS_REGULAR_EXPRESSION + "Hello, Cpp! I'm Rust!\r?\nHello, Cpp again! I'm Rust in (Debug|Release) mode again!\r?\nHello, Cpp again! I'm Rust again, third time the charm!\r?\n$" + ) + +corrosion_tests_add_test(cargo_config_rustflags "cargo_config_rustflags") diff --git a/libs/3rdparty/corrosion/test/rustflags/cargo_config_rustflags/.cargo/config.toml b/libs/3rdparty/corrosion/test/rustflags/cargo_config_rustflags/.cargo/config.toml new file mode 100644 index 00000000000..fb683000eaf --- /dev/null +++ b/libs/3rdparty/corrosion/test/rustflags/cargo_config_rustflags/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +rustflags = ["--cfg=some_cargo_config_rustflag"] diff --git a/libs/3rdparty/corrosion/test/rustflags/cargo_config_rustflags/CMakeLists.txt b/libs/3rdparty/corrosion/test/rustflags/cargo_config_rustflags/CMakeLists.txt new file mode 100644 index 00000000000..507bde8c66f --- /dev/null +++ b/libs/3rdparty/corrosion/test/rustflags/cargo_config_rustflags/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0) +include(../../test_header.cmake) + +corrosion_import_crate(MANIFEST_PATH Cargo.toml) + +# Do not use `corrosion_add_target_rustflags()` here, since we want to test if the rustflag from `.cargo/config.toml` +# is picked up. + +# Local rustflags should not interfere with `.cargo/config.toml`, so enable one. +corrosion_add_target_local_rustflags(cargo_config_rustflags "--cfg=local_rustflag") diff --git a/libs/3rdparty/corrosion/test/rustflags/cargo_config_rustflags/Cargo.lock b/libs/3rdparty/corrosion/test/rustflags/cargo_config_rustflags/Cargo.lock new file mode 100644 index 00000000000..906ca11417d --- /dev/null +++ b/libs/3rdparty/corrosion/test/rustflags/cargo_config_rustflags/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cargo_config_rustflags" +version = "0.1.0" diff --git a/libs/3rdparty/corrosion/test/rustflags/cargo_config_rustflags/Cargo.toml b/libs/3rdparty/corrosion/test/rustflags/cargo_config_rustflags/Cargo.toml new file mode 100644 index 00000000000..298b193e993 --- /dev/null +++ b/libs/3rdparty/corrosion/test/rustflags/cargo_config_rustflags/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "cargo_config_rustflags" +version = "0.1.0" +edition = "2018" diff --git a/libs/3rdparty/corrosion/test/rustflags/cargo_config_rustflags/src/main.rs b/libs/3rdparty/corrosion/test/rustflags/cargo_config_rustflags/src/main.rs new file mode 100644 index 00000000000..f4919bb1d4f --- /dev/null +++ b/libs/3rdparty/corrosion/test/rustflags/cargo_config_rustflags/src/main.rs @@ -0,0 +1,16 @@ + +#[cfg(some_cargo_config_rustflag)] +fn print_line() { + println!("Rustflag is enabled"); +} + +// test that local rustflags don't override global rustflags set via `.cargo/config` +#[cfg(local_rustflag)] +fn test_local_rustflag() { + println!("local_rustflag was enabled"); +} + +fn main() { + print_line(); + test_local_rustflag(); +} diff --git a/libs/3rdparty/corrosion/test/rustflags/rustflags/CMakeLists.txt b/libs/3rdparty/corrosion/test/rustflags/rustflags/CMakeLists.txt new file mode 100644 index 00000000000..9a4f25cd319 --- /dev/null +++ b/libs/3rdparty/corrosion/test/rustflags/rustflags/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0) +include(../../test_header.cmake) + +corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml) + +add_executable(rustflags-cpp-exe main.cpp) +target_link_libraries(rustflags-cpp-exe PUBLIC rustflag_test_lib) + +# Test --cfg=key="value" rustflag. +corrosion_add_target_rustflags(rustflag_test_lib --cfg=test_rustflag_cfg1="test_rustflag_cfg1_value") + +# Test using a generator expression to produce a rustflag and passing multiple rustflags. +corrosion_add_target_rustflags(rustflag_test_lib + --cfg=test_rustflag_cfg2="$,$>,debug,release>" + "--cfg=test_rustflag_cfg3" +) + +corrosion_add_target_local_rustflags(rustflag_test_lib "--cfg=test_local_rustflag1") +corrosion_add_target_local_rustflags(rustflag_test_lib --cfg=test_local_rustflag2="value") diff --git a/libs/3rdparty/corrosion/test/rustflags/rustflags/main.cpp b/libs/3rdparty/corrosion/test/rustflags/rustflags/main.cpp new file mode 100644 index 00000000000..0b9b1b92ac2 --- /dev/null +++ b/libs/3rdparty/corrosion/test/rustflags/rustflags/main.cpp @@ -0,0 +1,13 @@ +extern "C" void rust_function(char const *name); +extern "C" void rust_second_function(char const *name); +extern "C" void rust_third_function(char const *name); + +int main(int argc, char **argv) { + if (argc < 2) { + rust_function("Cpp"); + rust_second_function("Cpp again"); + rust_third_function("Cpp again"); + } else { + rust_function(argv[1]); + } +} diff --git a/libs/3rdparty/corrosion/test/rustflags/rustflags/rust/Cargo.lock b/libs/3rdparty/corrosion/test/rustflags/rustflags/rust/Cargo.lock new file mode 100644 index 00000000000..333ce249d04 --- /dev/null +++ b/libs/3rdparty/corrosion/test/rustflags/rustflags/rust/Cargo.lock @@ -0,0 +1,14 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rustflag-test-lib" +version = "0.1.0" +dependencies = [ + "some_dependency", +] + +[[package]] +name = "some_dependency" +version = "0.1.0" diff --git a/libs/3rdparty/corrosion/test/rustflags/rustflags/rust/Cargo.toml b/libs/3rdparty/corrosion/test/rustflags/rustflags/rust/Cargo.toml new file mode 100644 index 00000000000..2bdd26f769b --- /dev/null +++ b/libs/3rdparty/corrosion/test/rustflags/rustflags/rust/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "rustflag-test-lib" +version = "0.1.0" +license = "MIT" +edition = "2018" + +[dependencies] +some_dependency = { path = "some_dependency" } + +[lib] +crate-type=["staticlib"] diff --git a/libs/3rdparty/corrosion/test/rustflags/rustflags/rust/some_dependency/Cargo.toml b/libs/3rdparty/corrosion/test/rustflags/rustflags/rust/some_dependency/Cargo.toml new file mode 100644 index 00000000000..94627d03670 --- /dev/null +++ b/libs/3rdparty/corrosion/test/rustflags/rustflags/rust/some_dependency/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "some_dependency" +version = "0.1.0" +license = "MIT" +edition = "2018" + diff --git a/libs/3rdparty/corrosion/test/rustflags/rustflags/rust/some_dependency/src/lib.rs b/libs/3rdparty/corrosion/test/rustflags/rustflags/rust/some_dependency/src/lib.rs new file mode 100644 index 00000000000..d240a7caabb --- /dev/null +++ b/libs/3rdparty/corrosion/test/rustflags/rustflags/rust/some_dependency/src/lib.rs @@ -0,0 +1,10 @@ +//! Test that the local rustflags are only passed to the main crate and not to dependencies. +#[cfg(test_local_rustflag1)] +const _: [(); 1] = [(); 2]; + +#[cfg(test_local_rustflag2 = "value")] +const _: [(); 1] = [(); 2]; + +pub fn some_function() -> u32 { + 42 +} diff --git a/libs/3rdparty/corrosion/test/rustflags/rustflags/rust/src/lib.rs b/libs/3rdparty/corrosion/test/rustflags/rustflags/rust/src/lib.rs new file mode 100644 index 00000000000..f6da1f6e139 --- /dev/null +++ b/libs/3rdparty/corrosion/test/rustflags/rustflags/rust/src/lib.rs @@ -0,0 +1,40 @@ +#[cfg(test_rustflag_cfg1 = "test_rustflag_cfg1_value")] +use std::os::raw::c_char; + +#[no_mangle] +#[cfg(test_rustflag_cfg1 = "test_rustflag_cfg1_value")] +pub extern "C" fn rust_function(name: *const c_char) { + let name = unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() }; + println!("Hello, {}! I'm Rust!", name); +} + +#[no_mangle] +#[cfg(all(debug_assertions, test_rustflag_cfg2 = "debug"))] +pub extern "C" fn rust_second_function(name: *const c_char) { + let name = unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() }; + println!("Hello, {}! I'm Rust in Debug mode again!", name); +} + +#[no_mangle] +#[cfg(all(not(debug_assertions), test_rustflag_cfg2 = "release"))] +pub extern "C" fn rust_second_function(name: *const c_char) { + let name = unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() }; + println!("Hello, {}! I'm Rust in Release mode again!", name); +} + +#[no_mangle] +#[cfg(test_rustflag_cfg3)] +pub extern "C" fn rust_third_function(name: *const c_char) { + let name = unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() }; + println!("Hello, {}! I'm Rust again, third time the charm!", name); + assert_eq!(some_dependency::some_function(), 42); +} + +#[cfg(not(test_rustflag_cfg3))] +const _: [(); 1] = [(); 2]; + +#[cfg(not(test_local_rustflag1))] +const _: [(); 1] = [(); 2]; + +#[cfg(not(test_local_rustflag2 = "value"))] +const _: [(); 1] = [(); 2]; diff --git a/libs/3rdparty/corrosion/test/workspace/CMakeLists.txt b/libs/3rdparty/corrosion/test/workspace/CMakeLists.txt new file mode 100644 index 00000000000..39bec842c76 --- /dev/null +++ b/libs/3rdparty/corrosion/test/workspace/CMakeLists.txt @@ -0,0 +1,6 @@ +corrosion_tests_add_test(workspace "my_program") + +set_tests_properties("workspace_run_my_program" PROPERTIES PASS_REGULAR_EXPRESSION + "^Ok\r?\n$" + ) + diff --git a/libs/3rdparty/corrosion/test/workspace/workspace/CMakeLists.txt b/libs/3rdparty/corrosion/test/workspace/workspace/CMakeLists.txt new file mode 100644 index 00000000000..71a8c7d8f91 --- /dev/null +++ b/libs/3rdparty/corrosion/test/workspace/workspace/CMakeLists.txt @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 3.15) +project(test_project VERSION 0.1.0) +include(../../test_header.cmake) + +corrosion_import_crate( + MANIFEST_PATH ${CMAKE_CURRENT_SOURCE_DIR}/Cargo.toml + CRATES member1 member2 + IMPORTED_CRATES imported_crate_list +) + +#NOTE: member3 also contains a binary called my_program, but that shouldn't be a problem since it is not imported +add_executable(my_program main.cpp) +target_link_libraries(my_program PUBLIC member1 member2) + +# Test that the list of imported crates matches our expectations. +if(NOT DEFINED imported_crate_list) + message(FATAL_ERROR "Corrosion failed to set the variable passed via IMPORTED_CRATES.") +endif() +set(expected_crates member1 member2) +foreach(crate ${expected_crates}) + if(NOT "${crate}" IN_LIST imported_crate_list) + message(FATAL_ERROR "Expected ${crate} to be imported, but it wasn't. Imported crate list:\n" + "${imported_crate_list}" + ) + endif() +endforeach() +set(additional_crates ${imported_crate_list}) +list(REMOVE_ITEM additional_crates ${expected_crates}) +if(additional_crates) + message(FATAL_ERROR "Corrosion unexpectedly imported the following crates: ${additional_crates}") +endif() + diff --git a/libs/3rdparty/corrosion/test/workspace/workspace/Cargo.lock b/libs/3rdparty/corrosion/test/workspace/workspace/Cargo.lock new file mode 100644 index 00000000000..d99a3234ef7 --- /dev/null +++ b/libs/3rdparty/corrosion/test/workspace/workspace/Cargo.lock @@ -0,0 +1,18 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "member1" +version = "0.1.0" + +[[package]] +name = "member2" +version = "0.1.0" + +[[package]] +name = "member3" +version = "0.1.0" +dependencies = [ + "member1", +] diff --git a/libs/3rdparty/corrosion/test/workspace/workspace/Cargo.toml b/libs/3rdparty/corrosion/test/workspace/workspace/Cargo.toml new file mode 100644 index 00000000000..997ca5e2407 --- /dev/null +++ b/libs/3rdparty/corrosion/test/workspace/workspace/Cargo.toml @@ -0,0 +1,5 @@ +[workspace] +members=["member1", "member2", "member3"] + +[workspace.package] +version = "0.1.0" diff --git a/libs/3rdparty/corrosion/test/workspace/workspace/main.cpp b/libs/3rdparty/corrosion/test/workspace/workspace/main.cpp new file mode 100644 index 00000000000..5102b28e69f --- /dev/null +++ b/libs/3rdparty/corrosion/test/workspace/workspace/main.cpp @@ -0,0 +1,4 @@ +#include +int main() { + std::cout << "Ok"; +} diff --git a/libs/3rdparty/corrosion/test/workspace/workspace/member1/Cargo.toml b/libs/3rdparty/corrosion/test/workspace/workspace/member1/Cargo.toml new file mode 100644 index 00000000000..b8a4d0a6d52 --- /dev/null +++ b/libs/3rdparty/corrosion/test/workspace/workspace/member1/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "member1" +version = "0.1.0" +edition = "2018" +description = "descr;\"hello\\" + +[lib] +crate-type = [ "lib", "cdylib" ] diff --git a/libs/3rdparty/corrosion/test/workspace/workspace/member1/src/lib.rs b/libs/3rdparty/corrosion/test/workspace/workspace/member1/src/lib.rs new file mode 100644 index 00000000000..31e1bb209f9 --- /dev/null +++ b/libs/3rdparty/corrosion/test/workspace/workspace/member1/src/lib.rs @@ -0,0 +1,7 @@ +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} diff --git a/libs/3rdparty/corrosion/test/workspace/workspace/member2/Cargo.toml b/libs/3rdparty/corrosion/test/workspace/workspace/member2/Cargo.toml new file mode 100644 index 00000000000..9fd2fe4238c --- /dev/null +++ b/libs/3rdparty/corrosion/test/workspace/workspace/member2/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "member2" +version = "0.1.0" +authors = ["Olivier Goffart "] +edition = "2018" + +[lib] +crate-type = ["staticlib"] diff --git a/libs/3rdparty/corrosion/test/workspace/workspace/member2/src/lib.rs b/libs/3rdparty/corrosion/test/workspace/workspace/member2/src/lib.rs new file mode 100644 index 00000000000..31e1bb209f9 --- /dev/null +++ b/libs/3rdparty/corrosion/test/workspace/workspace/member2/src/lib.rs @@ -0,0 +1,7 @@ +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} diff --git a/libs/3rdparty/corrosion/test/workspace/workspace/member3/Cargo.toml b/libs/3rdparty/corrosion/test/workspace/workspace/member3/Cargo.toml new file mode 100644 index 00000000000..ac7ef1f58de --- /dev/null +++ b/libs/3rdparty/corrosion/test/workspace/workspace/member3/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "member3" +version = "0.1.0" +authors = ["Olivier Goffart "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[[bin]] +name = "my_program" +path = "src/main.rs" + +[dependencies] +member1 = { path = "../member1" } diff --git a/libs/3rdparty/corrosion/test/workspace/workspace/member3/src/main.rs b/libs/3rdparty/corrosion/test/workspace/workspace/member3/src/main.rs new file mode 100644 index 00000000000..e7a11a969c0 --- /dev/null +++ b/libs/3rdparty/corrosion/test/workspace/workspace/member3/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +}