Skip to content
Open
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
23 changes: 15 additions & 8 deletions cmake/everest-generate.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -184,20 +184,28 @@ if (EVEREST_ENABLE_RS_SUPPORT)
echo "everestrs = { path = \"$<TARGET_PROPERTY:everest::everestrs_sys,EVERESTRS_DIR>\" ${EVERESTRS_FEATURE_FLAGS} }" >> Cargo.toml
COMMAND
echo "everestrs-build = { path = \"$<TARGET_PROPERTY:everest::everestrs_sys,EVERESTRS_BUILD_DIR>\" }" >> Cargo.toml
COMMAND
echo $<TARGET_FILE:everest::framework> > .everestrs_link_dependencies
COMMAND
echo $<TARGET_FILE:everest::log> >> .everestrs_link_dependencies
WORKING_DIRECTORY
${RUST_WORKSPACE_DIR}
VERBATIM
DEPENDS
${RUST_WORKSPACE_DIR}
)

# Put the resulting file in the top-level build directory so that it can be easily accessed without CMake
set(RUST_LINK_DEPENDENCIES_FILE ${CMAKE_BINARY_DIR}/everestrs-link-dependencies.txt)
set(RUST_LINK_DEPENDENCIES "$<TARGET_GENEX_EVAL:everest::everestrs_sys,$<TARGET_PROPERTY:everest::everestrs_sys,EVERESTRS_LINK_DEPENDENCIES>>")

add_custom_command(OUTPUT ${RUST_LINK_DEPENDENCIES_FILE}
COMMAND_EXPAND_LISTS
VERBATIM
COMMAND
echo -e $<LIST:JOIN,${RUST_LINK_DEPENDENCIES},\\n> > "${RUST_LINK_DEPENDENCIES_FILE}"
)

add_custom_target(generate_rust
DEPENDS
${RUST_WORKSPACE_CARGO_FILE}
${RUST_LINK_DEPENDENCIES_FILE}
)

# Store the workspace directory as a target property so that it is accessible in different scopes
Expand All @@ -208,13 +216,13 @@ if (EVEREST_ENABLE_RS_SUPPORT)

# FIXME (aw): use generator expressions here, but this first needs to be fixed in the build.rs file ...
add_custom_target(build_rust_modules ALL
USES_TERMINAL
COMMENT
"Build rust modules"
COMMAND
${CMAKE_COMMAND} -E env
EVEREST_CORE_ROOT="${CMAKE_CURRENT_SOURCE_DIR}"
EVEREST_RS_FRAMEWORK_SOURCE_LOCATION="${everest-framework_SOURCE_DIR}"
EVEREST_RS_FRAMEWORK_BINARY_LOCATION="${everest-framework_BINARY_DIR}"
EVEREST_RS_LINK_DEPENDENCIES="${RUST_LINK_DEPENDENCIES_FILE}"
${CARGO_EXECUTABLE} build
$<IF:$<STREQUAL:$<CONFIG>,Release>,--release,>
# explicitly set the linker to match what we're using for C++ to avoid the following issue when cross compiling:
Expand All @@ -224,7 +232,6 @@ if (EVEREST_ENABLE_RS_SUPPORT)
WORKING_DIRECTORY
${RUST_WORKSPACE_DIR}
DEPENDS
everestrs_sys
generate_rust
)

Expand Down Expand Up @@ -759,4 +766,4 @@ endfunction()

set(EVEREST_EXCLUDE_MODULES "" CACHE STRING "A list of modules that will not be built")
set(EVEREST_INCLUDE_MODULES "" CACHE STRING "A list of modules that will be built. If the list is empty, all modules will be built.")
option(EVEREST_EXCLUDE_CPP_MODULES "Exclude all C++ modules from the build" OFF)
option(EVEREST_EXCLUDE_CPP_MODULES "Exclude all C++ modules from the build" OFF)
10 changes: 9 additions & 1 deletion lib/everest/framework/everestrs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,12 @@ target_link_libraries(everestrs_sys
everest::log
)

