- Update corrosion transitional_engine
authorunC0Rr
Wed, 20 Nov 2024 21:37:47 +0100
branchtransitional_engine
changeset 16038 d903f8d2395a
parent 16036 7b8d96fc8799
child 16042 14b83df1832b
- Update corrosion - Implement installation of targets imported with corrosion
CMakeLists.txt
tools/corrosion/.github/actions/setup_test/action.yaml
tools/corrosion/.github/scripts/toolchains/aarch64-apple-darwin-clang.cmake
tools/corrosion/.github/scripts/toolchains/aarch64-unknown-linux-gnu-clang.cmake
tools/corrosion/.github/scripts/toolchains/aarch64-unknown-linux-gnu-gcc.cmake
tools/corrosion/.github/scripts/toolchains/i686-unknown-linux-gnu-clang.cmake
tools/corrosion/.github/scripts/toolchains/i686-unknown-linux-gnu-gcc.cmake
tools/corrosion/.github/scripts/toolchains/x86_64-apple-darwin-clang.cmake
tools/corrosion/.github/scripts/toolchains/x86_64-pc-windows-gnullvm.cmake
tools/corrosion/.github/scripts/toolchains/x86_64-unknown-linux-gnu-clang.cmake
tools/corrosion/.github/scripts/toolchains/x86_64-unknown-linux-gnu-gcc.cmake
tools/corrosion/.github/workflows/gh-pages.yaml
tools/corrosion/.github/workflows/linux.yaml
tools/corrosion/.github/workflows/test.yaml
tools/corrosion/.github/workflows/test_legacy.yaml
tools/corrosion/.github/workflows/visual_studio.yaml
tools/corrosion/.gitignore
tools/corrosion/CMakeLists.txt
tools/corrosion/CMakePresets.json
tools/corrosion/README.md
tools/corrosion/RELEASES.md
tools/corrosion/cmake/Corrosion.cmake
tools/corrosion/cmake/CorrosionConfig.cmake.in
tools/corrosion/cmake/CorrosionGenerator.cmake
tools/corrosion/cmake/FindRust.cmake
tools/corrosion/doc/book.toml
tools/corrosion/doc/src/introduction.md
tools/corrosion/doc/src/quick_start.md
tools/corrosion/doc/src/usage.md
tools/corrosion/generator/CMakeLists.txt
tools/corrosion/generator/Cargo.toml
tools/corrosion/generator/Compat.Cargo.toml
tools/corrosion/generator/src/main.rs
tools/corrosion/generator/src/subcommands/gen_cmake.rs
tools/corrosion/generator/src/subcommands/gen_cmake/target.rs
tools/corrosion/test/CMakeLists.txt
tools/corrosion/test/ConfigureAndBuild.cmake
tools/corrosion/test/cbindgen/CMakeLists.txt
tools/corrosion/test/cbindgen/rust2cpp/main.cpp
tools/corrosion/test/cbindgen/rust2cpp/rust/cbindgen.toml
tools/corrosion/test/cbindgen/rust2cpp/rust/src/ffi.rs
tools/corrosion/test/cbindgen/rust2cpp/rust/src/lib.rs
tools/corrosion/test/cbindgen/rust2cpp/rust/src/other_mod/mod.rs
tools/corrosion/test/corrosion_install/CMakeLists.txt
tools/corrosion/test/corrosion_install/install_lib/CMakeLists.txt
tools/corrosion/test/corrosion_install/install_lib/main.cpp
tools/corrosion/test/corrosion_install/install_lib/rust_lib/CMakeLists.txt
tools/corrosion/test/corrosion_install/install_lib/rust_lib/Cargo.toml
tools/corrosion/test/corrosion_install/install_lib/rust_lib/include/rust_lib/rust_lib.hpp
tools/corrosion/test/corrosion_install/install_lib/rust_lib/src/lib.rs
tools/corrosion/test/corrosion_install/install_rust_bin/CMakeLists.txt
tools/corrosion/test/corrosion_install/install_rust_bin/rust_bin/CMakeLists.txt
tools/corrosion/test/corrosion_install/install_rust_bin/rust_bin/Cargo.toml
tools/corrosion/test/corrosion_install/install_rust_bin/rust_bin/src/main.rs
tools/corrosion/test/external_corrosion_generator/CMakeLists.txt
tools/corrosion/test/external_corrosion_generator/ExternalCorrosionGenerator/CMakeLists.txt
tools/corrosion/test/external_corrosion_generator/ExternalCorrosionGenerator/Test.cmake
tools/corrosion/test/hostbuild/CMakeLists.txt
tools/corrosion/test/output directory/CMakeLists.txt
tools/corrosion/test/output directory/output directory/CMakeLists.txt
tools/corrosion/test/output directory/output directory/proj3/Cargo.toml
tools/corrosion/test/output directory/output directory/proj3/src/lib.rs
tools/corrosion/test/override_crate_type/CMakeLists.txt
tools/corrosion/test/override_crate_type/override_crate_type/CMakeLists.txt
tools/corrosion/test/override_crate_type/override_crate_type/main.cpp
tools/corrosion/test/override_crate_type/override_crate_type/rust/Cargo.toml
tools/corrosion/test/override_crate_type/override_crate_type/rust/build.rs
tools/corrosion/test/override_crate_type/override_crate_type/rust/src/lib.rs
--- a/CMakeLists.txt	Wed Sep 18 14:10:51 2024 +0200
+++ b/CMakeLists.txt	Wed Nov 20 21:37:47 2024 +0100
@@ -269,7 +269,8 @@
 #rust libraries
 add_subdirectory(tools/corrosion)
 corrosion_import_crate(MANIFEST_PATH rust/lib-hwengine-future/Cargo.toml)
-
+corrosion_install(TARGETS hwengine_future EXPORT hwengine_future_install_target)
+install(EXPORT hwengine_future_install_target DESTINATION ${target_library_install_dir})
 
 #maybe this could be merged inside hedgewars/CMakeLists.txt
 if(BUILD_ENGINE_C)
--- a/tools/corrosion/.github/actions/setup_test/action.yaml	Wed Sep 18 14:10:51 2024 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,184 +0,0 @@
-name: Setup Corrosion Tests
-description: "Internal helper action to setup the Environment for Corrosions tests"
-inputs:
-  target_arch:
-    required: true
-    description: CMake target architecture
-  abi:
-    required: false
-    description: msvc, gnu or darwin
-    default: default
-  cmake:
-    required: true
-    description: Cmake version
-  rust:
-    required: true
-    description: Rust version
-  generator:
-    required: true
-    description: CMake Generator (e.g Ninja)
-  build_dir:
-    required: true
-    description: Path of the CMake build directory
-  configure_params:
-    required: false
-    description: Additional parameters to pass to CMake configure step
-  install_path:
-    required: false
-    description: CMake install prefix
-    default: ""
-  compiler:
-    required: false
-    description: Compiler to use. Valid options are clang, gcc, cl, default, or an empty string.
-    default: "default"
-
-runs:
-  using: composite
-  steps:
-    - name: Cache Cargo registry
-      id: cache-registry
-      uses: actions/cache@v4
-      with:
-        path: ~/.cargo/registry
-        key: ${{ runner.os }}-cargo-registry
-    - name: Determine Rust OS
-      id: determine_rust_os
-      shell: bash
-      run: |
-        if [ "${{ runner.os }}" == "Windows" ]; then
-          echo "os=pc-windows" >> $GITHUB_OUTPUT
-          echo "host_abi=msvc" >> $GITHUB_OUTPUT
-        elif [ "${{ runner.os }}" == "Linux" ]; then
-          echo "os=unknown-linux" >> $GITHUB_OUTPUT
-          echo "host_abi=gnu" >> $GITHUB_OUTPUT
-        elif [ "${{ runner.os }}" == "macOS" ]; then
-          echo "os=apple" >> $GITHUB_OUTPUT
-          echo "host_abi=darwin" >> $GITHUB_OUTPUT
-        fi
-    - name: Determine Rust ABI
-      id: determine_abi
-      shell: bash
-      run: |
-        if [[ ! ( -z "${{ inputs.abi }}" || "${{ inputs.abi }}" == "default" ) ]]; then
-           echo "abi=${{ inputs.abi }}" >> $GITHUB_OUTPUT
-         elif [ "${{ runner.os }}" == "Linux" ]; then
-           echo "abi=gnu" >> $GITHUB_OUTPUT
-         elif [ "${{ runner.os }}" == "macOS" ]; then
-           echo "abi=darwin" >> $GITHUB_OUTPUT
-         else 
-           echo "abi=msvc" >> $GITHUB_OUTPUT
-         fi
-    - name: Determine if Cross-compiling
-      id: determine_cross_compile
-      shell: bash
-      run: |
-        # For now it is safe to assume that all github runners are x86_64
-        if [[ "${{ inputs.target_arch }}" != "x86_64" ]]; then
-          echo "Cross-Compiling to ${{ inputs.target_arch }}"
-          if [[ "${{ runner.os }}" == "macOS" ]]; then
-            echo "system_name=-DCMAKE_SYSTEM_NAME=Darwin" >> $GITHUB_OUTPUT
-          else
-            # Either `Linux` or `Windows`
-            echo "system_name=-DCMAKE_SYSTEM_NAME=${{ runner.os }}" >> $GITHUB_OUTPUT
-          fi
-        fi
-    - name: Pick Compiler
-      id: pick_compiler
-      shell: bash
-      run: > 
-        ./.github/scripts/determine_compiler.sh 
-        "${{ inputs.compiler }}"
-        "${{ runner.os }}"
-        "${{ steps.determine_abi.outputs.abi }}"
-        "${{steps.determine_cross_compile.outputs.system_name}}"
-        "${{inputs.target_arch}}"
-    - name: Pick Generator
-      id: pick_generator
-      shell: bash
-      run: |
-        if [ "${{ inputs.generator }}" == "ninja" ]; then
-          echo "generator=-GNinja" >> $GITHUB_OUTPUT
-        elif [ "${{ inputs.generator }}" == "ninja-multiconfig" ];then
-          echo "generator=-GNinja Multi-Config" >> $GITHUB_OUTPUT
-        fi
-    - name: Arch Flags
-      id: arch_flags
-      shell: bash
-      run: | # Cross-compiling is currently only supported on Windows+MSVC with the default generator
-        if [ "${{ runner.os }}" == "Windows" ]; then
-          if [ "${{inputs.generator}}" == "default" ]; then
-            if [ "${{ inputs.target_arch }}" == "x86_64" ]; then
-              echo "msvc=amd64" >> $GITHUB_OUTPUT
-              echo "cmake=-Ax64" >> $GITHUB_OUTPUT
-            elif [ "${{ inputs.target_arch }}" == "i686" ]; then
-              echo "msvc=amd64_x86" >> $GITHUB_OUTPUT
-              echo "cmake=-AWin32" >> $GITHUB_OUTPUT
-            elif [ "${{ inputs.target_arch }}" == "aarch64" ]; then
-              echo "msvc=amd64_arm64" >> $GITHUB_OUTPUT
-              echo "cmake=-AARM64" >> $GITHUB_OUTPUT
-            fi
-          elif [ "${{inputs.generator}}" == "ninja" ]; then
-            # We don't do cross-compiling builds with Ninja
-            # Todo: Why not (cross-compile)?
-            echo "msvc=amd64" >> $GITHUB_OUTPUT
-          fi
-        elif [ "${{ runner.os }}" == "Linux" ]; then
-          echo "cmake=-DRust_CARGO_TARGET=${{inputs.target_arch}}-${{steps.determine_rust_os.outputs.os}}-${{steps.determine_abi.outputs.abi}}" >> $GITHUB_OUTPUT
-        fi
-    - name: Determine Install Prefix
-      id: install_prefix
-      shell: bash
-      run: |
-        if [ ! -z "${{ inputs.install_path }}" ]; then
-          echo "install_path=-DCMAKE_INSTALL_PREFIX=${{ inputs.install_path }}" >> $GITHUB_OUTPUT
-        fi
-    - name: Setup MSVC Development Environment
-      uses: ilammy/msvc-dev-cmd@v1
-      with:
-        arch: ${{ steps.arch_flags.outputs.msvc }}
-      if: ${{ 'msvc' == steps.determine_abi.outputs.abi }}
-    - 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}}-${{steps.determine_rust_os.outputs.os}}-${{steps.determine_abi.outputs.abi}}
-    - name: Install Cross Compiler
-      shell: bash
-      run: |
-        if [[ "${{ inputs.target_arch }}" != 'x86_64' ]]; then
-          echo "::group::apt-install"
-          sudo apt-get update
-          sudo apt-get install -y g++-$(echo "${{inputs.target_arch}}" | tr _ -)-linux-gnu
-          echo "::endgroup::"
-        fi
-      if: ${{ 'Linux' == runner.os }}
-    - name: Determine Configure Shell
-      id: configure_shell
-      shell: bash
-      run: |
-        if [ "${{ runner.os }}" == "Windows" ]; then
-            echo "shell=pwsh" >> $GITHUB_OUTPUT
-        else
-            echo "shell=bash" >> $GITHUB_OUTPUT
-        fi
-    - name: Configure
-      shell: ${{steps.configure_shell.outputs.shell}}
-      run: >
-        cmake
-        "-S."
-        "-B${{inputs.build_dir}}"
-        "-DCORROSION_VERBOSE_OUTPUT=ON"
-        "${{steps.arch_flags.outputs.cmake}}"
-        "${{steps.pick_compiler.outputs.c_compiler}}"
-        "${{steps.pick_compiler.outputs.cxx_compiler}}"
-        "${{steps.determine_cross_compile.outputs.system_name}}"
-        "${{steps.pick_generator.outputs.generator}}"
-        ${{steps.install_prefix.outputs.install_path}}
-        "-DRust_TOOLCHAIN=${{steps.install_rust.outputs.name}}"
-        ${{ inputs.configure_params }}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.github/scripts/toolchains/aarch64-apple-darwin-clang.cmake	Wed Nov 20 21:37:47 2024 +0100
@@ -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 "")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.github/scripts/toolchains/aarch64-unknown-linux-gnu-clang.cmake	Wed Nov 20 21:37:47 2024 +0100
@@ -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")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.github/scripts/toolchains/aarch64-unknown-linux-gnu-gcc.cmake	Wed Nov 20 21:37:47 2024 +0100
@@ -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")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.github/scripts/toolchains/i686-unknown-linux-gnu-clang.cmake	Wed Nov 20 21:37:47 2024 +0100
@@ -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")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.github/scripts/toolchains/i686-unknown-linux-gnu-gcc.cmake	Wed Nov 20 21:37:47 2024 +0100
@@ -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")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.github/scripts/toolchains/x86_64-apple-darwin-clang.cmake	Wed Nov 20 21:37:47 2024 +0100
@@ -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 "")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.github/scripts/toolchains/x86_64-pc-windows-gnullvm.cmake	Wed Nov 20 21:37:47 2024 +0100
@@ -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")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.github/scripts/toolchains/x86_64-unknown-linux-gnu-clang.cmake	Wed Nov 20 21:37:47 2024 +0100
@@ -0,0 +1,3 @@
+# Assumption: This is the native host target.
+set(CMAKE_C_COMPILER "clang")
+set(CMAKE_CXX_COMPILER "clang++")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.github/scripts/toolchains/x86_64-unknown-linux-gnu-gcc.cmake	Wed Nov 20 21:37:47 2024 +0100
@@ -0,0 +1,3 @@
+# Assumption: This is the native host target.
+set(CMAKE_C_COMPILER "gcc")
+set(CMAKE_CXX_COMPILER "g++")
--- a/tools/corrosion/.github/workflows/gh-pages.yaml	Wed Sep 18 14:10:51 2024 +0200
+++ b/tools/corrosion/.github/workflows/gh-pages.yaml	Wed Nov 20 21:37:47 2024 +0100
@@ -18,15 +18,13 @@
   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:
