tools/corrosion/cmake/CorrosionGenerator.cmake
branchtransitional_engine
changeset 16021 6a3dc15b78b9
equal deleted inserted replaced
16009:7544a7d7c819 16021:6a3dc15b78b9
       
     1 function(_cargo_metadata out manifest)
       
     2     set(OPTIONS LOCKED FROZEN)
       
     3     set(ONE_VALUE_KEYWORDS "")
       
     4     set(MULTI_VALUE_KEYWORDS "")
       
     5     cmake_parse_arguments(PARSE_ARGV 2 CM "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}")
       
     6 
       
     7     list(APPEND CMAKE_MESSAGE_CONTEXT "_cargo_metadata")
       
     8 
       
     9     if(DEFINED CM_UNPARSED_ARGUMENTS)
       
    10         message(FATAL_ERROR "Internal error - unexpected arguments: ${CM_UNPARSED_ARGUMENTS}")
       
    11     elseif(DEFINED CM_KEYWORDS_MISSING_VALUES)
       
    12         message(FATAL_ERROR "Internal error - the following keywords had no associated value(s):"
       
    13             "${CM_KEYWORDS_MISSING_VALUES}")
       
    14     endif()
       
    15 
       
    16     set(cargo_locked "")
       
    17     set(cargo_frozen "")
       
    18     if(LOCKED)
       
    19         set(cargo_locked "--locked")
       
    20     endif()
       
    21     if(FROZEN)
       
    22         set(cargo_frozen "--frozen")
       
    23     endif()
       
    24     execute_process(
       
    25         COMMAND
       
    26             ${CMAKE_COMMAND} -E env
       
    27                 "CARGO_BUILD_RUSTC=${_CORROSION_RUSTC}"
       
    28                 "${_CORROSION_CARGO}"
       
    29                     metadata
       
    30                         --manifest-path "${manifest}"
       
    31                         --format-version 1
       
    32                         # We don't care about non-workspace dependencies
       
    33                         --no-deps
       
    34                         ${cargo_locked}
       
    35                         ${cargo_frozen}
       
    36 
       
    37         OUTPUT_VARIABLE json
       
    38         COMMAND_ERROR_IS_FATAL ANY
       
    39     )
       
    40 
       
    41     set(${out} "${json}" PARENT_SCOPE)
       
    42 endfunction()
       
    43 
       
    44 # Add targets (crates) of one package
       
    45 function(_generator_add_package_targets)
       
    46     set(OPTIONS NO_LINKER_OVERRIDE)
       
    47     set(ONE_VALUE_KEYWORDS WORKSPACE_MANIFEST_PATH PACKAGE_MANIFEST_PATH PACKAGE_NAME PACKAGE_VERSION TARGETS_JSON OUT_CREATED_TARGETS)
       
    48     set(MULTI_VALUE_KEYWORDS CRATE_TYPES)
       
    49     cmake_parse_arguments(PARSE_ARGV 0 GAPT "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}")
       
    50 
       
    51     if(DEFINED GAPT_UNPARSED_ARGUMENTS)
       
    52         message(FATAL_ERROR "Internal error - unexpected arguments: ${GAPT_UNPARSED_ARGUMENTS}")
       
    53     elseif(DEFINED GAPT_KEYWORDS_MISSING_VALUES)
       
    54         message(FATAL_ERROR "Internal error - the following keywords had no associated value(s):"
       
    55                     "${GAPT_KEYWORDS_MISSING_VALUES}")
       
    56     endif()
       
    57 
       
    58     _corrosion_option_passthrough_helper(NO_LINKER_OVERRIDE GAPT no_linker_override)
       
    59 
       
    60     set(workspace_manifest_path "${GAPT_WORKSPACE_MANIFEST_PATH}")
       
    61     set(package_manifest_path "${GAPT_PACKAGE_MANIFEST_PATH}")
       
    62     set(package_name "${GAPT_PACKAGE_NAME}")
       
    63     set(package_version "${GAPT_PACKAGE_VERSION}")
       
    64     set(targets "${GAPT_TARGETS_JSON}")
       
    65     set(out_created_targets "${GAPT_OUT_CREATED_TARGETS}")
       
    66     set(crate_types "${GAPT_CRATE_TYPES}")
       
    67 
       
    68     set(corrosion_targets "")
       
    69 
       
    70     file(TO_CMAKE_PATH "${package_manifest_path}" manifest_path)
       
    71 
       
    72     string(JSON targets_len LENGTH "${targets}")
       
    73     math(EXPR targets_len-1 "${targets_len} - 1")
       
    74 
       
    75     message(DEBUG "Found ${targets_len} targets in package ${package_name}")
       
    76 
       
    77     foreach(ix RANGE ${targets_len-1})
       
    78         string(JSON target GET "${targets}" ${ix})
       
    79         string(JSON target_name GET "${target}" "name")
       
    80         string(JSON target_kind GET "${target}" "kind")
       
    81         string(JSON target_kind_len LENGTH "${target_kind}")
       
    82 
       
    83         math(EXPR target_kind_len-1 "${target_kind_len} - 1")
       
    84         set(kinds)
       
    85         foreach(ix RANGE ${target_kind_len-1})
       
    86             string(JSON kind GET "${target_kind}" ${ix})
       
    87             if(NOT crate_types OR ${kind} IN_LIST crate_types)
       
    88                 list(APPEND kinds ${kind})
       
    89             endif()
       
    90         endforeach()
       
    91 
       
    92         if(TARGET "${target_name}"
       
    93             AND ("staticlib" IN_LIST kinds OR "cdylib" IN_LIST kinds OR "bin" IN_LIST kinds)
       
    94             )
       
    95             message(WARNING "Failed to import Rust crate ${target_name} (kind: `${target_kind}`) because a target "
       
    96                 "with the same name already exists. Skipping this target.\n"
       
    97                 "Help: If you are importing a package which exposes both a `lib` and "
       
    98                 "a `bin` target, please consider explicitly naming the targets in your `Cargo.toml` manifest.\n"
       
    99                 "Note: If you have multiple different packages which have targets with the same name, please note that "
       
   100                 "this is currently not supported by Corrosion. Feel free to open an issue on Github to request "
       
   101                 "supporting this scenario."
       
   102                 )
       
   103             # Skip this target to prevent a hard error.
       
   104             continue()
       
   105         endif()
       
   106 
       
   107         if("staticlib" IN_LIST kinds OR "cdylib" IN_LIST kinds)
       
   108             # Explicitly set library names have always been forbidden from using dashes (by cargo).
       
   109             # Starting with Rust 1.79, names inherited from the package name will have dashes replaced
       
   110             # by underscores too. Corrosion will thus replace dashes with underscores, to make the target
       
   111             # name consistent independent of the Rust version. `bin` target names are not affected.
       
   112             # See https://github.com/corrosion-rs/corrosion/issues/501 for more details.
       
   113             string(REPLACE "\-" "_" target_name "${target_name}")
       
   114 
       
   115             set(archive_byproducts "")
       
   116             set(shared_lib_byproduct "")
       
   117             set(pdb_byproduct "")
       
   118 
       
   119             _corrosion_add_library_target(
       
   120                 WORKSPACE_MANIFEST_PATH "${workspace_manifest_path}"
       
   121                 TARGET_NAME "${target_name}"
       
   122                 LIB_KINDS ${kinds}
       
   123                 OUT_ARCHIVE_OUTPUT_BYPRODUCTS archive_byproducts
       
   124                 OUT_SHARED_LIB_BYPRODUCTS shared_lib_byproduct
       
   125                 OUT_PDB_BYPRODUCT pdb_byproduct
       
   126             )
       
   127 
       
   128             set(byproducts "")
       
   129             list(APPEND byproducts "${archive_byproducts}" "${shared_lib_byproduct}" "${pdb_byproduct}")
       
   130 
       
   131             set(cargo_build_out_dir "")
       
   132             _add_cargo_build(
       
   133                 cargo_build_out_dir
       
   134                 PACKAGE ${package_name}
       
   135                 TARGET ${target_name}
       
   136                 MANIFEST_PATH "${manifest_path}"
       
   137                 WORKSPACE_MANIFEST_PATH "${workspace_manifest_path}"
       
   138                 TARGET_KINDS "${kinds}"
       
   139                 BYPRODUCTS "${byproducts}"
       
   140                 # Optional
       
   141                 ${no_linker_override}
       
   142             )
       
   143             if(archive_byproducts)
       
   144                 _corrosion_copy_byproducts(
       
   145                     ${target_name} ARCHIVE_OUTPUT_DIRECTORY "${cargo_build_out_dir}" "${archive_byproducts}"
       
   146                 )
       
   147             endif()
       
   148             if(shared_lib_byproduct)
       
   149                 _corrosion_copy_byproducts(
       
   150                     ${target_name} LIBRARY_OUTPUT_DIRECTORY "${cargo_build_out_dir}" "${shared_lib_byproduct}"
       
   151                 )
       
   152             endif()
       
   153             if(pdb_byproduct)
       
   154                 _corrosion_copy_byproducts(
       
   155                     ${target_name} PDB_OUTPUT_DIRECTORY "${cargo_build_out_dir}" "${pdb_byproduct}"
       
   156                 )
       
   157             endif()
       
   158             list(APPEND corrosion_targets ${target_name})
       
   159             set_property(TARGET "${target_name}" PROPERTY INTERFACE_COR_CARGO_PACKAGE_NAME "${package_name}" )
       
   160         # Note: "bin" is mutually exclusive with "staticlib/cdylib", since `bin`s are seperate crates from libraries.
       
   161         elseif("bin" IN_LIST kinds)
       
   162             set(bin_byproduct "")
       
   163             set(pdb_byproduct "")
       
   164             _corrosion_add_bin_target("${workspace_manifest_path}" "${target_name}"
       
   165                 "bin_byproduct" "pdb_byproduct"
       
   166             )
       
   167 
       
   168             set(byproducts "")
       
   169             list(APPEND byproducts "${bin_byproduct}" "${pdb_byproduct}")
       
   170 
       
   171             set(cargo_build_out_dir "")
       
   172             _add_cargo_build(
       
   173                 cargo_build_out_dir
       
   174                 PACKAGE "${package_name}"
       
   175                 TARGET "${target_name}"
       
   176                 MANIFEST_PATH "${manifest_path}"
       
   177                 WORKSPACE_MANIFEST_PATH "${workspace_manifest_path}"
       
   178                 TARGET_KINDS "bin"
       
   179                 BYPRODUCTS "${byproducts}"
       
   180                 # Optional
       
   181                 ${no_linker_override}
       
   182             )
       
   183             _corrosion_copy_byproducts(
       
   184                     ${target_name} RUNTIME_OUTPUT_DIRECTORY "${cargo_build_out_dir}" "${bin_byproduct}"
       
   185             )
       
   186             if(pdb_byproduct)
       
   187                 _corrosion_copy_byproducts(
       
   188                         ${target_name} PDB_OUTPUT_DIRECTORY "${cargo_build_out_dir}" "${pdb_byproduct}"
       
   189                 )
       
   190             endif()
       
   191             list(APPEND corrosion_targets ${target_name})
       
   192             set_property(TARGET "${target_name}" PROPERTY INTERFACE_COR_CARGO_PACKAGE_NAME "${package_name}" )
       
   193         else()
       
   194             # ignore other kinds (like examples, tests, build scripts, ...)
       
   195         endif()
       
   196     endforeach()
       
   197 
       
   198     if(NOT corrosion_targets)
       
   199         message(DEBUG "No relevant targets found in package ${package_name} - Ignoring")
       
   200     else()
       
   201         set_target_properties(${corrosion_targets} PROPERTIES INTERFACE_COR_PACKAGE_MANIFEST_PATH "${package_manifest_path}")
       
   202     endif()
       
   203     set(${out_created_targets} "${corrosion_targets}" PARENT_SCOPE)
       
   204 
       
   205 endfunction()
       
   206 
       
   207 # Add all cargo targets defined in the packages defined in the Cargo.toml manifest at
       
   208 # `MANIFEST_PATH`.
       
   209 function(_generator_add_cargo_targets)
       
   210     set(options NO_LINKER_OVERRIDE)
       
   211     set(one_value_args MANIFEST_PATH IMPORTED_CRATES)
       
   212     set(multi_value_args CRATES CRATE_TYPES)
       
   213     cmake_parse_arguments(
       
   214         GGC
       
   215         "${options}"
       
   216         "${one_value_args}"
       
   217         "${multi_value_args}"
       
   218         ${ARGN}
       
   219     )
       
   220     list(APPEND CMAKE_MESSAGE_CONTEXT "_add_cargo_targets")
       
   221 
       
   222     _corrosion_option_passthrough_helper(NO_LINKER_OVERRIDE GGC no_linker_override)
       
   223     _corrosion_arg_passthrough_helper(CRATE_TYPES GGC crate_types)
       
   224 
       
   225     _cargo_metadata(json "${GGC_MANIFEST_PATH}")
       
   226     string(JSON packages GET "${json}" "packages")
       
   227     string(JSON workspace_members GET "${json}" "workspace_members")
       
   228 
       
   229     string(JSON pkgs_len LENGTH "${packages}")
       
   230     math(EXPR pkgs_len-1 "${pkgs_len} - 1")
       
   231 
       
   232     string(JSON ws_mems_len LENGTH ${workspace_members})
       
   233     math(EXPR ws_mems_len-1 "${ws_mems_len} - 1")
       
   234 
       
   235     set(created_targets "")
       
   236     set(available_package_names "")
       
   237     foreach(ix RANGE ${pkgs_len-1})
       
   238         string(JSON pkg GET "${packages}" ${ix})
       
   239         string(JSON pkg_id GET "${pkg}" "id")
       
   240         string(JSON pkg_name GET "${pkg}" "name")
       
   241         string(JSON pkg_manifest_path GET "${pkg}" "manifest_path")
       
   242         string(JSON pkg_version GET "${pkg}" "version")
       
   243         list(APPEND available_package_names "${pkg_name}")
       
   244 
       
   245         if(DEFINED GGC_CRATES)
       
   246             if(NOT pkg_name IN_LIST GGC_CRATES)
       
   247                 continue()
       
   248             endif()
       
   249         endif()
       
   250 
       
   251         # probably this loop is not necessary at all, since when using --no-deps, the
       
   252         # contents of packages should already be only workspace members!
       
   253         unset(pkg_is_ws_member)
       
   254         foreach(ix RANGE ${ws_mems_len-1})
       
   255             string(JSON ws_mem GET "${workspace_members}" ${ix})
       
   256             if(ws_mem STREQUAL pkg_id)
       
   257                 set(pkg_is_ws_member YES)
       
   258                 break()
       
   259             endif()
       
   260         endforeach()
       
   261 
       
   262         if(NOT DEFINED pkg_is_ws_member)
       
   263             # Since we pass `--no-deps` to cargo metadata now,  I think this situation can't happen, but lets check for
       
   264             # it anyway, just to discover any potential issues.
       
   265             # If nobody complains for a while, it should be safe to remove this check and the previous loop, which
       
   266             # should speed up the configuration process.
       
   267             message(WARNING "The package `${pkg_name}` unexpectedly is not part of the workspace."
       
   268                 "Please open an issue at corrosion with some background information on the package"
       
   269             )
       
   270         endif()
       
   271 
       
   272         string(JSON targets GET "${pkg}" "targets")
       
   273 
       
   274         _generator_add_package_targets(
       
   275             WORKSPACE_MANIFEST_PATH "${GGC_MANIFEST_PATH}"
       
   276             PACKAGE_MANIFEST_PATH "${pkg_manifest_path}"
       
   277             PACKAGE_NAME "${pkg_name}"
       
   278             PACKAGE_VERSION "${pkg_version}"
       
   279             TARGETS_JSON "${targets}"
       
   280             OUT_CREATED_TARGETS curr_created_targets
       
   281             ${no_linker_override}
       
   282             ${crate_types}
       
   283         )
       
   284         list(APPEND created_targets "${curr_created_targets}")
       
   285     endforeach()
       
   286 
       
   287     if(NOT created_targets)
       
   288         set(crates_error_message "")
       
   289         if(DEFINED GGC_CRATES)
       
   290             set(crates_error_message "\n`corrosion_import_crate()` was called with the `CRATES` "
       
   291                 "parameter set to `${GGC_CRATES}`. Corrosion will only attempt to import packages matching "
       
   292                     "names from this list."
       
   293             )
       
   294         endif()
       
   295         message(FATAL_ERROR
       
   296                 "Found no targets in ${pkgs_len} packages."
       
   297                 ${crates_error_message}.
       
   298                 "\nPlease keep in mind that corrosion will only import Rust `bin` targets or"
       
   299                 "`staticlib` or `cdylib` library targets."
       
   300                 "The following packages were found in the Manifest: ${available_package_names}"
       
   301         )
       
   302     else()
       
   303         message(DEBUG "Corrosion created the following CMake targets: ${created_targets}")
       
   304     endif()
       
   305 
       
   306     if(GGC_IMPORTED_CRATES)
       
   307         set(${GGC_IMPORTED_CRATES} "${created_targets}" PARENT_SCOPE)
       
   308     endif()
       
   309 
       
   310     foreach(target_name ${created_targets})
       
   311         foreach(output_var RUNTIME_OUTPUT_DIRECTORY ARCHIVE_OUTPUT_DIRECTORY LIBRARY_OUTPUT_DIRECTORY PDB_OUTPUT_DIRECTORY)
       
   312             get_target_property(output_dir ${target_name} "${output_var}")
       
   313             if (NOT output_dir AND DEFINED "CMAKE_${output_var}")
       
   314                 set_property(TARGET ${target_name} PROPERTY ${output_var} "${CMAKE_${output_var}}")
       
   315             endif()
       
   316 
       
   317             foreach(config_type ${CMAKE_CONFIGURATION_TYPES})
       
   318                 string(TOUPPER "${config_type}" config_type_upper)
       
   319                 get_target_property(output_dir ${target_name} "${output_var}_${config_type_upper}")
       
   320                 if (NOT output_dir AND DEFINED "CMAKE_${output_var}_${config_type_upper}")
       
   321                     set_property(TARGET ${target_name} PROPERTY "${output_var}_${config_type_upper}" "${CMAKE_${output_var}_${config_type_upper}}")
       
   322                 endif()
       
   323             endforeach()
       
   324         endforeach()
       
   325     endforeach()
       
   326 endfunction()