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

updated PYTHON_INSTALL_DIR generation #831

Closed
wants to merge 1 commit into from

Conversation

dirk-thomas
Copy link
Member

Replaces #636.

@ros/ros_team Since this significantly affects the core I would like to have some feedback. Not only but especially on the following thought:

  • It is a significant change. But it has been a long standing issue blocking some platforms. I would target Kinetic only for this patch.
  • Invoking Python will be an overhead which we avoided before. I just don't see a better way to make this work consistently across Linux, OS X, Windows, Gentoo / Arch.....
  • I tried to maintain the semantic of other variables like SETUPTOOLS_ARG_EXTRA.

Copy link
Member

@wjwwood wjwwood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could imagine a different way of handling this:

  • have a cmake file that finds the PYTHON_EXECUTABLE and calculates the PYTHON_INSTALL_DIR
  • execute this cmake file in a temporary directory with the build tool, extract the PYTHON_EXECUTABLE and PYTHON_INSTALL_DIR as a tuple
  • pass this "precomputed" tuple to each catkin package over the command line
  • in the cmake/python.cmake file:
    • find the PYTHON_EXECUTABLE
    • check for a PYTHON_INSTALL_DIR for that exec in the "precomputed" tuples passed on the command line
    • otherwise have the package calculate PYTHON_INSTALL_DIR using the file described above in the first bullet

This way you can avoid the costly call to python in each package by precomputing with the build tool, but without the risk of giving an incorrect PYTHON_INSTALL_DIR due to tool and cmake using different python executables. Also the packages retain the ability to function without the tool. This also avoids having the logic to calculate this code being duplicated in both cmake and python (regardless of how simple it is).

OUTPUT_VARIABLE _var
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT _res EQUAL 0)
message(FATAL_ERROR "Determine PYTHON_INSTALL_DIR failed")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Failed to determine the PYTHON_INSTALL_DIR" or "Determining the PYTHON_INSTALL_DIR failed"?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

# setuptools is fussy about windows paths, make sure the install prefix is in native format
file(TO_NATIVE_PATH "${CMAKE_INSTALL_PREFIX}" SETUPTOOLS_INSTALL_PREFIX)
set(PYTHON_INSTALL_DIR "${_var}"
CACHE INTERNAL "This needs to be in PYTHONPATH when 'setup.py install' is called. And it needs to match. But setuptools won't tell us where it will install things.")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It needs to match what? And what purpose does the stuff about setuptools serve. I don't understand these parts of the variable description. I think it either needs to be more specific or maybe just leave this stuff out.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The message was just moved around in the patch but I shortened it to avoid any confusion.