-      - uses: actions/checkout@v4
-      - name: Setup Pages
-        uses: actions/configure-pages@v3
       - name: Install mdbook
         env:
           MDBOOK_VERSION: 'v0.4.27'
@@ -34,10 +32,23 @@
           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: Build mdbook
-        run: |
-          cd doc
-          mdbook build
+      - 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@v3
+      - 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:
@@ -52,11 +63,16 @@
         working-directory: highlightjs
       - name: Override highlightjs
         run: |
-          cp highlightjs/build/highlight.min.js doc/book/highlight.js
+          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@v1
+        uses: actions/upload-pages-artifact@v2
         with:
-          path: 'doc/book'
+          path: 'main/doc/book'
       - name: Deploy to GitHub Pages
         id: deployment
-        uses: actions/deploy-pages@v1
+        uses: actions/deploy-pages@v2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.github/workflows/linux.yaml	Wed Nov 20 21:37:47 2024 +0100
@@ -0,0 +1,58 @@
+# 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
+      - 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
--- a/tools/corrosion/.github/workflows/test.yaml	Wed Sep 18 14:10:51 2024 +0200
+++ b/tools/corrosion/.github/workflows/test.yaml	Wed Nov 20 21:37:47 2024 +0100
@@ -9,225 +9,304 @@
       - 'stable/**'
 jobs:
 
-  test_legacy_linux:
-    name: Test Corrosion (CMake 3.15)
-    uses: ./.github/workflows/test_legacy.yaml
-    with :
-      os: ubuntu-20.04
-      rust: 1.46.0
-  test_legacy_mac:
-    name: Test Corrosion (CMake 3.15)
-    uses: ./.github/workflows/test_legacy.yaml
+  visual_studio_base:
+    name: Test Visual Studio (base)
+    uses: ./.github/workflows/visual_studio.yaml
     with:
-      os: macos-12
-      rust: 1.54.0
-  test_legacy_windows:
-    name: Test Corrosion (CMake 3.15)
-    uses: ./.github/workflows/test_legacy.yaml
-    with:
-      os: windows-2019
+      vs_version: "2022"
       rust: 1.46.0
 
-  test_legacy_stable:
-    name: Legacy CMake + stable Rust
-    uses: ./.github/workflows/test_legacy.yaml
+  visual_studio_stage2:
+    name: Test Visual Studio
+    uses: ./.github/workflows/visual_studio.yaml
+    needs:
+      - visual_studio_base
+    strategy:
+      matrix:
+        vs_version:
+          - "2019"
+          - "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-2019 # windows-latest is currently not having a supported MSVC compiler
-          - ubuntu-20.04
-          - macos-12
-    with:
-      os: ${{ matrix.os }}
-      rust: stable
-
-  test_legacy_nightly:
-    name: Legacy CMake + nightly Rust
-    uses: ./.github/workflows/test_legacy.yaml
-    with:
-      os: ubuntu-20.04
-      rust: nightly
-
-  test_legacy_new_lockfile_msrv:
-    name: Test MSRV of the new lockfile
-    runs-on: ubuntu-20.04
-    steps:
-      - uses: actions/checkout@v4
-      - name: Install Rust
-        id: install_rust
-        uses: dtolnay/rust-toolchain@1.56
-      - name: Test Generator build with MSRV
-        run: cargo build
-        working-directory: generator
-
-  test:
-    name: Test Corrosion
-    runs-on: ${{ matrix.os }}
-    continue-on-error: ${{ matrix.rust == 'nightly' }}
-    strategy:
-      fail-fast: false
-      matrix:
-        os:
-          - windows-2019 # windows-latest is currently not having a supported MSVC compiler
-          - ubuntu-latest
-          - macos-12
+          - windows-2022
         arch:
           - x86_64
           - i686
           - aarch64
-          - powerpc64le
-        abi:
-          - gnu
-          - darwin
-          - msvc
-        cmake:
-          - 3.19.0
-        rust:
-          # Our MSRV is already tested with the legacy generator, so just test the current stable rust here.
-          - stable
-        generator:
-          - default # This is just whatever the platform default is
-          - ninja
-        compiler: [default]
+        compiler:
+          - cl
+          - clang-cl
+          - clang
         include:
-          - rust: nightly
-            cmake: 3.19.0
-            generator: ninja
-            arch: x86_64
-            abi: msvc
-            os: windows-2019
-          - rust: nightly
-            cmake: 3.19.0
-            generator: ninja
-            arch: x86_64
-            abi: gnu
-            os: ubuntu-latest
-          - rust: nightly
-            cmake: 3.19.0
-            generator: ninja
-            arch: x86_64
-            abi: darwin
-            os: macos-12
-          - rust: 1.54
-            cmake: 3.19.0
-            generator: ninja
-            arch: x86_64
-            abi: msvc
-            os: windows-2019
-            compiler: clang
-          - os: ubuntu-latest
-            arch: x86_64
-            abi: gnu
-            cmake: 3.20.0
-            rust: 1.54
-            generator: ninja-multiconfig
-
+          - 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:
-
-          # We have a separate test Matrix for the Visual Studio Generator
-          - os: windows-2019
-            generator: default # Default generator is Visual Studio
-
-          # ARCH
-          - os: windows-2019
+          # Not sure what parameters CMake needs when cross-compiling with clang-cl, so exclude for now
+          - compiler: clang-cl
             arch: i686
-            abi: gnu
-          - os: windows-2019
-            arch: aarch64
-            abi: gnu
-          - os: windows-2019
-            arch: i686
-            generator: ninja
-          - os: windows-2019
+          - compiler: clang-cl
             arch: aarch64
-            generator: ninja
-          - os: windows-2019
-            arch: powerpc64le
-          - os: macos-12
+          - compiler: clang
             arch: i686
-          - os: macos-12
+          - compiler: clang
             arch: aarch64
-          - os: macos-12
-            arch: powerpc64le
-
-          # ABI
-          - os: ubuntu-latest
-            abi: msvc
-          - os: ubuntu-latest
-            abi: darwin
-          - os: windows-2019
-            abi: darwin
-          - os: macos-12
-            abi: msvc
-          - os: macos-12
-            abi: gnu
 
     steps:
       - uses: actions/checkout@v4
-      - name: Setup Environment and Configure CMake
-        uses: "./.github/actions/setup_test"
+      - 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:
-          target_arch: ${{matrix.arch}}
-          abi: ${{matrix.abi}}
-          cmake: ${{matrix.cmake}}
-          rust: ${{matrix.rust}}
-          generator: ${{matrix.generator}}
-          build_dir: build
-          compiler: ${{matrix.compiler}}
+          toolchain: ${{matrix.rust}}
+          targets: ${{matrix.arch}}-pc-windows-msvc
+      - 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
-        id: run_tests
         working-directory: build
         run: ctest --output-on-failure --build-config Debug -j 3
 
-  test_msvc:
-    name: Test MSVC Generator
+  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
+      - 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-2019
           - 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
+      - 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
+      - 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:
-          - rust: 1.54.0
-          # Override rust version for x86_64
+          # 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
-            rust: 1.46.0
-          - os: windows-2019
-            cmake: 3.20.6  # Multi-config Generators require at least CMake 3.20
-          - os: windows-2022
-            cmake: 3.21.5 # VS on windows-2022 requires at least CMake 3.21
+            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
-      # 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
+      - name: Install CMake
+        uses: lukka/get-cmake@519de0c7b4812477d74976b2523a9417f552d126
         with:
-          path: build
-          key: ${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.rust }}-msvc-build
-      - name: Setup Environment and Configure CMake
-        uses: "./.github/actions/setup_test"
+          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:
-          target_arch: ${{matrix.arch}}
-          abi: msvc
-          cmake: ${{matrix.cmake}}
-          rust: ${{matrix.rust}}
-          generator: default
-          build_dir: build
-          configure_params: "-DCORROSION_TESTS_KEEP_BUILDDIRS=ON"
+          toolchain: ${{matrix.rust}}
+          targets: ${{matrix.arch}}-apple-darwin
+      - 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 }}
@@ -235,39 +314,74 @@
       fail-fast: false
       matrix:
         os:
-          - windows-2019
+          - windows-2022
           - ubuntu-latest
-          - macos-12
+          - macos-13
         include:
-          - abi: default
-        #  - os: windows-2019
-        #    abi: gnu
+          # 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_1_0_86
+          key: ${{ runner.os }}-cxxbridge_${{ matrix.cxxbridge_version }}
       - name: Install cxxbridge
         if: steps.cache_cxxbridge.outputs.cache-hit != 'true'
-        run: cargo install cxxbridge-cmd@1.0.86
+        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 Environment and Configure CMake
-        uses: "./.github/actions/setup_test"
+      - name: Setup MSVC Development Environment
+        uses: ilammy/msvc-dev-cmd@v1
+        if: runner.os == 'Windows'
+      - name: Install CMake
+        uses: lukka/get-cmake@519de0c7b4812477d74976b2523a9417f552d126
         with:
-          target_arch: x86_64
-          cmake: 3.15.7
-          rust: stable minus 2 releases
-          abi: ${{ matrix.abi }}
-          generator: ninja
-          build_dir: build
-          configure_params: -DCORROSION_TESTS_CXXBRIDGE=ON
+          cmakeVersion: "~3.22.0"
+          ninjaVersion: "~1.10.0"
+      - name: Install Rust
+        uses: dtolnay/rust-toolchain@master
+        with:
+          toolchain: stable minus 2 releases
+      - 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 }}
@@ -275,13 +389,12 @@
       fail-fast: false
       matrix:
         os:
-          - windows-2019
+          - windows-2022
           - ubuntu-latest
-          - macos-12
+          - macos-13
         include:
-          - rust: 1.46.0
-          - os: macos-12
-            rust: 1.54.0  # On MacOS-12 linking fails before Rust 1.54
+          - rust: 1.54.0
+
     steps:
       - uses: actions/checkout@v4
       - name: Setup MSVC Development Environment
@@ -290,32 +403,17 @@
       - name: Install CMake
         uses: lukka/get-cmake@519de0c7b4812477d74976b2523a9417f552d126
         with:
-          cmakeVersion: "~3.18.0"
+          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}}
-      - name: CMake Version
-        run: cmake --version
-      - name: Rust Version
-        run: rustc --version
-      - name: Test Corrosion as subdirectory
-        run: >
-          cmake
-          -S.
-          -Bbuild
-          -GNinja
-          -DCORROSION_VERBOSE_OUTPUT=ON
-          -DCORROSION_TESTS_INSTALL_CORROSION=OFF
-          &&
-          cd build
-          &&
-          ctest --output-on-failure -C Debug -j 3
       - name: Test Corrosion as installed module
         run: >
-          cmake -E remove_directory build
-          &&
           cmake
           -S.
           -Bbuild
@@ -327,21 +425,21 @@
           cd build
           &&
           ctest --output-on-failure -C Release -j 3
-  # We need some "accumulation" job here because bors fails (timeouts) to
-  # listen on matrix builds.
-  # Hence, we have some kind of dummy here that bors can listen on
+
+  # 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:
-      - test_legacy_linux
-      - test_legacy_mac
-      - test_legacy_windows
-      - test_legacy_stable
-      - test_legacy_new_lockfile_msrv
-      - test
-      - test_msvc
+      - 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
--- a/tools/corrosion/.github/workflows/test_legacy.yaml	Wed Sep 18 14:10:51 2024 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-name: Test Corrosion using prebuilt legacy generator
-
-on:
-  workflow_call:
-    inputs:
-      os:
-        required: true
-        type: string
-      rust:
-        required: false
-        type: string
-        default: 1.46.0
-      target_arch:
-        required: false
-        type: string
-        default: x86_64
-      generator:
-        required: false
-        type: string
-        default : ninja
-
-jobs:
-  test_legacy:
-    name: Test (${{inputs.os}})
-    runs-on: ${{ inputs.os }}
-    strategy:
-      fail-fast: false
-    steps:
-      - uses: actions/checkout@v4
-      - name: Cache Legacy Generator
-        id: cache_generator
-        uses: actions/cache@v4
-        with:
-          path: ${{github.workspace}}/corrosion-prebuilt-generator
-          key: ${{ runner.os }}-${{ inputs.rust }}-generator-${{ hashFiles('generator/src/**', 'generator/Cargo.toml', 'generator/Cargo.lock') }}
-      - name: Setup Environment and Configure CMake
-        uses: "./.github/actions/setup_test"
-        with:
-          target_arch: x86_64
-          cmake: 3.15.7
-          rust: ${{inputs.rust}}
-          generator: ninja
-          build_dir: build
-          install_path: ${{github.workspace}}/corrosion-prebuilt-generator
-          configure_params: "-DCMAKE_BUILD_TYPE=Release"
-        if: steps.cache_generator.outputs.cache-hit != 'true'
-      - name: Build corrosion
-        run: cmake --build build --config Release
-        if: steps.cache_generator.outputs.cache-hit != 'true'
-      - name: Install corrosion
-        run: cmake --install build --config Release
-        if: steps.cache_generator.outputs.cache-hit != 'true'
-      - name: Determine Corrosion Generator path
-        id: cor_gen
-        shell: bash
-        run: |
-          export base_generator_bin="${{github.workspace}}/corrosion-prebuilt-generator/libexec/corrosion-generator"
-          if [ "${{ runner.os }}" == "Windows" ]; then
-            echo "generator_bin=${base_generator_bin}.exe" >> $GITHUB_OUTPUT
-          else
-            echo "generator_bin=${base_generator_bin}" >> $GITHUB_OUTPUT
-            chmod +x "${base_generator_bin}"
-          fi
-      - name: Setup Environment and Configure CMake
-        uses: "./.github/actions/setup_test"
-        with:
-          target_arch: ${{inputs.target_arch}}
-          cmake: 3.15.7
-          rust: ${{inputs.rust}}
-          generator: ${{inputs.generator}}
-          build_dir: build
-          configure_params: "-DCORROSION_GENERATOR_EXECUTABLE=${{steps.cor_gen.outputs.generator_bin}}"
-      - name: Run Tests
-        id: run_tests
-        working-directory: build
-        run: ctest --build-config Debug -j 3
-      - name: Rerun failed tests verbose
-        working-directory: build
-        run: ctest --rerun-failed --verbose --build-config Debug
-        if: ${{ failure() && steps.run_tests.conclusion == 'failure' }}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.github/workflows/visual_studio.yaml	Wed Nov 20 21:37:47 2024 +0100
@@ -0,0 +1,53 @@
+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
+      # 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
--- a/tools/corrosion/.gitignore	Wed Sep 18 14:10:51 2024 +0200
+++ b/tools/corrosion/.gitignore	Wed Nov 20 21:37:47 2024 +0100
@@ -2,7 +2,6 @@
 **/target/
 **/*.rs.bk
 build*/
