diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 29fa1bee2..c678075f7 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -87,7 +87,12 @@ jobs: for path in $(colcon list | awk '$3 == "(ament_cargo)" { print $2 }'); do cd $path echo "Running clippy in $path" - cargo clippy --all-targets --all-features -- -D warnings + # Run clippy for all features except generate_docs (needed for docs.rs) + if [ "$(basename $path)" = "rclrs" ]; then + cargo clippy --all-targets -F default,dyn_msg -- -D warnings + else + cargo clippy --all-targets --all-features -- -D warnings + fi cd - done @@ -98,7 +103,14 @@ jobs: for path in $(colcon list | awk '$3 == "(ament_cargo)" && $1 != "examples_rclrs_minimal_pub_sub" && $1 != "examples_rclrs_minimal_client_service" { print $2 }'); do cd $path echo "Running cargo test in $path" - cargo test --all-features + # Run cargo test for all features except generate_docs (needed for docs.rs) + if [ "$(basename $path)" = "rclrs" ]; then + cargo test -F default,dyn_msg + elif [ "$(basename $path)" = "rosidl_runtime_rs" ]; then + cargo test -F default + else + cargo test --all-features + fi cd - done diff --git a/rclrs/Cargo.toml b/rclrs/Cargo.toml index 01c6d082a..c13b75d1e 100644 --- a/rclrs/Cargo.toml +++ b/rclrs/Cargo.toml @@ -16,6 +16,9 @@ path = "src/lib.rs" [dependencies] # Needed for dynamically finding type support libraries ament_rs = { version = "0.2", optional = true } +# Needed for uploading documentation to docs.rs +cfg-if = "1.0.0" + # Needed for clients futures = "0.3" # Needed for dynamic messages @@ -30,6 +33,15 @@ tempfile = "3.3.0" [build-dependencies] # Needed for FFI bindgen = "0.66.1" +# Needed for uploading documentation to docs.rs +cfg-if = "1.0.0" [features] +default = [] dyn_msg = ["ament_rs", "libloading"] +# This feature is solely for the purpose of being able to generate documetation without a ROS installation +# The only intended usage of this feature is for docs.rs builders to work, and is not intended to be used by end users +generate_docs = ["rosidl_runtime_rs/generate_docs"] + +[package.metadata.docs.rs] +features = ["generate_docs"] diff --git a/rclrs/build.rs b/rclrs/build.rs index fe8cd8b9a..9da8afa7f 100644 --- a/rclrs/build.rs +++ b/rclrs/build.rs @@ -18,7 +18,21 @@ fn get_env_var_or_abort(env_var: &'static str) -> String { } fn main() { - let ros_distro = get_env_var_or_abort(ROS_DISTRO); + let ros_distro = if let Ok(value) = env::var(ROS_DISTRO) { + value + } else { + let error_msg = + "ROS_DISTRO environment variable not set - please source ROS 2 installation first."; + cfg_if::cfg_if! { + if #[cfg(feature="generate_docs")] { + println!("{}", error_msg); + return; + } else { + panic!("{}", error_msg); + } + } + }; + println!("cargo:rustc-cfg=ros_distro=\"{ros_distro}\""); let mut builder = bindgen::Builder::default() diff --git a/rclrs/src/arguments.rs b/rclrs/src/arguments.rs index c091bf759..21d410a5b 100644 --- a/rclrs/src/arguments.rs +++ b/rclrs/src/arguments.rs @@ -149,7 +149,7 @@ mod tests { .map(|x| x.to_string()); let non_ros_args: Vec = extract_non_ros_args(input_args).unwrap(); - let expected = vec!["non-ros1", "non-ros2", "non-ros3"]; + let expected = ["non-ros1", "non-ros2", "non-ros3"]; if non_ros_args.len() != expected.len() { return Err(format!( diff --git a/rclrs/src/rcl_bindings.rs b/rclrs/src/rcl_bindings.rs index 245430269..94491bc91 100644 --- a/rclrs/src/rcl_bindings.rs +++ b/rclrs/src/rcl_bindings.rs @@ -11,6 +11,140 @@ #![allow(clippy::all)] #![allow(missing_docs)] -include!(concat!(env!("OUT_DIR"), "/rcl_bindings_generated.rs")); +cfg_if::cfg_if! { + if #[cfg(feature="generate_docs")] { + #[repr(C)] + #[derive(Debug)] + pub struct rcl_allocator_t; -pub const RMW_GID_STORAGE_SIZE: usize = rmw_gid_storage_size_constant; + #[repr(C)] + #[derive(Debug)] + pub struct rcl_arguments_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rcl_client_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rcl_clock_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rcl_clock_type_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rcl_context_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rcl_guard_condition_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rcl_names_and_types_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rcl_node_options_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rcl_node_params_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rcl_node_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rcl_params_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rcl_publisher_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rcl_ret_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rcl_service_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rcl_subscription_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rcl_topic_endpoint_info_array_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rcl_variant_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rcl_wait_set_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rcutils_string_array_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rmw_message_info_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rmw_names_and_types_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rmw_qos_durability_policy_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rmw_qos_history_policy_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rmw_qos_liveliness_policy_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rmw_qos_profile_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rmw_qos_reliability_policy_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rmw_request_id_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rmw_time_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rmw_topic_endpoint_info_array_t; + + #[repr(C)] + #[derive(Debug)] + pub struct rosidl_message_type_support_t; + + pub const RMW_GID_STORAGE_SIZE: usize = 24; + + extern "C" { + pub fn rcl_context_is_valid(context: *const rcl_context_t) -> bool; + } + } else { + include!(concat!(env!("OUT_DIR"), "/rcl_bindings_generated.rs")); + + pub const RMW_GID_STORAGE_SIZE: usize = rmw_gid_storage_size_constant; + } +} diff --git a/rosidl_runtime_rs/Cargo.toml b/rosidl_runtime_rs/Cargo.toml index 2a363be74..e679b87a9 100644 --- a/rosidl_runtime_rs/Cargo.toml +++ b/rosidl_runtime_rs/Cargo.toml @@ -17,8 +17,21 @@ path = "src/lib.rs" # formats such as JSON, YAML, Pickle, etc. serde = { version = "1", optional = true } +[features] +default = [] +# This feature is solely for the purpose of being able to generate documetation without a ROS installation +# The only intended usage of this feature is for docs.rs builders to work, and is not intended to be used by end users +generate_docs = [] + [dev-dependencies] # Needed for writing property tests quickcheck = "1" # Needed for testing serde support serde_json = "1" + +[build-dependencies] +# Needed for uploading documentation to docs.rs +cfg-if = "1.0.0" + +[package.metadata.docs.rs] +features = ["generate_docs"] diff --git a/rosidl_runtime_rs/build.rs b/rosidl_runtime_rs/build.rs index b895cd24b..fb98aeb30 100644 --- a/rosidl_runtime_rs/build.rs +++ b/rosidl_runtime_rs/build.rs @@ -1,24 +1,31 @@ -use std::env; -use std::path::Path; +cfg_if::cfg_if! { + if #[cfg(not(feature="generate_docs"))] { + use std::env; + use std::path::Path; -const AMENT_PREFIX_PATH: &str = "AMENT_PREFIX_PATH"; + const AMENT_PREFIX_PATH: &str = "AMENT_PREFIX_PATH"; -fn get_env_var_or_abort(env_var: &'static str) -> String { - if let Ok(value) = env::var(env_var) { - value - } else { - panic!( - "{} environment variable not set - please source ROS 2 installation first.", - env_var - ); + fn get_env_var_or_abort(env_var: &'static str) -> String { + if let Ok(value) = env::var(env_var) { + value + } else { + panic!( + "{} environment variable not set - please source ROS 2 installation first.", + env_var + ); + } + } } } fn main() { - let ament_prefix_path_list = get_env_var_or_abort(AMENT_PREFIX_PATH); - for ament_prefix_path in ament_prefix_path_list.split(':') { - let library_path = Path::new(ament_prefix_path).join("lib"); - println!("cargo:rustc-link-search=native={}", library_path.display()); + #[cfg(not(feature = "generate_docs"))] + { + let ament_prefix_path_list = get_env_var_or_abort(AMENT_PREFIX_PATH); + for ament_prefix_path in ament_prefix_path_list.split(':') { + let library_path = Path::new(ament_prefix_path).join("lib"); + println!("cargo:rustc-link-search=native={}", library_path.display()); + } } // Invalidate the built crate whenever this script changes