Handle path changes to support Humble release

This commit is contained in:
Martin Dahl 2022-08-19 15:46:13 +02:00
parent aa812a2e8f
commit 7678acfb12
8 changed files with 170 additions and 198 deletions

View File

@ -1,32 +1,13 @@
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::path::PathBuf;
fn main() {
r2r_common::print_cargo_watches();
let msg_list = if let Ok(cmake_includes) = env::var("CMAKE_INCLUDE_DIRS") {
let packages = cmake_includes
.split(':')
.flat_map(|i| Path::new(i).parent())
.collect::<Vec<_>>();
let deps = env::var("CMAKE_IDL_PACKAGES").unwrap_or_default();
let deps = deps.split(':').collect::<Vec<_>>();
let msgs = r2r_common::get_ros_msgs(&packages);
r2r_common::parse_msgs(&msgs)
.into_iter()
.filter(|msg| deps.contains(&msg.module.as_str()))
.collect::<Vec<_>>()
} else {
let ament_prefix_var = env::var("AMENT_PREFIX_PATH").expect("Source your ROS!");
let paths = ament_prefix_var
.split(':')
.map(Path::new)
.collect::<Vec<_>>();
let msgs = r2r_common::get_ros_msgs(&paths);
r2r_common::parse_msgs(&msgs)
};
let msg_list = r2r_common::get_wanted_messages();
let msgs = r2r_common::as_map(&msg_list);
let mut modules = String::new();

View File

@ -16,5 +16,4 @@ r2r_msg_gen = { path = "../r2r_msg_gen", version = "0.3.2" }
[build-dependencies]
bindgen = "0.59.2"
itertools = "0.10.3"
r2r_common = { path = "../r2r_common", version = "0.3.1" }

View File

@ -1,58 +1,11 @@
use itertools::Itertools;
use std::env;
use std::path::{Path, PathBuf};
use std::path::PathBuf;
fn main() {
let mut builder = bindgen::Builder::default()
.header("src/action_wrapper.h")
.derive_copy(false)
.size_t_is_usize(true)
.default_enum_style(bindgen::EnumVariation::Rust {
non_exhaustive: false,
});
r2r_common::print_cargo_watches();
if let Ok(cmake_includes) = env::var("CMAKE_INCLUDE_DIRS") {
// we are running from cmake, do special thing.
let mut includes = cmake_includes.split(':').collect::<Vec<_>>();
includes.sort_unstable();
includes.dedup();
for x in &includes {
let clang_arg = format!("-I{}", x);
println!("adding clang arg: {}", clang_arg);
builder = builder.clang_arg(clang_arg);
}
env::var("CMAKE_LIBRARIES")
.unwrap_or_default()
.split(':')
.into_iter()
.filter(|s| s.contains(".so") || s.contains(".dylib"))
.flat_map(|l| Path::new(l).parent().and_then(|p| p.to_str()))
.unique()
.for_each(|pp| {
println!("cargo:rustc-link-search=native={}", pp)
// we could potentially do the below instead of hardcoding which libs we rely on.
// let filename = path.file_stem().and_then(|f| f.to_str()).unwrap();
// let without_lib = filename.strip_prefix("lib").unwrap();
// println!("cargo:rustc-link-lib=dylib={}", without_lib);
});
} else {
let ament_prefix_var_name = "AMENT_PREFIX_PATH";
let ament_prefix_var = env::var(ament_prefix_var_name).expect("Source your ROS!");
for ament_prefix_path in ament_prefix_var.split(':') {
if let Some(include_path) = r2r_common::guess_cmake_include_path(Path::new(ament_prefix_path)) {
if let Some(s) = include_path.to_str() {
builder = builder.clang_arg(format!("-I{}", s));
};
}
let lib_path = Path::new(ament_prefix_path).join("lib");
lib_path.to_str().map(|s| {
println!("cargo:rustc-link-search=native={}", s);
});
}
}
let mut builder = r2r_common::setup_bindgen_builder();
builder = builder.header("src/action_wrapper.h");
println!("cargo:rustc-link-lib=dylib=rcl_action");

View File

@ -9,3 +9,7 @@ readme = "README.md"
homepage = "https://github.com/sequenceplanner/r2r"
repository = "https://github.com/sequenceplanner/r2r"
documentation = "https://sequenceplanner.github.io/r2r/"
[dependencies]
bindgen = "0.59.2"
itertools = "0.10.3"

View File

@ -1,35 +1,9 @@
use std::collections::HashMap;
use std::fs::{self, File};
use std::io::Read;
use std::path::{Path, PathBuf};
// Hack to build rolling after https://github.com/ros2/rcl/pull/959 was merged.
//
// The problem is that now we need to use CMAKE to properly find the
// include paths. But we don't want to do that so we hope that the ros
// developers use the same convention everytime they move the include
// files to a subdirectory.
//
// The convention is to put include files in include/${PROJECT_NAME}
//
// So we check if there is a double directory on the form
// include/${PROJECT_NAME}/${PROJECT_NAME}, and if so append it only once.
//
// Should work mostly, and shouldn't really change often, so manual
// intervention could be applied. But yes it is hacky.
pub fn guess_cmake_include_path(path: &Path) -> Option<PathBuf> {
if let Some(leaf) = path.file_name() {
let double_include_path = Path::new(path).join("include").join(leaf).join(leaf);
if double_include_path.is_dir() {
// double dir detected, append the package name
return Some(path.to_owned().join("include").join(leaf));
} else {
// dont append
return Some(path.to_owned().join("include"));
}
}
return None;
}
use std::path::Path;
use std::env;
use itertools::Itertools;
pub fn print_cargo_watches() {
println!("cargo:rerun-if-env-changed=AMENT_PREFIX_PATH");
@ -38,6 +12,115 @@ pub fn print_cargo_watches() {
println!("cargo:rerun-if-env-changed=CMAKE_RECURSIVE_DEPENDENCIES");
}
pub fn setup_bindgen_builder() -> bindgen::Builder {
let mut builder = bindgen::Builder::default()
.derive_copy(false)
.size_t_is_usize(true)
.default_enum_style(bindgen::EnumVariation::Rust {
non_exhaustive: false,
});
if let Ok(cmake_includes) = env::var("CMAKE_INCLUDE_DIRS") {
// we are running from cmake, do special thing.
let mut includes = cmake_includes.split(':').collect::<Vec<_>>();
includes.sort_unstable();
includes.dedup();
for x in &includes {
let clang_arg = format!("-I{}", x);
println!("adding clang arg: {}", clang_arg);
builder = builder.clang_arg(clang_arg);
}
env::var("CMAKE_LIBRARIES")
.unwrap_or_default()
.split(':')
.into_iter()
.filter(|s| s.contains(".so") || s.contains(".dylib"))
.flat_map(|l| Path::new(l).parent().and_then(|p| p.to_str()))
.unique()
.for_each(|pp| println!("cargo:rustc-link-search=native={}", pp));
} else {
let ament_prefix_var_name = "AMENT_PREFIX_PATH";
let ament_prefix_var = env::var(ament_prefix_var_name).expect("Source your ROS!");
for p in ament_prefix_var.split(':') {
let path = Path::new(p).join("include");
let entries = std::fs::read_dir(path.clone());
if let Ok(e) = entries {
let dirs = e.filter_map(|a| {
let path = a.unwrap().path();
if path.is_dir() {
Some(path)
} else {
None
}
}).collect::<Vec<_>>();
builder = dirs.iter().fold(builder, |builder, d| {
// Hack to build rolling after https://github.com/ros2/rcl/pull/959 was merged.
//
// The problem is that now we need to use CMAKE to properly find the
// include paths. But we don't want to do that so we hope that the ros
// developers use the same convention everytime they move the include
// files to a subdirectory.
//
// The convention is to put include files in include/${PROJECT_NAME}
//
// So we check if there is a double directory on the form
// include/${PROJECT_NAME}/${PROJECT_NAME}, and if so append it only once.
//
// Should work mostly, and shouldn't really change often, so manual
// intervention could be applied. But yes it is hacky.
if let Some(leaf) = d.file_name() {
let double_include_path = Path::new(d).join(leaf);
if double_include_path.is_dir() {
let temp = d.to_str().unwrap();
builder.clang_arg(format!("-I{}", temp))
} else {
// pre humble case, where we did not have include/package/package
let temp = d.parent().unwrap().to_str().unwrap();
builder.clang_arg(format!("-I{}", temp))
}
} else { builder }
});
}
let lib_path = Path::new(p).join("lib");
lib_path.to_str().map(|s| {
println!("cargo:rustc-link-search=native={}", s);
});
}
}
return builder;
}
pub fn get_wanted_messages() -> Vec<RosMsg> {
let msgs = if let Ok(cmake_package_dirs) = env::var("CMAKE_IDL_PACKAGES") {
// CMAKE_PACKAGE_DIRS should be a (cmake) list of "cmake" dirs
// e.g. For each dir install/r2r_minimal_node_msgs/share/r2r_minimal_node_msgs/cmake
// we can traverse back and then look for .msg files in msg/ srv/ action/
let dirs = cmake_package_dirs.split(':')
.flat_map(|i| Path::new(i).parent())
.collect::<Vec<_>>();
get_ros_msgs_files(&dirs)
} else {
// Else we look for all msgs we can find using the ament prefix path.
let ament_prefix_var = env::var("AMENT_PREFIX_PATH").expect("Source your ROS!");
let paths = ament_prefix_var
.split(':')
.map(Path::new)
.collect::<Vec<_>>();
get_ros_msgs(&paths)
};
parse_msgs(&msgs)
}
#[derive(Debug)]
pub struct RosMsg {
pub module: String, // e.g. std_msgs
@ -57,13 +140,10 @@ fn get_msgs_from_package(package: &Path) -> Vec<String> {
if let Ok(paths) = fs::read_dir(path) {
for path in paths {
// println!("PATH Name: {}", path.unwrap().path().display());
let path = path.unwrap().path();
let path2 = path.clone();
let file_name = path2.file_name().unwrap();
// println!("Messages for: {:?}", file_name);
if let Ok(mut file) = File::open(path) {
let mut s = String::new();
file.read_to_string(&mut s).unwrap();
@ -109,9 +189,7 @@ pub fn get_ros_msgs(paths: &[&Path]) -> Vec<String> {
let mut msgs: Vec<String> = Vec::new();
for p in paths {
println!("looking at prefix: {:?}", p);
let package_msgs = get_msgs_from_package(p);
println!("... found {:?}", package_msgs);
msgs.extend(package_msgs)
}
msgs.sort();
@ -119,6 +197,47 @@ pub fn get_ros_msgs(paths: &[&Path]) -> Vec<String> {
msgs
}
fn get_msgs_in_dir(base: &Path, subdir: &str, package: &str) -> Vec<String> {
let path = base.to_owned();
let path = path.join(subdir);
let mut msgs = vec![];
if let Ok(paths) = fs::read_dir(path) {
for path in paths {
let path = path.unwrap().path();
let filename = path.file_name().unwrap().to_str().unwrap();
// message name.idl or name.msg
if !filename.ends_with(".idl") {
continue;
}
let substr = &filename[0..filename.len() - 4];
msgs.push(format!("{}/{}/{}",package, subdir, substr));
}
}
msgs
}
pub fn get_ros_msgs_files(paths: &[&Path]) -> Vec<String> {
let mut msgs: Vec<String> = Vec::new();
for p in paths {
if let Some(package_name) = p.file_name() {
let package_name = package_name.to_str().unwrap();
msgs.extend(get_msgs_in_dir(p, "msg", package_name));
msgs.extend(get_msgs_in_dir(p, "srv", package_name));
msgs.extend(get_msgs_in_dir(p, "action", package_name));
}
}
msgs.sort();
msgs.dedup();
msgs
}
pub fn parse_msgs(msgs: &[String]) -> Vec<RosMsg> {
let v: Vec<Vec<&str>> = msgs
.iter()

View File

@ -3,45 +3,14 @@ use heck::ToSnakeCase;
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::path::PathBuf;
fn main() {
r2r_common::print_cargo_watches();
let mut builder = bindgen::Builder::default();
let msg_list = if let Ok(cmake_includes) = env::var("CMAKE_INCLUDE_DIRS") {
let packages = cmake_includes
.split(':')
.flat_map(|i| Path::new(i).parent())
.collect::<Vec<_>>();
for p in cmake_includes.split(':') {
builder = builder.clang_arg(format!("-I{}", p));
}
let deps = env::var("CMAKE_IDL_PACKAGES").unwrap_or_default();
let deps = deps.split(':').collect::<Vec<_>>();
let msgs = r2r_common::get_ros_msgs(&packages);
r2r_common::parse_msgs(&msgs)
.into_iter()
.filter(|msg| deps.contains(&msg.module.as_str()))
.collect::<Vec<_>>()
} else {
let ament_prefix_var = env::var("AMENT_PREFIX_PATH").expect("Source your ROS!");
for p in ament_prefix_var.split(':') {
let path = Path::new(p).join("include");
if let Some(s) = path.to_str() {
builder = builder.clang_arg(format!("-I{}", s));
}
}
let paths = ament_prefix_var
.split(':')
.map(Path::new)
.collect::<Vec<_>>();
let msgs = r2r_common::get_ros_msgs(&paths);
r2r_common::parse_msgs(&msgs)
};
let mut builder = r2r_common::setup_bindgen_builder();
let msg_list = r2r_common::get_wanted_messages();
let msg_map = r2r_common::as_map(&msg_list);
for module in msg_map.keys() {

View File

@ -16,5 +16,4 @@ widestring = "0.5.1"
[build-dependencies]
bindgen = "0.59.2"
itertools = "0.10.3"
r2r_common = { path = "../r2r_common", version = "0.3.1" }

View File

@ -1,63 +1,11 @@
extern crate bindgen;
use itertools::Itertools;
use std::env;
use std::path::{Path, PathBuf};
use std::path::PathBuf;
fn main() {
r2r_common::print_cargo_watches();
let mut builder = bindgen::Builder::default()
.header("src/rcl_wrapper.h")
.derive_copy(false)
.size_t_is_usize(true)
.default_enum_style(bindgen::EnumVariation::Rust {
non_exhaustive: false,
});
if let Ok(cmake_includes) = env::var("CMAKE_INCLUDE_DIRS") {
// we are running from cmake, do special thing.
let mut includes = cmake_includes.split(':').collect::<Vec<_>>();
includes.sort_unstable();
includes.dedup();
for x in &includes {
let clang_arg = format!("-I{}", x);
println!("adding clang arg: {}", clang_arg);
builder = builder.clang_arg(clang_arg);
}
env::var("CMAKE_LIBRARIES")
.unwrap_or_default()
.split(':')
.into_iter()
.filter(|s| s.contains(".so") || s.contains(".dylib"))
.flat_map(|l| Path::new(l).parent().and_then(|p| p.to_str()))
.unique()
.for_each(|pp| {
println!("cargo:rustc-link-search=native={}", pp)
// we could potentially do the below instead of hardcoding which libs we rely on.
// let filename = path.file_stem().and_then(|f| f.to_str()).unwrap();
// let without_lib = filename.strip_prefix("lib").unwrap();
// println!("cargo:rustc-link-lib=dylib={}", without_lib);
});
} else {
let ament_prefix_var_name = "AMENT_PREFIX_PATH";
let ament_prefix_var = env::var(ament_prefix_var_name).expect("Source your ROS!");
for ament_prefix_path in ament_prefix_var.split(':') {
if let Some(include_path) = r2r_common::guess_cmake_include_path(Path::new(ament_prefix_path)) {
if let Some(s) = include_path.to_str() {
builder = builder.clang_arg(format!("-I{}", s));
};
}
let lib_path = Path::new(ament_prefix_path).join("lib");
lib_path.to_str().map(|s| {
println!("cargo:rustc-link-search=native={}", s);
});
}
}
let mut builder = r2r_common::setup_bindgen_builder();
builder = builder.header("src/rcl_wrapper.h");
println!("cargo:rustc-link-lib=dylib=rcl");
println!("cargo:rustc-link-lib=dylib=rcl_logging_spdlog");