-install*/
 .vscode
 .idea
 cmake-build-*
--- a/tools/corrosion/CMakeLists.txt	Wed Sep 18 14:10:51 2024 +0200
+++ b/tools/corrosion/CMakeLists.txt	Wed Nov 20 21:37:47 2024 +0100
@@ -1,64 +1,24 @@
-cmake_minimum_required(VERSION 3.15)
+cmake_minimum_required(VERSION 3.22)
 project(Corrosion
     # Official releases will be major.minor.patch. When the `tweak` field is
     # set it indicates that we are on a commit, that is not a officially
     # tagged release. Users don't need to care about this, it is mainly to
     # clearly see in configure logs which version was used, without needing to
     # rely on `git`, since Corrosion may be installed or otherwise packaged.
-    VERSION 0.5.0
+    VERSION 0.99.99 # 1.0-pre-release
     LANGUAGES NONE
     HOMEPAGE_URL "https://corrosion-rs.github.io/corrosion/"
 )
 
-# Default behavior:
-# - If the project is being used as a subdirectory, then don't build tests and
-#   don't enable any languages.
-# - If this is a top level project, then build tests and enable the C++ compiler
-if (NOT CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
-    set(_CORROSION_TOP_LEVEL OFF)
-else()
-    set(_CORROSION_TOP_LEVEL ON)
-endif()
-
 # ==== Corrosion Configuration ====
 
 option(
-    CORROSION_DEV_MODE
-    "Enables some additional features if you're developing Corrosion"
-    ${_CORROSION_TOP_LEVEL}
-)
-
-option(
     CORROSION_BUILD_TESTS
     "Build Corrosion test project"
-    ${_CORROSION_TOP_LEVEL}
+    ${PROJECT_IS_TOP_LEVEL}
 )
 
-set(
-  CORROSION_GENERATOR_EXECUTABLE CACHE STRING
-  "Use prebuilt, non-bootstrapped corrosion-generator")
-mark_as_advanced(CORROSION_GENERATOR_EXECUTABLE)
-
-if (CORROSION_GENERATOR_EXECUTABLE)
-    add_executable(Corrosion::Generator IMPORTED GLOBAL)
-    set_property(
-        TARGET Corrosion::Generator
-        PROPERTY IMPORTED_LOCATION ${CORROSION_GENERATOR_EXECUTABLE})
-    set(CORROSION_INSTALL_EXECUTABLE_DEFAULT OFF)
-elseif(CORROSION_NATIVE_TOOLING OR CMAKE_VERSION VERSION_LESS 3.19.0)
-        set(CORROSION_INSTALL_EXECUTABLE_DEFAULT "ON")
-else()
-    set(CORROSION_INSTALL_EXECUTABLE_DEFAULT OFF)
-endif()
-
-option(
-    CORROSION_INSTALL_EXECUTABLE
-    "Controls whether corrosion-generator is installed with the package"
-    ${CORROSION_INSTALL_EXECUTABLE_DEFAULT}
-)
-mark_as_advanced(CORROSION_INSTALL_EXECUTABLE)
-
-if (_CORROSION_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)
@@ -69,8 +29,11 @@
 #
 # It is strongly encouraged to install Corrosion separately and use
 # `find_package(Corrosion REQUIRED)` instead if that works with your workflow.
-list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
-include(Corrosion)
+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)
@@ -79,7 +42,7 @@
 endif()
 
 # If Corrosion is a subdirectory, do not enable its install code
-if (NOT _CORROSION_TOP_LEVEL)
+if (NOT PROJECT_IS_TOP_LEVEL)
     return()
 endif()
 
@@ -87,18 +50,6 @@
 
 include(GNUInstallDirs)
 
-if(CORROSION_INSTALL_EXECUTABLE)
-    get_property(
-            _CORROSION_GENERATOR_EXE
-            TARGET Corrosion::Generator PROPERTY IMPORTED_LOCATION
-    )
-    install(PROGRAMS "${_CORROSION_GENERATOR_EXE}" DESTINATION "${CMAKE_INSTALL_FULL_LIBEXECDIR}")
-else()
-    message(DEBUG "Not installing corrosion-generator since "
-        "`CORROSION_INSTALL_EXECUTABLE` is set to ${CORROSION_INSTALL_EXECUTABLE}"
-    )
-endif()
-
 # Generate the Config file
 include(CMakePackageConfigHelpers)
 
@@ -112,7 +63,7 @@
     "${CMAKE_CURRENT_BINARY_DIR}/CorrosionConfigVersion.cmake"
     VERSION ${PROJECT_VERSION}
     COMPATIBILITY
