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

change how commands are executed #1628

Merged
merged 7 commits into from
Mar 16, 2019
Merged

change how commands are executed #1628

merged 7 commits into from
Mar 16, 2019

Conversation

kejxu
Copy link
Contributor

@kejxu kejxu commented Feb 22, 2019

this is another problem due to the lack of shebang support on Windows, there are 2 common ways of using the command attribute in the launch file:

  • call into an executable in PATH variable, for example, rosversion, an entry point that comes with an executable. this kind of executables tend to sit in <python_install_dir>\Scripts, and can be called and executed directly. because of this, usually only the executable's name (not an absolute path) is given, like this:
<... command="rosversion roslaunch" />
  • call into an executable from a package (some specific location), so a specific path is given, like such:
<... command="$(find xacro)/xacro ......" />

the first scenario works like a charm on Windows too, thanks to the console_script support. However, for the second scenario, things are a little bit different:

  • $(find xacro)/xacro would point to a file without any extension, that means the file would not be executable on Windows
  • even if a win32 executable wrapper (like the one proposed in add win_ros script wrappers to make python scripts executable catkin#978) is added for the Python script under the same directory, the wrapper's name would be xacro.exe. unless the subprocess (subprocess.Popen(command, stdout=subprocess.PIPE)) is spawned with an extra shell=True flag, the following error would be returned:
Traceback (most recent call last):
  File "C:\opt\ros\melodic\x64\lib\site-packages\roslaunch\__init__.py", line 322, in main
    p.start()
  File "C:\opt\ros\melodic\x64\lib\site-packages\roslaunch\parent.py", line 277, in start
    self._start_infrastructure()
  File "C:\opt\ros\melodic\x64\lib\site-packages\roslaunch\parent.py", line 226, in _start_infrastructure
    self._load_config()
  File "C:\opt\ros\melodic\x64\lib\site-packages\roslaunch\parent.py", line 138, in _load_config
    roslaunch_strs=self.roslaunch_strs, verbose=self.verbose)
  File "C:\opt\ros\melodic\x64\lib\site-packages\roslaunch\config.py", line 464, in load_config_default
    loader.load(f, config, argv=args, verbose=verbose)
  File "C:\opt\ros\melodic\x64\lib\site-packages\roslaunch\xmlloader.py", line 769, in load
    self._load_launch(launch, ros_config, is_core=core, filename=filename, argv=argv, verbose=verbose)
  File "C:\opt\ros\melodic\x64\lib\site-packages\roslaunch\xmlloader.py", line 739, in _load_launch
    self._recurse_load(ros_config, launch.childNodes, self.root_context, None, is_core, verbose)
  File "C:\opt\ros\melodic\x64\lib\site-packages\roslaunch\xmlloader.py", line 705, in _recurse_load
    val = self._include_tag(tag, context, ros_config, default_machine, is_core, verbose)
  File "C:\opt\ros\melodic\x64\lib\site-packages\roslaunch\xmlloader.py", line 101, in call
    return f(*args, **kwds)
  File "C:\opt\ros\melodic\x64\lib\site-packages\roslaunch\xmlloader.py", line 641, in _include_tag
    default_machine, is_core, verbose)
  File "C:\opt\ros\melodic\x64\lib\site-packages\roslaunch\xmlloader.py", line 685, in _recurse_load
    self._param_tag(tag, context, ros_config, verbose=verbose)
  File "C:\opt\ros\melodic\x64\lib\site-packages\roslaunch\xmlloader.py", line 101, in call
    return f(*args, **kwds)
  File "C:\opt\ros\melodic\x64\lib\site-packages\roslaunch\xmlloader.py", line 276, in _param_tag
    value = self.param_value(verbose, name, ptype, *vals)
  File "C:\opt\ros\melodic\x64\lib\site-packages\roslaunch\loader.py", line 506, in param_value
    p = subprocess.Popen(command, stdout=subprocess.PIPE)
  File "C:\opt\python27amd64\lib\subprocess.py", line 394, in __init__
    errread, errwrite)
  File "C:\opt\python27amd64\lib\subprocess.py", line 644, in _execute_child
    startupinfo)
WindowsError: [Error 193] %1 is not a valid Win32 application

to fix this, here is our proposed solution:

  1. when the executable from that package is a Python script:
    • try to find an executable of the same name, this would be a win32 executable wrapper (this might not always be generated)
    • if no executable is found, try to launch the Python script with the Python executable
  2. when the executable from that package is a native executable (for example, .exe files on Windows), but no extension (e.g. .exe) is given
    • when a command is like $(find pkg)/exec, try to find an executable (exec.exe on Windows) of the same name

questions I asked myself:

is this the best fix?

not necessarily. since rosrun already does something very similar, this would create a separate logic from existing code. the actual right fix (imo) is to change commands like

$(find xacro)/xacro

to

rosrun xacro xacro

speaking of which, we're working on another pull request to create a Windows-version of rosrun. which just like the existing shell script, would be a batch script. however, it would probably be helpful to Python-ize rosrun in the future so we/ROS only need to maintain one code base across all platforms.

is this fix still needed? can't we just change those commands to use rosrun?

I believe so (that's why we're still sending this out =) ), the reasons are as follows:

  • we don't know how the downstream packages are using the command attribute, it would be hard to find and fix them all
  • there is possibility that people might be trying to use some executable from a specific location instead of a ROS package, so rosrun cannot be used, and for some reason, still don't want to add .exe extension, maybe for better portability across platforms. in this case, it would be helpful if roslaunch could search for an executable of the same name under the same directory

Sean Yen and others added 4 commits February 22, 2019 10:37
* rework shell=True for Windows change

* remove .exe handling, prepend python for python scripts instead

* update Windows search logic

* move comments around and remove unnecessary comments

* minor refactor

* file is a keyword in python2, rename as f

* remove unnecessary \ at the end of line
@kejxu
Copy link
Contributor Author

kejxu commented Feb 22, 2019

I checked CI log, but not exactly sure about why the build failed. is there anything specific I should check for?

@dirk-thomas
Copy link
Member

@ros-pull-request-builder retest this please

tools/roslaunch/src/roslaunch/loader.py Outdated Show resolved Hide resolved
tools/roslaunch/src/roslaunch/loader.py Outdated Show resolved Hide resolved
@kejxu
Copy link
Contributor Author

kejxu commented Mar 5, 2019

just pinging on this thread =) is there any change we would need to make?

@dirk-thomas
Copy link
Member

Thank you for the patch.

@dirk-thomas dirk-thomas merged commit 64c9af6 into ros:melodic-devel Mar 16, 2019
@kejxu kejxu deleted the change_how_commands_are_executed branch March 18, 2019 16:04
tahsinkose pushed a commit to tahsinkose/ros_comm that referenced this pull request Apr 15, 2019
* Use non-posix way to split command string.

* Use shell feature for roslaunch command.

* Resolved the merge again.

* rework shell=True for Windows change (ros#51)

* rework shell=True for Windows change

* remove .exe handling, prepend python for python scripts instead

* update Windows search logic

* move comments around and remove unnecessary comments

* minor refactor

* file is a keyword in python2, rename as f

* remove unnecessary \ at the end of line

* use sys.executable to launch Python interpreter

* follow inline comment style in PEP8

* invert logic
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants