Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allowing overriding the crate type of libraries. #557

Merged
merged 3 commits into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion RELEASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
### New features

- Support using the `$<CONFIG>` generator expression in `OUTPUT_DIRECTORY`. [#459]

- Add `OVERRIDE_CRATE_TYPE` option to corrosion_import_crate, allowing users to override
the crate-types of Rust libraries (e.g. force building as a staticlib instead of an rlib).
- Support *-windows-gnullvm targets.
- experimental support in corrosion_install for installing libraries and header files

[#459]: https://github.com/corrosion-rs/corrosion/pull/459

Expand Down
60 changes: 58 additions & 2 deletions cmake/Corrosion.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -579,11 +579,20 @@ function(_add_cargo_build out_cargo_build_out_dir)
set(workspace_manifest_path "${ACB_WORKSPACE_MANIFEST_PATH}")
set(build_byproducts "${ACB_BYPRODUCTS}")


unset(cargo_rustc_crate_types)
if(NOT target_kinds)
message(FATAL_ERROR "TARGET_KINDS not specified")
elseif("staticlib" IN_LIST target_kinds OR "cdylib" IN_LIST target_kinds)
set(cargo_rustc_filter "--lib")
if("${Rust_VERSION}" VERSION_GREATER_EQUAL "1.64")
# https://doc.rust-lang.org/1.64.0/cargo/commands/cargo-rustc.html
# `--crate-type` is documented since Rust 1.64 for `cargo rustc`.
# We just unconditionally set it when available, to support overriding the crate type.
# Due to https://github.com/rust-lang/cargo/issues/14498 we can't use one argument and pass a
# comma seperated list. Instead we use multiple arguments.
set(cargo_rustc_crate_types "${target_kinds}")
list(TRANSFORM cargo_rustc_crate_types PREPEND "--crate-type=")
endif()
elseif("bin" IN_LIST target_kinds)
set(cargo_rustc_filter "--bin=${target_name}")
else()
Expand Down Expand Up @@ -777,6 +786,7 @@ function(_add_cargo_build out_cargo_build_out_dir)
${no_default_features_arg}
${features_genex}
--package ${package_name}
${cargo_rustc_crate_types}
--manifest-path "${path_to_toml}"
--target-dir "${cargo_target_dir}"
${cargo_profile}
Expand Down Expand Up @@ -846,6 +856,7 @@ corrosion_import_crate(
[PROFILE <cargo-profile>]
[IMPORTED_CRATES <variable-name>]
[CRATE_TYPES <crate_type1> ... <crate_typeN>]
[OVERRIDE_CRATE_TYPE <crate_name>=<crate_type1,crate_type2,...> ...]
[CRATES <crate1> ... <crateN>]
[FEATURES <feature1> ... <featureN>]
[FLAGS <flag1> ... <flagN>]
Expand All @@ -861,6 +872,9 @@ corrosion_import_crate(
* **PROFILE**: Specify cargo build profile (`dev`/`release` or a [custom profile]; `bench` and `test` are not supported)
* **IMPORTED_CRATES**: Save the list of imported crates into the variable with the provided name in the current scope.
* **CRATE_TYPES**: Only import the specified crate types. Valid values: `staticlib`, `cdylib`, `bin`.
* **OVERRIDE_CRATE_TYPE**: Override the crate-types of a cargo crate with the given comma-separated values.
Internally uses the `rustc` flag [`--crate-type`] to override the crate-type.
Valid values for the crate types are the library types `staticlib` and `cdylib`.
* **CRATES**: Only import the specified crates from a workspace. Values: Crate names.
* **FEATURES**: Enable the specified features. Equivalent to [--features] passed to `cargo build`.
* **FLAGS**: Arbitrary flags to `cargo build`.
Expand All @@ -871,14 +885,15 @@ corrosion_import_crate(
[--features]: https://doc.rust-lang.org/cargo/reference/features.html#command-line-feature-options
[`--locked`]: https://doc.rust-lang.org/cargo/commands/cargo.html#manifest-options
[`--frozen`]: https://doc.rust-lang.org/cargo/commands/cargo.html#manifest-options
[`--crate-type`]: https://doc.rust-lang.org/rustc/command-line-arguments.html#--crate-type-a-list-of-types-of-crates-for-the-compiler-to-emit
[Cargo.toml Manifest]: https://doc.rust-lang.org/cargo/appendix/glossary.html#manifest

ANCHOR_END: corrosion-import-crate
#]=======================================================================]
function(corrosion_import_crate)
set(OPTIONS ALL_FEATURES NO_DEFAULT_FEATURES NO_STD NO_LINKER_OVERRIDE LOCKED FROZEN)
set(ONE_VALUE_KEYWORDS MANIFEST_PATH PROFILE IMPORTED_CRATES)
set(MULTI_VALUE_KEYWORDS CRATE_TYPES CRATES FEATURES FLAGS)
set(MULTI_VALUE_KEYWORDS CRATE_TYPES CRATES FEATURES FLAGS OVERRIDE_CRATE_TYPE)
cmake_parse_arguments(COR "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}" ${ARGN})
list(APPEND CMAKE_MESSAGE_CONTEXT "corrosion_import_crate")

Expand Down Expand Up @@ -917,6 +932,46 @@ function(corrosion_import_crate)
endif()
endif()

# intended to be used with foreach(... ZIP_LISTS ...), meaning
# that the crate_types at index i of `override_crate_type_types_list` are
# for the package_name at index i of `override_crate_type_package_name_list`.
# It would really be nice if CMake had structs or dicts.
unset(override_crate_type_package_name_list)
unset(override_crate_type_types_list)
unset(OVERRIDE_CRATE_TYPE_ARGS)
if(DEFINED COR_OVERRIDE_CRATE_TYPE)
string(JOIN " " usage_help
"Each argument to OVERRIDE_CRATE_TYPE must be of the form `<package_name>=<crate_type(s)>."
"The package_name must be a valid cargo package name and the crate_type must be "
"a comma-seperated list with valid values being `staticlib`, `cdylib` and `bin`"
)
foreach(entry IN LISTS COR_OVERRIDE_CRATE_TYPE)
string(REPLACE "=" ";" key_val_list ${entry})
list(LENGTH key_val_list key_val_list_len)
if(NOT key_val_list_len EQUAL "2")
message(FATAL_ERROR "Invalid argument: `${entry}` for parameter OVERRIDE_CRATE_TYPE!\n"
"${usage_help}"
)
endif()
list(GET key_val_list "0" package_name)
list(GET key_val_list "1" crate_types)
list(APPEND override_crate_type_package_name_list "${package_name}")
list(APPEND override_crate_type_types_list "${crate_types}")
endforeach()
list(LENGTH override_crate_type_package_name_list num_override_packages)
list(LENGTH override_crate_type_types_list num_override_packages2)
if("${Rust_VERSION}" VERSION_LESS "1.64")
message(WARNING "OVERRIDE_CRATE_TYPE requires at Rust 1.64 or newer. Ignoring the option")
elseif(NOT num_override_packages EQUAL num_override_packages2)
message(WARNING "Internal error while parsing OVERRIDE_CRATE_TYPE arguments.\n"
"Corrosion will ignore this argument and continue."
)
else()
# Pass by ref: we intentionally pass the list names here!
set(override_crate_types_arg "OVERRIDE_CRATE_TYPE_ARGS" "override_crate_type_package_name_list" "override_crate_type_types_list")
endif()
endif()

if (NOT IS_ABSOLUTE "${COR_MANIFEST_PATH}")
set(COR_MANIFEST_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${COR_MANIFEST_PATH})
endif()
Expand All @@ -940,6 +995,7 @@ function(corrosion_import_crate)
${crate_allowlist}
${crate_types}
${no_linker_override}
${override_crate_types_arg}
)

# Not target props yet:
Expand Down
45 changes: 35 additions & 10 deletions cmake/CorrosionGenerator.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,14 @@ endfunction()
# Add targets (crates) of one package
function(_generator_add_package_targets)
set(OPTIONS NO_LINKER_OVERRIDE)
set(ONE_VALUE_KEYWORDS WORKSPACE_MANIFEST_PATH PACKAGE_MANIFEST_PATH PACKAGE_NAME PACKAGE_VERSION TARGETS_JSON OUT_CREATED_TARGETS)
set(MULTI_VALUE_KEYWORDS CRATE_TYPES)
set(ONE_VALUE_KEYWORDS
WORKSPACE_MANIFEST_PATH
PACKAGE_MANIFEST_PATH
PACKAGE_NAME
PACKAGE_VERSION
TARGETS_JSON
OUT_CREATED_TARGETS)
set(MULTI_VALUE_KEYWORDS CRATE_TYPES OVERRIDE_CRATE_TYPE_ARGS)
cmake_parse_arguments(PARSE_ARGV 0 GAPT "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}")

if(DEFINED GAPT_UNPARSED_ARGUMENTS)
Expand All @@ -64,6 +70,10 @@ function(_generator_add_package_targets)
set(targets "${GAPT_TARGETS_JSON}")
set(out_created_targets "${GAPT_OUT_CREATED_TARGETS}")
set(crate_types "${GAPT_CRATE_TYPES}")
if(DEFINED GAPT_OVERRIDE_CRATE_TYPE_ARGS)
list(GET GAPT_OVERRIDE_CRATE_TYPE_ARGS 0 override_crate_name_list_ref)
list(GET GAPT_OVERRIDE_CRATE_TYPE_ARGS 1 override_crate_types_list_ref)
endif()

set(corrosion_targets "")

Expand All @@ -82,13 +92,26 @@ function(_generator_add_package_targets)

math(EXPR target_kind_len-1 "${target_kind_len} - 1")
set(kinds)
foreach(ix RANGE ${target_kind_len-1})
string(JSON kind GET "${target_kind}" ${ix})
if(NOT crate_types OR ${kind} IN_LIST crate_types)
list(APPEND kinds ${kind})
endif()
endforeach()

unset(override_package_crate_type)
# OVERRIDE_CRATE_TYPE is more specific than the CRATE_TYPES argument to corrosion_import_crate, and thus takes
# priority.
if(DEFINED GAPT_OVERRIDE_CRATE_TYPE_ARGS)
foreach(override_crate_name override_crate_types IN ZIP_LISTS ${override_crate_name_list_ref} ${override_crate_types_list_ref})
if("${override_crate_name}" STREQUAL "${target_name}")
message(DEBUG "Forcing crate ${target_name} to crate-type(s): ${override_crate_types}.")
# Convert to CMake list
string(REPLACE "," ";" kinds "${override_crate_types}")
break()
endif()
endforeach()
else()
foreach(ix RANGE ${target_kind_len-1})
string(JSON kind GET "${target_kind}" ${ix})
if(NOT crate_types OR ${kind} IN_LIST crate_types)
list(APPEND kinds ${kind})
endif()
endforeach()
endif()
if(TARGET "${target_name}"
AND ("staticlib" IN_LIST kinds OR "cdylib" IN_LIST kinds OR "bin" IN_LIST kinds)
)
Expand Down Expand Up @@ -213,7 +236,7 @@ endfunction()
function(_generator_add_cargo_targets)
set(options NO_LINKER_OVERRIDE)
set(one_value_args MANIFEST_PATH IMPORTED_CRATES)
set(multi_value_args CRATES CRATE_TYPES)
set(multi_value_args CRATES CRATE_TYPES OVERRIDE_CRATE_TYPE_ARGS)
cmake_parse_arguments(
GGC
"${options}"
Expand All @@ -225,6 +248,7 @@ function(_generator_add_cargo_targets)

_corrosion_option_passthrough_helper(NO_LINKER_OVERRIDE GGC no_linker_override)
_corrosion_arg_passthrough_helper(CRATE_TYPES GGC crate_types)
_corrosion_arg_passthrough_helper(OVERRIDE_CRATE_TYPE_ARGS GGC override_crate_types)

_cargo_metadata(json "${GGC_MANIFEST_PATH}")
string(JSON packages GET "${json}" "packages")
Expand Down Expand Up @@ -284,6 +308,7 @@ function(_generator_add_cargo_targets)
OUT_CREATED_TARGETS curr_created_targets
${no_linker_override}
${crate_types}
${override_crate_types}
)
list(APPEND created_targets "${curr_created_targets}")
endforeach()
Expand Down
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ add_subdirectory(cpp2rust)
if(Rust_VERSION VERSION_GREATER_EQUAL "1.64.0")
# Flag `--crate-type` is only supported since Rust 1.64.0
add_subdirectory(crate_type)
add_subdirectory(override_crate_type)
endif()
add_subdirectory(custom_profiles)
add_subdirectory(cbindgen)
Expand Down
9 changes: 9 additions & 0 deletions test/override_crate_type/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
corrosion_tests_add_test(override_crate_type "cpp-exe;cpp-exe-shared")

set_tests_properties("override_crate_type_run_cpp-exe" PROPERTIES PASS_REGULAR_EXPRESSION
"^Hello, Cpp! I'm Rust!\r?\n$"
)

set_tests_properties("override_crate_type_run_cpp-exe-shared" PROPERTIES PASS_REGULAR_EXPRESSION
"^Hello, Cpp! I'm Rust!\r?\n$"
)
12 changes: 12 additions & 0 deletions test/override_crate_type/override_crate_type/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
cmake_minimum_required(VERSION 3.15)
project(test_project VERSION 0.1.0)
include(../../test_header.cmake)

corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml OVERRIDE_CRATE_TYPE my_rust_lib=staticlib,cdylib)

add_executable(cpp-exe main.cpp)
target_link_libraries(cpp-exe PUBLIC my_rust_lib)

add_executable(cpp-exe-shared main.cpp)
target_link_libraries(cpp-exe-shared
PUBLIC my_rust_lib-shared)
9 changes: 9 additions & 0 deletions test/override_crate_type/override_crate_type/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
extern "C" void rust_function(char const *name);

int main(int argc, char **argv) {
if (argc < 2) {
rust_function("Cpp");
} else {
rust_function(argv[1]);
}
}
5 changes: 5 additions & 0 deletions test/override_crate_type/override_crate_type/rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions test/override_crate_type/override_crate_type/rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "rust-lib"
version = "0.1.0"
authors = ["Andrew Gaspar <andrew.gaspar@outlook.com>"]
license = "MIT"
edition = "2018"


[lib]
name = "my_rust_lib"
4 changes: 4 additions & 0 deletions test/override_crate_type/override_crate_type/rust/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Build-scripts also need to be linked, so just add a dummy buildscript ensuring this works.
fn main() {
println!("Build-script is running.")
}
7 changes: 7 additions & 0 deletions test/override_crate_type/override_crate_type/rust/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use std::os::raw::c_char;

#[no_mangle]
pub extern "C" fn rust_function(name: *const c_char) {
let name = unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() };
println!("Hello, {}! I'm Rust!", name);
}