-
Notifications
You must be signed in to change notification settings - Fork 192
Description
In ROS 1, command line arguments specific to ROS were removed, see:
argc and argv
ROS uses these to parse remapping arguments from the command line. It also modifies them so that they no longer contain any remapping arguments, so that if you call ros::init() before processing your command line you will not need to skip those arguments yourself.
-- https://wiki.ros.org/roscpp/Overview/Initialization%20and%20Shutdown#Initializing_the_roscpp_Node
And the signature for roscpp::init() uses int & argc, char ** argv, allowing it technically to modify what ever C array of strings you give it. This is permissible according to my research, e.g.:
The strings are modifiable, although these modifications do not propagate back to the execution environment: they can be used, for example, with std::strtok. The size of the array pointed to by argv is at least argc+1, and the last element, argv[argc], is guaranteed to be a null pointer.
-- http://en.cppreference.com/w/cpp/language/main_function
But modifying the system provided argv automatically (implicitly) is a bit surprising for users.
Other places recommend int main(int argc, char const * argv[]) as the signature to main, which I can't find a foundation for, but seems like a reasonable thing to do.
For ROS 2, I'd like to propose that we change our rcl interface and down to not directly modify argv, and instead provide a function that removes the arguments by returning a copy that is pruned (still not modifying the originals). In rclcpp we can do something like have rclcpp::init() return a vector<string> rather than mutate the argc and argv it was given. Which keeps the number of statements low, but again avoids mutating the arguments in place.
So that would mean:
-
void init(int argc, char * argv[])->void init(int argc, char const * const argv[]) -
rcl_ret_t rcl_init(int argc, char ** argv, rcl_allocator_t allocator)->rcl_ret_t rcl_init(int argc, char const * const argv[], rcl_allocator_t allocator)Lines 123 to 124 in beee7c2
rcl_ret_t rcl_init(int argc, char ** argv, rcl_allocator_t allocator);
- add function to
rcllikercl_ret_t rcl_remove_ros_arguments(int argc, char const * const argv[], size_t pruned_argc, char const * pruned_argv[], const rcl_cli_arguments_t * parsed_arguments)- note
rcl_cli_arguments_tis created after callingrcl_parse_arguments, whichrcl_initdoes - this is dependent on Command line static remapping (ROS1 compatible syntax + nodename prefix) #217
- note
- add C++ version of
rcl_remove_ros_arguments, e.g.vector<string> rclcpp::remove_ros_arguments(int argc, char const * const argv[], const rcl_cli_arguments_t * parsed_arguments)or something like that - add convenience version of
rclcpp::initwhich removes the args and exposed the pruned args automatically, e.g.vector<string> rclcpp::init_and_remove_ros_arguments(int argc, char const * const argv[])or something like that - add a similar behavior for
rclpy, not sure off hand how this should look
Optionally there are few things we could do at the same time:
- add support for command line arguments to
rmw_init, it would need to:- take
argcandargvand - have a way to indicate which indices in
argvwere "consumed" by the middleware and should/could be remove for the user
- take
- make all the global init functions not global, by returning a handle or structure
- this would just be good to do, and while we're touching these functions anyways...
- this would also allow us to simplify the
remove_ros_argslike functions in a few cases, especially in C++
- perhaps other things I'll think of later...