-        SameMinorVersion # TODO: Should be SameMajorVersion when 1.0 is released
+        SameMajorVersion
     ARCH_INDEPENDENT
 )
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/CMakePresets.json	Wed Nov 20 21:37:47 2024 +0100
@@ -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"
+        }
+    ]
+}
--- a/tools/corrosion/README.md	Wed Sep 18 14:10:51 2024 +0200
+++ b/tools/corrosion/README.md	Wed Nov 20 21:37:47 2024 +0100
@@ -38,3 +38,13 @@
 target_link_libraries(your_cpp_bin PUBLIC rust-lib)
 ```
 
+## Requirements
+
+### Stable v0.5 Release
+
+- 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
+
+### Development (master branch)
+
+- CMake 3.22 or newer
--- a/tools/corrosion/RELEASES.md	Wed Sep 18 14:10:51 2024 +0200
+++ b/tools/corrosion/RELEASES.md	Wed Nov 20 21:37:47 2024 +0100
@@ -1,3 +1,22 @@
+# Unreleased
+
+### Breaking Changes
+
+- The master branch of 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.
+
+### New features
+
+- Support using the `$<CONFIG>` 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
+
+[#459]: https://github.com/corrosion-rs/corrosion/pull/459
+
 # v0.5.0 (2024-05-11)
 
 ### Breaking Changes
@@ -23,7 +42,7 @@
 
 - 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])
+  the package and crate name are identical. ([11e27c])
 - Set the `AR_<triple>` variable for `cc-rs` (except for msvc targets) [#456]
 - Fix hostbuild when cross-compiling to windows [#477]
 - Consider vworks executable suffix [#504]
@@ -43,7 +62,7 @@
 
 # v0.4.9 (2024-05-01)
 
-### New Features 
+### New Features
 
 - Automatically detect Rust target for OpenHarmony ([#510]).
 
@@ -67,7 +86,7 @@
 
 ### Fixes
 
-- The C/C++ compiler passed from corrosion to `cc-rs` can now be overriden by users setting
+- The C/C++ compiler passed from corrosion to `cc-rs` can now be overridden by users setting
   `CC_<target>` (e.g. `CC_x86_64-unknown-linux-gnu=/path/to/my-compiler`) environment variables ([#475]).
 
 [#475]: https://github.com/corrosion-rs/corrosion/pull/475
--- a/tools/corrosion/cmake/Corrosion.cmake	Wed Sep 18 14:10:51 2024 +0200
+++ b/tools/corrosion/cmake/Corrosion.cmake	Wed Nov 20 21:37:47 2024 +0100
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.15)
+cmake_minimum_required(VERSION 3.22)
 
 list(APPEND CMAKE_MESSAGE_CONTEXT "Corrosion")
 
@@ -10,14 +10,8 @@
 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 (COR_IS_MULTI_CONFIG AND CMAKE_VERSION VERSION_LESS 3.20.0)
-    message(FATAL_ERROR "Corrosion requires at least CMake 3.20 with Multi-Config Generators such as "
-        "\"Ninja Multi-Config\" or Visual Studio. "
-        "Please use a different generator or update to cmake >= 3.20.\n"
-        "Note: You are using CMake ${CMAKE_VERSION} (Path: `${CMAKE_COMMAND}`) with "
-        " the `${CMAKE_GENERATOR}` Generator."
-    )
-elseif(NOT COR_IS_MULTI_CONFIG AND DEFINED CMAKE_CONFIGURATION_TYPES)
+
+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."
@@ -26,25 +20,10 @@
 
 option(CORROSION_VERBOSE_OUTPUT "Enables verbose output from Corrosion and Cargo" OFF)
 
-set(CORROSION_NATIVE_TOOLING_DESCRIPTION
-    "Use native tooling - Required on CMake < 3.19 and available as a fallback option for recent versions"
-    )
-
-set(CORROSION_RESPECT_OUTPUT_DIRECTORY_DESCRIPTION
-    "Respect the CMake target properties specifying the output directory of a target, such as
-    `RUNTIME_OUTPUT_DIRECTORY`. This requires CMake >= 3.19, otherwise this option is forced off."
-)
-
-option(
-    CORROSION_NATIVE_TOOLING
-    "${CORROSION_NATIVE_TOOLING_DESCRIPTION}"
-    OFF
-)
-
-option(CORROSION_RESPECT_OUTPUT_DIRECTORY
-    "${CORROSION_RESPECT_OUTPUT_DIRECTORY_DESCRIPTION}"
-    ON
-)
+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
@@ -52,39 +31,8 @@
     OFF
 )
 
-# The native tooling is required on CMAke < 3.19 so we override whatever the user may have set.
-if (CMAKE_VERSION VERSION_LESS 3.19.0)
-    set(CORROSION_NATIVE_TOOLING ON CACHE INTERNAL "${CORROSION_NATIVE_TOOLING_DESCRIPTION}" FORCE)
-    set(CORROSION_RESPECT_OUTPUT_DIRECTORY OFF CACHE INTERNAL
-        "${CORROSION_RESPECT_OUTPUT_DIRECTORY_DESCRIPTION}" FORCE
-    )
-endif()
-
 find_package(Rust REQUIRED)
 
-if(Rust_TOOLCHAIN_IS_RUSTUP_MANAGED)
-    execute_process(COMMAND rustup target list --toolchain "${Rust_TOOLCHAIN}"
-            OUTPUT_VARIABLE AVAILABLE_TARGETS_RAW
-    )
-    string(REPLACE "\n" ";" AVAILABLE_TARGETS_RAW "${AVAILABLE_TARGETS_RAW}")
-    string(REPLACE " (installed)" "" "AVAILABLE_TARGETS" "${AVAILABLE_TARGETS_RAW}")
-    set(INSTALLED_TARGETS_RAW "${AVAILABLE_TARGETS_RAW}")
-    list(FILTER INSTALLED_TARGETS_RAW INCLUDE REGEX " \\(installed\\)")
-    string(REPLACE " (installed)" "" "INSTALLED_TARGETS" "${INSTALLED_TARGETS_RAW}")
-    list(TRANSFORM INSTALLED_TARGETS STRIP)
-    if("${Rust_CARGO_TARGET}" IN_LIST AVAILABLE_TARGETS)
-        message(DEBUG "Cargo target ${Rust_CARGO_TARGET} is an official target-triple")
-        message(DEBUG "Installed targets: ${INSTALLED_TARGETS}")
-        if(NOT ("${Rust_CARGO_TARGET}" IN_LIST INSTALLED_TARGETS))
-            message(FATAL_ERROR "Target ${Rust_CARGO_TARGET} is not installed for toolchain ${Rust_TOOLCHAIN}.\n"
-                    "Help: Run `rustup target add --toolchain ${Rust_TOOLCHAIN} ${Rust_CARGO_TARGET}` to install "
-                    "the missing target."
-            )
-        endif()
-    endif()
-
-endif()
-
 if(CMAKE_GENERATOR MATCHES "Visual Studio"
         AND (NOT CMAKE_VS_PLATFORM_NAME STREQUAL CMAKE_VS_PLATFORM_NAME_DEFAULT)
         AND Rust_VERSION VERSION_LESS "1.54")
@@ -93,9 +41,7 @@
             " causes the build to fail. Please upgrade your Rust version to 1.54 or newer.")
 endif()
 
-if (NOT TARGET Corrosion::Generator)
-    message(STATUS "Using Corrosion as a subdirectory")
-endif()
+#    message(STATUS "Using Corrosion as a subdirectory")
 
 get_property(
     RUSTC_EXECUTABLE
@@ -107,43 +53,6 @@
     TARGET Rust::Cargo PROPERTY IMPORTED_LOCATION
 )
 
-# Note: Legacy function, used when respecting the `XYZ_OUTPUT_DIRECTORY` target properties is not
-# possible.
-function(_corrosion_set_imported_location_legacy target_name base_property filename)
-    foreach(config_type ${CMAKE_CONFIGURATION_TYPES})
-        set(binary_root "${CMAKE_CURRENT_BINARY_DIR}/${config_type}")
-        string(TOUPPER "${config_type}" config_type_upper)
-        message(DEBUG "Setting ${base_property}_${config_type_upper} for target ${target_name}"
-                " to `${binary_root}/${filename}`.")
-        # For Multiconfig we want to specify the correct location for each configuration
-        set_property(
-            TARGET ${target_name}
-            PROPERTY "${base_property}_${config_type_upper}"
-                "${binary_root}/${filename}"
-        )
-    endforeach()
-    if(NOT COR_IS_MULTI_CONFIG)
-        set(binary_root "${CMAKE_CURRENT_BINARY_DIR}")
-    endif()
-
-    message(DEBUG "Setting ${base_property} for target ${target_name}"
-                " to `${binary_root}/${filename}`.")
-
-    # IMPORTED_LOCATION must be set regardless of possible overrides. In the multiconfig case,
-    # the last configuration "wins".
-    set_property(
-            TARGET ${target_name}
-            PROPERTY "${base_property}" "${binary_root}/${filename}"
-        )
-endfunction()
-
-
-# Sets out_var to true if the byproduct copying and imported location is done in a deferred
-# manner to respect target properties, etc. that may be set later.
-function(_corrosion_determine_deferred_byproduct_copying_and_import_location_handling out_var)
-    set(${out_var} ${CORROSION_RESPECT_OUTPUT_DIRECTORY} PARENT_SCOPE)
-endfunction()
-
 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)
@@ -177,9 +86,7 @@
     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")
-        if(suffix)
-            set(filename "${filename}${suffix}")
-        endif()
+        string(APPEND filename "${suffix}")
     endif()
 
     get_target_property(output_directory "${output_dir_prop_target_name}" "${output_directory_property}")
@@ -197,8 +104,17 @@
         else()
             set(curr_out_dir "${CMAKE_CURRENT_BINARY_DIR}")
         endif()
+        string(REPLACE "\$<CONFIG>" "${config_type}" curr_out_dir "${curr_out_dir}")
         message(DEBUG "Setting ${base_property}_${config_type_upper} for target ${target_name}"
                 " to `${curr_out_dir}/${filename}`.")
+
+        string(GENEX_STRIP "${curr_out_dir}" stripped_out_dir)
+        if(NOT ("${stripped_out_dir}" STREQUAL "${curr_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 `\$<CONFIG>` generator expression for output directories.")
+        endif()
+
         # For Multiconfig we want to specify the correct location for each configuration
         set_property(
             TARGET ${target_name}
@@ -214,6 +130,13 @@
         else()
             set(base_output_directory "${CMAKE_CURRENT_BINARY_DIR}")
         endif()
+        string(REPLACE "\$<CONFIG>" "${CMAKE_BUILD_TYPE}" base_output_directory "${base_output_directory}")
+        string(GENEX_STRIP "${base_output_directory}" stripped_out_dir)
+        if(NOT ("${stripped_out_dir}" STREQUAL "${base_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 `\$<CONFIG>` generator expression for output directories.")
+        endif()
     endif()
 
     message(DEBUG "Setting ${base_property} for target ${target_name}"
@@ -227,22 +150,6 @@
         )
 endfunction()
 
-# Helper function to call _corrosion_set_imported_location_deferred while eagerly
-# evaluating arguments.
-# Refer to https://cmake.org/cmake/help/latest/command/cmake_language.html#deferred-call-examples
-function(_corrosion_call_set_imported_location_deferred target_name base_property output_directory_property filename)
-    cmake_language(EVAL CODE "
-        cmake_language(DEFER
-            CALL
-            _corrosion_set_imported_location_deferred
-            [[${target_name}]]
-            [[${base_property}]]
-            [[${output_directory_property}]]
-            [[${filename}]]
-        )
-    ")
-endfunction()
-
 # Set the imported location of a Rust target.
 #
 # Rust targets are built via custom targets / custom commands. The actual artifacts are exposed
@@ -258,55 +165,41 @@
 #    artifact.
 # - filename of the artifact.
 function(_corrosion_set_imported_location target_name base_property output_directory_property filename)
-    _corrosion_determine_deferred_byproduct_copying_and_import_location_handling("defer")
-    if(defer)
-        _corrosion_call_set_imported_location_deferred("${target_name}" "${base_property}" "${output_directory_property}" "${filename}")
-    else()
-        _corrosion_set_imported_location_legacy("${target_name}" "${base_property}" "${filename}")
-    endif()
+        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_legacy target_name cargo_build_dir file_names)
+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()
 
-    if(COR_IS_MULTI_CONFIG)
-        set(output_dir "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>")
-    else()
-        set(output_dir "${CMAKE_CURRENT_BINARY_DIR}")
-    endif()
-
-    list(TRANSFORM file_names PREPEND "${cargo_build_dir}/" OUTPUT_VARIABLE src_file_names)
-    list(TRANSFORM file_names PREPEND "${output_dir}/" OUTPUT_VARIABLE dst_file_names)
-    message(DEBUG "Adding command to copy byproducts `${file_names}` to ${dst_file_names}")
-    add_custom_command(TARGET _cargo-build_${target_name}
-                        POST_BUILD
-                        COMMAND  ${CMAKE_COMMAND} -E make_directory "${output_dir}"
-                        COMMAND
-                        ${CMAKE_COMMAND} -E copy_if_different
-                            # tested to work with both multiple files and paths with spaces
-                            ${src_file_names}
-                            "${output_dir}"
-                        BYPRODUCTS ${dst_file_names}
-                        COMMENT "Copying byproducts `${file_names}` to ${output_dir}"
-                        VERBATIM
-                        COMMAND_EXPAND_LISTS
-    )
-endfunction()
-
-function(_corrosion_copy_byproduct_deferred target_name output_dir_prop_name cargo_build_dir file_names)
-    if(ARGN)
-        message(FATAL_ERROR "Unexpected additional arguments")
-    endif()
-    get_target_property(output_dir ${target_name} "${output_dir_prop_name}")
+    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)
-        get_target_property(output_dir_curr_config ${target_name} "${output_dir_prop_name}_${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}")
@@ -348,8 +241,12 @@
             string(APPEND file_names "${suffix}")
         endif()
     endif()
-
-    list(TRANSFORM file_names PREPEND "${cargo_build_dir}/" OUTPUT_VARIABLE src_file_names)
+    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}
@@ -368,37 +265,27 @@
     )
 endfunction()
 
-function(_corrosion_call_copy_byproduct_deferred target_name output_dir_prop_name cargo_build_dir file_names)
+# 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_name}]]
+                [[${output_dir_prop_names}]]
                 [[${cargo_build_dir}]]
                 [[${file_names}]]
             )
         ")
 endfunction()
 
-# Copy the artifacts generated by cargo to the appropriate destination.
-#
-# Parameters:
-# - target_name: The name of the Rust target
-# - output_dir_prop_name: The property name controlling the destination (e.g.
-#   `RUNTIME_OUTPUT_DIRECTORY`)
-# - cargo_build_dir: the directory cargo build places it's output artifacts in.
-# - filenames: the file names of any output artifacts as a list.
-# - is_binary: TRUE if the byproducts are program executables.
-function(_corrosion_copy_byproducts target_name output_dir_prop_name cargo_build_dir filenames)
-    _corrosion_determine_deferred_byproduct_copying_and_import_location_handling("defer")
-    if(defer)
-        _corrosion_call_copy_byproduct_deferred("${target_name}" "${output_dir_prop_name}" "${cargo_build_dir}" "${filenames}")
-    else()
-        _corrosion_copy_byproduct_legacy("${target_name}" "${cargo_build_dir}" "${filenames}")
-    endif()
-endfunction()
-
 
 # Add targets for the static and/or shared libraries of the rust target.
 # The generated byproduct names are returned via the `OUT_<type>_BYPRODUCTS` arguments.
@@ -449,7 +336,7 @@
         set(is_windows TRUE)
         if(Rust_CARGO_TARGET_ENV STREQUAL "msvc")
             set(is_windows_msvc TRUE)
-        elseif(Rust_CARGO_TARGET_ENV STREQUAL "gnu")
+        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")
@@ -500,11 +387,10 @@
     endif()
     set("${CALT_OUT_ARCHIVE_OUTPUT_BYPRODUCTS}" "${archive_output_byproducts}" PARENT_SCOPE)
 
-    add_library(${target_name} INTERFACE)
-
     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"
@@ -531,6 +417,7 @@
     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"
@@ -546,6 +433,7 @@
                     "ARCHIVE_OUTPUT_DIRECTORY"
                     "${implib_name}"
             )
+            set_target_properties(${target_name}-shared PROPERTIES COR_IMPLIB_FILE_NAME ${implib_name})
         endif()
 
         if(is_macos)
@@ -581,22 +469,10 @@
         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}")
-    _corrosion_determine_deferred_byproduct_copying_and_import_location_handling("defer")
-    if(defer)
-        # .exe suffix will be added later, also depending on possible hostbuild
-        # target property
-    else()
-        if(Rust_CARGO_TARGET_OS STREQUAL "windows")
-            set(bin_filename "${bin_name}.exe")
-        endif()
-    endif()
     set(${out_bin_byproduct} "${bin_filename}" PARENT_SCOPE)
-
-
-    # Todo: This is compatible with the way corrosion previously exposed the bin name,
-    # but maybe we want to prefix the exposed name with the package name?
-    add_executable(${bin_name} IMPORTED GLOBAL)
     add_dependencies(${bin_name} cargo-build_${bin_name})
 
     if(Rust_CARGO_TARGET_OS STREQUAL "darwin")
@@ -613,9 +489,7 @@
 endfunction()
 
 
-if (NOT CORROSION_NATIVE_TOOLING)
-    include(CorrosionGenerator)
-endif()
+include(CorrosionGenerator)
 
 # Note: `cmake_language(GET_MESSAGE_LOG_LEVEL <output_variable>)` requires CMake 3.25,
 # so we offer our own option to control verbosity of downstream commands (e.g. cargo build)
@@ -626,25 +500,6 @@
     set(_CORROSION_QUIET_OUTPUT_FLAG --quiet CACHE INTERNAL "")
 endif()
 
-if(CORROSION_NATIVE_TOOLING)
-    if (NOT TARGET Corrosion::Generator )
-        add_subdirectory(generator)
-    endif()
-    get_property(
-        _CORROSION_GENERATOR_EXE
-        TARGET Corrosion::Generator PROPERTY IMPORTED_LOCATION
-    )
-    set(
-        _CORROSION_GENERATOR
-        ${CMAKE_COMMAND} -E env
-            CARGO_BUILD_RUSTC=${RUSTC_EXECUTABLE}
-            ${_CORROSION_GENERATOR_EXE}
-            --cargo ${CARGO_EXECUTABLE}
-            ${_CORROSION_VERBOSE_OUTPUT_FLAG}
-        CACHE INTERNAL "corrosion-generator runner"
-    )
-endif()
-
 set(_CORROSION_CARGO_VERSION ${Rust_CARGO_VERSION} CACHE INTERNAL "cargo version used by corrosion")
 set(_CORROSION_RUST_CARGO_TARGET ${Rust_CARGO_TARGET} CACHE INTERNAL "target triple used by corrosion")
 set(_CORROSION_RUST_CARGO_HOST_TARGET ${Rust_CARGO_HOST_TARGET} CACHE INTERNAL "host triple used by corrosion")
@@ -665,19 +520,11 @@
 # immediately, we are using a different property name depending on the CMake version. However users avoid using
 # any of the properties directly, as they are no longer part of the public API and are to be considered deprecated.
 # Instead use the corrosion_set_... functions as documented in the Readme.
-if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.19.0)
-    set(_CORR_PROP_FEATURES CORROSION_FEATURES CACHE INTERNAL "")
-    set(_CORR_PROP_ALL_FEATURES CORROSION_ALL_FEATURES CACHE INTERNAL "")
-    set(_CORR_PROP_NO_DEFAULT_FEATURES CORROSION_NO_DEFAULT_FEATURES CACHE INTERNAL "")
-    set(_CORR_PROP_ENV_VARS CORROSION_ENVIRONMENT_VARIABLES CACHE INTERNAL "")
-    set(_CORR_PROP_HOST_BUILD CORROSION_USE_HOST_BUILD CACHE INTERNAL "")
-else()
-    set(_CORR_PROP_FEATURES INTERFACE_CORROSION_FEATURES CACHE INTERNAL "")
-    set(_CORR_PROP_ALL_FEATURES INTERFACE_CORROSION_ALL_FEATURES CACHE INTERNAL "")
-    set(_CORR_PROP_NO_DEFAULT_FEATURES INTERFACE_NO_DEFAULT_FEATURES CACHE INTERNAL "")
-    set(_CORR_PROP_ENV_VARS INTERFACE_CORROSION_ENVIRONMENT_VARIABLES CACHE INTERNAL "")
-    set(_CORR_PROP_HOST_BUILD INTERFACE_CORROSION_USE_HOST_BUILD CACHE INTERNAL "")
-endif()
+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)
 #
@@ -707,12 +554,22 @@
     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()
@@ -846,6 +703,11 @@
         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}" "$<$<BOOL:${corrosion_link_args}>:-Clink-args=${corrosion_link_args}>")
 
     # todo: this should probably also be guarded by if_not_host_build_condition.
@@ -883,7 +745,7 @@
         corrosion_add_target_local_rustflags("${target_name}" "$<$<NOT:${explicit_linker_defined}>:${rustflag_linker_arg}>")
     endif()
 
-    message(DEBUG "TARGET ${target_name} produces byproducts ${byproducts}")
+    message(DEBUG "TARGET ${target_name} produces byproducts ${build_byproducts}")
 
     add_custom_target(
         _cargo-build_${target_name}
@@ -906,6 +768,7 @@
                 ${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}
@@ -914,12 +777,11 @@
                 ${local_rustflags_delimiter}
                 ${local_rustflags_genex}
 
-        # Note: Adding `build_byproducts` (the byproducts in the cargo target directory) here
-        # causes CMake to fail during the Generate stage, because the target `target_name` was not
-        # found. I don't know why this happens, so we just don't specify byproducts here and
-        # only specify the actual byproducts in the `POST_BUILD` custom command that copies the
-        # byproducts to the final destination.
-        # BYPRODUCTS  ${build_byproducts}
+        # Note: `BYPRODUCTS` may not contain **target specific** generator expressions.
+        # This means we cannot use `${cargo_build_dir}`, since it currently uses `$<TARGET_PROPERTY>`
+        # to determine the correct target directory, depending on if the hostbuild target property is
+        # set or not.
+        # BYPRODUCTS  "${cargo_build_dir}/${build_byproducts}"
         # The build is conducted in the directory of the Manifest, so that configuration files such as
         # `.cargo/config.toml` or `toolchain.toml` are applied as expected.
         WORKING_DIRECTORY "${workspace_toml_dir}"
@@ -976,6 +838,7 @@
         [PROFILE <cargo-profile>]
         [IMPORTED_CRATES <variable-name>]
         [CRATE_TYPES <crate_type1> ... <crate_typeN>]
+        [OVERRIDE_CRATE_TYPE <crate_name>=<crate_type1,crate_type2,...> ...]
         [CRATES <crate1> ... <crateN>]
         [FEATURES <feature1> ... <featureN>]
         [FLAGS <flag1> ... <flagN>]
@@ -991,6 +854,9 @@
 * **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`.
@@ -1001,6 +867,7 @@
 [--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
@@ -1008,7 +875,7 @@
 function(corrosion_import_crate)
     set(OPTIONS ALL_FEATURES NO_DEFAULT_FEATURES NO_STD NO_LINKER_OVERRIDE LOCKED FROZEN)
     set(ONE_VALUE_KEYWORDS MANIFEST_PATH PROFILE IMPORTED_CRATES)
-    set(MULTI_VALUE_KEYWORDS CRATE_TYPES CRATES FEATURES FLAGS)
+    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")
 
@@ -1047,6 +914,46 @@
         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 `<package_name>=<crate_type(s)>."
+               "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()
@@ -1061,65 +968,17 @@
     endif()
 
     set(imported_crates "")
-    if (CORROSION_NATIVE_TOOLING)
-        get_filename_component(manifest_directory "${COR_MANIFEST_PATH}" DIRECTORY)
-        get_filename_component(toml_dir_name ${manifest_directory} NAME)
 
-        set(
-            generated_cmake
-            "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/corrosion/${toml_dir_name}.dir/cargo-build.cmake"
-        )
-
-        if (CMAKE_VS_PLATFORM_NAME)
-            set (_CORROSION_CONFIGURATION_ROOT --configuration-root ${CMAKE_VS_PLATFORM_NAME})
-        endif()
-
-        set(crates_args)
-        foreach(crate ${COR_CRATES})
-            list(APPEND crates_args --crates ${crate})
-        endforeach()
-        if(DEFINED COR_CRATE_TYPES)
-            set(crate_types "--crate-type=${COR_CRATE_TYPES}")
-        endif()
-
-        list(APPEND passthrough_to_acb_args ${no_linker_override})
-        if(passthrough_to_acb_args)
-            # 31 == 0x1f
-            string(ASCII 31 unit_seperator)
-            list(JOIN passthrough_to_acb_args "${unit_seperator}" joined_args)
-            set(passthrough_to_acb "--passthrough-acb=${joined_args}")
-        endif()
-
-        execute_process(
-            COMMAND
-                ${_CORROSION_GENERATOR}
-                    --manifest-path ${COR_MANIFEST_PATH}
-                    gen-cmake
-                        ${_CORROSION_CONFIGURATION_ROOT}
-                        ${crates_args}
-                        ${crate_types}
-                        --imported-crates=imported_crates
-                        ${passthrough_to_acb}
-                        -o ${generated_cmake}
-            WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
-            RESULT_VARIABLE ret)
-
-        if (NOT ret EQUAL "0")
-            message(FATAL_ERROR "corrosion-generator failed")
-        endif()
-
-        include(${generated_cmake})
-    else()
-        _generator_add_cargo_targets(
-            MANIFEST_PATH
-                "${COR_MANIFEST_PATH}"
-            IMPORTED_CRATES
-                imported_crates
-            ${crate_allowlist}
-            ${crate_types}
-            ${no_linker_override}
-        )
-    endif()
+    _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
@@ -1143,11 +1002,6 @@
     endif()
 endfunction()
 
-function(corrosion_set_linker_language target_name language)
-    message(FATAL_ERROR "corrosion_set_linker_language was deprecated and removed."
-            "Please use corrosion_set_linker and set a specific linker.")
-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")
@@ -1269,7 +1123,6 @@
             return()
         endif()
     endif()
-    add_dependencies(_cargo-build_${target_name} ${ARGN})
     foreach(library ${ARGN})
         set_property(
             TARGET _cargo-build_${target_name}
@@ -1278,11 +1131,48 @@
             $<TARGET_PROPERTY:${library},LINKER_LANGUAGE>
         )
 
-        corrosion_add_target_local_rustflags(${target_name} "-L$<TARGET_LINKER_FILE_DIR:${library}>")
-        corrosion_add_target_local_rustflags(${target_name} "-l$<TARGET_LINKER_FILE_BASE_NAME:${library}>")
+        if (TARGET "${library}")
+            corrosion_add_target_local_rustflags(${target_name}
+                "-L$<TARGET_LINKER_FILE_DIR:${library}>"
+                "-l$<TARGET_LINKER_FILE_BASE_NAME:${library}>"
+            )
+            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 <target1> ... <targetN> [EXPORT <export-name>]
+                  [[ARCHIVE|LIBRARY|RUNTIME|PUBLIC_HEADER]
+                   [DESTINATION <dir>]
+                   [PERMISSIONS <permissions...>]
+                   [CONFIGURATIONS [Debug|Release|<other-configuration>]]
+                  ] [...])
+```
+* **TARGETS**: Target or targets to install.
+* **EXPORT**: Creates an export that can be installed with `install(EXPORT)`. <export-name> must be globally unique.
+             Also creates a file at ${CMAKE_BINARY_DIR}/corrosion/<export-name>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)
@@ -1303,13 +1193,6 @@
     set(TARGET_ARGS ${OPTIONS} ${ONE_VALUE_ARGS} ${MULTI_VALUE_ARGS})
 
     if (INSTALL_TYPE STREQUAL "TARGETS")
-        # corrosion_install(TARGETS ... [EXPORT <export-name>]
-        #                   [[ARCHIVE|LIBRARY|RUNTIME|PRIVATE_HEADER|PUBLIC_HEADER]
-        #                    [DESTINATION <dir>]
-        #                    [PERMISSIONS permissions...]
-        #                    [CONFIGURATIONS [Debug|Release|...]]
-        #                   ] [...])
-
         # Extract targets
         set(INSTALL_TARGETS)
         list(LENGTH ARGN ARGN_LENGTH)
@@ -1337,8 +1220,16 @@
 
                 list(GET ARGN 0 EXPORT_NAME)
                 list(REMOVE_AT ARGN 0) # Pop <export-name>
-                message(FATAL_ERROR "EXPORT keyword not yet implemented!")
+                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
@@ -1395,6 +1286,9 @@
 
         # 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(
@@ -1436,11 +1330,187 @@
                     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 $<TARGET_PROPERTY:${INSTALL_TARGET}-static,IMPORTED_LOCATION>
+                            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()
 
@@ -1453,6 +1523,7 @@
 ```cmake
 corrosion_add_cxxbridge(cxx_target
         CRATE <imported_target_name>
+        REGEN_TARGET <regen_target_name>
         [FILES <file1.rs> <file2.rs>]
 )
 ```
@@ -1463,6 +1534,7 @@
 * `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
 
@@ -1500,7 +1572,7 @@
 #]=======================================================================]
 function(corrosion_add_cxxbridge cxx_target)
     set(OPTIONS)
-    set(ONE_VALUE_KEYWORDS CRATE)
+    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}")
 
@@ -1564,7 +1636,11 @@
     # 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}")
-            add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/corrosion/cxxbridge_v${cxx_required_version}/bin/cxxbridge"
+            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
@@ -1579,10 +1655,10 @@
                 COMMENT "Building cxxbridge (version ${cxx_required_version})"
                 )
             add_custom_target("cxxbridge_v${cxx_required_version}"
-                DEPENDS "${CMAKE_BINARY_DIR}/corrosion/cxxbridge_v${cxx_required_version}/bin/cxxbridge"
+                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")
+        set(cxxbridge "${CMAKE_BINARY_DIR}/corrosion/cxxbridge_v${cxx_required_version}/bin/cxxbridge${executable_postfix}")
     endif()
 
 
@@ -1638,6 +1714,8 @@
             COMMENT "Generating rust/cxx.h header"
     )
 
+    set(GENERATED_FILES "${generated_dir}/include/rust/cxx.h")
+
     foreach(filepath ${_arg_FILES})
         get_filename_component(filename ${filepath} NAME_WE)
         get_filename_component(directory ${filepath} DIRECTORY)
@@ -1665,16 +1743,21 @@
                     --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}"
+            COMMENT "Generating cxx bindings for crate ${_arg_CRATE} and file src/${filepath}"
         )
 
-        target_sources(${cxx_target}
-            PRIVATE
-                "${header_placement_dir}/${cxx_header}"
-                "${generated_dir}/include/rust/cxx.h"
-                "${source_placement_dir}/${cxx_source}"
-        )
+        list(APPEND GENERATED_FILES
+            "${header_placement_dir}/${cxx_header}"
+            "${source_placement_dir}/${cxx_source}")
     endforeach()
+    target_sources(${cxx_target} PRIVATE ${GENERATED_FILES})
+
+    if(DEFINED _arg_REGEN_TARGET)
+        add_custom_target(${_arg_REGEN_TARGET}
+            DEPENDS ${GENERATED_FILES}
+            COMMENT "Generated cxx bindings for crate ${_arg_CRATE}")
+    endif()
+
 endfunction()
 
 #[=======================================================================[.md:
@@ -1683,6 +1766,7 @@
 corrosion_cbindgen(
         TARGET <imported_target_name>
         HEADER_NAME <output_header_name>
+        [CARGO_PACKAGE <cargo_package_name>]
         [MANIFEST_DIRECTORY <package_manifest_directory>]
         [CBINDGEN_VERSION <version>]
         [FLAGS <flag1> ... <flagN>]
@@ -1695,7 +1779,7 @@
 between multiple invocations of this function.
 
 
-* **TARGET**: The name of an imported Rust library target (crate), for which bindings should be generated.
+* **TARGET**: The name of an imported Rust library target, for which bindings should be generated.
               If the target was not previously imported by Corrosion, because the crate only produces an
               `rlib`, you must additionally specify `MANIFEST_DIRECTORY`.
 
@@ -1710,11 +1794,24 @@
 
 [cbindgen]: https://github.com/eqrion/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 HEADER_NAME CBINDGEN_VERSION)
+    set(ONE_VALUE_KEYWORDS
+            TARGET
+            MANIFEST_DIRECTORY
+            HEADER_NAME
+            CBINDGEN_VERSION)
     set(MULTI_VALUE_KEYWORDS "FLAGS")
     cmake_parse_arguments(PARSE_ARGV 0 CCN "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}")
 
@@ -1750,14 +1847,10 @@
         endif()
     endif()
 
-    unset(rust_cargo_package)
-    if(NOT DEFINED CCN_CARGO_PACKAGE)
-        get_target_property(rust_cargo_package "${rust_target}" INTERFACE_COR_CARGO_PACKAGE_NAME )
-        if(NOT rust_cargo_package)
-            message(FATAL_ERROR "Could not determine cargo package name for cbindgen!")
-        endif()
-    else()
-        set(rust_cargo_package "${CCN_CARGO_PACKAGE}")
+    get_target_property(rust_cargo_package "${rust_target}" COR_CARGO_PACKAGE_NAME )
+    if(NOT rust_cargo_package)
+        message(FATAL_ERROR "Internal Error: Could not determine cargo package name for cbindgen. "
+        )
     endif()
     message(STATUS "Using package ${rust_cargo_package} as crate for cbindgen")
 
@@ -1828,43 +1921,22 @@
     file(MAKE_DIRECTORY "${generated_depfile_dir}")
     set(depfile_cbindgen_arg "--depfile=${generated_depfile}")
 
-    # 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 )
-    if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.22")
-        add_custom_command(
-            OUTPUT
-            "${generated_header}"
-            COMMAND
-            "${CMAKE_COMMAND}" -E env
-                TARGET="${cbindgen_target_triple}"
-                "${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}"
-        )
-        add_custom_target("_corrosion_cbindgen_${rust_target}_bindings_${header_identifier}"
-                          DEPENDS "${generated_header}"
-                          COMMENT "Generate ${generated_header} for ${rust_target}"
-        )
-    else()
-        add_custom_target("_corrosion_cbindgen_${rust_target}_bindings_${header_identifier}"
-                          "${CMAKE_COMMAND}" -E env
-                              TARGET="${cbindgen_target_triple}"
-                              "${cbindgen}"
-                              --output "${generated_header}"
-                              --crate "${rust_cargo_package}"
-                              ${depfile_cbindgen_arg}
-                              ${CCN_FLAGS}
-                          COMMENT "Generate ${generated_header} for ${rust_target}"
-                          COMMAND_EXPAND_LISTS
-                          WORKING_DIRECTORY "${package_manifest_dir}"
-        )
-    endif()
+    add_custom_command(
+        OUTPUT
+        "${generated_header}"
+        COMMAND
+        "${CMAKE_COMMAND}" -E env
+            TARGET="${cbindgen_target_triple}"
+            "${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(
@@ -1879,7 +1951,12 @@
                 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_${rust_target}_bindings_${header_identifier}"
+            DEPENDS "${generated_header}"
+            COMMENT "Generate ${generated_header} for ${rust_target}"
+    )
     add_dependencies("_corrosion_cbindgen_${rust_target}_bindings" "_corrosion_cbindgen_${rust_target}_bindings_${header_identifier}")
     add_dependencies(${rust_target} "_corrosion_cbindgen_${rust_target}_bindings")
 endfunction()
@@ -1931,6 +2008,22 @@
     endif()
 endfunction()
 
+function(_corrosion_initialize_properties target_name)
+    # Initialize the `<XYZ>_OUTPUT_DIRECTORY` properties based on `CMAKE_<XYZ>_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 <var_name> will be set to the same option name again,
--- a/tools/corrosion/cmake/CorrosionConfig.cmake.in	Wed Sep 18 14:10:51 2024 +0200
+++ b/tools/corrosion/cmake/CorrosionConfig.cmake.in	Wed Nov 20 21:37:47 2024 +0100
@@ -6,13 +6,4 @@
 
 list(APPEND CMAKE_MODULE_PATH "${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_DATADIR@/cmake")
 
-set(CORROSION_NATIVE_TOOLING_INSTALLED @CORROSION_NATIVE_TOOLING@)
-if(CORROSION_NATIVE_TOOLING_INSTALLED AND NOT TARGET Corrosion::Generator)
-    add_executable(Corrosion::Generator IMPORTED GLOBAL)
-
-    set_property(
-        TARGET Corrosion::Generator
-        PROPERTY IMPORTED_LOCATION "@CMAKE_INSTALL_FULL_LIBEXECDIR@/corrosion-generator")
-endif()
-
 include(Corrosion)
--- a/tools/corrosion/cmake/CorrosionGenerator.cmake	Wed Sep 18 14:10:51 2024 +0200
+++ b/tools/corrosion/cmake/CorrosionGenerator.cmake	Wed Nov 20 21:37:47 2024 +0100
@@ -44,8 +44,14 @@
 # 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)
+    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)
@@ -64,6 +70,10 @@
     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 "")
 
@@ -82,13 +92,26 @@
 
         math(EXPR target_kind_len-1 "${target_kind_len} - 1")
         set(kinds)
-        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()
-
+        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)
             )
@@ -116,6 +139,8 @@
             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}"
@@ -152,15 +177,17 @@
             endif()
             if(pdb_byproduct)
                 _corrosion_copy_byproducts(
-                    ${target_name} PDB_OUTPUT_DIRECTORY "${cargo_build_out_dir}" "${pdb_byproduct}"
+                    ${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 INTERFACE_COR_CARGO_PACKAGE_NAME "${package_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"
             )
@@ -185,11 +212,11 @@
             )
             if(pdb_byproduct)
                 _corrosion_copy_byproducts(
-                        ${target_name} PDB_OUTPUT_DIRECTORY "${cargo_build_out_dir}" "${pdb_byproduct}"
+                        ${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 INTERFACE_COR_CARGO_PACKAGE_NAME "${package_name}" )
+            set_property(TARGET "${target_name}" PROPERTY COR_CARGO_PACKAGE_NAME "${package_name}" )
         else()
             # ignore other kinds (like examples, tests, build scripts, ...)
         endif()
@@ -209,7 +236,7 @@
 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)
+    set(multi_value_args CRATES CRATE_TYPES OVERRIDE_CRATE_TYPE_ARGS)
     cmake_parse_arguments(
         GGC
         "${options}"
@@ -221,6 +248,7 @@
 
     _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")
@@ -280,6 +308,7 @@
             OUT_CREATED_TARGETS curr_created_targets
             ${no_linker_override}
             ${crate_types}
+            ${override_crate_types}
         )
         list(APPEND created_targets "${curr_created_targets}")
     endforeach()
@@ -306,21 +335,4 @@
     if(GGC_IMPORTED_CRATES)
         set(${GGC_IMPORTED_CRATES} "${created_targets}" PARENT_SCOPE)
     endif()
-
-    foreach(target_name ${created_targets})
-        foreach(output_var RUNTIME_OUTPUT_DIRECTORY ARCHIVE_OUTPUT_DIRECTORY LIBRARY_OUTPUT_DIRECTORY PDB_OUTPUT_DIRECTORY)
-            get_target_property(output_dir ${target_name} "${output_var}")
-            if (NOT output_dir AND 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)
-                get_target_property(output_dir ${target_name} "${output_var}_${config_type_upper}")
-                if (NOT output_dir AND 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()
-    endforeach()
 endfunction()
--- a/tools/corrosion/cmake/FindRust.cmake	Wed Sep 18 14:10:51 2024 +0200
+++ b/tools/corrosion/cmake/FindRust.cmake	Wed Nov 20 21:37:47 2024 +0100
@@ -12,20 +12,25 @@
 
 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.
+# 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()
-    # Note: PARENT_SCOPE is the scope of the caller of the caller of this macro.
-    set(Rust_FOUND "" PARENT_SCOPE)
+    set(Rust_FOUND "")
     return()
 endmacro()
 
@@ -179,7 +184,13 @@
                 
                 # Flags start with / for MSVC
                 if (lib MATCHES "^/" AND ${target_triple} MATCHES "msvc$")
-                    list(APPEND flag_list "${lib}")
+                    # 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}")
@@ -188,8 +199,10 @@
                 endif()
             endforeach()
             set(libs_list "${stripped_lib_list}")
-            # Special case `msvcrt` to link with the debug version in Debug mode.
-            list(TRANSFORM libs_list REPLACE "^msvcrt$" "\$<\$<CONFIG:Debug>:msvcrtd>")
+            # 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}`")
@@ -242,7 +255,8 @@
     else()
         find_program(_Rust_COMPILER_TEST rustc PATHS "$ENV{HOME}/.cargo/bin")
         if(NOT EXISTS "${_Rust_COMPILER_TEST}")
-            set(_ERROR_MESSAGE "`rustc` not found in PATH or `$ENV{HOME}/.cargo/bin`.\n"
+            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})
@@ -389,23 +403,20 @@
         )
     endif()
 
