Skip to content

Commit 3c5cbfa

Browse files
estevecarter
and
carter
authored
Allow rustdoc to run without a ROS distribution (#347)
* Allow rustdoc to run without a ROS distribution * Extensions to get working * Fail if generate_docs feature is not enabled and ROS_DISTRO is not set * Fix formatting * Fix formatting * Make clippy slightly less unhappy * Do not run clippy for all features if checking rclrs * Clean up rcl_bindings.rs * Fix comparison * Avoid warnings for rosidl_runtime_rs * Avoid running cargo test with all features for rclrs * Ignore rosidl_runtime_rs for cargo test * rosidl_runtime_rs does not have a dyn_msg feature * Add comment about the generate_docs feature --------- Co-authored-by: carter <[email protected]>
1 parent 533abc6 commit 3c5cbfa

File tree

7 files changed

+213
-21
lines changed

7 files changed

+213
-21
lines changed

.github/workflows/rust.yml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,12 @@ jobs:
8787
for path in $(colcon list | awk '$3 == "(ament_cargo)" { print $2 }'); do
8888
cd $path
8989
echo "Running clippy in $path"
90-
cargo clippy --all-targets --all-features -- -D warnings
90+
# Run clippy for all features except generate_docs (needed for docs.rs)
91+
if [ "$(basename $path)" = "rclrs" ]; then
92+
cargo clippy --all-targets -F default,dyn_msg -- -D warnings
93+
else
94+
cargo clippy --all-targets --all-features -- -D warnings
95+
fi
9196
cd -
9297
done
9398
@@ -98,7 +103,14 @@ jobs:
98103
for path in $(colcon list | awk '$3 == "(ament_cargo)" && $1 != "examples_rclrs_minimal_pub_sub" && $1 != "examples_rclrs_minimal_client_service" { print $2 }'); do
99104
cd $path
100105
echo "Running cargo test in $path"
101-
cargo test --all-features
106+
# Run cargo test for all features except generate_docs (needed for docs.rs)
107+
if [ "$(basename $path)" = "rclrs" ]; then
108+
cargo test -F default,dyn_msg
109+
elif [ "$(basename $path)" = "rosidl_runtime_rs" ]; then
110+
cargo test -F default
111+
else
112+
cargo test --all-features
113+
fi
102114
cd -
103115
done
104116

rclrs/Cargo.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ path = "src/lib.rs"
1616
[dependencies]
1717
# Needed for dynamically finding type support libraries
1818
ament_rs = { version = "0.2", optional = true }
19+
# Needed for uploading documentation to docs.rs
20+
cfg-if = "1.0.0"
21+
1922
# Needed for clients
2023
futures = "0.3"
2124
# Needed for dynamic messages
@@ -30,6 +33,15 @@ tempfile = "3.3.0"
3033
[build-dependencies]
3134
# Needed for FFI
3235
bindgen = "0.66.1"
36+
# Needed for uploading documentation to docs.rs
37+
cfg-if = "1.0.0"
3338

3439
[features]
40+
default = []
3541
dyn_msg = ["ament_rs", "libloading"]
42+
# This feature is solely for the purpose of being able to generate documetation without a ROS installation
43+
# The only intended usage of this feature is for docs.rs builders to work, and is not intended to be used by end users
44+
generate_docs = ["rosidl_runtime_rs/generate_docs"]
45+
46+
[package.metadata.docs.rs]
47+
features = ["generate_docs"]

rclrs/build.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,21 @@ fn get_env_var_or_abort(env_var: &'static str) -> String {
1818
}
1919

2020
fn main() {
21-
let ros_distro = get_env_var_or_abort(ROS_DISTRO);
21+
let ros_distro = if let Ok(value) = env::var(ROS_DISTRO) {
22+
value
23+
} else {
24+
let error_msg =
25+
"ROS_DISTRO environment variable not set - please source ROS 2 installation first.";
26+
cfg_if::cfg_if! {
27+
if #[cfg(feature="generate_docs")] {
28+
println!("{}", error_msg);
29+
return;
30+
} else {
31+
panic!("{}", error_msg);
32+
}
33+
}
34+
};
35+
2236
println!("cargo:rustc-cfg=ros_distro=\"{ros_distro}\"");
2337

2438
let mut builder = bindgen::Builder::default()

rclrs/src/arguments.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ mod tests {
149149
.map(|x| x.to_string());
150150

151151
let non_ros_args: Vec<String> = extract_non_ros_args(input_args).unwrap();
152-
let expected = vec!["non-ros1", "non-ros2", "non-ros3"];
152+
let expected = ["non-ros1", "non-ros2", "non-ros3"];
153153

154154
if non_ros_args.len() != expected.len() {
155155
return Err(format!(

rclrs/src/rcl_bindings.rs

Lines changed: 136 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,140 @@
1111
#![allow(clippy::all)]
1212
#![allow(missing_docs)]
1313

14-
include!(concat!(env!("OUT_DIR"), "/rcl_bindings_generated.rs"));
14+
cfg_if::cfg_if! {
15+
if #[cfg(feature="generate_docs")] {
16+
#[repr(C)]
17+
#[derive(Debug)]
18+
pub struct rcl_allocator_t;
1519

16-
pub const RMW_GID_STORAGE_SIZE: usize = rmw_gid_storage_size_constant;
20+
#[repr(C)]
21+
#[derive(Debug)]
22+
pub struct rcl_arguments_t;
23+
24+
#[repr(C)]
25+
#[derive(Debug)]
26+
pub struct rcl_client_t;
27+
28+
#[repr(C)]
29+
#[derive(Debug)]
30+
pub struct rcl_clock_t;
31+
32+
#[repr(C)]
33+
#[derive(Debug)]
34+
pub struct rcl_clock_type_t;
35+
36+
#[repr(C)]
37+
#[derive(Debug)]
38+
pub struct rcl_context_t;
39+
40+
#[repr(C)]
41+
#[derive(Debug)]
42+
pub struct rcl_guard_condition_t;
43+
44+
#[repr(C)]
45+
#[derive(Debug)]
46+
pub struct rcl_names_and_types_t;
47+
48+
#[repr(C)]
49+
#[derive(Debug)]
50+
pub struct rcl_node_options_t;
51+
52+
#[repr(C)]
53+
#[derive(Debug)]
54+
pub struct rcl_node_params_t;
55+
56+
#[repr(C)]
57+
#[derive(Debug)]
58+
pub struct rcl_node_t;
59+
60+
#[repr(C)]
61+
#[derive(Debug)]
62+
pub struct rcl_params_t;
63+
64+
#[repr(C)]
65+
#[derive(Debug)]
66+
pub struct rcl_publisher_t;
67+
68+
#[repr(C)]
69+
#[derive(Debug)]
70+
pub struct rcl_ret_t;
71+
72+
#[repr(C)]
73+
#[derive(Debug)]
74+
pub struct rcl_service_t;
75+
76+
#[repr(C)]
77+
#[derive(Debug)]
78+
pub struct rcl_subscription_t;
79+
80+
#[repr(C)]
81+
#[derive(Debug)]
82+
pub struct rcl_topic_endpoint_info_array_t;
83+
84+
#[repr(C)]
85+
#[derive(Debug)]
86+
pub struct rcl_variant_t;
87+
88+
#[repr(C)]
89+
#[derive(Debug)]
90+
pub struct rcl_wait_set_t;
91+
92+
#[repr(C)]
93+
#[derive(Debug)]
94+
pub struct rcutils_string_array_t;
95+
96+
#[repr(C)]
97+
#[derive(Debug)]
98+
pub struct rmw_message_info_t;
99+
100+
#[repr(C)]
101+
#[derive(Debug)]
102+
pub struct rmw_names_and_types_t;
103+
104+
#[repr(C)]
105+
#[derive(Debug)]
106+
pub struct rmw_qos_durability_policy_t;
107+
108+
#[repr(C)]
109+
#[derive(Debug)]
110+
pub struct rmw_qos_history_policy_t;
111+
112+
#[repr(C)]
113+
#[derive(Debug)]
114+
pub struct rmw_qos_liveliness_policy_t;
115+
116+
#[repr(C)]
117+
#[derive(Debug)]
118+
pub struct rmw_qos_profile_t;
119+
120+
#[repr(C)]
121+
#[derive(Debug)]
122+
pub struct rmw_qos_reliability_policy_t;
123+
124+
#[repr(C)]
125+
#[derive(Debug)]
126+
pub struct rmw_request_id_t;
127+
128+
#[repr(C)]
129+
#[derive(Debug)]
130+
pub struct rmw_time_t;
131+
132+
#[repr(C)]
133+
#[derive(Debug)]
134+
pub struct rmw_topic_endpoint_info_array_t;
135+
136+
#[repr(C)]
137+
#[derive(Debug)]
138+
pub struct rosidl_message_type_support_t;
139+
140+
pub const RMW_GID_STORAGE_SIZE: usize = 24;
141+
142+
extern "C" {
143+
pub fn rcl_context_is_valid(context: *const rcl_context_t) -> bool;
144+
}
145+
} else {
146+
include!(concat!(env!("OUT_DIR"), "/rcl_bindings_generated.rs"));
147+
148+
pub const RMW_GID_STORAGE_SIZE: usize = rmw_gid_storage_size_constant;
149+
}
150+
}

rosidl_runtime_rs/Cargo.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,21 @@ path = "src/lib.rs"
1717
# formats such as JSON, YAML, Pickle, etc.
1818
serde = { version = "1", optional = true }
1919

20+
[features]
21+
default = []
22+
# This feature is solely for the purpose of being able to generate documetation without a ROS installation
23+
# The only intended usage of this feature is for docs.rs builders to work, and is not intended to be used by end users
24+
generate_docs = []
25+
2026
[dev-dependencies]
2127
# Needed for writing property tests
2228
quickcheck = "1"
2329
# Needed for testing serde support
2430
serde_json = "1"
31+
32+
[build-dependencies]
33+
# Needed for uploading documentation to docs.rs
34+
cfg-if = "1.0.0"
35+
36+
[package.metadata.docs.rs]
37+
features = ["generate_docs"]

rosidl_runtime_rs/build.rs

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,31 @@
1-
use std::env;
2-
use std::path::Path;
1+
cfg_if::cfg_if! {
2+
if #[cfg(not(feature="generate_docs"))] {
3+
use std::env;
4+
use std::path::Path;
35

4-
const AMENT_PREFIX_PATH: &str = "AMENT_PREFIX_PATH";
6+
const AMENT_PREFIX_PATH: &str = "AMENT_PREFIX_PATH";
57

6-
fn get_env_var_or_abort(env_var: &'static str) -> String {
7-
if let Ok(value) = env::var(env_var) {
8-
value
9-
} else {
10-
panic!(
11-
"{} environment variable not set - please source ROS 2 installation first.",
12-
env_var
13-
);
8+
fn get_env_var_or_abort(env_var: &'static str) -> String {
9+
if let Ok(value) = env::var(env_var) {
10+
value
11+
} else {
12+
panic!(
13+
"{} environment variable not set - please source ROS 2 installation first.",
14+
env_var
15+
);
16+
}
17+
}
1418
}
1519
}
1620

1721
fn main() {
18-
let ament_prefix_path_list = get_env_var_or_abort(AMENT_PREFIX_PATH);
19-
for ament_prefix_path in ament_prefix_path_list.split(':') {
20-
let library_path = Path::new(ament_prefix_path).join("lib");
21-
println!("cargo:rustc-link-search=native={}", library_path.display());
22+
#[cfg(not(feature = "generate_docs"))]
23+
{
24+
let ament_prefix_path_list = get_env_var_or_abort(AMENT_PREFIX_PATH);
25+
for ament_prefix_path in ament_prefix_path_list.split(':') {
26+
let library_path = Path::new(ament_prefix_path).join("lib");
27+
println!("cargo:rustc-link-search=native={}", library_path.display());
28+
}
2229
}
2330

2431
// Invalidate the built crate whenever this script changes

0 commit comments

Comments
 (0)