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

Allow rustdoc to run without a ROS distribution #347

Merged
merged 14 commits into from
Nov 24, 2023
Merged
16 changes: 14 additions & 2 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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

Expand Down
12 changes: 12 additions & 0 deletions rclrs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
generate_docs = ["rosidl_runtime_rs/generate_docs"]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we document somewhere about how this feature works?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jhdcs good point. Where do you think it'd be the best place for this?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure, it depends on how much information needs to be conveyed. If it can be summarized in a couple of sentences, you might be able to get away with doing it in the comments here. Otherwise, we may need to create a separate documentation file...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feature's only purpose is so that docs.rs can run ros2-rust, so it's not intended to be used by users.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But nevertheless, I agree with documenting it somewhere, I'll add something more explanatory here and we can move it elsewhere if it needs more details.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jhdcs can you approve this PR again if it looks good to you? I pushed a change and your review was unfortunately discarded. Thanks.


[package.metadata.docs.rs]
features = ["generate_docs"]
16 changes: 15 additions & 1 deletion rclrs/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
2 changes: 1 addition & 1 deletion rclrs/src/arguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ mod tests {
.map(|x| x.to_string());

let non_ros_args: Vec<String> = 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!(
Expand Down
138 changes: 136 additions & 2 deletions rclrs/src/rcl_bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
12 changes: 12 additions & 0 deletions rosidl_runtime_rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,20 @@ path = "src/lib.rs"
# formats such as JSON, YAML, Pickle, etc.
serde = { version = "1", optional = true }

[features]
default = []
# Used solely to enable docs generate with docs.rs that does not have a ROS installation
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"]
37 changes: 22 additions & 15 deletions rosidl_runtime_rs/build.rs
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Loading