CMake自定义目标显式调用bash却似乎使用sh?
Let me walk you through what's going wrong here and how to fix it, plus clean up a couple of bugs in your current create_ros_target function.
Why This Is Happening
The core issue is xargs defaults to using /bin/sh to execute commands, even when you launch the parent process with bash -c. So when you pipe your setup scripts to xargs -r source, those source calls are running in a sh shell—not the bash you intended. That's why it looks like sh is being used.
On top of that, there's a bug in your target property lookup: you're assigning the dependency path to dep_path but then trying to use ${BUILD_PATH} (a non-existent variable) when building your ament_deps list.
Fixed Implementation
Here's the corrected function, with explanations of the changes:
function(create_ros_target NAME DIR DEPENDENCIES) set(ament_deps "") foreach(dep ${DEPENDENCIES}) # Fixed: Reference the loop variable ${dep} instead of literal "dep" get_target_property(dep_path ${dep} BUILD_PATH) # Add safety check to skip dependencies without a valid BUILD_PATH if(dep_path) list(APPEND ament_deps "${dep_path}/install/local_setup.bash") endif() endforeach() add_custom_target(${NAME} COMMAND bash -c " # Source each setup script in bash (no xargs to avoid sh fallback) for setup_script in ${ament_deps}; do if [ -f \"\${setup_script}\" ]; then source \"\${setup_script}\" fi done # Run ament build in the same bash context to preserve environment ament build --symlink-install ${DIR} " COMMENT "Building ROS target ${NAME} in directory ${DIR}" ) # Complete your target properties here (your original code was cut off) # set_target_properties(${NAME} PROPERTIES ...) endfunction()
Key Changes Made
- Fixed target property lookup: Changed
get_target_property(dep_path dep BUILD_PATH)toget_target_property(dep_path ${dep} BUILD_PATH)to correctly reference the loop's dependency target. Added a check to skip invalid paths. - Replaced xargs with a bash loop: This eliminates xargs' sh fallback entirely. All
sourcecommands run in the same bash shell, ensuring your ROS setup scripts (which use bash-specific syntax) work as expected. - Single bash context: The entire command runs in one bash process, so environment variables from the setup scripts are preserved when executing
ament build.
Alternative: Force xargs to Use Bash
If you prefer to keep using xargs for some reason, you can explicitly tell it to use bash for each source call:
COMMAND bash -c "echo ${ament_deps} | xargs -r -I {} bash -c 'source {}' ; ament build --symlink-install ${DIR}"
But the bash loop approach is cleaner, more readable, and less prone to edge cases (like path names with spaces, though rare in ROS workspaces).
内容的提问来源于stack exchange,提问作者kutschkem