-    set(Rust_RUSTUP_TOOLCHAINS CACHE INTERNAL "List of available Rustup toolchains" "${_DISCOVERED_TOOLCHAINS}")
-    set(Rust_RUSTUP_TOOLCHAINS_RUSTC_PATH
+    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`."
-        "${_DISCOVERED_TOOLCHAINS_RUSTC_PATH}"
     )
-    set(Rust_RUSTUP_TOOLCHAINS_CARGO_PATH
+    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."
-        "${_DISCOVERED_TOOLCHAINS_CARGO_PATH}"
     )
-    set(Rust_RUSTUP_TOOLCHAINS_VERSION
+    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`."
-        "${_DISCOVERED_TOOLCHAINS_VERSION}"
     )
 
     # Rust_TOOLCHAIN is preferred over a requested version if it is set.
@@ -486,16 +497,15 @@
         rustc
             HINTS "${_RUST_TOOLCHAIN_PATH}/bin"
             NO_DEFAULT_PATH)
-elseif (Rust_RUSTUP)
-    get_filename_component(_RUST_TOOLCHAIN_PATH "${Rust_RUSTUP}" DIRECTORY)
-    get_filename_component(_RUST_TOOLCHAIN_PATH "${_RUST_TOOLCHAIN_PATH}" DIRECTORY)
-    find_program(
-        Rust_COMPILER_CACHED
-        rustc
-            HINTS "${_RUST_TOOLCHAIN_PATH}/bin"
-            NO_DEFAULT_PATH)
 else()
-    find_program(Rust_COMPILER_CACHED rustc)
+    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 `<toolchain_path>/bin/rustc`.
         get_filename_component(_RUST_TOOLCHAIN_PATH "${Rust_COMPILER_CACHED}" DIRECTORY)
@@ -686,13 +696,29 @@
             set(_CARGO_ABI msvc)
         elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU"
             OR "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU"