set(_PYTHON_PATH_VERSION_SUFFIX "${PYTHON_VERSION_MAJOR}")
# this block determines the same value as the Python function get_python_install_dir() from python/catkin/builder.py
if(NOT DEFINED PYTHON_INSTALL_DIR)
execute_process(COMMAND "${PYTHON_EXECUTABLE}"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a feeling (no evidence) that this will have a pretty large impact on build times in workspaces with lots of packages. Can we change catkin_make and catkin_make_isolated to calculate this and pass it to cmake to avoid this extra call to Python, or is that already happening?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

catkin_make will only process this once since all packages share the same context.

catkin_make_isolated (as well as catkin build) will have the cost of an extra Python invocation. The tool can decide to pass in that value (which will put it in the cache) to avoid the computation. Anyway I don't plan to add that to cmi. The tool would then also need to make sure that it sets a patching path if its using a different Python version then detected in CMake (related to your other comment https://github.com/ros/catkin/pull/831/files#r84345010).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be easier for a tool to support this if the checking to make sure the python executables match is done in this cmake code, i.e. passing PYTHON_EXECUTABLE:PYTHON_INSTALL_DIR rather than just PYTHON_INSTALL_DIR from the tool. It is very difficult for the tool to determine if it has the same PYTHON_EXECUTABLE as this cmake code and since this CMake logic cannot be run separately (at least in its current configuration) the tool cannot do anything to resolve the mismatch if/when it was detected.

My suggestion would be to:

  • separate the logic that calculates the PYTHON_EXECUTABLE and the PYTHON_INSTALL_DIR into a separate CMake file so it can be reused
    • this would allow the tool to make sure it is using the same PYTHON_EXECUTABLE and therefore PYTHON_INSTALL_DIR as the package will be using in most cases
      • this allows us to avoid the extra python invocation, without this I think it leaves a clear con for this pr (increased build time)
    • prevent the issue where the PYTHONPATH and installed subdirectory disagree
      • though I agree that this not the responsibility of this pr to solve, it is a nice benefit
  • add some code here to handle the PYTHON_EXECUTABLE:PYTHON_INSTALL_DIR tuple input
    • protects the individual package from any unforeseen mismatches when the tool is attempting to precompute the PYTHON_INSTALL_DIR for the package
      • again this wouldn't be necessary if this pr didn't introduce an additional call to python, so I see it as in scope to provide a mechanism to mitigate that drawback

I can help implement the changes, but I think they're pretty important to consider and possibly get in before merging the other changes (which introduce the extra Python call).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you could write a PR for this enhancement that would be great.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that this pr covers the changes: #832

I didn't find a need to refactor the python.cmake file after all. I can just call it with cmake in script mode and extract the information from the existing I/O. It is a bit fragile in that a change in the structure of that output could break the Python code, but it is covered in tests, so the tests would start failing in that case.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order to ensure that the tool and CMake "agree" on the same location the patch still needs to pass the command line argument for -DPYTHON_EXECUTABLE to the Python functions, right?

Copy link
Member

@wjwwood wjwwood Oct 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. The above pr fixes one case, i.e. where the tool is using one version of Python but cmake finds another and the users is not using any cmake arguments to affect the process. It does not address any case where the user affects the version that cmake finds using variables like PYTHON_VERSION or PYTHON_EXECUTABLE. To cover those, the build tool needs to pass any extra cmake arguments to the new Python functions (which is the purpose of the cmake_args parameters that were added to those functions).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason I didn't take the last step was that I didn't know if naively passing all the user provided cmake arguments to this function would work or if they needed to be intelligently pruned for just options that affect Python version selection. Also it seemed like a good stopping point for the afternoon (so I can work on some other stuff). I can try to pass along the user defined cmake args to these functions and see if that works fine, but it will probably be next week.

@@ -287,17 +288,8 @@ def get_multiarch():

def get_python_install_dir():
# this function returns the same value as the CMake variable PYTHON_INSTALL_DIR from catkin/cmake/python.cmake
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the tool is invoked with a different python executable than the one found in PYTHON_EXECUTABLE in cmake?

I can imagine, that if the tool is using Python3 and then the CMake code find_package(PythonInterp) finds Python2, the code will be installed to something like <prefix>/lib/python2.7/site-packages but the path <prefix>/lib/python3.5/site-packages would be added to the PYTHONPATH using the setup file which is generated elsewhere in this file.

Or maybe this function is really only about getting site-packages versus dist-packages?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Python version of the tool calling cmake is not relevant for this. CMake will make a choice and use it throughout the process. So whatever is chosen in CMake (which can be influenced by passing PYTHON_VERSION) decides the install path for Python code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the python code here is actually called by CMake and not the build tool?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is used here:

https://github.com/ros/catkin/blob/kinetic-devel/python/catkin/builder.py#L602

And that is used to generate a setup file here:

https://github.com/ros/catkin/blob/kinetic-devel/python/catkin/builder.py#L641

So maybe it only affects catkin_make_isolated in non-merged spaces, but I still think it could result in the PYTHONPATH pointing to one place and the code getting installed to another.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The build tool is also using get_python_install_dir in order to do additional stuff, e.g. generating additional environment variables. So the constraint that the Python versions needs to match is still the case. But I don't think that this is affected in any way by this patch. It was the case before as well as after this change.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's true, but it was related to potentially avoiding every package calling python itself by having the tool compute it once and pass it on the command line.

@nikonikolov
Copy link

Hi sorry for the very, late reaction. I tried this on Slackware 14.2 but it still does not seem to be working - on 64 bit OS packages are installed in both lib and lib64 - as mentioned in ros-infrastructure/catkin_pkg#153. Just wanted to make sure I am doing it correctly - I substituted my ~/ros_catkin_ws/src/catkin with the contents of this branch, removed any installed packages to ensure clean build and invoked ./src/catkin/bin/catkin_make_isolated --install -DCMAKE_BUILD_TYPE=Release. Or should I pass other command line arguments too?

@dirk-thomas
Copy link
Member Author

I will set the milestone to "untargeted" for now until @wjwwood will have a chance to continue implementing the approach he described above.

@dirk-thomas dirk-thomas added this to the untargeted milestone Jan 25, 2017
@wjwwood
Copy link
Member

wjwwood commented Jan 25, 2017

@nikonikolov I think that you could instead test the contents of #832 to see if it would work. I'm not sure what I'm doing there would be necessary for your fix or not.

@allenh1
Copy link
Contributor

allenh1 commented Jun 5, 2017

Hey, what's the status of this issue/is it going to be resolved?

@wjwwood
Copy link
Member

wjwwood commented Jun 5, 2017

I have not had time to implement the fix I described. I don't think I'll have time to do it in the near future.

@wjwwood
Copy link
Member

wjwwood commented Jun 5, 2017

See: #831 (comment) and the following comment for what needs to be done still.

@dirk-thomas
Copy link
Member Author

Closing due to inactivity.

@dirk-thomas dirk-thomas removed this from the untargeted milestone Aug 12, 2019
@dirk-thomas dirk-thomas deleted the replace_636 branch November 11, 2019 19:15
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.

None yet

4 participants