install(TARGETS everestrs_sys LIBRARY)
set_property(
TARGET
everestrs_sys
PROPERTY
EVERESTRS_LINK_DEPENDENCIES
$<TARGET_FILE:everest::everestrs_sys>
$<TARGET_FILE:everest::framework>
$<TARGET_FILE:everest::log>
)
3 changes: 2 additions & 1 deletion lib/everest/framework/everestrs/everestrs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ serde_yaml = "0.9.34"
thiserror = "1.0.48"

# Note: the version must be kept in sync with the `cxxbridge-cmd` version installed in `everestrs/CMakeLists.txt`.
cxx = { version = "1.0.189", features = ["c++17"] }
# The `=` before the version number ensures that Cargo uses exactly this version when generating new lockfiles.
cxx = { version = "=1.0.189", features = ["c++17"] }

[features]
build_bazel = []
Expand Down
16 changes: 5 additions & 11 deletions lib/everest/framework/everestrs/everestrs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ This is Rust support using cxx.rs to wrap the framework C++ library.
- Install Rust as outlined on <https://rustup.rs/>, which should just be this
one line: `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh`
- Built your workspace as outlined in `everest-core` README, make sure to tell
cMake to enable `EVEREST_ENABLE_RS_SUPPORT`. Note, that the Rust code relies
on being built in a workspace where `make install` was run once.
cMake to enable `EVEREST_ENABLE_RS_SUPPORT`.
- You can now try building the code, but it will not do anything: `cd everestrs
&& cargo build --all`
- You should now be able to configure the `RsExample` or `RsExampleUser` modules in your config
Expand Down Expand Up @@ -53,16 +52,11 @@ required for rust-analyzer's IDE integration to work properly.

- First, build your EVerest workspace with Rust support enabled by
passing `-DEVEREST_ENABLE_RS_SUPPORT=ON` to CMake.
- Install it using `cmake --install . --prefix build/dist`. Replace
`build/dist` with the installation directory you'd like to use.
- Create a file named `.cargo/config.toml` in your repository's `modules`
directory. This file should contain the following, with `<dist-path>`
replaced by the installation directory you used in the previous step:
- Create a file at `modules/.cargo/config.toml` in your repository.
It file should contain the following, with `<build-dir>` replaced with the
path to your EVerest build directory.

```toml
[env]
# Match CMAKE_INSTALL_LIBDIR, unfortunately Cargo cannot pick automatically:
# https://github.com/rust-lang/cargo/issues/10273
EVEREST_LIB_DIR = "../../<dist-path>/lib64" # For x86_64
EVEREST_LIB_DIR = "../../<dist-path>/lib" # For aarch64
EVEREST_RS_LINK_DEPENDENCIES = "<build-dir>/everestrs-link-dependencies.txt"
```
89 changes: 70 additions & 19 deletions lib/everest/framework/everestrs/everestrs/build.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::env;
use std::fs::File;
use std::io::BufRead;
use std::path::{Path, PathBuf};
use std::{env, io};