-            OR "${CMAKE_CXX_COMPILER_TARGET}" MATCHES "-gnu$"
-            OR "${CMAKE_C_COMPILER_TARGET}" MATCHES "-gnu$"
-            OR (NOT CMAKE_CROSSCOMPILING AND "${Rust_DEFAULT_HOST_TARGET}" MATCHES "-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 branch matches to ensure this fallback is only used
+            # 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()
@@ -748,6 +774,46 @@
     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()
--- a/tools/corrosion/doc/book.toml	Wed Sep 18 14:10:51 2024 +0200
+++ b/tools/corrosion/doc/book.toml	Wed Nov 20 21:37:47 2024 +0100
@@ -2,4 +2,4 @@
 language = "en"
 multilingual = false
 src = "src"
-title = "Corrosion v0.5 documentation"
+title = "Corrosion documentation"
--- a/tools/corrosion/doc/src/introduction.md	Wed Sep 18 14:10:51 2024 +0200
+++ b/tools/corrosion/doc/src/introduction.md	Wed Nov 20 21:37:47 2024 +0100
@@ -10,10 +10,10 @@
 helper function to conveniently add the necessary flags to link C/C++ libraries into
 the rust target.
 
-You are currently viewing the documentation of the stable v0.5 release branch.
+## Requirements
+
+- Corrosion supports CMake 3.15 and newer with the v0.5 release. If you are using the v0.5 release, please
+  view [the documentation here](./v0.5/introduction.md)
+- The master branch of Corrosion currently requires CMake 3.22 or newer.
 
 [`target_link_libraries()`]: https://cmake.org/cmake/help/latest/command/target_link_libraries.html
-
-## Requirements
-
-Corrosion v0.5 requires at least CMake 3.15 and at least Rust 1.46 or newer.
\ No newline at end of file
--- a/tools/corrosion/doc/src/quick_start.md	Wed Sep 18 14:10:51 2024 +0200
+++ b/tools/corrosion/doc/src/quick_start.md	Wed Nov 20 21:37:47 2024 +0100
@@ -33,4 +33,5 @@
 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.
--- a/tools/corrosion/doc/src/usage.md	Wed Sep 18 14:10:51 2024 +0200
+++ b/tools/corrosion/doc/src/usage.md	Wed Nov 20 21:37:47 2024 +0100
@@ -32,6 +32,93 @@
 [`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
+        GIT_TAG v0.5 # 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 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
+        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+        $<INSTALL_INTERFACE:include>
+)
+target_sources(is_odd
+        INTERFACE
+        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/rust-lib/rust-lib.h>
+        $<INSTALL_INTERFACE:include/rust-lib/rust-lib.h>
+)
+
+# 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
@@ -68,7 +155,10 @@
 
 
 ### Global Corrosion Options
-All of the following variables are evaluated automatically in most cases. In typical cases you
+
+#### 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)`.
 
@@ -90,25 +180,20 @@
 - `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_NATIVE_TOOLING:BOOL` - Use a native tool (written in Rust) as part of Corrosion. This
-  option increases the configure-time significantly unless Corrosion is installed.
-  Default: `OFF` if CMake >= 3.19.0. Forced `ON` for CMake < 3.19.
+
+#### 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_DEV_MODE:BOOL` - Indicates that Corrosion is being actively developed. Default: `OFF`
-  if Corrosion is a subdirectory, `ON` if it is the top-level project
 - `CORROSION_BUILD_TESTS:BOOL` - Build the Corrosion tests. Default: `Off` if Corrosion is a
   subdirectory, `ON` if it is the top-level project
-- `CORROSION_GENERATOR_EXECUTABLE:STRING` - Specify a path to the corrosion-generator executable.
-  This is to support scenarios where it's easier to build corrosion-generator outside of the normal
-  bootstrap path, such as in the case of package managers that make it very easy to import Rust
-  crates for fully reproducible, offline builds.
-- `CORROSION_INSTALL_EXECUTABLE:BOOL` - Controls whether corrosion-generator is installed with the
-  package. Default: `ON` with `CORROSION_GENERATOR_EXECUTABLE` unset, otherwise `OFF`
 
 
 ### Information provided by Corrosion
@@ -295,14 +380,14 @@
 
 **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.15. If you're using Android Studio to build your project,
+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 on CMake >= 3.19:
+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)
--- a/tools/corrosion/generator/CMakeLists.txt	Wed Sep 18 14:10:51 2024 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-message(STATUS "Building CMake Generator for Corrosion - This may take a while")
-
-set(generator_src "${CMAKE_CURRENT_BINARY_DIR}/legacy_generator_src")
-set(generator_destination "${CMAKE_CURRENT_BINARY_DIR}/legacy_generator")
-set(generator_build_quiet "")
-
-file(MAKE_DIRECTORY "${generator_src}")
-file(COPY src DESTINATION "${generator_src}")
-if(Rust_VERSION VERSION_LESS "1.56")
-    message(STATUS "Corrosion Generator: Using Compatibility lock file, due to rust version less than 1.56")
-    file(COPY Compat.Cargo.lock Compat.Cargo.toml DESTINATION "${generator_src}")
-    file(RENAME "${generator_src}/Compat.Cargo.lock" "${generator_src}/Cargo.lock")
-    file(RENAME "${generator_src}/Compat.Cargo.toml" "${generator_src}/Cargo.toml")
-else()
-    file(COPY Cargo.lock Cargo.toml DESTINATION "${generator_src}")
-endif()
-
-# Using cargo install has the advantage of caching the build in the user .cargo directory,
-# so likely the rebuild will be very cheap even after deleting the build directory.
-execute_process(
-        COMMAND ${CMAKE_COMMAND}
-        -E env
-        # If the Generator is built at configure of a project (instead of being pre-installed)
-        # We don't want environment variables like `RUSTFLAGS` affecting the Generator build.
-        --unset=RUSTFLAGS
-        "CARGO_BUILD_RUSTC=${RUSTC_EXECUTABLE}"
-        "${CARGO_EXECUTABLE}" install
-        --path "."
-        --root "${generator_destination}"
-        --locked
-        ${_CORROSION_QUIET_OUTPUT_FLAG}
-        WORKING_DIRECTORY "${generator_src}"
-        RESULT_VARIABLE generator_build_failed
-)
-if(generator_build_failed)
-    message(FATAL_ERROR "Building CMake Generator for Corrosion - failed")
-else()
-    message(STATUS "Building CMake Generator for Corrosion - done")
-endif()
-set(host_executable_suffix "")
-if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
-    set(host_executable_suffix ".exe")
-endif()
-
-set(_CORROSION_GENERATOR_EXE
-        "${generator_destination}/bin/corrosion-generator${host_executable_suffix}"
-)
-
-add_executable(Corrosion::Generator IMPORTED GLOBAL)
-set_property(
-        TARGET Corrosion::Generator
-        PROPERTY IMPORTED_LOCATION "${_CORROSION_GENERATOR_EXE}")
-
-if (CORROSION_DEV_MODE)
-    # If you're developing Corrosion, you want to make sure to re-configure whenever the
-    # generator changes.
-    file(GLOB_RECURSE _RUST_FILES CONFIGURE_DEPENDS generator/src/*.rs)
-    file(GLOB _CARGO_FILES CONFIGURE_DEPENDS generator/Cargo.*)
-    set_property(
-            DIRECTORY APPEND
-            PROPERTY CMAKE_CONFIGURE_DEPENDS
-            ${_RUST_FILES} ${_CARGO_FILES})
-endif()
-
--- a/tools/corrosion/generator/Cargo.toml	Wed Sep 18 14:10:51 2024 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-[package]
-name = "corrosion-generator"
-version = "0.1.0"
-authors = ["Andrew Gaspar <andrew.gaspar@outlook.com>"]
-license = "MIT"
-edition = "2018"
-
-[dependencies]
-cargo_metadata = "0.17"
-serde = { version = " 1.0.186", features = ["derive"] }
-
-[dependencies.clap]
-version = "2.34"
-default-features = false
-# Make sure this crate still compiles while it is checked out
-# in a sub-directory of a repository that has a Cargo.toml.
-[workspace]
--- a/tools/corrosion/generator/Compat.Cargo.toml	Wed Sep 18 14:10:51 2024 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-[package]
-name = "corrosion-generator"
-version = "0.1.0"
-authors = ["Andrew Gaspar <andrew.gaspar@outlook.com>"]
-license = "MIT"
-edition = "2018"
-
-[dependencies]
-cargo_metadata = "0.15"
-# The crates below are indirect dependencies of cargo metadata,
-# We explicitly specify maximum versions to allow building the generator
-# with older toolchains.
-# Version 1.0.157 upgrades to syn 2.0 and raises MSRV to 1.56
-serde = { version = ">=1, <1.0.157", default-features=false }
-# Version 1.0.40 upgrades to syn 2.0 and raises MSRV to 1.56
-thiserror = { version = ">=1, <1.0.40", default-features=false }
-
-[dependencies.clap]
-version = "2.34"
-default-features = false
-# Make sure this crate still compiles while it is checked out
-# in a sub-directory of a repository that has a Cargo.toml.
-[workspace]
--- a/tools/corrosion/generator/src/main.rs	Wed Sep 18 14:10:51 2024 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,95 +0,0 @@
-use std::path::PathBuf;
-
-use cargo_metadata::Metadata;
-use clap::{App, Arg};
-
-mod subcommands {
-    pub mod gen_cmake;
-}
-
-use subcommands::*;
-
-// common options
-const MANIFEST_PATH: &str = "manifest-path";
-const CARGO_EXECUTABLE: &str = "cargo-executable";
-const VERBOSE: &str = "verbose";
-const LOCKED: &str = "locked";
-const FROZEN: &str = "frozen";
-
-pub struct GeneratorSharedArgs {
-    pub manifest_path: PathBuf,
-    pub cargo_executable: PathBuf,
-    pub metadata: Metadata,
-    pub verbose: bool,
-}
-
-fn main() -> Result<(), Box<dyn std::error::Error>> {
-    let matches = App::new("CMake Generator for Cargo")
-        .version("0.1")
-        .author("Andrew Gaspar <andrew.gaspar@outlook.com>")
-        .about("Generates CMake files for Cargo projects")
-        .arg(
-            Arg::with_name(MANIFEST_PATH)
-                .long("manifest-path")
-                .value_name("Cargo.toml")
-                .help("Specifies the target Cargo project")
-                .required(true)
-                .takes_value(true),
-        )
-        .arg(
-            Arg::with_name(CARGO_EXECUTABLE)
-                .long("cargo")
-                .value_name("EXECUTABLE")
-                .required(true)
-                .help("Path to the cargo executable to use"),
-        )
-        .arg(
-            Arg::with_name(VERBOSE)
-                .long("verbose")
-                .help("Request verbose output"),
-        )
-        .arg(
-            Arg::with_name(LOCKED)
-                .long("locked")
-                .help("Pass --locked to cargo invocations"),
-        )
-        .arg(
-            Arg::with_name(FROZEN)
-                .long("frozen")
-                .help("Pass --frozen to cargo invocations"),
-        )
-        .subcommand(gen_cmake::subcommand())
-        .get_matches();
-
-    let mut cmd = cargo_metadata::MetadataCommand::new();
-    cmd.no_deps();
-    if matches.is_present(LOCKED) {
-        cmd.other_options(["--locked".into()]);
-    }
-    if matches.is_present(FROZEN) {
-        cmd.other_options(["--frozen".into()]);
-    }
-
-    let manifest_path = matches.value_of(MANIFEST_PATH).unwrap();
-    let cargo_executable = matches.value_of(CARGO_EXECUTABLE).unwrap();
-
-    cmd.manifest_path(manifest_path);
-    cmd.cargo_path(cargo_executable);
-
-    let metadata = cmd.exec()?;
-
-    let shared_args = GeneratorSharedArgs {
-        manifest_path: manifest_path.into(),
-        cargo_executable: cargo_executable.into(),
-        metadata,
-        verbose: matches.is_present(VERBOSE),
-    };
-
-    match matches.subcommand() {
-        (gen_cmake::GEN_CMAKE, Some(matches)) => gen_cmake::invoke(&shared_args, matches)?,
-        _ => unreachable!(),
-    };
-
-    // We should never reach this statement
-    std::process::exit(1);
-}
--- a/tools/corrosion/generator/src/subcommands/gen_cmake.rs	Wed Sep 18 14:10:51 2024 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,160 +0,0 @@
-use std::{
-    fs::{create_dir_all, File},
-    io::{stdout, Write},
-    path::Path,
-    rc::Rc,
-};
-
-use clap::{App, Arg, ArgMatches, SubCommand};
-
-mod target;
-
-// Command name
-pub const GEN_CMAKE: &str = "gen-cmake";
-
-// Options
-const OUT_FILE: &str = "out-file";
-const CONFIGURATION_ROOT: &str = "configuration-root";
-const CRATES: &str = "crates";
-const IMPORTED_CRATES: &str = "imported-crates";
-const CRATE_TYPE: &str = "crate-type";
-const PASSTHROUGH_ADD_CARGO_BUILD: &str = "passthrough-acb";
-
-pub fn subcommand() -> App<'static, 'static> {
-    SubCommand::with_name(GEN_CMAKE)
-        .arg(
-            Arg::with_name(CONFIGURATION_ROOT)
-                .long("configuration-root")
-                .value_name("DIRECTORY")
-                .takes_value(true)
-                .help(
-                    "Specifies a root directory for configuration folders. E.g. Win32 \
-                 in VS Generator.",
-                ),
-        )
-        .arg(
-            Arg::with_name(CRATES)
-                .long("crates")
-                .value_name("crates")
-                .takes_value(true)
-                .multiple(true)
-                .require_delimiter(true)
-                .help("Specifies which crates of the workspace to import"),
-        )
-        .arg(
-            Arg::with_name(CRATE_TYPE)
-                .long(CRATE_TYPE)
-                .value_name("kind")
-                .possible_values(&["staticlib", "cdylib", "bin"])
-                .multiple(true)
-                .value_delimiter(";")
-                .help("Only import the specified crate types")
-        )
-        .arg(
-            Arg::with_name(OUT_FILE)
-                .short("o")
-                .long("out-file")
-                .value_name("FILE")
-                .help("Output CMake file name. Defaults to stdout."),
-        )
-        .arg(
-            Arg::with_name(IMPORTED_CRATES)
-                .long(IMPORTED_CRATES)
-                .value_name("variable_name")
-                .takes_value(true)
-                .help("Save a list of the imported target names into c CMake variable with the given name"),
-        )
-        .arg(
-            Arg::with_name(PASSTHROUGH_ADD_CARGO_BUILD)
-                .long(PASSTHROUGH_ADD_CARGO_BUILD)
-                .takes_value(true)
-                .multiple(true)
-                .value_delimiter(std::char::from_u32(0x1f).unwrap().to_string().as_str())
-                .help("Passthrough arguments to the _add_cargo_build invocation(s) in CMake")
-        )
-}
-
-pub fn invoke(
-    args: &crate::GeneratorSharedArgs,
-    matches: &ArgMatches,
-) -> Result<(), Box<dyn std::error::Error>> {
-    let mut out_file: Box<dyn Write> = if let Some(path) = matches.value_of(OUT_FILE) {
-        let path = Path::new(path);
-        if let Some(parent) = path.parent() {
-            create_dir_all(parent).expect("Failed to create directory!");
-        }
-        let file = File::create(path).expect("Unable to open out-file!");
-        Box::new(file)
-    } else {
-        Box::new(stdout())
-    };
-
-    writeln!(
-        out_file,
-        "\
-cmake_minimum_required(VERSION 3.15)
-"
-    )?;
-
-    let crates = matches
-        .values_of(CRATES)
-        .map_or(Vec::new(), |c| c.collect());
-    let crate_kinds: Option<Vec<&str>> = matches.values_of(CRATE_TYPE).map(|c| c.collect());
-    let workspace_manifest_path = Rc::new(args.manifest_path.clone());
-    let targets: Vec<_> = args
-        .metadata
-        .packages
-        .iter()
-        .filter(|p| {
-            args.metadata.workspace_members.contains(&p.id)
-                && (crates.is_empty() || crates.contains(&p.name.as_str()))
-        })
-        .cloned()
-        .map(Rc::new)
-        .flat_map(|package| {
-            package
-                .targets
-                .iter()
-                .filter_map(|t| {
-                    target::CargoTarget::from_metadata(
-                        package.clone(),
-                        t.clone(),
-                        workspace_manifest_path.clone(),
-                        &crate_kinds,
-                    )
-                })
-                .collect::<Vec<_>>()
-        })
-        .collect();
-
-    let passthrough_args: Vec<String> = matches
-        .values_of(PASSTHROUGH_ADD_CARGO_BUILD)
-        .map(|values| {
-            // Add quotes around each argument for CMake to preserve which arguments belong together.
-            values
-                .filter(|val| !val.is_empty())
-                .map(|val| format!("\"{}\"", val))
-                .collect()
-        })
-        .unwrap_or_default();
-    let passthrough_str = passthrough_args.join(" ");
-
-    for target in &targets {
-        target
-            .emit_cmake_target(&mut out_file, &passthrough_str)
-            .unwrap();
-    }
-    if let Some(imported_crate_list_name) = matches.value_of(IMPORTED_CRATES) {
-        let imported_targets: Vec<_> = targets.iter().map(|target| target.target_name()).collect();
-        let imported_targets_list = imported_targets.join(";");
-        writeln!(
-            out_file,
-            "set({} \"{}\")",
-            imported_crate_list_name, imported_targets_list
-        )?;
-    }
-
-    writeln!(out_file)?;
-
-    std::process::exit(0);
-}
--- a/tools/corrosion/generator/src/subcommands/gen_cmake/target.rs	Wed Sep 18 14:10:51 2024 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,222 +0,0 @@
-use std::error::Error;
-use std::path::PathBuf;
-use std::rc::Rc;
-
-#[derive(Clone)]
-pub enum CargoTargetType {
-    Executable,
-    Library {
-        has_staticlib: bool,
-        has_cdylib: bool,
-    },
-}
-
-#[derive(Clone)]
-pub struct CargoTarget {
-    cargo_package: Rc<cargo_metadata::Package>,
-    cargo_target: cargo_metadata::Target,
-    target_type: CargoTargetType,
-    workspace_manifest_path: Rc<PathBuf>,
-}
-
-impl CargoTargetType {
-    fn to_string(&self) -> String {
-        let mut s = String::new();
-        match self {
-            Self::Executable => {
-                s.push_str("bin");
-            }
-            Self::Library {
-                has_staticlib,
-                has_cdylib,
-            } => {
-                if *has_staticlib {
-                    s.push_str("staticlib")
-                }
-                if *has_cdylib {
-                    s.push_str(" cdylib")
-                }
-            }
-        }
-        s
-    }
-}
-
-impl CargoTarget {
-    pub fn from_metadata(
-        cargo_package: Rc<cargo_metadata::Package>,
-        cargo_target: cargo_metadata::Target,
-        workspace_manifest_path: Rc<PathBuf>,
-        // If Some, only import crates if the kind variant is given in crate_kinds.
-        crate_kinds: &Option<Vec<&str>>,
-    ) -> Option<Self> {
-        let filtered_kinds: Vec<String> = cargo_target
-            .kind
-            .clone()
-            .into_iter()
-            .filter(|kind| match crate_kinds {
-                None => true,
-                Some(allowed_kinds_subset) => allowed_kinds_subset.contains(&&**kind),
-            })
-            .collect();
-
-        let target_type = if filtered_kinds
-            .iter()
-            .any(|k| k.as_str() == "staticlib" || k.as_str() == "cdylib")
-        {
-            CargoTargetType::Library {
-                has_staticlib: filtered_kinds.iter().any(|k| k == "staticlib"),
-                has_cdylib: filtered_kinds.iter().any(|k| k == "cdylib"),
-            }
-        } else if filtered_kinds.iter().any(|k| k == "bin") {
-            CargoTargetType::Executable
-        } else {
-            return None;
-        };
-
-        Some(Self {
-            cargo_package,
-            cargo_target,
-            target_type,
-            workspace_manifest_path,
-        })
-    }
-
-    /// Cargo / Rust 1.78 and newer replace dashes with underscores in libraries
-    /// To make the names consistent across versions we also do the replacement here.
-    pub(crate) fn target_name(&self) -> String {
-        match self.target_type {
-            CargoTargetType::Library { .. } => self.cargo_target.name.replace("-", "_"),
-            _ => self.cargo_target.name.to_string(),
-        }
-    }
-
-    pub fn emit_cmake_target(
-        &self,
-        out_file: &mut dyn std::io::Write,
-        passthrough_add_cargo_build: &str,
-    ) -> Result<(), Box<dyn Error>> {
-        writeln!(
-            out_file,
-            "set(byproducts \"\")
-                            set(cargo_build_out_dir \"\")
-                            set(archive_byproducts \"\")
-                            set(shared_lib_byproduct \"\")
-                            set(pdb_byproduct \"\")
-                            set(bin_byproduct \"\")
-        "
-        )?;
-        let ws_manifest = self
-            .workspace_manifest_path
-            .to_str()
-            .expect("Non-utf8 path encountered")
-            .replace("\\", "/");
-
-        match self.target_type {
-            CargoTargetType::Library {
-                has_staticlib,
-                has_cdylib,
-            } => {
-                assert!(has_staticlib || has_cdylib);
-                let ws_manifest = self
-                    .workspace_manifest_path
-                    .to_str()
-                    .expect("Non-utf8 path encountered")
-                    .replace("\\", "/");
-                let mut lib_kinds = if has_staticlib { "staticlib" } else { "" }.to_string();
-                if has_cdylib {
-                    if has_staticlib {
-                        lib_kinds.push(' ');
-                    }
-                    lib_kinds.push_str("cdylib")
-                }
-
-                writeln!(
-                    out_file,
-                    "
-                    _corrosion_add_library_target(
-                            WORKSPACE_MANIFEST_PATH \"{workspace_manifest_path}\"
-                            TARGET_NAME \"{target_name}\"
-                            LIB_KINDS {lib_kinds}
-                            OUT_ARCHIVE_OUTPUT_BYPRODUCTS archive_byproducts
-                            OUT_SHARED_LIB_BYPRODUCTS shared_lib_byproduct
-                            OUT_PDB_BYPRODUCT pdb_byproduct
-                    )
-                    list(APPEND byproducts
-                            \"${{archive_byproducts}}\"
-                            \"${{shared_lib_byproduct}}\"
-                            \"${{pdb_byproduct}}\"
-                    )
-                    ",
-                    workspace_manifest_path = ws_manifest,
-                    target_name = self.target_name(),
-                    lib_kinds = lib_kinds,
-                )?;
-            }
-            CargoTargetType::Executable => {
-                writeln!(
-                    out_file,
-                    "
-                    _corrosion_add_bin_target(\"{workspace_manifest_path}\" \"{target_name}\"
-                        bin_byproduct pdb_byproduct
-                    )
-                    set(byproducts \"\")
-                    list(APPEND byproducts \"${{bin_byproduct}}\" \"${{pdb_byproduct}}\")
-                    ",
-                    workspace_manifest_path = ws_manifest,
-                    target_name = self.target_name(),
-                )?;
-            }
-        };
-        let target_kinds = self.target_type.to_string();
-        writeln!(out_file,
-            "
-            set(cargo_build_out_dir \"\")
-            _add_cargo_build(
-                cargo_build_out_dir
-                PACKAGE \"{package_name}\"
-                TARGET \"{target_name}\"
-                MANIFEST_PATH \"{package_manifest_path}\"
-                WORKSPACE_MANIFEST_PATH \"{workspace_manifest_path}\"
-                TARGET_KINDS {target_kinds}
-                BYPRODUCTS \"${{byproducts}}\"
-                {passthrough_add_cargo_build}
-            )
-
-            set_target_properties({target_name} PROPERTIES
-                INTERFACE_COR_PACKAGE_MANIFEST_PATH \"{package_manifest_path}\"
-            )
-
-            if(archive_byproducts)
-                _corrosion_copy_byproducts(
-                    {target_name} ARCHIVE_OUTPUT_DIRECTORY \"${{cargo_build_out_dir}}\" \"${{archive_byproducts}}\" FALSE
-                )
-            endif()
-            if(shared_lib_byproduct)
-                _corrosion_copy_byproducts(
-                    {target_name} LIBRARY_OUTPUT_DIRECTORY \"${{cargo_build_out_dir}}\" \"${{shared_lib_byproduct}}\" FALSE
-                )
-            endif()
-            if(pdb_byproduct)
-                _corrosion_copy_byproducts(
-                    {target_name} PDB_OUTPUT_DIRECTORY \"${{cargo_build_out_dir}}\" \"${{pdb_byproduct}}\" FALSE
-                )
-            endif()
-            if(bin_byproduct)
-                _corrosion_copy_byproducts(
-                    {target_name} RUNTIME_OUTPUT_DIRECTORY \"${{cargo_build_out_dir}}\" \"${{bin_byproduct}}\" TRUE
-                )
-            endif()
-            set_property(TARGET {target_name} PROPERTY INTERFACE_COR_CARGO_PACKAGE_NAME {package_name} )
-            ",
-            package_name = self.cargo_package.name,
-            target_name = self.target_name(),
-            package_manifest_path = self.cargo_package.manifest_path.as_str().replace("\\", "/"),
-            workspace_manifest_path = ws_manifest,
-            target_kinds = target_kinds,
-            passthrough_add_cargo_build = passthrough_add_cargo_build,
-
-        )?;
-        Ok(())
-    }
-}
--- a/tools/corrosion/test/CMakeLists.txt	Wed Sep 18 14:10:51 2024 +0200
+++ b/tools/corrosion/test/CMakeLists.txt	Wed Nov 20 21:37:47 2024 +0100
@@ -15,14 +15,14 @@
 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(\"${CMAKE_CURRENT_SOURCE_DIR}/..\" corrosion)"
+        "    add_subdirectory(\"${corrosion_source_dir}\" corrosion)"
         "endif()"
 )
 
@@ -73,7 +73,7 @@
 endif()
 
 function(corrosion_tests_add_test test_name bin_names)
-    set(options "")
+    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}")
@@ -87,22 +87,30 @@
         set(test_dir "${test_name}")
     endif()
 
-
+    set(configure_cmake_args)
     if(CMAKE_C_COMPILER)
-        set(TEST_C_COMPILER "C_COMPILER" "${CMAKE_C_COMPILER}")
+        list(APPEND configure_cmake_args "C_COMPILER" "${CMAKE_C_COMPILER}")
     endif()
     if(CMAKE_CXX_COMPILER)
-        set(TEST_CXX_COMPILER "CXX_COMPILER" "${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)
-        set(TEST_GENERATOR_PLATFORM "GENERATOR_PLATFORM" "${CMAKE_GENERATOR_PLATFORM}")
-    endif()
-    if(CORROSION_GENERATOR_EXECUTABLE)
-        # Mainly used in CI to build the native generator once and then reuse it for all tests
-        set(TEST_GENERATOR_BIN EXTERNAL_CORROSION_GENERATOR "${CORROSION_GENERATOR_EXECUTABLE}")
+        list(APPEND configure_cmake_args "GENERATOR_PLATFORM" "${CMAKE_GENERATOR_PLATFORM}")
     endif()
     if(CMAKE_CROSSCOMPILING)
-        set(TEST_SYSTEM_NAME SYSTEM_NAME "${CMAKE_SYSTEM_NAME}")
+        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"
@@ -114,11 +122,7 @@
             GENERATOR "${CMAKE_GENERATOR}"
             RUST_TOOLCHAIN "${Rust_TOOLCHAIN}"
             CARGO_TARGET "${Rust_CARGO_TARGET}"
-            "${TEST_SYSTEM_NAME}"
-            "${TEST_C_COMPILER}"
-            "${TEST_CXX_COMPILER}"
-            "${TEST_GENERATOR_PLATFORM}"
-            "${TEST_GENERATOR_BIN}"
+            ${configure_cmake_args}
             ${pass_through_arguments}
 
             COMMAND_EXPAND_LISTS
@@ -137,7 +141,7 @@
         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)
+        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()
@@ -164,12 +168,13 @@
 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)
 add_subdirectory(cbindgen)
+add_subdirectory(corrosion_install)
 add_subdirectory(cxxbridge)
 add_subdirectory(envvar)
-add_subdirectory(external_corrosion_generator)
 add_subdirectory(features)
 add_subdirectory(find_rust)
 add_subdirectory(gensource)
--- a/tools/corrosion/test/ConfigureAndBuild.cmake	Wed Sep 18 14:10:51 2024 +0200
+++ b/tools/corrosion/test/ConfigureAndBuild.cmake	Wed Nov 20 21:37:47 2024 +0100
@@ -17,39 +17,50 @@
     CARGO_TARGET
     C_COMPILER
     CXX_COMPILER
+    C_COMPILER_TARGET
+    CXX_COMPILER_TARGET
     SYSTEM_NAME
-    EXTERNAL_CORROSION_GENERATOR
     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)
-    set(TEST_Rust_CARGO_TARGET "-DRust_CARGO_TARGET=${TEST_CARGO_TARGET}")
+    list(APPEND configure_args "-DRust_CARGO_TARGET=${TEST_CARGO_TARGET}")
 endif()
 if(TEST_USE_INSTALLED_CORROSION)
-    set(TEST_CORROSION_INSTALL "-DCORROSION_TESTS_FIND_CORROSION=ON")
+    list(APPEND configure_args "-DCORROSION_TESTS_FIND_CORROSION=ON")
 endif()
 if(TEST_GENERATOR_PLATFORM)
-    set(TEST_GENERATOR_PLATFORM "-A${TEST_GENERATOR_PLATFORM}")
+    list(APPEND configure_args "-A${TEST_GENERATOR_PLATFORM}")
 endif()
 if(TEST_C_COMPILER)
-    set(TEST_C_COMPILER "-DCMAKE_C_COMPILER=${TEST_C_COMPILER}")
+    list(APPEND configure_args "-DCMAKE_C_COMPILER=${TEST_C_COMPILER}")
 endif()
 if(TEST_CXX_COMPILER)
-    set(TEST_CXX_COMPILER "-DCMAKE_CXX_COMPILER=${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)
-    set(TEST_SYSTEM_NAME "-DCMAKE_SYSTEM_NAME=${TEST_SYSTEM_NAME}")
+    list(APPEND configure_args "-DCMAKE_SYSTEM_NAME=${TEST_SYSTEM_NAME}")
 endif()
-if(TEST_EXTERNAL_CORROSION_GENERATOR)
-    set(TEST_EXTERNAL_CORROSION_GENERATOR
-        "-DCORROSION_GENERATOR_EXECUTABLE=${TEST_EXTERNAL_CORROSION_GENERATOR}"
-    )
+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)
-    set(TEST_CARGO_PROFILE "-DCARGO_PROFILE=${TEST_CARGO_PROFILE}")
+    list(APPEND configure_args "-DCARGO_PROFILE=${TEST_CARGO_PROFILE}")
 endif()
 
 # Remove old binary directory
@@ -65,14 +76,7 @@
             "-G${TEST_GENERATOR}"
             "-DRust_TOOLCHAIN=${TEST_RUST_TOOLCHAIN}"
             --log-level Debug
-            ${TEST_Rust_CARGO_TARGET}
-            ${TEST_CORROSION_INSTALL}
-            ${TEST_GENERATOR_PLATFORM}
-            ${TEST_C_COMPILER}
-            ${TEST_CXX_COMPILER}
-            ${TEST_SYSTEM_NAME}
-            ${TEST_EXTERNAL_CORROSION_GENERATOR}
-            ${TEST_CARGO_PROFILE}
+            ${configure_args}
             ${TEST_PASS_THROUGH_ARGS}
             -S "${TEST_SOURCE_DIR}"
             -B "${TEST_BINARY_DIR}"
--- a/tools/corrosion/test/cbindgen/CMakeLists.txt	Wed Sep 18 14:10:51 2024 +0200
+++ b/tools/corrosion/test/cbindgen/CMakeLists.txt	Wed Nov 20 21:37:47 2024 +0100
@@ -7,3 +7,5 @@
 # - 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.
--- a/tools/corrosion/test/cbindgen/rust2cpp/main.cpp	Wed Sep 18 14:10:51 2024 +0200
+++ b/tools/corrosion/test/cbindgen/rust2cpp/main.cpp	Wed Nov 20 21:37:47 2024 +0100
@@ -16,4 +16,7 @@
     add_point(&p1, NULL);
     assert(p1.x == 100);
     assert(p1.y == 100);
+
+    assert(OTHER_MOD_MAGIC_NUMBER == 192312312);
+    assert(FFI_MAGIC_NUMBER == 0xFDA00184);
 }
--- a/tools/corrosion/test/cbindgen/rust2cpp/rust/cbindgen.toml	Wed Sep 18 14:10:51 2024 +0200
+++ b/tools/corrosion/test/cbindgen/rust2cpp/rust/cbindgen.toml	Wed Nov 20 21:37:47 2024 +0100
@@ -1,2 +1,4 @@
 language = "C++"
 include_version = true
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cbindgen/rust2cpp/rust/src/ffi.rs	Wed Nov 20 21:37:47 2024 +0100
@@ -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;
--- a/tools/corrosion/test/cbindgen/rust2cpp/rust/src/lib.rs	Wed Sep 18 14:10:51 2024 +0200
+++ b/tools/corrosion/test/cbindgen/rust2cpp/rust/src/lib.rs	Wed Nov 20 21:37:47 2024 +0100
@@ -1,5 +1,8 @@
 pub const MAGIC_NUMBER: u64 = 0xABCD_EFAB;
 
+pub mod ffi;
+pub mod other_mod;
+
 #[derive(Debug)]
 #[repr(C)]
 pub struct Point {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cbindgen/rust2cpp/rust/src/other_mod/mod.rs	Wed Nov 20 21:37:47 2024 +0100
@@ -0,0 +1,1 @@
+pub const OTHER_MOD_MAGIC_NUMBER: u32 = 192312312;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/corrosion_install/CMakeLists.txt	Wed Nov 20 21:37:47 2024 +0100
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/corrosion_install/install_lib/CMakeLists.txt	Wed Nov 20 21:37:47 2024 +0100
@@ -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)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/corrosion_install/install_lib/main.cpp	Wed Nov 20 21:37:47 2024 +0100
@@ -0,0 +1,11 @@
+#include <stdint.h>
+#include <assert.h>
+#include <iostream>
+
+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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/corrosion_install/install_lib/rust_lib/CMakeLists.txt	Wed Nov 20 21:37:47 2024 +0100
@@ -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)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/corrosion_install/install_lib/rust_lib/Cargo.toml	Wed Nov 20 21:37:47 2024 +0100
@@ -0,0 +1,9 @@
+[package]
+name = "rust_lib"
+version = "0.1.0"
+edition = "2018"
+
+[dependencies]
+
+[lib]
+crate-type = ["staticlib", "cdylib"]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/corrosion_install/install_lib/rust_lib/include/rust_lib/rust_lib.hpp	Wed Nov 20 21:37:47 2024 +0100
@@ -0,0 +1,3 @@
+#include <cstdint.h>
+
+extern "C" uint64_t add(uint64_t left, uint64_t right);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/corrosion_install/install_lib/rust_lib/src/lib.rs	Wed Nov 20 21:37:47 2024 +0100
@@ -0,0 +1,5 @@
+
+#[no_mangle]
+pub extern "C" fn add(left: u64, right: u64) -> u64 {
+    left + right
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/corrosion_install/install_rust_bin/CMakeLists.txt	Wed Nov 20 21:37:47 2024 +0100
@@ -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)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/corrosion_install/install_rust_bin/rust_bin/CMakeLists.txt	Wed Nov 20 21:37:47 2024 +0100
@@ -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)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/corrosion_install/install_rust_bin/rust_bin/Cargo.toml	Wed Nov 20 21:37:47 2024 +0100
@@ -0,0 +1,7 @@
+[package]
+name = "my_rust_bin"
+version = "0.1.0"
+edition = "2018"
+license = "MIT"
+
+[dependencies]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/corrosion_install/install_rust_bin/rust_bin/src/main.rs	Wed Nov 20 21:37:47 2024 +0100
@@ -0,0 +1,9 @@
+fn main() {
+    println!(
+"#include <iostream>
+int main() {{
+    std::cout << \"Hello World! I'm generated code\";
+    return 0;
+}}"
+    );
+}
--- a/tools/corrosion/test/external_corrosion_generator/CMakeLists.txt	Wed Sep 18 14:10:51 2024 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-if(CORROSION_TESTS_INSTALL_CORROSION)
-    add_test(NAME "ExternalCorrosionGenerator"
-            COMMAND
-            ${CMAKE_COMMAND}
-            -P "${CMAKE_SOURCE_DIR}/test/ConfigureAndBuild.cmake"
-            SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/ExternalCorrosionGenerator"
-            BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/build"
-            GENERATOR "${CMAKE_GENERATOR}"
-            RUST_TOOLCHAIN "${Rust_TOOLCHAIN}"
-            EXTERNAL_CORROSION_GENERATOR "${test_install_path}/libexec/corrosion-generator"
-            COMMAND_EXPAND_LISTS
-            )
-    set_tests_properties("ExternalCorrosionGenerator" PROPERTIES FIXTURES_REQUIRED "fixture_corrosion_install")
-endif()
\ No newline at end of file
--- a/tools/corrosion/test/external_corrosion_generator/ExternalCorrosionGenerator/CMakeLists.txt	Wed Sep 18 14:10:51 2024 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,18 +0,0 @@
-cmake_minimum_required(VERSION 3.15)
-project(ExternalCorrosionGenerator LANGUAGES C)
-
-add_subdirectory(../../.. corrosion)
-
-get_property(
-    GENERATOR_EXE_LOCATION
-    TARGET Corrosion::Generator PROPERTY IMPORTED_LOCATION
-)
-
-if (NOT GENERATOR_EXE_LOCATION STREQUAL CORROSION_GENERATOR_EXECUTABLE)
-    message(
-        FATAL_ERROR
-        "\
-Corrosion Generator not Imported Correctly:
-    Corrosion::Generator IMPORTED_LOCATION: ${GENERATOR_EXE_LOCATION}
-    CORROSION_GENERATOR_EXECUTABLE:         ${CORROSION_GENERATOR_EXECUTABLE}")
-endif()
--- a/tools/corrosion/test/external_corrosion_generator/ExternalCorrosionGenerator/Test.cmake	Wed Sep 18 14:10:51 2024 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-set(CORROSION_DIR ${CMAKE_ARGV3})
-set(CORROSION_INSTALL ${CMAKE_ARGV4})
-
-execute_process(
-    COMMAND
-        ${CMAKE_COMMAND} .
-            -DCORROSION_GENERATOR_EXECUTABLE=${CORROSION_INSTALL}/libexec/corrosion-generator
-    COMMAND_ECHO STDOUT
-    RESULT_VARIABLE SUCCESS
-)
-
-if (NOT SUCCESS EQUAL 0)
-    message(FATAL_ERROR)
-endif()
--- a/tools/corrosion/test/hostbuild/CMakeLists.txt	Wed Sep 18 14:10:51 2024 +0200
+++ b/tools/corrosion/test/hostbuild/CMakeLists.txt	Wed Nov 20 21:37:47 2024 +0100
@@ -1,11 +1,6 @@
-# FIXME: ONly test this when cross-compiling?
-corrosion_tests_add_test(hostbuild "rust-host-program")
+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"
         )
-# Run tests are disabled by default when cross-compiling, however we still want to test hostbuild!
-# So we manually re-enable the test here.
-if(CMAKE_CROSSCOMPILING)
-    set_tests_properties("hostbuild_run_rust-host-program" PROPERTIES DISABLED FALSE)
-endif()
+
--- a/tools/corrosion/test/output directory/CMakeLists.txt	Wed Sep 18 14:10:51 2024 +0200
+++ b/tools/corrosion/test/output directory/CMakeLists.txt	Wed Nov 20 21:37:47 2024 +0100
@@ -1,15 +1,24 @@
-if(CMAKE_VERSION VERSION_LESS 3.19.0)
-    return()
-endif()
-
+set(configure_cmake_args)
 if(CMAKE_C_COMPILER)
-    set(TEST_C_COMPILER "C_COMPILER" "${CMAKE_C_COMPILER}")
+    list(APPEND configure_cmake_args "C_COMPILER" "${CMAKE_C_COMPILER}")
 endif()
 if(CMAKE_CXX_COMPILER)
-    set(TEST_CXX_COMPILER "CXX_COMPILER" "${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)
-    set(TEST_GENERATOR_PLATFORM "GENERATOR_PLATFORM" "${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"
@@ -22,9 +31,7 @@
         RUST_TOOLCHAIN "${Rust_TOOLCHAIN}"
         CARGO_TARGET "${Rust_CARGO_TARGET}"
         SYSTEM_NAME "${CMAKE_SYSTEM_NAME}"
-        "${TEST_C_COMPILER}"
-        "${TEST_CXX_COMPILER}"
-        "${TEST_GENERATOR_PLATFORM}"
+        ${configure_cmake_args}
 
         COMMAND_EXPAND_LISTS
 )
@@ -33,11 +40,13 @@
     set_tests_properties("output_directory_build" PROPERTIES FIXTURES_REQUIRED "fixture_corrosion_install")
 endif()
 
-foreach(output_approach targetprop var)
+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()
@@ -102,6 +111,9 @@
                 # 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()
@@ -138,3 +150,5 @@
 
 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")
+
+
--- a/tools/corrosion/test/output directory/output directory/CMakeLists.txt	Wed Sep 18 14:10:51 2024 +0200
+++ b/tools/corrosion/test/output directory/output directory/CMakeLists.txt	Wed Nov 20 21:37:47 2024 +0100
@@ -42,3 +42,17 @@
 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"
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/output directory/output directory/proj3/Cargo.toml	Wed Nov 20 21:37:47 2024 +0100
@@ -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"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/output directory/output directory/proj3/src/lib.rs	Wed Nov 20 21:37:47 2024 +0100
@@ -0,0 +1,4 @@
+#[no_mangle]
+pub extern "C" fn ret_12() -> u32 {
+    12
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/override_crate_type/CMakeLists.txt	Wed Nov 20 21:37:47 2024 +0100
@@ -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$"
+        )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/override_crate_type/override_crate_type/CMakeLists.txt	Wed Nov 20 21:37:47 2024 +0100
@@ -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)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/override_crate_type/override_crate_type/main.cpp	Wed Nov 20 21:37:47 2024 +0100
@@ -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]);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/override_crate_type/override_crate_type/rust/Cargo.toml	Wed Nov 20 21:37:47 2024 +0100
@@ -0,0 +1,10 @@
+[package]
+name = "rust-lib"
+version = "0.1.0"
+authors = ["Andrew Gaspar <andrew.gaspar@outlook.com>"]
+license = "MIT"
+edition = "2018"
+
+
+[lib]
+name = "my_rust_lib"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/override_crate_type/override_crate_type/rust/build.rs	Wed Nov 20 21:37:47 2024 +0100
@@ -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.")
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/override_crate_type/override_crate_type/rust/src/lib.rs	Wed Nov 20 21:37:47 2024 +0100
@@ -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);
+}