tools/corrosion/cmake/Corrosion.cmake
branchtransitional_engine
changeset 16038 d903f8d2395a
parent 16021 6a3dc15b78b9
equal deleted inserted replaced
16036:7b8d96fc8799 16038:d903f8d2395a
     1 cmake_minimum_required(VERSION 3.15)
     1 cmake_minimum_required(VERSION 3.22)
     2 
     2 
     3 list(APPEND CMAKE_MESSAGE_CONTEXT "Corrosion")
     3 list(APPEND CMAKE_MESSAGE_CONTEXT "Corrosion")
     4 
     4 
     5 message(DEBUG "Using Corrosion ${Corrosion_VERSION} with CMake ${CMAKE_VERSION} "
     5 message(DEBUG "Using Corrosion ${Corrosion_VERSION} with CMake ${CMAKE_VERSION} "
     6         "and the `${CMAKE_GENERATOR}` Generator"
     6         "and the `${CMAKE_GENERATOR}` Generator"
     8 
     8 
     9 get_cmake_property(COR_IS_MULTI_CONFIG GENERATOR_IS_MULTI_CONFIG)
     9 get_cmake_property(COR_IS_MULTI_CONFIG GENERATOR_IS_MULTI_CONFIG)
    10 set(COR_IS_MULTI_CONFIG "${COR_IS_MULTI_CONFIG}" CACHE BOOL "Do not change this" FORCE)
    10 set(COR_IS_MULTI_CONFIG "${COR_IS_MULTI_CONFIG}" CACHE BOOL "Do not change this" FORCE)
    11 mark_as_advanced(FORCE COR_IS_MULTI_CONFIG)
    11 mark_as_advanced(FORCE COR_IS_MULTI_CONFIG)
    12 
    12 
    13 if (COR_IS_MULTI_CONFIG AND CMAKE_VERSION VERSION_LESS 3.20.0)
    13 
    14     message(FATAL_ERROR "Corrosion requires at least CMake 3.20 with Multi-Config Generators such as "
    14 if(NOT COR_IS_MULTI_CONFIG AND DEFINED CMAKE_CONFIGURATION_TYPES)
    15         "\"Ninja Multi-Config\" or Visual Studio. "
       
    16         "Please use a different generator or update to cmake >= 3.20.\n"
       
    17         "Note: You are using CMake ${CMAKE_VERSION} (Path: `${CMAKE_COMMAND}`) with "
       
    18         " the `${CMAKE_GENERATOR}` Generator."
       
    19     )
       
    20 elseif(NOT COR_IS_MULTI_CONFIG AND DEFINED CMAKE_CONFIGURATION_TYPES)
       
    21     message(WARNING "The Generator is ${CMAKE_GENERATOR}, which is not a multi-config "
    15     message(WARNING "The Generator is ${CMAKE_GENERATOR}, which is not a multi-config "
    22         "Generator, but CMAKE_CONFIGURATION_TYPES is set. Please don't set "
    16         "Generator, but CMAKE_CONFIGURATION_TYPES is set. Please don't set "
    23         "CMAKE_CONFIGURATION_TYPES unless you are using a multi-config Generator."
    17         "CMAKE_CONFIGURATION_TYPES unless you are using a multi-config Generator."
    24     )
    18     )
    25 endif()
    19 endif()
    26 
    20 
    27 option(CORROSION_VERBOSE_OUTPUT "Enables verbose output from Corrosion and Cargo" OFF)
    21 option(CORROSION_VERBOSE_OUTPUT "Enables verbose output from Corrosion and Cargo" OFF)
    28 
    22 
    29 set(CORROSION_NATIVE_TOOLING_DESCRIPTION
    23 if(DEFINED CORROSION_RESPECT_OUTPUT_DIRECTORY AND NOT CORROSION_RESPECT_OUTPUT_DIRECTORY)
    30     "Use native tooling - Required on CMake < 3.19 and available as a fallback option for recent versions"
    24     message(WARNING "The option CORROSION_RESPECT_OUTPUT_DIRECTORY was removed."
    31     )
    25     " Corrosion now always attempts to respect the output directory.")
    32 
    26 endif()
    33 set(CORROSION_RESPECT_OUTPUT_DIRECTORY_DESCRIPTION
       
    34     "Respect the CMake target properties specifying the output directory of a target, such as
       
    35     `RUNTIME_OUTPUT_DIRECTORY`. This requires CMake >= 3.19, otherwise this option is forced off."
       
    36 )
       
    37 
       
    38 option(
       
    39     CORROSION_NATIVE_TOOLING
       
    40     "${CORROSION_NATIVE_TOOLING_DESCRIPTION}"
       
    41     OFF
       
    42 )
       
    43 
       
    44 option(CORROSION_RESPECT_OUTPUT_DIRECTORY
       
    45     "${CORROSION_RESPECT_OUTPUT_DIRECTORY_DESCRIPTION}"
       
    46     ON
       
    47 )
       
    48 
    27 
    49 option(
    28 option(
    50     CORROSION_NO_WARN_PARSE_TARGET_TRIPLE_FAILED
    29     CORROSION_NO_WARN_PARSE_TARGET_TRIPLE_FAILED
    51     "Surpresses a warning if the parsing the target triple failed."
    30     "Surpresses a warning if the parsing the target triple failed."
    52     OFF
    31     OFF
    53 )
    32 )
    54 
    33 
    55 # The native tooling is required on CMAke < 3.19 so we override whatever the user may have set.
       
    56 if (CMAKE_VERSION VERSION_LESS 3.19.0)
       
    57     set(CORROSION_NATIVE_TOOLING ON CACHE INTERNAL "${CORROSION_NATIVE_TOOLING_DESCRIPTION}" FORCE)
       
    58     set(CORROSION_RESPECT_OUTPUT_DIRECTORY OFF CACHE INTERNAL
       
    59         "${CORROSION_RESPECT_OUTPUT_DIRECTORY_DESCRIPTION}" FORCE
       
    60     )
       
    61 endif()
       
    62 
       
    63 find_package(Rust REQUIRED)
    34 find_package(Rust REQUIRED)
    64 
       
    65 if(Rust_TOOLCHAIN_IS_RUSTUP_MANAGED)
       
    66     execute_process(COMMAND rustup target list --toolchain "${Rust_TOOLCHAIN}"
       
    67             OUTPUT_VARIABLE AVAILABLE_TARGETS_RAW
       
    68     )
       
    69     string(REPLACE "\n" ";" AVAILABLE_TARGETS_RAW "${AVAILABLE_TARGETS_RAW}")
       
    70     string(REPLACE " (installed)" "" "AVAILABLE_TARGETS" "${AVAILABLE_TARGETS_RAW}")
       
    71     set(INSTALLED_TARGETS_RAW "${AVAILABLE_TARGETS_RAW}")
       
    72     list(FILTER INSTALLED_TARGETS_RAW INCLUDE REGEX " \\(installed\\)")
       
    73     string(REPLACE " (installed)" "" "INSTALLED_TARGETS" "${INSTALLED_TARGETS_RAW}")
       
    74     list(TRANSFORM INSTALLED_TARGETS STRIP)
       
    75     if("${Rust_CARGO_TARGET}" IN_LIST AVAILABLE_TARGETS)
       
    76         message(DEBUG "Cargo target ${Rust_CARGO_TARGET} is an official target-triple")
       
    77         message(DEBUG "Installed targets: ${INSTALLED_TARGETS}")
       
    78         if(NOT ("${Rust_CARGO_TARGET}" IN_LIST INSTALLED_TARGETS))
       
    79             message(FATAL_ERROR "Target ${Rust_CARGO_TARGET} is not installed for toolchain ${Rust_TOOLCHAIN}.\n"
       
    80                     "Help: Run `rustup target add --toolchain ${Rust_TOOLCHAIN} ${Rust_CARGO_TARGET}` to install "
       
    81                     "the missing target."
       
    82             )
       
    83         endif()
       
    84     endif()
       
    85 
       
    86 endif()
       
    87 
    35 
    88 if(CMAKE_GENERATOR MATCHES "Visual Studio"
    36 if(CMAKE_GENERATOR MATCHES "Visual Studio"
    89         AND (NOT CMAKE_VS_PLATFORM_NAME STREQUAL CMAKE_VS_PLATFORM_NAME_DEFAULT)
    37         AND (NOT CMAKE_VS_PLATFORM_NAME STREQUAL CMAKE_VS_PLATFORM_NAME_DEFAULT)
    90         AND Rust_VERSION VERSION_LESS "1.54")
    38         AND Rust_VERSION VERSION_LESS "1.54")
    91     message(FATAL_ERROR "Due to a cargo issue, cross-compiling with a Visual Studio generator and rust versions"
    39     message(FATAL_ERROR "Due to a cargo issue, cross-compiling with a Visual Studio generator and rust versions"
    92             " before 1.54 is not supported. Rust build scripts would be linked with the cross-compiler linker, which"
    40             " before 1.54 is not supported. Rust build scripts would be linked with the cross-compiler linker, which"
    93             " causes the build to fail. Please upgrade your Rust version to 1.54 or newer.")
    41             " causes the build to fail. Please upgrade your Rust version to 1.54 or newer.")
    94 endif()
    42 endif()
    95 
    43 
    96 if (NOT TARGET Corrosion::Generator)
    44 #    message(STATUS "Using Corrosion as a subdirectory")
    97     message(STATUS "Using Corrosion as a subdirectory")
       
    98 endif()
       
    99 
    45 
   100 get_property(
    46 get_property(
   101     RUSTC_EXECUTABLE
    47     RUSTC_EXECUTABLE
   102     TARGET Rust::Rustc PROPERTY IMPORTED_LOCATION
    48     TARGET Rust::Rustc PROPERTY IMPORTED_LOCATION
   103 )
    49 )
   104 
    50 
   105 get_property(
    51 get_property(
   106     CARGO_EXECUTABLE
    52     CARGO_EXECUTABLE
   107     TARGET Rust::Cargo PROPERTY IMPORTED_LOCATION
    53     TARGET Rust::Cargo PROPERTY IMPORTED_LOCATION
   108 )
    54 )
   109 
       
   110 # Note: Legacy function, used when respecting the `XYZ_OUTPUT_DIRECTORY` target properties is not
       
   111 # possible.
       
   112 function(_corrosion_set_imported_location_legacy target_name base_property filename)
       
   113     foreach(config_type ${CMAKE_CONFIGURATION_TYPES})
       
   114         set(binary_root "${CMAKE_CURRENT_BINARY_DIR}/${config_type}")
       
   115         string(TOUPPER "${config_type}" config_type_upper)
       
   116         message(DEBUG "Setting ${base_property}_${config_type_upper} for target ${target_name}"
       
   117                 " to `${binary_root}/${filename}`.")
       
   118         # For Multiconfig we want to specify the correct location for each configuration
       
   119         set_property(
       
   120             TARGET ${target_name}
       
   121             PROPERTY "${base_property}_${config_type_upper}"
       
   122                 "${binary_root}/${filename}"
       
   123         )
       
   124     endforeach()
       
   125     if(NOT COR_IS_MULTI_CONFIG)
       
   126         set(binary_root "${CMAKE_CURRENT_BINARY_DIR}")
       
   127     endif()
       
   128 
       
   129     message(DEBUG "Setting ${base_property} for target ${target_name}"
       
   130                 " to `${binary_root}/${filename}`.")
       
   131 
       
   132     # IMPORTED_LOCATION must be set regardless of possible overrides. In the multiconfig case,
       
   133     # the last configuration "wins".
       
   134     set_property(
       
   135             TARGET ${target_name}
       
   136             PROPERTY "${base_property}" "${binary_root}/${filename}"
       
   137         )
       
   138 endfunction()
       
   139 
       
   140 
       
   141 # Sets out_var to true if the byproduct copying and imported location is done in a deferred
       
   142 # manner to respect target properties, etc. that may be set later.
       
   143 function(_corrosion_determine_deferred_byproduct_copying_and_import_location_handling out_var)
       
   144     set(${out_var} ${CORROSION_RESPECT_OUTPUT_DIRECTORY} PARENT_SCOPE)
       
   145 endfunction()
       
   146 
    55 
   147 function(_corrosion_bin_target_suffix target_name out_var_suffix)
    56 function(_corrosion_bin_target_suffix target_name out_var_suffix)
   148     get_target_property(hostbuild "${target_name}" ${_CORR_PROP_HOST_BUILD})
    57     get_target_property(hostbuild "${target_name}" ${_CORR_PROP_HOST_BUILD})
   149     if((hostbuild AND CMAKE_HOST_WIN32)
    58     if((hostbuild AND CMAKE_HOST_WIN32)
   150        OR ((NOT hostbuild) AND (Rust_CARGO_TARGET_OS STREQUAL "windows")))
    59        OR ((NOT hostbuild) AND (Rust_CARGO_TARGET_OS STREQUAL "windows")))
   175     # Append .exe suffix for executable by-products if the target is windows or if it's a host
    84     # Append .exe suffix for executable by-products if the target is windows or if it's a host
   176     # build and the host is Windows.
    85     # build and the host is Windows.
   177     get_target_property(target_type ${target_name} TYPE)
    86     get_target_property(target_type ${target_name} TYPE)
   178     if(${target_type} STREQUAL "EXECUTABLE" AND (NOT "${filename}" MATCHES "\.pdb$"))
    87     if(${target_type} STREQUAL "EXECUTABLE" AND (NOT "${filename}" MATCHES "\.pdb$"))
   179         _corrosion_bin_target_suffix(${target_name} "suffix")
    88         _corrosion_bin_target_suffix(${target_name} "suffix")
   180         if(suffix)
    89         string(APPEND filename "${suffix}")
   181             set(filename "${filename}${suffix}")
       
   182         endif()
       
   183     endif()
    90     endif()
   184 
    91 
   185     get_target_property(output_directory "${output_dir_prop_target_name}" "${output_directory_property}")
    92     get_target_property(output_directory "${output_dir_prop_target_name}" "${output_directory_property}")
   186     message(DEBUG "Output directory property (target ${output_dir_prop_target_name}): ${output_directory_property} dir: ${output_directory}")
    93     message(DEBUG "Output directory property (target ${output_dir_prop_target_name}): ${output_directory_property} dir: ${output_directory}")
   187 
    94 
   195         elseif(output_directory)
   102         elseif(output_directory)
   196             set(curr_out_dir "${output_directory}")
   103             set(curr_out_dir "${output_directory}")
   197         else()
   104         else()
   198             set(curr_out_dir "${CMAKE_CURRENT_BINARY_DIR}")
   105             set(curr_out_dir "${CMAKE_CURRENT_BINARY_DIR}")
   199         endif()
   106         endif()
       
   107         string(REPLACE "\$<CONFIG>" "${config_type}" curr_out_dir "${curr_out_dir}")
   200         message(DEBUG "Setting ${base_property}_${config_type_upper} for target ${target_name}"
   108         message(DEBUG "Setting ${base_property}_${config_type_upper} for target ${target_name}"
   201                 " to `${curr_out_dir}/${filename}`.")
   109                 " to `${curr_out_dir}/${filename}`.")
       
   110 
       
   111         string(GENEX_STRIP "${curr_out_dir}" stripped_out_dir)
       
   112         if(NOT ("${stripped_out_dir}" STREQUAL "${curr_out_dir}"))
       
   113             message(FATAL_ERROR "${output_directory_property} for target ${output_dir_prop_target_name} "
       
   114                     "contained an unexpected Generator expression. Output dir: `${curr_out_dir}`"
       
   115                 "Note: Corrosion only supports the `\$<CONFIG>` generator expression for output directories.")
       
   116         endif()
       
   117 
   202         # For Multiconfig we want to specify the correct location for each configuration
   118         # For Multiconfig we want to specify the correct location for each configuration
   203         set_property(
   119         set_property(
   204             TARGET ${target_name}
   120             TARGET ${target_name}
   205             PROPERTY "${base_property}_${config_type_upper}"
   121             PROPERTY "${base_property}_${config_type_upper}"
   206                 "${curr_out_dir}/${filename}"
   122                 "${curr_out_dir}/${filename}"
   212         if(output_directory)
   128         if(output_directory)
   213             set(base_output_directory "${output_directory}")
   129             set(base_output_directory "${output_directory}")
   214         else()
   130         else()
   215             set(base_output_directory "${CMAKE_CURRENT_BINARY_DIR}")
   131             set(base_output_directory "${CMAKE_CURRENT_BINARY_DIR}")
   216         endif()
   132         endif()
       
   133         string(REPLACE "\$<CONFIG>" "${CMAKE_BUILD_TYPE}" base_output_directory "${base_output_directory}")
       
   134         string(GENEX_STRIP "${base_output_directory}" stripped_out_dir)
       
   135         if(NOT ("${stripped_out_dir}" STREQUAL "${base_output_directory}"))
       
   136             message(FATAL_ERROR "${output_dir_prop_target_name} for target ${output_dir_prop_target_name} "
       
   137                     "contained an unexpected Generator expression. Output dir: `${base_output_directory}`"
       
   138                     "Note: Corrosion only supports the `\$<CONFIG>` generator expression for output directories.")
       
   139         endif()
   217     endif()
   140     endif()
   218 
   141 
   219     message(DEBUG "Setting ${base_property} for target ${target_name}"
   142     message(DEBUG "Setting ${base_property} for target ${target_name}"
   220                 " to `${base_output_directory}/${filename}`.")
   143                 " to `${base_output_directory}/${filename}`.")
   221 
   144 
   223     # the last configuration "wins" (IMPORTED_LOCATION is not documented to have Genex support).
   146     # the last configuration "wins" (IMPORTED_LOCATION is not documented to have Genex support).
   224     set_property(
   147     set_property(
   225             TARGET ${target_name}
   148             TARGET ${target_name}
   226             PROPERTY "${base_property}" "${base_output_directory}/${filename}"
   149             PROPERTY "${base_property}" "${base_output_directory}/${filename}"
   227         )
   150         )
   228 endfunction()
       
   229 
       
   230 # Helper function to call _corrosion_set_imported_location_deferred while eagerly
       
   231 # evaluating arguments.
       
   232 # Refer to https://cmake.org/cmake/help/latest/command/cmake_language.html#deferred-call-examples
       
   233 function(_corrosion_call_set_imported_location_deferred target_name base_property output_directory_property filename)
       
   234     cmake_language(EVAL CODE "
       
   235         cmake_language(DEFER
       
   236             CALL
       
   237             _corrosion_set_imported_location_deferred
       
   238             [[${target_name}]]
       
   239             [[${base_property}]]
       
   240             [[${output_directory_property}]]
       
   241             [[${filename}]]
       
   242         )
       
   243     ")
       
   244 endfunction()
   151 endfunction()
   245 
   152 
   246 # Set the imported location of a Rust target.
   153 # Set the imported location of a Rust target.
   247 #
   154 #
   248 # Rust targets are built via custom targets / custom commands. The actual artifacts are exposed
   155 # Rust targets are built via custom targets / custom commands. The actual artifacts are exposed
   256 # - base_property: Name of the base property - i.e. `IMPORTED_LOCATION` or `IMPORTED_IMPLIB`.
   163 # - base_property: Name of the base property - i.e. `IMPORTED_LOCATION` or `IMPORTED_IMPLIB`.
   257 # - output_directory_property: Target property name that determines the standard location for the
   164 # - output_directory_property: Target property name that determines the standard location for the
   258 #    artifact.
   165 #    artifact.
   259 # - filename of the artifact.
   166 # - filename of the artifact.
   260 function(_corrosion_set_imported_location target_name base_property output_directory_property filename)
   167 function(_corrosion_set_imported_location target_name base_property output_directory_property filename)
   261     _corrosion_determine_deferred_byproduct_copying_and_import_location_handling("defer")
   168         cmake_language(EVAL CODE "
   262     if(defer)
   169             cmake_language(DEFER
   263         _corrosion_call_set_imported_location_deferred("${target_name}" "${base_property}" "${output_directory_property}" "${filename}")
   170                 CALL
   264     else()
   171                 _corrosion_set_imported_location_deferred
   265         _corrosion_set_imported_location_legacy("${target_name}" "${base_property}" "${filename}")
   172                 [[${target_name}]]
   266     endif()
   173                 [[${base_property}]]
   267 endfunction()
   174                 [[${output_directory_property}]]
   268 
   175                 [[${filename}]]
   269 function(_corrosion_copy_byproduct_legacy target_name cargo_build_dir file_names)
   176             )
       
   177         ")
       
   178 endfunction()
       
   179 
       
   180 function(_corrosion_copy_byproduct_deferred target_name output_dir_prop_names cargo_build_dir file_names)
   270     if(ARGN)
   181     if(ARGN)
   271         message(FATAL_ERROR "Unexpected additional arguments")
   182         message(FATAL_ERROR "Unexpected additional arguments")
   272     endif()
   183     endif()
   273 
   184 
   274     if(COR_IS_MULTI_CONFIG)
   185     foreach(output_dir_prop_name ${output_dir_prop_names})
   275         set(output_dir "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>")
   186         get_target_property(output_dir ${target_name} "${output_dir_prop_name}")
   276     else()
   187         if(output_dir)
   277         set(output_dir "${CMAKE_CURRENT_BINARY_DIR}")
   188             break()
   278     endif()
   189         endif()
   279 
   190     endforeach()
   280     list(TRANSFORM file_names PREPEND "${cargo_build_dir}/" OUTPUT_VARIABLE src_file_names)
       
   281     list(TRANSFORM file_names PREPEND "${output_dir}/" OUTPUT_VARIABLE dst_file_names)
       
   282     message(DEBUG "Adding command to copy byproducts `${file_names}` to ${dst_file_names}")
       
   283     add_custom_command(TARGET _cargo-build_${target_name}
       
   284                         POST_BUILD
       
   285                         COMMAND  ${CMAKE_COMMAND} -E make_directory "${output_dir}"
       
   286                         COMMAND
       
   287                         ${CMAKE_COMMAND} -E copy_if_different
       
   288                             # tested to work with both multiple files and paths with spaces
       
   289                             ${src_file_names}
       
   290                             "${output_dir}"
       
   291                         BYPRODUCTS ${dst_file_names}
       
   292                         COMMENT "Copying byproducts `${file_names}` to ${output_dir}"
       
   293                         VERBATIM
       
   294                         COMMAND_EXPAND_LISTS
       
   295     )
       
   296 endfunction()
       
   297 
       
   298 function(_corrosion_copy_byproduct_deferred target_name output_dir_prop_name cargo_build_dir file_names)
       
   299     if(ARGN)
       
   300         message(FATAL_ERROR "Unexpected additional arguments")
       
   301     endif()
       
   302     get_target_property(output_dir ${target_name} "${output_dir_prop_name}")
       
   303 
   191 
   304     # A Genex expanding to the output directory depending on the configuration.
   192     # A Genex expanding to the output directory depending on the configuration.
   305     set(multiconfig_out_dir_genex "")
   193     set(multiconfig_out_dir_genex "")
   306 
   194 
   307     foreach(config_type ${CMAKE_CONFIGURATION_TYPES})
   195     foreach(config_type ${CMAKE_CONFIGURATION_TYPES})
   308         string(TOUPPER "${config_type}" config_type_upper)
   196         string(TOUPPER "${config_type}" config_type_upper)
   309         get_target_property(output_dir_curr_config ${target_name} "${output_dir_prop_name}_${config_type_upper}")
   197         foreach(output_dir_prop_name ${output_dir_prop_names})
       
   198             get_target_property(output_dir_curr_config ${target_name} "${output_dir_prop_name}_${config_type_upper}")
       
   199             if(output_dir_curr_config)
       
   200                 break()
       
   201             endif()
       
   202         endforeach()
   310 
   203 
   311         if(output_dir_curr_config)
   204         if(output_dir_curr_config)
   312             set(curr_out_dir "${output_dir_curr_config}")
   205             set(curr_out_dir "${output_dir_curr_config}")
   313         elseif(output_dir)
   206         elseif(output_dir)
   314             # Fallback to `output_dir` if specified
   207             # Fallback to `output_dir` if specified
   346         if(suffix AND (NOT "${file_names}" MATCHES "\.pdb$"))
   239         if(suffix AND (NOT "${file_names}" MATCHES "\.pdb$"))
   347             # For executable targets we know / checked that only one file will be passed.
   240             # For executable targets we know / checked that only one file will be passed.
   348             string(APPEND file_names "${suffix}")
   241             string(APPEND file_names "${suffix}")
   349         endif()
   242         endif()
   350     endif()
   243     endif()
   351 
   244     set(src_file_names "${file_names}")
   352     list(TRANSFORM file_names PREPEND "${cargo_build_dir}/" OUTPUT_VARIABLE src_file_names)
   245     if(Rust_CARGO_TARGET_ENV STREQUAL "gnullvm")
       
   246         # Workaround for cargo not exposing implibs yet.
       
   247         list(TRANSFORM src_file_names PREPEND "deps/" REGEX "\.dll\.a$")
       
   248     endif()
       
   249     list(TRANSFORM src_file_names PREPEND "${cargo_build_dir}/")
   353     list(TRANSFORM file_names PREPEND "${output_dir}/" OUTPUT_VARIABLE dst_file_names)
   250     list(TRANSFORM file_names PREPEND "${output_dir}/" OUTPUT_VARIABLE dst_file_names)
   354     message(DEBUG "Adding command to copy byproducts `${file_names}` to ${dst_file_names}")
   251     message(DEBUG "Adding command to copy byproducts `${file_names}` to ${dst_file_names}")
   355     add_custom_command(TARGET _cargo-build_${target_name}
   252     add_custom_command(TARGET _cargo-build_${target_name}
   356                         POST_BUILD
   253                         POST_BUILD
   357                         # output_dir may contain a Generator expression.
   254                         # output_dir may contain a Generator expression.
   366                         VERBATIM
   263                         VERBATIM
   367                         COMMAND_EXPAND_LISTS
   264                         COMMAND_EXPAND_LISTS
   368     )
   265     )
   369 endfunction()
   266 endfunction()
   370 
   267 
   371 function(_corrosion_call_copy_byproduct_deferred target_name output_dir_prop_name cargo_build_dir file_names)
   268 # Copy the artifacts generated by cargo to the appropriate destination.
       
   269 #
       
   270 # Parameters:
       
   271 # - target_name: The name of the Rust target
       
   272 # - output_dir_prop_names: The property name(s) controlling the destination (e.g.
       
   273 #   `LIBRARY_OUTPUT_DIRECTORY` or `PDB_OUTPUT_DIRECTORY;RUNTIME_OUTPUT_DIRECTORY`)
       
   274 # - cargo_build_dir: the directory cargo build places it's output artifacts in.
       
   275 # - filenames: the file names of any output artifacts as a list.
       
   276 function(_corrosion_copy_byproducts target_name output_dir_prop_names cargo_build_dir file_names)
   372         cmake_language(EVAL CODE "
   277         cmake_language(EVAL CODE "
   373             cmake_language(DEFER
   278             cmake_language(DEFER
   374                 CALL
   279                 CALL
   375                 _corrosion_copy_byproduct_deferred
   280                 _corrosion_copy_byproduct_deferred
   376                 [[${target_name}]]
   281                 [[${target_name}]]
   377                 [[${output_dir_prop_name}]]
   282                 [[${output_dir_prop_names}]]
   378                 [[${cargo_build_dir}]]
   283                 [[${cargo_build_dir}]]
   379                 [[${file_names}]]
   284                 [[${file_names}]]
   380             )
   285             )
   381         ")
   286         ")
   382 endfunction()
       
   383 
       
   384 # Copy the artifacts generated by cargo to the appropriate destination.
       
   385 #
       
   386 # Parameters:
       
   387 # - target_name: The name of the Rust target
       
   388 # - output_dir_prop_name: The property name controlling the destination (e.g.
       
   389 #   `RUNTIME_OUTPUT_DIRECTORY`)
       
   390 # - cargo_build_dir: the directory cargo build places it's output artifacts in.
       
   391 # - filenames: the file names of any output artifacts as a list.
       
   392 # - is_binary: TRUE if the byproducts are program executables.
       
   393 function(_corrosion_copy_byproducts target_name output_dir_prop_name cargo_build_dir filenames)
       
   394     _corrosion_determine_deferred_byproduct_copying_and_import_location_handling("defer")
       
   395     if(defer)
       
   396         _corrosion_call_copy_byproduct_deferred("${target_name}" "${output_dir_prop_name}" "${cargo_build_dir}" "${filenames}")
       
   397     else()
       
   398         _corrosion_copy_byproduct_legacy("${target_name}" "${cargo_build_dir}" "${filenames}")
       
   399     endif()
       
   400 endfunction()
   287 endfunction()
   401 
   288 
   402 
   289 
   403 # Add targets for the static and/or shared libraries of the rust target.
   290 # Add targets for the static and/or shared libraries of the rust target.
   404 # The generated byproduct names are returned via the `OUT_<type>_BYPRODUCTS` arguments.
   291 # The generated byproduct names are returned via the `OUT_<type>_BYPRODUCTS` arguments.
   447     set(is_macos "")
   334     set(is_macos "")
   448     if(Rust_CARGO_TARGET_OS STREQUAL "windows")
   335     if(Rust_CARGO_TARGET_OS STREQUAL "windows")
   449         set(is_windows TRUE)
   336         set(is_windows TRUE)
   450         if(Rust_CARGO_TARGET_ENV STREQUAL "msvc")
   337         if(Rust_CARGO_TARGET_ENV STREQUAL "msvc")
   451             set(is_windows_msvc TRUE)
   338             set(is_windows_msvc TRUE)
   452         elseif(Rust_CARGO_TARGET_ENV STREQUAL "gnu")
   339         elseif(Rust_CARGO_TARGET_ENV STREQUAL "gnu" OR Rust_CARGO_TARGET_ENV STREQUAL "gnullvm")
   453             set(is_windows_gnu TRUE)
   340             set(is_windows_gnu TRUE)
   454         endif()
   341         endif()
   455     elseif(Rust_CARGO_TARGET_OS STREQUAL "darwin")
   342     elseif(Rust_CARGO_TARGET_OS STREQUAL "darwin")
   456         set(is_macos TRUE)
   343         set(is_macos TRUE)
   457     endif()
   344     endif()
   498             set("${CALT_OUT_PDB_BYPRODUCT}" "${pdb_name}" PARENT_SCOPE)
   385             set("${CALT_OUT_PDB_BYPRODUCT}" "${pdb_name}" PARENT_SCOPE)
   499         endif()
   386         endif()
   500     endif()
   387     endif()
   501     set("${CALT_OUT_ARCHIVE_OUTPUT_BYPRODUCTS}" "${archive_output_byproducts}" PARENT_SCOPE)
   388     set("${CALT_OUT_ARCHIVE_OUTPUT_BYPRODUCTS}" "${archive_output_byproducts}" PARENT_SCOPE)
   502 
   389 
   503     add_library(${target_name} INTERFACE)
       
   504 
       
   505     if(has_staticlib)
   390     if(has_staticlib)
   506         add_library(${target_name}-static STATIC IMPORTED GLOBAL)
   391         add_library(${target_name}-static STATIC IMPORTED GLOBAL)
   507         add_dependencies(${target_name}-static cargo-build_${target_name})
   392         add_dependencies(${target_name}-static cargo-build_${target_name})
       
   393         set_target_properties(${target_name}-static PROPERTIES COR_FILE_NAME ${static_lib_name})
   508 
   394 
   509         _corrosion_set_imported_location("${target_name}-static" "IMPORTED_LOCATION"
   395         _corrosion_set_imported_location("${target_name}-static" "IMPORTED_LOCATION"
   510                 "ARCHIVE_OUTPUT_DIRECTORY"
   396                 "ARCHIVE_OUTPUT_DIRECTORY"
   511                 "${static_lib_name}")
   397                 "${static_lib_name}")
   512 
   398 
   529     endif()
   415     endif()
   530 
   416 
   531     if(has_cdylib)
   417     if(has_cdylib)
   532         add_library(${target_name}-shared SHARED IMPORTED GLOBAL)
   418         add_library(${target_name}-shared SHARED IMPORTED GLOBAL)
   533         add_dependencies(${target_name}-shared cargo-build_${target_name})
   419         add_dependencies(${target_name}-shared cargo-build_${target_name})
       
   420         set_target_properties(${target_name}-shared PROPERTIES COR_FILE_NAME ${dynamic_lib_name})
   534 
   421 
   535         # Todo: (Not new issue): What about IMPORTED_SONAME and IMPORTED_NO_SYSTEM?
   422         # Todo: (Not new issue): What about IMPORTED_SONAME and IMPORTED_NO_SYSTEM?
   536         _corrosion_set_imported_location("${target_name}-shared" "IMPORTED_LOCATION"
   423         _corrosion_set_imported_location("${target_name}-shared" "IMPORTED_LOCATION"
   537                 "LIBRARY_OUTPUT_DIRECTORY"
   424                 "LIBRARY_OUTPUT_DIRECTORY"
   538                 "${dynamic_lib_name}"
   425                 "${dynamic_lib_name}"
   544         if(is_windows)
   431         if(is_windows)
   545             _corrosion_set_imported_location("${target_name}-shared" "IMPORTED_IMPLIB"
   432             _corrosion_set_imported_location("${target_name}-shared" "IMPORTED_IMPLIB"
   546                     "ARCHIVE_OUTPUT_DIRECTORY"
   433                     "ARCHIVE_OUTPUT_DIRECTORY"
   547                     "${implib_name}"
   434                     "${implib_name}"
   548             )
   435             )
       
   436             set_target_properties(${target_name}-shared PROPERTIES COR_IMPLIB_FILE_NAME ${implib_name})
   549         endif()
   437         endif()
   550 
   438 
   551         if(is_macos)
   439         if(is_macos)
   552             set_property(TARGET ${target_name}-shared
   440             set_property(TARGET ${target_name}-shared
   553                     PROPERTY INTERFACE_LINK_DIRECTORIES "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib"
   441                     PROPERTY INTERFACE_LINK_DIRECTORIES "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib"
   579 
   467 
   580     if(Rust_CARGO_TARGET_ENV STREQUAL "msvc")
   468     if(Rust_CARGO_TARGET_ENV STREQUAL "msvc")
   581         set(${out_pdb_byproduct} "${pdb_name}" PARENT_SCOPE)
   469         set(${out_pdb_byproduct} "${pdb_name}" PARENT_SCOPE)
   582     endif()
   470     endif()
   583 
   471 
       
   472     # Potential .exe suffix will be added later, also depending on possible hostbuild
       
   473     # target property
   584     set(bin_filename "${bin_name}")
   474     set(bin_filename "${bin_name}")
   585     _corrosion_determine_deferred_byproduct_copying_and_import_location_handling("defer")
       
   586     if(defer)
       
   587         # .exe suffix will be added later, also depending on possible hostbuild
       
   588         # target property
       
   589     else()
       
   590         if(Rust_CARGO_TARGET_OS STREQUAL "windows")
       
   591             set(bin_filename "${bin_name}.exe")
       
   592         endif()
       
   593     endif()
       
   594     set(${out_bin_byproduct} "${bin_filename}" PARENT_SCOPE)
   475     set(${out_bin_byproduct} "${bin_filename}" PARENT_SCOPE)
   595 
       
   596 
       
   597     # Todo: This is compatible with the way corrosion previously exposed the bin name,
       
   598     # but maybe we want to prefix the exposed name with the package name?
       
   599     add_executable(${bin_name} IMPORTED GLOBAL)
       
   600     add_dependencies(${bin_name} cargo-build_${bin_name})
   476     add_dependencies(${bin_name} cargo-build_${bin_name})
   601 
   477 
   602     if(Rust_CARGO_TARGET_OS STREQUAL "darwin")
   478     if(Rust_CARGO_TARGET_OS STREQUAL "darwin")
   603         set_property(TARGET ${bin_name}
   479         set_property(TARGET ${bin_name}
   604                 PROPERTY INTERFACE_LINK_DIRECTORIES "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib"
   480                 PROPERTY INTERFACE_LINK_DIRECTORIES "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib"
   611     )
   487     )
   612 
   488 
   613 endfunction()
   489 endfunction()
   614 
   490 
   615 
   491 
   616 if (NOT CORROSION_NATIVE_TOOLING)
   492 include(CorrosionGenerator)
   617     include(CorrosionGenerator)
       
   618 endif()
       
   619 
   493 
   620 # Note: `cmake_language(GET_MESSAGE_LOG_LEVEL <output_variable>)` requires CMake 3.25,
   494 # Note: `cmake_language(GET_MESSAGE_LOG_LEVEL <output_variable>)` requires CMake 3.25,
   621 # so we offer our own option to control verbosity of downstream commands (e.g. cargo build)
   495 # so we offer our own option to control verbosity of downstream commands (e.g. cargo build)
   622 if (CORROSION_VERBOSE_OUTPUT)
   496 if (CORROSION_VERBOSE_OUTPUT)
   623     set(_CORROSION_VERBOSE_OUTPUT_FLAG --verbose CACHE INTERNAL "")
   497     set(_CORROSION_VERBOSE_OUTPUT_FLAG --verbose CACHE INTERNAL "")
   624 else()
   498 else()
   625     # We want to silence some less important commands by default.
   499     # We want to silence some less important commands by default.
   626     set(_CORROSION_QUIET_OUTPUT_FLAG --quiet CACHE INTERNAL "")
   500     set(_CORROSION_QUIET_OUTPUT_FLAG --quiet CACHE INTERNAL "")
   627 endif()
   501 endif()
   628 
   502 
   629 if(CORROSION_NATIVE_TOOLING)
       
   630     if (NOT TARGET Corrosion::Generator )
       
   631         add_subdirectory(generator)
       
   632     endif()
       
   633     get_property(
       
   634         _CORROSION_GENERATOR_EXE
       
   635         TARGET Corrosion::Generator PROPERTY IMPORTED_LOCATION
       
   636     )
       
   637     set(
       
   638         _CORROSION_GENERATOR
       
   639         ${CMAKE_COMMAND} -E env
       
   640             CARGO_BUILD_RUSTC=${RUSTC_EXECUTABLE}
       
   641             ${_CORROSION_GENERATOR_EXE}
       
   642             --cargo ${CARGO_EXECUTABLE}
       
   643             ${_CORROSION_VERBOSE_OUTPUT_FLAG}
       
   644         CACHE INTERNAL "corrosion-generator runner"
       
   645     )
       
   646 endif()
       
   647 
       
   648 set(_CORROSION_CARGO_VERSION ${Rust_CARGO_VERSION} CACHE INTERNAL "cargo version used by corrosion")
   503 set(_CORROSION_CARGO_VERSION ${Rust_CARGO_VERSION} CACHE INTERNAL "cargo version used by corrosion")
   649 set(_CORROSION_RUST_CARGO_TARGET ${Rust_CARGO_TARGET} CACHE INTERNAL "target triple used by corrosion")
   504 set(_CORROSION_RUST_CARGO_TARGET ${Rust_CARGO_TARGET} CACHE INTERNAL "target triple used by corrosion")
   650 set(_CORROSION_RUST_CARGO_HOST_TARGET ${Rust_CARGO_HOST_TARGET} CACHE INTERNAL "host triple used by corrosion")
   505 set(_CORROSION_RUST_CARGO_HOST_TARGET ${Rust_CARGO_HOST_TARGET} CACHE INTERNAL "host triple used by corrosion")
   651 set(_CORROSION_RUSTC "${RUSTC_EXECUTABLE}" CACHE INTERNAL  "Path to rustc used by corrosion")
   506 set(_CORROSION_RUSTC "${RUSTC_EXECUTABLE}" CACHE INTERNAL  "Path to rustc used by corrosion")
   652 set(_CORROSION_CARGO "${CARGO_EXECUTABLE}" CACHE INTERNAL "Path to cargo used by corrosion")
   507 set(_CORROSION_CARGO "${CARGO_EXECUTABLE}" CACHE INTERNAL "Path to cargo used by corrosion")
   663 # We previously specified some Custom properties as part of our public API, however the chosen names prevented us from
   518 # We previously specified some Custom properties as part of our public API, however the chosen names prevented us from
   664 # supporting CMake versions before 3.19. In order to both support older CMake versions and not break existing code
   519 # supporting CMake versions before 3.19. In order to both support older CMake versions and not break existing code
   665 # immediately, we are using a different property name depending on the CMake version. However users avoid using
   520 # immediately, we are using a different property name depending on the CMake version. However users avoid using
   666 # any of the properties directly, as they are no longer part of the public API and are to be considered deprecated.
   521 # any of the properties directly, as they are no longer part of the public API and are to be considered deprecated.
   667 # Instead use the corrosion_set_... functions as documented in the Readme.
   522 # Instead use the corrosion_set_... functions as documented in the Readme.
   668 if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.19.0)
   523 set(_CORR_PROP_FEATURES CORROSION_FEATURES CACHE INTERNAL "")
   669     set(_CORR_PROP_FEATURES CORROSION_FEATURES CACHE INTERNAL "")
   524 set(_CORR_PROP_ALL_FEATURES CORROSION_ALL_FEATURES CACHE INTERNAL "")
   670     set(_CORR_PROP_ALL_FEATURES CORROSION_ALL_FEATURES CACHE INTERNAL "")
   525 set(_CORR_PROP_NO_DEFAULT_FEATURES CORROSION_NO_DEFAULT_FEATURES CACHE INTERNAL "")
   671     set(_CORR_PROP_NO_DEFAULT_FEATURES CORROSION_NO_DEFAULT_FEATURES CACHE INTERNAL "")
   526 set(_CORR_PROP_ENV_VARS CORROSION_ENVIRONMENT_VARIABLES CACHE INTERNAL "")
   672     set(_CORR_PROP_ENV_VARS CORROSION_ENVIRONMENT_VARIABLES CACHE INTERNAL "")
   527 set(_CORR_PROP_HOST_BUILD CORROSION_USE_HOST_BUILD CACHE INTERNAL "")
   673     set(_CORR_PROP_HOST_BUILD CORROSION_USE_HOST_BUILD CACHE INTERNAL "")
       
   674 else()
       
   675     set(_CORR_PROP_FEATURES INTERFACE_CORROSION_FEATURES CACHE INTERNAL "")
       
   676     set(_CORR_PROP_ALL_FEATURES INTERFACE_CORROSION_ALL_FEATURES CACHE INTERNAL "")
       
   677     set(_CORR_PROP_NO_DEFAULT_FEATURES INTERFACE_NO_DEFAULT_FEATURES CACHE INTERNAL "")
       
   678     set(_CORR_PROP_ENV_VARS INTERFACE_CORROSION_ENVIRONMENT_VARIABLES CACHE INTERNAL "")
       
   679     set(_CORR_PROP_HOST_BUILD INTERFACE_CORROSION_USE_HOST_BUILD CACHE INTERNAL "")
       
   680 endif()
       
   681 
   528 
   682 # Add custom command to build one target in a package (crate)
   529 # Add custom command to build one target in a package (crate)
   683 #
   530 #
   684 # A target may be either a specific bin
   531 # A target may be either a specific bin
   685 function(_add_cargo_build out_cargo_build_out_dir)
   532 function(_add_cargo_build out_cargo_build_out_dir)
   705     set(package_name "${ACB_PACKAGE}")
   552     set(package_name "${ACB_PACKAGE}")
   706     set(target_name "${ACB_TARGET}")
   553     set(target_name "${ACB_TARGET}")
   707     set(path_to_toml "${ACB_MANIFEST_PATH}")
   554     set(path_to_toml "${ACB_MANIFEST_PATH}")
   708     set(target_kinds "${ACB_TARGET_KINDS}")
   555     set(target_kinds "${ACB_TARGET_KINDS}")
   709     set(workspace_manifest_path "${ACB_WORKSPACE_MANIFEST_PATH}")
   556     set(workspace_manifest_path "${ACB_WORKSPACE_MANIFEST_PATH}")
   710 
   557     set(build_byproducts "${ACB_BYPRODUCTS}")
   711 
   558 
       
   559     unset(cargo_rustc_crate_types)
   712     if(NOT target_kinds)
   560     if(NOT target_kinds)
   713         message(FATAL_ERROR "TARGET_KINDS not specified")
   561         message(FATAL_ERROR "TARGET_KINDS not specified")
   714     elseif("staticlib" IN_LIST target_kinds OR "cdylib" IN_LIST target_kinds)
   562     elseif("staticlib" IN_LIST target_kinds OR "cdylib" IN_LIST target_kinds)
   715         set(cargo_rustc_filter "--lib")
   563         set(cargo_rustc_filter "--lib")
       
   564         if("${Rust_VERSION}" VERSION_GREATER_EQUAL "1.64")
       
   565             # https://doc.rust-lang.org/1.64.0/cargo/commands/cargo-rustc.html
       
   566             # `--crate-type` is documented since Rust 1.64 for `cargo rustc`.
       
   567             # We just unconditionally set it when available, to support overriding the crate type.
       
   568             # Due to https://github.com/rust-lang/cargo/issues/14498 we can't use one argument and pass a
       
   569             # comma seperated list. Instead we use multiple arguments.
       
   570             set(cargo_rustc_crate_types "${target_kinds}")
       
   571             list(TRANSFORM cargo_rustc_crate_types PREPEND "--crate-type=")
       
   572         endif()
   716     elseif("bin" IN_LIST target_kinds)
   573     elseif("bin" IN_LIST target_kinds)
   717         set(cargo_rustc_filter "--bin=${target_name}")
   574         set(cargo_rustc_filter "--bin=${target_name}")
   718     else()
   575     else()
   719         message(FATAL_ERROR "TARGET_KINDS contained unknown kind `${target_kind}`")
   576         message(FATAL_ERROR "TARGET_KINDS contained unknown kind `${target_kind}`")
   720     endif()
   577     endif()
   844     # variable, which we can set for use when cc-rs invokes the compiler.
   701     # variable, which we can set for use when cc-rs invokes the compiler.
   845     if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_OSX_SYSROOT)
   702     if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_OSX_SYSROOT)
   846         list(APPEND corrosion_cc_rs_flags "SDKROOT=${CMAKE_OSX_SYSROOT}")
   703         list(APPEND corrosion_cc_rs_flags "SDKROOT=${CMAKE_OSX_SYSROOT}")
   847     endif()
   704     endif()
   848 
   705 
       
   706     # Ensure that cc-rs targets same Apple platform version as the CMake build
       
   707     if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_OSX_DEPLOYMENT_TARGET)
       
   708         list(APPEND corrosion_cc_rs_flags "MACOSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}")
       
   709     endif()
       
   710 
   849     corrosion_add_target_local_rustflags("${target_name}" "$<$<BOOL:${corrosion_link_args}>:-Clink-args=${corrosion_link_args}>")
   711     corrosion_add_target_local_rustflags("${target_name}" "$<$<BOOL:${corrosion_link_args}>:-Clink-args=${corrosion_link_args}>")
   850 
   712 
   851     # todo: this should probably also be guarded by if_not_host_build_condition.
   713     # todo: this should probably also be guarded by if_not_host_build_condition.
   852     if(COR_NO_STD)
   714     if(COR_NO_STD)
   853         corrosion_add_target_local_rustflags("${target_name}" "-Cdefault-linker-libraries=no")
   715         corrosion_add_target_local_rustflags("${target_name}" "-Cdefault-linker-libraries=no")
   881         # explicit_linker_property will not be set when this function runs.
   743         # explicit_linker_property will not be set when this function runs.
   882         # Passing this rustflag is necessary for clang.
   744         # Passing this rustflag is necessary for clang.
   883         corrosion_add_target_local_rustflags("${target_name}" "$<$<NOT:${explicit_linker_defined}>:${rustflag_linker_arg}>")
   745         corrosion_add_target_local_rustflags("${target_name}" "$<$<NOT:${explicit_linker_defined}>:${rustflag_linker_arg}>")
   884     endif()
   746     endif()
   885 
   747 
   886     message(DEBUG "TARGET ${target_name} produces byproducts ${byproducts}")
   748     message(DEBUG "TARGET ${target_name} produces byproducts ${build_byproducts}")
   887 
   749 
   888     add_custom_target(
   750     add_custom_target(
   889         _cargo-build_${target_name}
   751         _cargo-build_${target_name}
   890         # Build crate
   752         # Build crate
   891         COMMAND
   753         COMMAND
   904                 ${_CORROSION_VERBOSE_OUTPUT_FLAG}
   766                 ${_CORROSION_VERBOSE_OUTPUT_FLAG}
   905                 ${all_features_arg}
   767                 ${all_features_arg}
   906                 ${no_default_features_arg}
   768                 ${no_default_features_arg}
   907                 ${features_genex}
   769                 ${features_genex}
   908                 --package ${package_name}
   770                 --package ${package_name}
       
   771                 ${cargo_rustc_crate_types}
   909                 --manifest-path "${path_to_toml}"
   772                 --manifest-path "${path_to_toml}"
   910                 --target-dir "${cargo_target_dir}"
   773                 --target-dir "${cargo_target_dir}"
   911                 ${cargo_profile}
   774                 ${cargo_profile}
   912                 ${flags_genex}
   775                 ${flags_genex}
   913                 # Any arguments to cargo must be placed before this line
   776                 # Any arguments to cargo must be placed before this line
   914                 ${local_rustflags_delimiter}
   777                 ${local_rustflags_delimiter}
   915                 ${local_rustflags_genex}
   778                 ${local_rustflags_genex}
   916 
   779 
   917         # Note: Adding `build_byproducts` (the byproducts in the cargo target directory) here
   780         # Note: `BYPRODUCTS` may not contain **target specific** generator expressions.
   918         # causes CMake to fail during the Generate stage, because the target `target_name` was not
   781         # This means we cannot use `${cargo_build_dir}`, since it currently uses `$<TARGET_PROPERTY>`
   919         # found. I don't know why this happens, so we just don't specify byproducts here and
   782         # to determine the correct target directory, depending on if the hostbuild target property is
   920         # only specify the actual byproducts in the `POST_BUILD` custom command that copies the
   783         # set or not.
   921         # byproducts to the final destination.
   784         # BYPRODUCTS  "${cargo_build_dir}/${build_byproducts}"
   922         # BYPRODUCTS  ${build_byproducts}
       
   923         # The build is conducted in the directory of the Manifest, so that configuration files such as
   785         # The build is conducted in the directory of the Manifest, so that configuration files such as
   924         # `.cargo/config.toml` or `toolchain.toml` are applied as expected.
   786         # `.cargo/config.toml` or `toolchain.toml` are applied as expected.
   925         WORKING_DIRECTORY "${workspace_toml_dir}"
   787         WORKING_DIRECTORY "${workspace_toml_dir}"
   926         USES_TERMINAL
   788         USES_TERMINAL
   927         COMMAND_EXPAND_LISTS
   789         COMMAND_EXPAND_LISTS
   974         [LOCKED]
   836         [LOCKED]
   975         [FROZEN]
   837         [FROZEN]
   976         [PROFILE <cargo-profile>]
   838         [PROFILE <cargo-profile>]
   977         [IMPORTED_CRATES <variable-name>]
   839         [IMPORTED_CRATES <variable-name>]
   978         [CRATE_TYPES <crate_type1> ... <crate_typeN>]
   840         [CRATE_TYPES <crate_type1> ... <crate_typeN>]
       
   841         [OVERRIDE_CRATE_TYPE <crate_name>=<crate_type1,crate_type2,...> ...]
   979         [CRATES <crate1> ... <crateN>]
   842         [CRATES <crate1> ... <crateN>]
   980         [FEATURES <feature1> ... <featureN>]
   843         [FEATURES <feature1> ... <featureN>]
   981         [FLAGS <flag1> ... <flagN>]
   844         [FLAGS <flag1> ... <flagN>]
   982 )
   845 )
   983 ```
   846 ```
   989 * **LOCKED**: Pass [`--locked`] to cargo build and cargo metadata.
   852 * **LOCKED**: Pass [`--locked`] to cargo build and cargo metadata.
   990 * **FROZEN**: Pass [`--frozen`] to cargo build and cargo metadata.
   853 * **FROZEN**: Pass [`--frozen`] to cargo build and cargo metadata.
   991 * **PROFILE**: Specify cargo build profile (`dev`/`release` or a [custom profile]; `bench` and `test` are not supported)
   854 * **PROFILE**: Specify cargo build profile (`dev`/`release` or a [custom profile]; `bench` and `test` are not supported)
   992 * **IMPORTED_CRATES**: Save the list of imported crates into the variable with the provided name in the current scope.
   855 * **IMPORTED_CRATES**: Save the list of imported crates into the variable with the provided name in the current scope.
   993 * **CRATE_TYPES**: Only import the specified crate types. Valid values: `staticlib`, `cdylib`, `bin`.
   856 * **CRATE_TYPES**: Only import the specified crate types. Valid values: `staticlib`, `cdylib`, `bin`.
       
   857 * **OVERRIDE_CRATE_TYPE**: Override the crate-types of a cargo crate with the given comma-separated values.
       
   858                            Internally uses the `rustc` flag [`--crate-type`] to override the crate-type.
       
   859                            Valid values for the crate types are the library types `staticlib` and `cdylib`.
   994 * **CRATES**: Only import the specified crates from a workspace. Values: Crate names.
   860 * **CRATES**: Only import the specified crates from a workspace. Values: Crate names.
   995 * **FEATURES**: Enable the specified features. Equivalent to [--features] passed to `cargo build`.
   861 * **FEATURES**: Enable the specified features. Equivalent to [--features] passed to `cargo build`.
   996 * **FLAGS**:  Arbitrary flags to `cargo build`.
   862 * **FLAGS**:  Arbitrary flags to `cargo build`.
   997 
   863 
   998 [custom profile]: https://doc.rust-lang.org/cargo/reference/profiles.html#custom-profiles
   864 [custom profile]: https://doc.rust-lang.org/cargo/reference/profiles.html#custom-profiles
   999 [--all-features]: https://doc.rust-lang.org/cargo/reference/features.html#command-line-feature-options
   865 [--all-features]: https://doc.rust-lang.org/cargo/reference/features.html#command-line-feature-options
  1000 [--no-default-features]: https://doc.rust-lang.org/cargo/reference/features.html#command-line-feature-options
   866 [--no-default-features]: https://doc.rust-lang.org/cargo/reference/features.html#command-line-feature-options
  1001 [--features]: https://doc.rust-lang.org/cargo/reference/features.html#command-line-feature-options
   867 [--features]: https://doc.rust-lang.org/cargo/reference/features.html#command-line-feature-options
  1002 [`--locked`]: https://doc.rust-lang.org/cargo/commands/cargo.html#manifest-options
   868 [`--locked`]: https://doc.rust-lang.org/cargo/commands/cargo.html#manifest-options
  1003 [`--frozen`]: https://doc.rust-lang.org/cargo/commands/cargo.html#manifest-options
   869 [`--frozen`]: https://doc.rust-lang.org/cargo/commands/cargo.html#manifest-options
       
   870 [`--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
  1004 [Cargo.toml Manifest]: https://doc.rust-lang.org/cargo/appendix/glossary.html#manifest
   871 [Cargo.toml Manifest]: https://doc.rust-lang.org/cargo/appendix/glossary.html#manifest
  1005 
   872 
  1006 ANCHOR_END: corrosion-import-crate
   873 ANCHOR_END: corrosion-import-crate
  1007 #]=======================================================================]
   874 #]=======================================================================]
  1008 function(corrosion_import_crate)
   875 function(corrosion_import_crate)
  1009     set(OPTIONS ALL_FEATURES NO_DEFAULT_FEATURES NO_STD NO_LINKER_OVERRIDE LOCKED FROZEN)
   876     set(OPTIONS ALL_FEATURES NO_DEFAULT_FEATURES NO_STD NO_LINKER_OVERRIDE LOCKED FROZEN)
  1010     set(ONE_VALUE_KEYWORDS MANIFEST_PATH PROFILE IMPORTED_CRATES)
   877     set(ONE_VALUE_KEYWORDS MANIFEST_PATH PROFILE IMPORTED_CRATES)
  1011     set(MULTI_VALUE_KEYWORDS CRATE_TYPES CRATES FEATURES FLAGS)
   878     set(MULTI_VALUE_KEYWORDS CRATE_TYPES CRATES FEATURES FLAGS OVERRIDE_CRATE_TYPE)
  1012     cmake_parse_arguments(COR "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}" ${ARGN})
   879     cmake_parse_arguments(COR "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}" ${ARGN})
  1013     list(APPEND CMAKE_MESSAGE_CONTEXT "corrosion_import_crate")
   880     list(APPEND CMAKE_MESSAGE_CONTEXT "corrosion_import_crate")
  1014 
   881 
  1015     if(DEFINED COR_UNPARSED_ARGUMENTS)
   882     if(DEFINED COR_UNPARSED_ARGUMENTS)
  1016         message(AUTHOR_WARNING "Unexpected arguments: " ${COR_UNPARSED_ARGUMENTS}
   883         message(AUTHOR_WARNING "Unexpected arguments: " ${COR_UNPARSED_ARGUMENTS}
  1045                     " built-in profile instead."
   912                     " built-in profile instead."
  1046             )
   913             )
  1047         endif()
   914         endif()
  1048     endif()
   915     endif()
  1049 
   916 
       
   917     # intended to be used with foreach(... ZIP_LISTS ...), meaning
       
   918     # that the crate_types at index i of `override_crate_type_types_list` are
       
   919     # for the package_name at index i of `override_crate_type_package_name_list`.
       
   920     # It would really be nice if CMake had structs or dicts.
       
   921     unset(override_crate_type_package_name_list)
       
   922     unset(override_crate_type_types_list)
       
   923     unset(OVERRIDE_CRATE_TYPE_ARGS)
       
   924     if(DEFINED COR_OVERRIDE_CRATE_TYPE)
       
   925         string(JOIN " " usage_help
       
   926                "Each argument to OVERRIDE_CRATE_TYPE must be of the form `<package_name>=<crate_type(s)>."
       
   927                "The package_name must be a valid cargo package name and the crate_type must be "
       
   928                "a comma-seperated list with valid values being `staticlib`, `cdylib` and `bin`"
       
   929         )
       
   930         foreach(entry IN LISTS COR_OVERRIDE_CRATE_TYPE)
       
   931             string(REPLACE "=" ";" key_val_list ${entry})
       
   932             list(LENGTH key_val_list key_val_list_len)
       
   933             if(NOT key_val_list_len EQUAL "2")
       
   934                 message(FATAL_ERROR "Invalid argument: `${entry}` for parameter OVERRIDE_CRATE_TYPE!\n"
       
   935                     "${usage_help}"
       
   936                 )
       
   937             endif()
       
   938             list(GET key_val_list "0" package_name)
       
   939             list(GET key_val_list "1" crate_types)
       
   940             list(APPEND override_crate_type_package_name_list "${package_name}")
       
   941             list(APPEND override_crate_type_types_list "${crate_types}")
       
   942         endforeach()
       
   943         list(LENGTH override_crate_type_package_name_list num_override_packages)
       
   944         list(LENGTH override_crate_type_types_list num_override_packages2)
       
   945         if("${Rust_VERSION}" VERSION_LESS "1.64")
       
   946             message(WARNING "OVERRIDE_CRATE_TYPE requires at Rust 1.64 or newer. Ignoring the option")
       
   947         elseif(NOT num_override_packages EQUAL num_override_packages2)
       
   948             message(WARNING "Internal error while parsing OVERRIDE_CRATE_TYPE arguments.\n"
       
   949                     "Corrosion will ignore this argument and continue."
       
   950             )
       
   951         else()
       
   952             # Pass by ref: we intentionally pass the list names here!
       
   953             set(override_crate_types_arg "OVERRIDE_CRATE_TYPE_ARGS" "override_crate_type_package_name_list" "override_crate_type_types_list")
       
   954         endif()
       
   955     endif()
       
   956 
  1050     if (NOT IS_ABSOLUTE "${COR_MANIFEST_PATH}")
   957     if (NOT IS_ABSOLUTE "${COR_MANIFEST_PATH}")
  1051         set(COR_MANIFEST_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${COR_MANIFEST_PATH})
   958         set(COR_MANIFEST_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${COR_MANIFEST_PATH})
  1052     endif()
   959     endif()
  1053 
   960 
  1054     set(additional_cargo_flags ${COR_FLAGS})
   961     set(additional_cargo_flags ${COR_FLAGS})
  1059     if(COR_FROZEN AND NOT "--frozen" IN_LIST additional_cargo_flags)
   966     if(COR_FROZEN AND NOT "--frozen" IN_LIST additional_cargo_flags)
  1060         list(APPEND additional_cargo_flags  "--frozen")
   967         list(APPEND additional_cargo_flags  "--frozen")
  1061     endif()
   968     endif()
  1062 
   969 
  1063     set(imported_crates "")
   970     set(imported_crates "")
  1064     if (CORROSION_NATIVE_TOOLING)
   971 
  1065         get_filename_component(manifest_directory "${COR_MANIFEST_PATH}" DIRECTORY)
   972     _generator_add_cargo_targets(
  1066         get_filename_component(toml_dir_name ${manifest_directory} NAME)
   973         MANIFEST_PATH
  1067 
   974             "${COR_MANIFEST_PATH}"
  1068         set(
   975         IMPORTED_CRATES
  1069             generated_cmake
   976             imported_crates
  1070             "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/corrosion/${toml_dir_name}.dir/cargo-build.cmake"
   977         ${crate_allowlist}
  1071         )
   978         ${crate_types}
  1072 
   979         ${no_linker_override}
  1073         if (CMAKE_VS_PLATFORM_NAME)
   980         ${override_crate_types_arg}
  1074             set (_CORROSION_CONFIGURATION_ROOT --configuration-root ${CMAKE_VS_PLATFORM_NAME})
   981     )
  1075         endif()
       
  1076 
       
  1077         set(crates_args)
       
  1078         foreach(crate ${COR_CRATES})
       
  1079             list(APPEND crates_args --crates ${crate})
       
  1080         endforeach()
       
  1081         if(DEFINED COR_CRATE_TYPES)
       
  1082             set(crate_types "--crate-type=${COR_CRATE_TYPES}")
       
  1083         endif()
       
  1084 
       
  1085         list(APPEND passthrough_to_acb_args ${no_linker_override})
       
  1086         if(passthrough_to_acb_args)
       
  1087             # 31 == 0x1f
       
  1088             string(ASCII 31 unit_seperator)
       
  1089             list(JOIN passthrough_to_acb_args "${unit_seperator}" joined_args)
       
  1090             set(passthrough_to_acb "--passthrough-acb=${joined_args}")
       
  1091         endif()
       
  1092 
       
  1093         execute_process(
       
  1094             COMMAND
       
  1095                 ${_CORROSION_GENERATOR}
       
  1096                     --manifest-path ${COR_MANIFEST_PATH}
       
  1097                     gen-cmake
       
  1098                         ${_CORROSION_CONFIGURATION_ROOT}
       
  1099                         ${crates_args}
       
  1100                         ${crate_types}
       
  1101                         --imported-crates=imported_crates
       
  1102                         ${passthrough_to_acb}
       
  1103                         -o ${generated_cmake}
       
  1104             WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
       
  1105             RESULT_VARIABLE ret)
       
  1106 
       
  1107         if (NOT ret EQUAL "0")
       
  1108             message(FATAL_ERROR "corrosion-generator failed")
       
  1109         endif()
       
  1110 
       
  1111         include(${generated_cmake})
       
  1112     else()
       
  1113         _generator_add_cargo_targets(
       
  1114             MANIFEST_PATH
       
  1115                 "${COR_MANIFEST_PATH}"
       
  1116             IMPORTED_CRATES
       
  1117                 imported_crates
       
  1118             ${crate_allowlist}
       
  1119             ${crate_types}
       
  1120             ${no_linker_override}
       
  1121         )
       
  1122     endif()
       
  1123 
   982 
  1124     # Not target props yet:
   983     # Not target props yet:
  1125     # NO_STD
   984     # NO_STD
  1126     # NO_LINKER_OVERRIDE # We could simply zero INTERFACE_CORROSION_LINKER if this is set.
   985     # NO_LINKER_OVERRIDE # We could simply zero INTERFACE_CORROSION_LINKER if this is set.
  1127     # LOCKED / FROZEN get merged into FLAGS after cargo metadata.
   986     # LOCKED / FROZEN get merged into FLAGS after cargo metadata.
  1139 
   998 
  1140     # _CORR_PROP_ENV_VARS
   999     # _CORR_PROP_ENV_VARS
  1141     if(DEFINED COR_IMPORTED_CRATES)
  1000     if(DEFINED COR_IMPORTED_CRATES)
  1142         set(${COR_IMPORTED_CRATES} ${imported_crates} PARENT_SCOPE)
  1001         set(${COR_IMPORTED_CRATES} ${imported_crates} PARENT_SCOPE)
  1143     endif()
  1002     endif()
  1144 endfunction()
       
  1145 
       
  1146 function(corrosion_set_linker_language target_name language)
       
  1147     message(FATAL_ERROR "corrosion_set_linker_language was deprecated and removed."
       
  1148             "Please use corrosion_set_linker and set a specific linker.")
       
  1149 endfunction()
  1003 endfunction()
  1150 
  1004 
  1151 function(corrosion_set_linker target_name linker)
  1005 function(corrosion_set_linker target_name linker)
  1152     if(NOT linker)
  1006     if(NOT linker)
  1153         message(FATAL_ERROR "The linker passed to `corrosion_set_linker` may not be empty")
  1007         message(FATAL_ERROR "The linker passed to `corrosion_set_linker` may not be empty")
  1267         if(NOT TARGET "${target_name}-shared")
  1121         if(NOT TARGET "${target_name}-shared")
  1268             # Early return, since Rust won't invoke the linker for static libraries
  1122             # Early return, since Rust won't invoke the linker for static libraries
  1269             return()
  1123             return()
  1270         endif()
  1124         endif()
  1271     endif()
  1125     endif()
  1272     add_dependencies(_cargo-build_${target_name} ${ARGN})
       
  1273     foreach(library ${ARGN})
  1126     foreach(library ${ARGN})
  1274         set_property(
  1127         set_property(
  1275             TARGET _cargo-build_${target_name}
  1128             TARGET _cargo-build_${target_name}
  1276             APPEND
  1129             APPEND
  1277             PROPERTY CARGO_DEPS_LINKER_LANGUAGES
  1130             PROPERTY CARGO_DEPS_LINKER_LANGUAGES
  1278             $<TARGET_PROPERTY:${library},LINKER_LANGUAGE>
  1131             $<TARGET_PROPERTY:${library},LINKER_LANGUAGE>
  1279         )
  1132         )
  1280 
  1133 
  1281         corrosion_add_target_local_rustflags(${target_name} "-L$<TARGET_LINKER_FILE_DIR:${library}>")
  1134         if (TARGET "${library}")
  1282         corrosion_add_target_local_rustflags(${target_name} "-l$<TARGET_LINKER_FILE_BASE_NAME:${library}>")
  1135             corrosion_add_target_local_rustflags(${target_name}
       
  1136                 "-L$<TARGET_LINKER_FILE_DIR:${library}>"
       
  1137                 "-l$<TARGET_LINKER_FILE_BASE_NAME:${library}>"
       
  1138             )
       
  1139             add_dependencies(_cargo-build_${target_name} ${library})
       
  1140         elseif(IS_ABSOLUTE "${library}")
       
  1141             # Linking via full path (See https://doc.rust-lang.org/rustc/command-line-arguments.html#linking-modifiers-verbatim)
       
  1142             corrosion_add_target_local_rustflags(${target_name} "-Clink-arg=${library}")
       
  1143         else()
       
  1144             # We have to assume ${library} is a non-CMake library name
       
  1145             corrosion_add_target_local_rustflags(${target_name} "-l${library}")
       
  1146         endif()
  1283     endforeach()
  1147     endforeach()
  1284 endfunction()
  1148 endfunction()
  1285 
  1149 
       
  1150 #[=======================================================================[.md:
       
  1151 ANCHOR: corrosion-install
       
  1152 ** EXPERIMENTAL **: This function is currently still considered experimental
       
  1153   and is not officially released yet. Feedback and Suggestions are welcome.
       
  1154 
       
  1155 ```cmake
       
  1156 corrosion_install(TARGETS <target1> ... <targetN> [EXPORT <export-name>]
       
  1157                   [[ARCHIVE|LIBRARY|RUNTIME|PUBLIC_HEADER]
       
  1158                    [DESTINATION <dir>]
       
  1159                    [PERMISSIONS <permissions...>]
       
  1160                    [CONFIGURATIONS [Debug|Release|<other-configuration>]]
       
  1161                   ] [...])
       
  1162 ```
       
  1163 * **TARGETS**: Target or targets to install.
       
  1164 * **EXPORT**: Creates an export that can be installed with `install(EXPORT)`. <export-name> must be globally unique.
       
  1165              Also creates a file at ${CMAKE_BINARY_DIR}/corrosion/<export-name>Corrosion.cmake that must be included in the installed config file.
       
  1166 * **ARCHIVE**/**LIBRARY**/**RUNTIME**/PUBLIC_HEADER: Designates that the following settings only apply to that specific type of object.
       
  1167 * **DESTINATION**: The subdirectory within the CMAKE_INSTALL_PREFIX that a specific object should be placed. Defaults to values from GNUInstallDirs.
       
  1168 * **PERMISSIONS**: The permissions of files copied into the install prefix.
       
  1169 
       
  1170 Any `PUBLIC` or `INTERFACE` [file sets] will be installed.
       
  1171 
       
  1172 [file sets]: https://cmake.org/cmake/help/latest/command/target_sources.html#file-sets
       
  1173 
       
  1174 ANCHOR_END: corrosion-install
       
  1175 #]=======================================================================]
  1286 function(corrosion_install)
  1176 function(corrosion_install)
  1287     # Default install dirs
  1177     # Default install dirs
  1288     include(GNUInstallDirs)
  1178     include(GNUInstallDirs)
  1289 
  1179 
  1290     # Parse arguments to corrosion_install
  1180     # Parse arguments to corrosion_install
  1301     set(ONE_VALUE_ARGS DESTINATION)
  1191     set(ONE_VALUE_ARGS DESTINATION)
  1302     set(MULTI_VALUE_ARGS PERMISSIONS CONFIGURATIONS)
  1192     set(MULTI_VALUE_ARGS PERMISSIONS CONFIGURATIONS)
  1303     set(TARGET_ARGS ${OPTIONS} ${ONE_VALUE_ARGS} ${MULTI_VALUE_ARGS})
  1193     set(TARGET_ARGS ${OPTIONS} ${ONE_VALUE_ARGS} ${MULTI_VALUE_ARGS})
  1304 
  1194 
  1305     if (INSTALL_TYPE STREQUAL "TARGETS")
  1195     if (INSTALL_TYPE STREQUAL "TARGETS")
  1306         # corrosion_install(TARGETS ... [EXPORT <export-name>]
       
  1307         #                   [[ARCHIVE|LIBRARY|RUNTIME|PRIVATE_HEADER|PUBLIC_HEADER]
       
  1308         #                    [DESTINATION <dir>]
       
  1309         #                    [PERMISSIONS permissions...]
       
  1310         #                    [CONFIGURATIONS [Debug|Release|...]]
       
  1311         #                   ] [...])
       
  1312 
       
  1313         # Extract targets
  1196         # Extract targets
  1314         set(INSTALL_TARGETS)
  1197         set(INSTALL_TARGETS)
  1315         list(LENGTH ARGN ARGN_LENGTH)
  1198         list(LENGTH ARGN ARGN_LENGTH)
  1316         set(DELIMITERS EXPORT ${INSTALL_TARGET_TYPES} ${TARGET_ARGS})
  1199         set(DELIMITERS EXPORT ${INSTALL_TARGET_TYPES} ${TARGET_ARGS})
  1317         while(ARGN_LENGTH)
  1200         while(ARGN_LENGTH)
  1335             if (FRONT STREQUAL "EXPORT")
  1218             if (FRONT STREQUAL "EXPORT")
  1336                 list(REMOVE_AT ARGN 0) # Pop "EXPORT"
  1219                 list(REMOVE_AT ARGN 0) # Pop "EXPORT"
  1337 
  1220 
  1338                 list(GET ARGN 0 EXPORT_NAME)
  1221                 list(GET ARGN 0 EXPORT_NAME)
  1339                 list(REMOVE_AT ARGN 0) # Pop <export-name>
  1222                 list(REMOVE_AT ARGN 0) # Pop <export-name>
  1340                 message(FATAL_ERROR "EXPORT keyword not yet implemented!")
  1223                 set(EXTRA_TARGETS_EXPORT_NAME ${EXPORT_NAME}Corrosion.cmake)
       
  1224                 set(EXPORT_NAME EXPORT ${EXPORT_NAME})
       
  1225                 set(EXPORT_FILE_PATH "${CMAKE_BINARY_DIR}/corrosion/${EXTRA_TARGETS_EXPORT_NAME}")
       
  1226                 # Remove first, since otherwise we will append to the file on every reconfigure.
       
  1227                 # Assumes that the corrosion_install will only be called once for a given EXPORT_NAME.
       
  1228                 file(REMOVE "${EXPORT_FILE_PATH}")
  1341             endif()
  1229             endif()
       
  1230         else()
       
  1231             # Prevent variable set in user code from interfering
       
  1232             set(EXPORT_NAME)
  1342         endif()
  1233         endif()
  1343 
  1234 
  1344         # Loop over all arguments and get options for each install target type
  1235         # Loop over all arguments and get options for each install target type
  1345         list(LENGTH ARGN ARGN_LENGTH)
  1236         list(LENGTH ARGN ARGN_LENGTH)
  1346         while(ARGN_LENGTH)
  1237         while(ARGN_LENGTH)
  1393         # Default permissions for all files
  1284         # Default permissions for all files
  1394         set(DEFAULT_PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
  1285         set(DEFAULT_PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
  1395 
  1286 
  1396         # Loop through each install target and register file installations
  1287         # Loop through each install target and register file installations
  1397         foreach(INSTALL_TARGET ${INSTALL_TARGETS})
  1288         foreach(INSTALL_TARGET ${INSTALL_TARGETS})
       
  1289             if(NOT TARGET ${INSTALL_TARGET})
       
  1290                 message(FATAL_ERROR "Install target ${INSTALL_TARGET} is not a valid target")
       
  1291             endif()
  1398             # Don't both implementing target type differentiation using generator expressions since
  1292             # Don't both implementing target type differentiation using generator expressions since
  1399             # TYPE cannot change after target creation
  1293             # TYPE cannot change after target creation
  1400             get_property(
  1294             get_property(
  1401                 TARGET_TYPE
  1295                 TARGET_TYPE
  1402                 TARGET ${INSTALL_TARGET} PROPERTY TYPE
  1296                 TARGET ${INSTALL_TARGET} PROPERTY TYPE
  1434                     FILES $<TARGET_FILE:${INSTALL_TARGET}>
  1328                     FILES $<TARGET_FILE:${INSTALL_TARGET}>
  1435                     DESTINATION ${DESTINATION}
  1329                     DESTINATION ${DESTINATION}
  1436                     PERMISSIONS ${PERMISSIONS}
  1330                     PERMISSIONS ${PERMISSIONS}
  1437                     ${CONFIGURATIONS}
  1331                     ${CONFIGURATIONS}
  1438                 )
  1332                 )
       
  1333             elseif(TARGET_TYPE STREQUAL "INTERFACE_LIBRARY")
       
  1334                 if(TARGET ${INSTALL_TARGET}-static)
       
  1335                     if (DEFINED COR_INSTALL_ARCHIVE_DESTINATION)
       
  1336                         set(DESTINATION ${COR_INSTALL_ARCHIVE_DESTINATION})
       
  1337                     elseif (DEFINED COR_INSTALL_DEFAULT_DESTINATION)
       
  1338                         set(DESTINATION ${COR_INSTALL_DEFAULT_DESTINATION})
       
  1339                     else()
       
  1340                         set(DESTINATION ${CMAKE_INSTALL_LIBDIR})
       
  1341                     endif()
       
  1342 
       
  1343                     if (DEFINED COR_INSTALL_ARCHIVE_PERMISSIONS)
       
  1344                         set(PERMISSIONS ${COR_INSTALL_ARCHIVE_PERMISSIONS})
       
  1345                     elseif (DEFINED COR_INSTALL_DEFAULT_PERMISSIONS)
       
  1346                         set(PERMISSIONS ${COR_INSTALL_DEFAULT_PERMISSIONS})
       
  1347                     else()
       
  1348                         set(PERMISSIONS ${DEFAULT_PERMISSIONS})
       
  1349                     endif()
       
  1350 
       
  1351                     if (DEFINED COR_INSTALL_ARCHIVE_CONFIGURATIONS)
       
  1352                         set(CONFIGURATIONS CONFIGURATIONS ${COR_INSTALL_ARCHIVE_CONFIGURATIONS})
       
  1353                     elseif (DEFINED COR_INSTALL_DEFAULT_CONFIGURATIONS)
       
  1354                         set(CONFIGURATIONS CONFIGURATIONS ${COR_INSTALL_DEFAULT_CONFIGURATIONS})
       
  1355                     else()
       
  1356                         set(CONFIGURATIONS)
       
  1357                     endif()
       
  1358 
       
  1359                     install(
       
  1360                             FILES $<TARGET_PROPERTY:${INSTALL_TARGET}-static,IMPORTED_LOCATION>
       
  1361                             DESTINATION ${DESTINATION}
       
  1362                             PERMISSIONS ${PERMISSIONS}
       
  1363                             ${CONFIGURATIONS}
       
  1364                     )
       
  1365 
       
  1366                     if(EXPORT_NAME)
       
  1367                         get_target_property(COR_FILE_NAME ${INSTALL_TARGET}-static COR_FILE_NAME)
       
  1368                         file(APPEND "${EXPORT_FILE_PATH}"
       
  1369 "
       
  1370 add_library(${INSTALL_TARGET}-static STATIC IMPORTED)
       
  1371 set_target_properties(${INSTALL_TARGET}-static
       
  1372     PROPERTIES
       
  1373     IMPORTED_LOCATION \"\${PACKAGE_PREFIX_DIR}/${DESTINATION}/${COR_FILE_NAME}\"
       
  1374 )
       
  1375 "
       
  1376                         )
       
  1377                     endif()
       
  1378                 endif()
       
  1379 
       
  1380                 if(TARGET ${INSTALL_TARGET}-shared)
       
  1381                     if (DEFINED COR_INSTALL_LIBRARY_DESTINATION)
       
  1382                         set(DESTINATION ${COR_INSTALL_LIBRARY_DESTINATION})
       
  1383                     elseif (DEFINED COR_INSTALL_DEFAULT_DESTINATION)
       
  1384                         set(DESTINATION ${COR_INSTALL_DEFAULT_DESTINATION})
       
  1385                     else()
       
  1386                         set(DESTINATION ${CMAKE_INSTALL_LIBDIR})
       
  1387                     endif()
       
  1388 
       
  1389                     if (DEFINED COR_INSTALL_LIBRARY_PERMISSIONS)
       
  1390                         set(PERMISSIONS ${COR_INSTALL_LIBRARY_PERMISSIONS})
       
  1391                     elseif (DEFINED COR_INSTALL_DEFAULT_PERMISSIONS)
       
  1392                         set(PERMISSIONS ${COR_INSTALL_DEFAULT_PERMISSIONS})
       
  1393                     else()
       
  1394                         set(
       
  1395                             PERMISSIONS
       
  1396                             ${DEFAULT_PERMISSIONS} OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE
       
  1397                         )
       
  1398                     endif()
       
  1399 
       
  1400                     if (DEFINED COR_INSTALL_LIBRARY_CONFIGURATIONS)
       
  1401                         set(CONFIGURATIONS CONFIGURATIONS ${COR_INSTALL_LIBRARY_CONFIGURATIONS})
       
  1402                     elseif (DEFINED COR_INSTALL_DEFAULT_CONFIGURATIONS)
       
  1403                         set(CONFIGURATIONS CONFIGURATIONS ${COR_INSTALL_DEFAULT_CONFIGURATIONS})
       
  1404                     else()
       
  1405                         set(CONFIGURATIONS)
       
  1406                     endif()
       
  1407 
       
  1408                     install(
       
  1409                             IMPORTED_RUNTIME_ARTIFACTS ${INSTALL_TARGET}-shared
       
  1410                             PERMISSIONS ${PERMISSIONS}
       
  1411                             DESTINATION ${DESTINATION}
       
  1412                             ${CONFIGURATIONS}
       
  1413                     )
       
  1414 
       
  1415                     if(EXPORT_NAME)
       
  1416                         get_target_property(COR_FILE_NAME ${INSTALL_TARGET}-shared COR_FILE_NAME)
       
  1417                         file(APPEND "${EXPORT_FILE_PATH}"
       
  1418 "
       
  1419 add_library(${INSTALL_TARGET}-shared SHARED IMPORTED)
       
  1420 set_target_properties(${INSTALL_TARGET}-shared
       
  1421     PROPERTIES
       
  1422     IMPORTED_LOCATION \"\${PACKAGE_PREFIX_DIR}/${DESTINATION}/${COR_FILE_NAME}\"
       
  1423 )
       
  1424 "
       
  1425                             )
       
  1426 
       
  1427                             get_target_property(COR_IMPLIB_FILE_NAME ${INSTALL_TARGET}-shared COR_IMPLIB_FILE_NAME)
       
  1428                             if (NOT COR_IMPLIB_FILE_NAME MATCHES .*-NOTFOUND)
       
  1429                                 file(APPEND "${EXPORT_FILE_PATH}"
       
  1430 "
       
  1431 set_target_properties(${INSTALL_TARGET}-shared
       
  1432     PROPERTIES
       
  1433     IMPORTED_IMPLIB \"\${PACKAGE_PREFIX_DIR}/${DESTINATION}/${COR_IMPLIB_FILE_NAME}\"
       
  1434 )"
       
  1435                                 )
       
  1436                             endif()
       
  1437                     endif()
       
  1438                 endif()
       
  1439             else()
       
  1440                 message(FATAL_ERROR "Unknown target type ${TARGET_TYPE} for install target ${INSTALL_TARGET}")
       
  1441             endif()
       
  1442 
       
  1443             # Executables can also have export tables, so they _might_ also need header files
       
  1444             if (DEFINED COR_INSTALL_PUBLIC_HEADER_DESTINATION)
       
  1445                 set(DESTINATION ${COR_INSTALL_PUBLIC_HEADER_DESTINATION})
       
  1446             elseif (DEFINED COR_INSTALL_DEFAULT_DESTINATION)
       
  1447                 set(DESTINATION ${COR_INSTALL_DEFAULT_DESTINATION})
       
  1448             else()
       
  1449                 set(DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
       
  1450             endif()
       
  1451 
       
  1452             if (DEFINED COR_INSTALL_PUBLIC_HEADER_PERMISSIONS)
       
  1453                 set(PERMISSIONS ${COR_INSTALL_PUBLIC_HEADER_PERMISSIONS})
       
  1454             elseif (DEFINED COR_INSTALL_DEFAULT_PERMISSIONS)
       
  1455                 set(PERMISSIONS ${COR_INSTALL_DEFAULT_PERMISSIONS})
       
  1456             else()
       
  1457                 # Directories need OWNER_EXECUTE in order to be deletable by owner
       
  1458                 set(PERMISSIONS ${DEFAULT_PERMISSIONS} OWNER_EXECUTE)
       
  1459             endif()
       
  1460 
       
  1461             if (DEFINED COR_INSTALL_PUBLIC_HEADER_CONFIGURATIONS)
       
  1462                 set(CONFIGURATIONS CONFIGURATIONS ${COR_INSTALL_PUBLIC_HEADER_CONFIGURATIONS})
       
  1463             elseif (DEFINED COR_INSTALL_DEFAULT_CONFIGURATIONS)
       
  1464                 set(CONFIGURATIONS CONFIGURATIONS ${COR_INSTALL_DEFAULT_CONFIGURATIONS})
       
  1465             else()
       
  1466                 set(CONFIGURATIONS)
       
  1467             endif()
       
  1468 
       
  1469             get_target_property(FILE_SET ${INSTALL_TARGET} INTERFACE_HEADER_SETS)
       
  1470             if(NOT FILE_SET OR FILE_SET MATCHES .*-NOTFOUND)
       
  1471                 set(TARGET_HAS_FILE_SET FALSE)
       
  1472             else()
       
  1473                 set(TARGET_HAS_FILE_SET TRUE)
       
  1474             endif()
       
  1475 
       
  1476             if(NOT TARGET_HAS_FILE_SET)
       
  1477                 if(EXPORT_NAME)
       
  1478                     # We still need to generate a EXPORT but we can't do that with install(DIRECTORY)
       
  1479                     install(TARGETS ${INSTALL_TARGET} ${EXPORT_NAME})
       
  1480                 endif()
       
  1481 
       
  1482                 set(PUBLIC_HEADER_PROPERTIES INCLUDE_DIRECTORIES PUBLIC_INCLUDE_DIRECTORIES INTERFACE_INCLUDE_DIRECTORIES)
       
  1483                 foreach(PUBLIC_HEADER_PROPERTY ${PUBLIC_HEADER_PROPERTIES})
       
  1484                     get_target_property(PUBLIC_HEADER ${INSTALL_TARGET} ${PUBLIC_HEADER_PROPERTY})
       
  1485 
       
  1486                     if(NOT PUBLIC_HEADER MATCHES .*-NOTFOUND)
       
  1487                         foreach(INCLUDE_DIRECTORY ${PUBLIC_HEADER})
       
  1488                             install(
       
  1489                                     DIRECTORY ${INCLUDE_DIRECTORY}
       
  1490                                     DESTINATION .
       
  1491                                     FILE_PERMISSIONS ${PERMISSIONS}
       
  1492                                     DIRECTORY_PERMISSIONS ${PERMISSIONS}
       
  1493                                     ${CONFIGURATIONS}
       
  1494                             )
       
  1495                         endforeach()
       
  1496                     endif()
       
  1497                 endforeach()
       
  1498             else()
       
  1499                 install(
       
  1500                         TARGETS ${INSTALL_TARGET}
       
  1501                         ${EXPORT_NAME}
       
  1502                         FILE_SET HEADERS
       
  1503                         DESTINATION ${DESTINATION}
       
  1504                         PERMISSIONS ${PERMISSIONS}
       
  1505                         ${CONFIGURATIONS}
       
  1506                 )
  1439             endif()
  1507             endif()
  1440         endforeach()
  1508         endforeach()
  1441 
  1509 
  1442     elseif(INSTALL_TYPE STREQUAL "EXPORT")
  1510     elseif(INSTALL_TYPE STREQUAL "EXPORT")
  1443         message(FATAL_ERROR "install(EXPORT ...) not yet implemented")
  1511         message(FATAL_ERROR "install(EXPORT ...) not yet implemented")
       
  1512     else()
       
  1513         message(FATAL_ERROR "Unknown arg: ${INSTALL_TYPE}")
  1444     endif()
  1514     endif()
  1445 endfunction()
  1515 endfunction()
  1446 
  1516 
  1447 #[=======================================================================[.md:
  1517 #[=======================================================================[.md:
  1448 ** EXPERIMENTAL **: This function is currently still considered experimental
  1518 ** EXPERIMENTAL **: This function is currently still considered experimental
  1451 ANCHOR: corrosion_add_cxxbridge
  1521 ANCHOR: corrosion_add_cxxbridge
  1452 
  1522 
  1453 ```cmake
  1523 ```cmake
  1454 corrosion_add_cxxbridge(cxx_target
  1524 corrosion_add_cxxbridge(cxx_target
  1455         CRATE <imported_target_name>
  1525         CRATE <imported_target_name>
       
  1526         REGEN_TARGET <regen_target_name>
  1456         [FILES <file1.rs> <file2.rs>]
  1527         [FILES <file1.rs> <file2.rs>]
  1457 )
  1528 )
  1458 ```
  1529 ```
  1459 
  1530 
  1460 Adds build-rules to create C++ bindings using the [cxx] crate.
  1531 Adds build-rules to create C++ bindings using the [cxx] crate.
  1461 
  1532 
  1462 ### Arguments:
  1533 ### Arguments:
  1463 * `cxxtarget`: Name of the C++ library target for the bindings, which corrosion will create.
  1534 * `cxxtarget`: Name of the C++ library target for the bindings, which corrosion will create.
  1464 * **FILES**: Input Rust source file containing #[cxx::bridge].
  1535 * **FILES**: Input Rust source file containing #[cxx::bridge].
  1465 * **CRATE**: Name of an imported Rust target. Note: Parameter may be renamed before release
  1536 * **CRATE**: Name of an imported Rust target. Note: Parameter may be renamed before release
       
  1537 * **REGEN_TARGET**: Name of a custom target that will regenerate the cxx bindings **without** recompiling. Note: Parameter may be renamed before release
  1466 
  1538 
  1467 #### Currently missing arguments
  1539 #### Currently missing arguments
  1468 
  1540 
  1469 The following arguments to cxxbridge **currently** have no way to be passed by the user:
  1541 The following arguments to cxxbridge **currently** have no way to be passed by the user:
  1470 - `--cfg`
  1542 - `--cfg`
  1498 
  1570 
  1499 ANCHOR_END: corrosion_add_cxxbridge
  1571 ANCHOR_END: corrosion_add_cxxbridge
  1500 #]=======================================================================]
  1572 #]=======================================================================]
  1501 function(corrosion_add_cxxbridge cxx_target)
  1573 function(corrosion_add_cxxbridge cxx_target)
  1502     set(OPTIONS)
  1574     set(OPTIONS)
  1503     set(ONE_VALUE_KEYWORDS CRATE)
  1575     set(ONE_VALUE_KEYWORDS CRATE REGEN_TARGET)
  1504     set(MULTI_VALUE_KEYWORDS FILES)
  1576     set(MULTI_VALUE_KEYWORDS FILES)
  1505     cmake_parse_arguments(PARSE_ARGV 1 _arg "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}")
  1577     cmake_parse_arguments(PARSE_ARGV 1 _arg "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}")
  1506 
  1578 
  1507     set(required_keywords CRATE FILES)
  1579     set(required_keywords CRATE FILES)
  1508     foreach(keyword ${required_keywords})
  1580     foreach(keyword ${required_keywords})
  1562     endif()
  1634     endif()
  1563 
  1635 
  1564     # No suitable version of cxxbridge was installed, so use custom target to build correct version.
  1636     # No suitable version of cxxbridge was installed, so use custom target to build correct version.
  1565     if(NOT cxxbridge)
  1637     if(NOT cxxbridge)
  1566         if(NOT TARGET "cxxbridge_v${cxx_required_version}")
  1638         if(NOT TARGET "cxxbridge_v${cxx_required_version}")
  1567             add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/corrosion/cxxbridge_v${cxx_required_version}/bin/cxxbridge"
  1639             unset(executable_postfix)
       
  1640             if(Rust_CARGO_HOST_OS STREQUAL "windows")
       
  1641                 set(executable_postfix ".exe")
       
  1642             endif()
       
  1643             add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/corrosion/cxxbridge_v${cxx_required_version}/bin/cxxbridge${executable_postfix}"
  1568                 COMMAND
  1644                 COMMAND
  1569                 ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/corrosion/cxxbridge_v${cxx_required_version}"
  1645                 ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/corrosion/cxxbridge_v${cxx_required_version}"
  1570                 COMMAND
  1646                 COMMAND
  1571                     ${CMAKE_COMMAND} -E env
  1647                     ${CMAKE_COMMAND} -E env
  1572                         "CARGO_BUILD_RUSTC=${_CORROSION_RUSTC}"
  1648                         "CARGO_BUILD_RUSTC=${_CORROSION_RUSTC}"
  1577                     --quiet
  1653                     --quiet
  1578                     # todo: use --target-dir to potentially reuse artifacts
  1654                     # todo: use --target-dir to potentially reuse artifacts
  1579                 COMMENT "Building cxxbridge (version ${cxx_required_version})"
  1655                 COMMENT "Building cxxbridge (version ${cxx_required_version})"
  1580                 )
  1656                 )
  1581             add_custom_target("cxxbridge_v${cxx_required_version}"
  1657             add_custom_target("cxxbridge_v${cxx_required_version}"
  1582                 DEPENDS "${CMAKE_BINARY_DIR}/corrosion/cxxbridge_v${cxx_required_version}/bin/cxxbridge"
  1658                 DEPENDS "${CMAKE_BINARY_DIR}/corrosion/cxxbridge_v${cxx_required_version}/bin/cxxbridge${executable_postfix}"
  1583                 )
  1659                 )
  1584         endif()
  1660         endif()
  1585         set(cxxbridge "${CMAKE_BINARY_DIR}/corrosion/cxxbridge_v${cxx_required_version}/bin/cxxbridge")
  1661         set(cxxbridge "${CMAKE_BINARY_DIR}/corrosion/cxxbridge_v${cxx_required_version}/bin/cxxbridge${executable_postfix}")
  1586     endif()
  1662     endif()
  1587 
  1663 
  1588 
  1664 
  1589     # The generated folder structure will be of the following form
  1665     # The generated folder structure will be of the following form
  1590     #
  1666     #
  1636             ${cxxbridge} --header --output "${generated_dir}/include/rust/cxx.h"
  1712             ${cxxbridge} --header --output "${generated_dir}/include/rust/cxx.h"
  1637             DEPENDS "cxxbridge_v${cxx_required_version}"
  1713             DEPENDS "cxxbridge_v${cxx_required_version}"
  1638             COMMENT "Generating rust/cxx.h header"
  1714             COMMENT "Generating rust/cxx.h header"
  1639     )
  1715     )
  1640 
  1716 
       
  1717     set(GENERATED_FILES "${generated_dir}/include/rust/cxx.h")
       
  1718 
  1641     foreach(filepath ${_arg_FILES})
  1719     foreach(filepath ${_arg_FILES})
  1642         get_filename_component(filename ${filepath} NAME_WE)
  1720         get_filename_component(filename ${filepath} NAME_WE)
  1643         get_filename_component(directory ${filepath} DIRECTORY)
  1721         get_filename_component(directory ${filepath} DIRECTORY)
  1644         set(directory_component "")
  1722         set(directory_component "")
  1645         if(directory)
  1723         if(directory)
  1663             COMMAND
  1741             COMMAND
  1664                 ${cxxbridge} ${rust_source_path}
  1742                 ${cxxbridge} ${rust_source_path}
  1665                     --output "${source_placement_dir}/${cxx_source}"
  1743                     --output "${source_placement_dir}/${cxx_source}"
  1666                     --include "${cxx_target}/${cxx_header}"
  1744                     --include "${cxx_target}/${cxx_header}"
  1667             DEPENDS "cxxbridge_v${cxx_required_version}" "${rust_source_path}"
  1745             DEPENDS "cxxbridge_v${cxx_required_version}" "${rust_source_path}"
  1668             COMMENT "Generating cxx bindings for crate ${_arg_CRATE}"
  1746             COMMENT "Generating cxx bindings for crate ${_arg_CRATE} and file src/${filepath}"
  1669         )
  1747         )
  1670 
  1748 
  1671         target_sources(${cxx_target}
  1749         list(APPEND GENERATED_FILES
  1672             PRIVATE
  1750             "${header_placement_dir}/${cxx_header}"
  1673                 "${header_placement_dir}/${cxx_header}"
  1751             "${source_placement_dir}/${cxx_source}")
  1674                 "${generated_dir}/include/rust/cxx.h"
       
  1675                 "${source_placement_dir}/${cxx_source}"
       
  1676         )
       
  1677     endforeach()
  1752     endforeach()
       
  1753     target_sources(${cxx_target} PRIVATE ${GENERATED_FILES})
       
  1754 
       
  1755     if(DEFINED _arg_REGEN_TARGET)
       
  1756         add_custom_target(${_arg_REGEN_TARGET}
       
  1757             DEPENDS ${GENERATED_FILES}
       
  1758             COMMENT "Generated cxx bindings for crate ${_arg_CRATE}")
       
  1759     endif()
       
  1760 
  1678 endfunction()
  1761 endfunction()
  1679 
  1762 
  1680 #[=======================================================================[.md:
  1763 #[=======================================================================[.md:
  1681 ANCHOR: corrosion_cbindgen
  1764 ANCHOR: corrosion_cbindgen
  1682 ```cmake
  1765 ```cmake
  1683 corrosion_cbindgen(
  1766 corrosion_cbindgen(
  1684         TARGET <imported_target_name>
  1767         TARGET <imported_target_name>
  1685         HEADER_NAME <output_header_name>
  1768         HEADER_NAME <output_header_name>
       
  1769         [CARGO_PACKAGE <cargo_package_name>]
  1686         [MANIFEST_DIRECTORY <package_manifest_directory>]
  1770         [MANIFEST_DIRECTORY <package_manifest_directory>]
  1687         [CBINDGEN_VERSION <version>]
  1771         [CBINDGEN_VERSION <version>]
  1688         [FLAGS <flag1> ... <flagN>]
  1772         [FLAGS <flag1> ... <flagN>]
  1689 )
  1773 )
  1690 ```
  1774 ```
  1693 If `cbindgen` is not in `PATH` the helper function will automatically try to download
  1777 If `cbindgen` is not in `PATH` the helper function will automatically try to download
  1694 `cbindgen` and place the built binary into `CMAKE_BINARY_DIR`. The binary is shared
  1778 `cbindgen` and place the built binary into `CMAKE_BINARY_DIR`. The binary is shared
  1695 between multiple invocations of this function.
  1779 between multiple invocations of this function.
  1696 
  1780 
  1697 
  1781 
  1698 * **TARGET**: The name of an imported Rust library target (crate), for which bindings should be generated.
  1782 * **TARGET**: The name of an imported Rust library target, for which bindings should be generated.
  1699               If the target was not previously imported by Corrosion, because the crate only produces an
  1783               If the target was not previously imported by Corrosion, because the crate only produces an
  1700               `rlib`, you must additionally specify `MANIFEST_DIRECTORY`.
  1784               `rlib`, you must additionally specify `MANIFEST_DIRECTORY`.
  1701 
  1785 
  1702 * **MANIFEST_DIRECTORY**: Directory of the package defining the library crate bindings should be generated for.
  1786 * **MANIFEST_DIRECTORY**: Directory of the package defining the library crate bindings should be generated for.
  1703     If you want to avoid specifying `MANIFEST_DIRECTORY` you could add a `staticlib` target to your package
  1787     If you want to avoid specifying `MANIFEST_DIRECTORY` you could add a `staticlib` target to your package
  1708 * **CBINDGEN_VERSION**: Version requirement for cbindgen. Exact semantics to be specified. Currently not implemented.
  1792 * **CBINDGEN_VERSION**: Version requirement for cbindgen. Exact semantics to be specified. Currently not implemented.
  1709 * **FLAGS**: Arbitrary other flags for `cbindgen`. Run `cbindgen --help` to see the possible flags.
  1793 * **FLAGS**: Arbitrary other flags for `cbindgen`. Run `cbindgen --help` to see the possible flags.
  1710 
  1794 
  1711 [cbindgen]: https://github.com/eqrion/cbindgen
  1795 [cbindgen]: https://github.com/eqrion/cbindgen
  1712 
  1796 
       
  1797 ### Current limitations
       
  1798 
       
  1799 - Cbindgens (optional) macro expansion feature internally actually builds the crate / runs the build script.
       
  1800   For this to work as expected in all cases, we probably need to set all the same environment variables
       
  1801   as when corrosion builds the crate. However the crate is a **library**, so we would need to figure out which
       
  1802   target builds it - and if there are multiple, potentially generate bindings per-target?
       
  1803   Alternatively we could add support of setting some environment variables on rlibs, and pulling that
       
  1804   information in when building the actual corrosion targets
       
  1805   Alternatively we could restrict corrosions support of this feature to actual imported staticlib/cdylib targets.
  1713 ANCHOR_END: corrosion_cbindgen
  1806 ANCHOR_END: corrosion_cbindgen
  1714 #]=======================================================================]
  1807 #]=======================================================================]
  1715 function(corrosion_experimental_cbindgen)
  1808 function(corrosion_experimental_cbindgen)
  1716     set(OPTIONS "")
  1809     set(OPTIONS "")
  1717     set(ONE_VALUE_KEYWORDS TARGET MANIFEST_DIRECTORY HEADER_NAME CBINDGEN_VERSION)
  1810     set(ONE_VALUE_KEYWORDS
       
  1811             TARGET
       
  1812             MANIFEST_DIRECTORY
       
  1813             HEADER_NAME
       
  1814             CBINDGEN_VERSION)
  1718     set(MULTI_VALUE_KEYWORDS "FLAGS")
  1815     set(MULTI_VALUE_KEYWORDS "FLAGS")
  1719     cmake_parse_arguments(PARSE_ARGV 0 CCN "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}")
  1816     cmake_parse_arguments(PARSE_ARGV 0 CCN "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}")
  1720 
  1817 
  1721     set(required_keywords TARGET HEADER_NAME)
  1818     set(required_keywords TARGET HEADER_NAME)
  1722     foreach(keyword ${required_keywords})
  1819     foreach(keyword ${required_keywords})
  1748         else()
  1845         else()
  1749             set(package_manifest_dir "${CCN_MANIFEST_DIRECTORY}")
  1846             set(package_manifest_dir "${CCN_MANIFEST_DIRECTORY}")
  1750         endif()
  1847         endif()
  1751     endif()
  1848     endif()
  1752 
  1849 
  1753     unset(rust_cargo_package)
  1850     get_target_property(rust_cargo_package "${rust_target}" COR_CARGO_PACKAGE_NAME )
  1754     if(NOT DEFINED CCN_CARGO_PACKAGE)
  1851     if(NOT rust_cargo_package)
  1755         get_target_property(rust_cargo_package "${rust_target}" INTERFACE_COR_CARGO_PACKAGE_NAME )
  1852         message(FATAL_ERROR "Internal Error: Could not determine cargo package name for cbindgen. "
  1756         if(NOT rust_cargo_package)
  1853         )
  1757             message(FATAL_ERROR "Could not determine cargo package name for cbindgen!")
       
  1758         endif()
       
  1759     else()
       
  1760         set(rust_cargo_package "${CCN_CARGO_PACKAGE}")
       
  1761     endif()
  1854     endif()
  1762     message(STATUS "Using package ${rust_cargo_package} as crate for cbindgen")
  1855     message(STATUS "Using package ${rust_cargo_package} as crate for cbindgen")
  1763 
  1856 
  1764 
  1857 
  1765     set(output_header_name "${CCN_HEADER_NAME}")
  1858     set(output_header_name "${CCN_HEADER_NAME}")
  1826     unset(depfile_cmake_arg)
  1919     unset(depfile_cmake_arg)
  1827     get_filename_component(generated_depfile_dir "${generated_depfile}" DIRECTORY)
  1920     get_filename_component(generated_depfile_dir "${generated_depfile}" DIRECTORY)
  1828     file(MAKE_DIRECTORY "${generated_depfile_dir}")
  1921     file(MAKE_DIRECTORY "${generated_depfile_dir}")
  1829     set(depfile_cbindgen_arg "--depfile=${generated_depfile}")
  1922     set(depfile_cbindgen_arg "--depfile=${generated_depfile}")
  1830 
  1923 
  1831     # Users might want to call cbindgen multiple times, e.g. to generate separate C++ and C header files.
  1924     add_custom_command(
  1832     string(MAKE_C_IDENTIFIER "${output_header_name}" header_identifier )
  1925         OUTPUT
  1833     if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.22")
  1926         "${generated_header}"
  1834         add_custom_command(
  1927         COMMAND
  1835             OUTPUT
  1928         "${CMAKE_COMMAND}" -E env
  1836             "${generated_header}"
  1929             TARGET="${cbindgen_target_triple}"
  1837             COMMAND
  1930             "${cbindgen}"
  1838             "${CMAKE_COMMAND}" -E env
  1931                     --output "${generated_header}"
  1839                 TARGET="${cbindgen_target_triple}"
  1932                     --crate "${rust_cargo_package}"
  1840                 "${cbindgen}"
  1933                     ${depfile_cbindgen_arg}
  1841                         --output "${generated_header}"
  1934                     ${CCN_FLAGS}
  1842                         --crate "${rust_cargo_package}"
  1935         COMMENT "Generate cbindgen bindings for package ${rust_cargo_package} and output header ${generated_header}"
  1843                         ${depfile_cbindgen_arg}
  1936         DEPFILE "${generated_depfile}"
  1844                         ${CCN_FLAGS}
  1937         COMMAND_EXPAND_LISTS
  1845             COMMENT "Generate cbindgen bindings for package ${rust_cargo_package} and output header ${generated_header}"
  1938         WORKING_DIRECTORY "${package_manifest_dir}"
  1846             DEPFILE "${generated_depfile}"
  1939     )
  1847             COMMAND_EXPAND_LISTS
       
  1848             WORKING_DIRECTORY "${package_manifest_dir}"
       
  1849         )
       
  1850         add_custom_target("_corrosion_cbindgen_${rust_target}_bindings_${header_identifier}"
       
  1851                           DEPENDS "${generated_header}"
       
  1852                           COMMENT "Generate ${generated_header} for ${rust_target}"
       
  1853         )
       
  1854     else()
       
  1855         add_custom_target("_corrosion_cbindgen_${rust_target}_bindings_${header_identifier}"
       
  1856                           "${CMAKE_COMMAND}" -E env
       
  1857                               TARGET="${cbindgen_target_triple}"
       
  1858                               "${cbindgen}"
       
  1859                               --output "${generated_header}"
       
  1860                               --crate "${rust_cargo_package}"
       
  1861                               ${depfile_cbindgen_arg}
       
  1862                               ${CCN_FLAGS}
       
  1863                           COMMENT "Generate ${generated_header} for ${rust_target}"
       
  1864                           COMMAND_EXPAND_LISTS
       
  1865                           WORKING_DIRECTORY "${package_manifest_dir}"
       
  1866         )
       
  1867     endif()
       
  1868 
  1940 
  1869     if(NOT installed_cbindgen)
  1941     if(NOT installed_cbindgen)
  1870         add_custom_command(
  1942         add_custom_command(
  1871             OUTPUT "${generated_header}"
  1943             OUTPUT "${generated_header}"
  1872             APPEND
  1944             APPEND
  1877     if(NOT TARGET "_corrosion_cbindgen_${rust_target}_bindings")
  1949     if(NOT TARGET "_corrosion_cbindgen_${rust_target}_bindings")
  1878         add_custom_target(_corrosion_cbindgen_${rust_target}_bindings
  1950         add_custom_target(_corrosion_cbindgen_${rust_target}_bindings
  1879                 COMMENT "Generate cbindgen bindings for package ${rust_cargo_package}"
  1951                 COMMENT "Generate cbindgen bindings for package ${rust_cargo_package}"
  1880         )
  1952         )
  1881     endif()
  1953     endif()
  1882 
  1954     # Users might want to call cbindgen multiple times, e.g. to generate separate C++ and C header files.
       
  1955     string(MAKE_C_IDENTIFIER "${output_header_name}" header_identifier )
       
  1956     add_custom_target("_corrosion_cbindgen_${rust_target}_bindings_${header_identifier}"
       
  1957             DEPENDS "${generated_header}"
       
  1958             COMMENT "Generate ${generated_header} for ${rust_target}"
       
  1959     )
  1883     add_dependencies("_corrosion_cbindgen_${rust_target}_bindings" "_corrosion_cbindgen_${rust_target}_bindings_${header_identifier}")
  1960     add_dependencies("_corrosion_cbindgen_${rust_target}_bindings" "_corrosion_cbindgen_${rust_target}_bindings_${header_identifier}")
  1884     add_dependencies(${rust_target} "_corrosion_cbindgen_${rust_target}_bindings")
  1961     add_dependencies(${rust_target} "_corrosion_cbindgen_${rust_target}_bindings")
  1885 endfunction()
  1962 endfunction()
  1886 
  1963 
  1887 # Parse the version of a Rust package from it's package manifest (Cargo.toml)
  1964 # Parse the version of a Rust package from it's package manifest (Cargo.toml)
  1927         set(${out_package_version}
  2004         set(${out_package_version}
  1928             "NOTFOUND"
  2005             "NOTFOUND"
  1929             PARENT_SCOPE
  2006             PARENT_SCOPE
  1930         )
  2007         )
  1931     endif()
  2008     endif()
       
  2009 endfunction()
       
  2010 
       
  2011 function(_corrosion_initialize_properties target_name)
       
  2012     # Initialize the `<XYZ>_OUTPUT_DIRECTORY` properties based on `CMAKE_<XYZ>_OUTPUT_DIRECTORY`.
       
  2013     foreach(output_var RUNTIME_OUTPUT_DIRECTORY ARCHIVE_OUTPUT_DIRECTORY LIBRARY_OUTPUT_DIRECTORY PDB_OUTPUT_DIRECTORY)
       
  2014         if (DEFINED "CMAKE_${output_var}")
       
  2015             set_property(TARGET ${target_name} PROPERTY "${output_var}" "${CMAKE_${output_var}}")
       
  2016         endif()
       
  2017 
       
  2018         foreach(config_type ${CMAKE_CONFIGURATION_TYPES})
       
  2019             string(TOUPPER "${config_type}" config_type_upper)
       
  2020             if (DEFINED "CMAKE_${output_var}_${config_type_upper}")
       
  2021                 set_property(TARGET ${target_name} PROPERTY "${output_var}_${config_type_upper}" "${CMAKE_${output_var}_${config_type_upper}}")
       
  2022             endif()
       
  2023         endforeach()
       
  2024     endforeach()
  1932 endfunction()
  2025 endfunction()
  1933 
  2026 
  1934 # Helper macro to pass through an optional `OPTION` argument parsed via `cmake_parse_arguments`
  2027 # Helper macro to pass through an optional `OPTION` argument parsed via `cmake_parse_arguments`
  1935 # to another function that takes the same OPTION.
  2028 # to another function that takes the same OPTION.
  1936 # If the option was set, then the variable <var_name> will be set to the same option name again,
  2029 # If the option was set, then the variable <var_name> will be set to the same option name again,