struct Libraries {
everestrs_sys: PathBuf,
Expand Down Expand Up @@ -73,12 +75,15 @@ fn find_libs_in_everest_core_build_dist(root: &Path) -> Option<Libraries> {
/// Takes a path to a library like `libframework.so` and returns the name for the linker, aka
/// `framework`
fn libname_from_path(p: &Path) -> String {
p.file_stem()
let base = p
.file_stem()
.and_then(|os_str| os_str.to_str())
.expect("'p' must be valid UTF-8 and have a .so extension.")
.expect("'p' must be valid UTF-8 and have an extension.")
.strip_prefix("lib")
.expect("'p' should start with `lib`")
.to_string()
.expect("'p' should start with `lib`");

// foo.so.1.2.3 -> foo
base.split('.').next().unwrap_or(base).to_string()
}

fn print_link_options(p: &Path) {
Expand All @@ -87,11 +92,6 @@ fn print_link_options(p: &Path) {
p.parent().unwrap().to_string_lossy()
);
println!("cargo:rustc-link-lib={}", libname_from_path(p));
// If the c++ libraries are build with `-fprofile-arcs -ftest-coverage`
// compiler flags we've to link against the `gcov` lib as well.
if env::var("CARGO_FEATURE_LINK_GCOV").is_ok() {
println!("cargo:rustc-link-lib=gcov");
}
}

fn find_libs_in_everest_workspace() -> Option<Libraries> {
Expand All @@ -103,6 +103,40 @@ fn find_libs_in_everest_workspace() -> Option<Libraries> {
find_libs_in_everest_framework(&root)
}

/// Registers the libraries specified in the `EVEREST_RS_LINK_DEPENDENCIES` environment variable.
/// Expected to be a path to a text file that contains one object file path per line.
fn register_everest_link_deps(link_deps_path: &str) -> io::Result<()> {
let link_deps = File::open(link_deps_path).map_err(|e| {
io::Error::new(
e.kind(),
format!("Could not open EVEREST_RS_LINK_DEPENDENCIES file '{link_deps_path}': {e}"),
)
})?;

let mut found_any = false;
for line in io::BufReader::new(link_deps).lines() {
let line = line?;
let path = Path::new(&line);
if !path.is_file() {
return Err(io::Error::new(io::ErrorKind::NotFound, format!(
"Cannot find library path '{line}' specified in EVEREST_RS_LINK_DEPENDENCIES ({link_deps_path}).",
)));
}

print_link_options(path);
found_any = true;
}

if found_any {
Ok(())
} else {
Err(io::Error::new(
io::ErrorKind::NotFound,
format!("No library paths found in EVEREST_RS_LINK_DEPENDENCIES ({link_deps_path})."),
))
}
}

fn main() {
// See https://doc.rust-lang.org/cargo/reference/features.html#build-scripts
// for details.
Expand All @@ -111,17 +145,34 @@ fn main() {
return;
}

let libs = match env::var("EVEREST_LIB_DIR") {
Ok(p) => find_libs_in_dir(&Path::new(&p)),
Err(_) => find_libs_in_everest_workspace(),
};
match env::var("EVEREST_RS_LINK_DEPENDENCIES") {
Ok(p) => {
register_everest_link_deps(&p)
.expect("Failed to register libraries specified in EVEREST_RS_LINK_DEPENDENCIES");
}
Err(_) => {
let libs = match env::var("EVEREST_LIB_DIR") {
Ok(p) => find_libs_in_dir(Path::new(&p)),
Err(_) => find_libs_in_everest_workspace(),
};

let libs = libs
.expect("Could not find libframework.so and libeverestrs_sys. There are a few ways to solve this:
- Set EVEREST_LIB_DIR to a path that contains them.
- Set EVEREST_RS_LINK_DEPENDENCIES to the build/everestrs-link-dependencies.txt file generated by CMake (preferable).
- Or run the build again with everestrs being inside an everest workspace.");

let libs = libs
.expect("Could not find libframework.so and libeverestrs_sys. Either set EVEREST_LIB_DIR to a path
that contains them or run the build again with everestrs being inside an everest workspace.");
print_link_options(&libs.everestrs_sys);
print_link_options(&libs.framework);
}
}

print_link_options(&libs.everestrs_sys);
print_link_options(&libs.framework);
println!("cargo:rustc-link-lib=boost_log");
println!("cargo:rustc-link-lib=boost_log_setup");

// If the c++ libraries are build with `-fprofile-arcs -ftest-coverage`
// compiler flags we've to link against the `gcov` lib as well.
if env::var("CARGO_FEATURE_LINK_GCOV").is_ok() {
println!("cargo:rustc-link-lib=gcov");
}
}