On 07/22/2010 09:18 AM, Alan W. Irwin wrote: > On 2010-07-22 03:09+0200 Michael Hertling wrote: > >> In summary, my point is: Even if the loops are swapped, we wouldn't get >> a solution that works well in real-world scenarios so I doubt if it's >> worth the effort [...]. > > Hi Michael: > > I think find issues are a really important topic so I am glad you are > adding so much to the discussion. > > Although I agree with much of what you say, in this particular case I > believe your above premise is too general, and you have therefore > drawn an incorrect conclusion. PLplot and other software packages > with CMake-based build systems have run into a number of real-world > Find issues that would be solved if 10718 were fixed. [...]
Wouldn't they be solved if the find modules were fixed instead of 10718? > [...] Obviously, this > fix does not deal with the same-directory case, but at least the fix > limits find issues to just that case alone, and I believe that > simplification is well worth having. > > Assuming 10718 gets fixed, then one possibility for dealing with the > same-directory case is to simply publicize this is a well-known find > issue with current CMake find modules and leave it at that. That > "solution" certainly has the merit of simplicity and only fails for > the rare case where an older version is desired that resides in the > same directory as a later version (assuming the NAMES are ordered from > newest to oldest version). Particularly in regard to Python, I'm not sure if a solution to the same-directory case should be dropped just like that. Thanks to the systematically versioned vital components - interpreter, libraries, library subdirectory and include directory - Python is predestined to allow multiple installations under the same prefix. Now, from a user's point of view, I would greatly appreciate an opportunity to say FIND_PACKAGE(Python 2.5 EXACT ...), and vice versa, I would be greatly displeased if this attempt fails, despite of 2.5 installed and even mentioned after NAMES, because of the mere 2.6 presence. >> [...] one should >> prefer to improve the find modules and get rid of those non-equivalent >> alternatives after the NAMES option, in particular hardcoded version >> lists, and freshly developed modules should use FIND_PACKAGES()'s >> version interface right from the beginning. > > This certainly sounds promising for dealing with the same-directory > case. However, although the version interface appears in the usual > documentation, I cannot find a single example of a > <config-file>Version.cmake file. Am I missing something or is there > no practical demonstration of the version interface for any Find > module included with CMake? As MW already pointed out, these version files aren't relevant to the search for Python until GvR switches over to CMake. ;) > Until there is a practical demonstration of the version interface it > is hard to be sure this is the solution we should recommend for all > find modules. Therefore, would you be willing to create a simple > project demonstrating your idea and share it with this list? > > The simple project I have in mind would consist of a single Python > find module (the usual boiler plate + three find commands) which did > essentially nothing but find the (versioned) python interpreter, > header file directory, and library under the version interface; the > accompanying file mentioned in the documentation to support the > version interface; and a single CMakeLists.txt file consisting of ~10 > lines which specified the location of that find module (and version > interface support file); allowed the user the option of setting the > python version to anything they liked (e.g., nothing, 2, 2.5, 2.6, 3, > etc.); and used find_package to find and print out the appropriate > Python interpreter, header file directory, and library for the > user-specified version. Look at CMakeLists.txt and FindPython.cmake in the attachment. To prevent further references to John Ronald Reuel T.: This finder is neither fully-featured nor production-ready, and it also doesn't claim to be the most beautiful piece of code ever written; furthermore, it is targeted at *nix and most probably won't run on another platform out of the box. Instead, it's just meant to outline a possible approach how to use FIND_PACKAGE()'s version interface to locate a Python installation without relying on hardcoded version numbers or an interpreter which possibly cannot run on the current system. Remarks: - PYTHON_NATIVE indicates whether the interpreter may by invoked. - Requesting "Python" without version means searching for an unversioned interpreter and the highest versioned library unless PYTHON_NATIVE is true which means querying the interpreter for its accompanying library; the former may possibly result in inconsistent interpreter/library combinations. - Requesting "Python 2" means searching for the highest Python 2 but not 3; EXACT doesn't matter here. - Requesting "Python 2.5" means searching for the highest Python 2 but at least 2.5 and not 3. - Requesting "Python 2.5 EXACT" means searching for the highest Python 2.5 but not 2.6 or higher or 3. - Requesting "Python 2.5.4" means searching for the highest Python 2 but at least 2.5.4 and not 3; without PYTHON_NATIVE, this may fail as the interpreter is necessary to check for a three-digit version. - Requesting "Python 2.5.4 EXACT" means searching for Python 2.5.4; without PYTHON_NATIVE, this fails for the same reason as above. - GET_LIBRARY_PATH() is of general purpose and could be transferred to a module of its own, possibly along with a GET_PROGRAM_PATH() etc. - Components aren't recognized, but this shouldn't be hard to implement. Regards, Michael
# CMakeLists.txt: # Call with -DVERSION=[...] -DEXACT=[Y/N] -DPYTHON_NATIVE=[Y/N] CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR) PROJECT(FINDPYTHON NONE) SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}") IF(EXACT) SET(EXACT "EXACT") ELSE() SET(EXACT "") ENDIF() FIND_PACKAGE(Python ${VERSION} ${EXACT}) MESSAGE("PYTHON_EXECUTABLE: ${PYTHON_EXECUTABLE}") MESSAGE("PYTHON_LIBRARY: ${PYTHON_LIBRARY}") MESSAGE("PYTHON_INCLUDE_DIR: ${PYTHON_INCLUDE_DIR}") MESSAGE("PYTHON_FOUND: ${PYTHON_FOUND}")
# FindPython.cmake: # PYTHON_NATIVE indicates an executable Python interpreter. # Get FIND_LIBRARY()'s search path: FUNCTION(GET_LIBRARY_PATH PATH) UNSET(p) FOREACH(i IN LISTS CMAKE_PREFIX_PATH) LIST(APPEND p ${i}/lib) ENDFOREACH() FOREACH(i IN LISTS CMAKE_LIBRARY_PATH CMAKE_FRAMEWORK_PATH) LIST(APPEND p ${i}) ENDFOREACH() SET(CMAKE_PREFIX_PATH_ENV $ENV{CMAKE_PREFIX_PATH}) FOREACH(i IN LISTS CMAKE_PREFIX_PATH_ENV) LIST(APPEND p ${i}/lib) ENDFOREACH() SET(CMAKE_LIBRARY_PATH_ENV $ENV{CMAKE_LIBRARY_PATH}) SET(CMAKE_FRAMEWORK_PATH_ENV $ENV{CMAKE_FRAMEWORK_PATH}) FOREACH(i IN LISTS CMAKE_LIBRARY_PATH_ENV CMAKE_FRAMEWORK_PATH_ENV) LIST(APPEND p ${i}) ENDFOREACH() SET(PATH_ENV $ENV{PATH}) STRING(REGEX REPLACE ":" ";" PATH_ENV ${PATH_ENV}) SET(LIB_ENV $ENV{LIB}) FOREACH(i IN LISTS PATH_ENV LIB_ENV) LIST(APPEND p ${i}) ENDFOREACH() FOREACH(i IN LISTS CMAKE_SYSTEM_PREFIX_PATH) LIST(APPEND p ${i}/lib) ENDFOREACH() FOREACH(i IN LISTS CMAKE_SYSTEM_LIBRARY_PATH CMAKE_SYSTEM_FRAMEWORK_PATH) LIST(APPEND p ${i}) ENDFOREACH() # To be enhanced: HINTS/PATHS, NO_..._PATH, CMAKE_FIND_ROOT_PATH etc. SET(${PATH} ${p} PARENT_SCOPE) ENDFUNCTION() # Search the highest Python version according to GLOBEXPR: FUNCTION(GET_PYTHON_VERSION VERSION GLOBEXPR) SET(v "0") FOREACH(i IN LISTS ARGN) FILE(GLOB j ${i}/python${GLOBEXPR}) FOREACH(k IN LISTS j) IF(k MATCHES "python[0-9][0-9.]*\$") STRING(REGEX REPLACE "^.*python([0-9][0-9.]*)\$" "\\1" k ${k}) IF(k VERSION_GREATER v) SET(v ${k}) ENDIF() ENDIF() ENDFOREACH() ENDFOREACH() SET(${VERSION} ${v} PARENT_SCOPE) ENDFUNCTION() # Query Python interpreter for library: FUNCTION(QUERY_PYTHON_LIBRARY PATHS NAME INTERPRETER) EXECUTE_PROCESS( COMMAND ${INTERPRETER} -c " import distutils.sysconfig; print(distutils.sysconfig.get_config_var('LIBDIR') +';'+distutils.sysconfig.get_config_var('LIBPL'))" OUTPUT_VARIABLE p OUTPUT_STRIP_TRAILING_WHITESPACE ) EXECUTE_PROCESS( COMMAND ${INTERPRETER} -c " import distutils.sysconfig; print('python'+distutils.sysconfig.get_config_var('VERSION'))" OUTPUT_VARIABLE n OUTPUT_STRIP_TRAILING_WHITESPACE ) SET(${PATHS} ${p} PARENT_SCOPE) SET(${NAME} ${n} PARENT_SCOPE) ENDFUNCTION() # Query Python interpreter for include directory: FUNCTION(QUERY_PYTHON_INCLUDE_DIR PATH INTERPRETER) EXECUTE_PROCESS( COMMAND ${INTERPRETER} -c " import distutils.sysconfig; print(distutils.sysconfig.get_config_var('INCLUDEPY'))" OUTPUT_VARIABLE p OUTPUT_STRIP_TRAILING_WHITESPACE ) SET(${PATH} ${p} PARENT_SCOPE) ENDFUNCTION() # Query Python interpreter for version: FUNCTION(QUERY_PYTHON_VERSION VERSION INTERPRETER) EXECUTE_PROCESS( COMMAND ${INTERPRETER} -c "import sys; print(sys.version)" OUTPUT_VARIABLE v OUTPUT_STRIP_TRAILING_WHITESPACE ) STRING(REGEX REPLACE "^([^ ]*) .*\$" "\\1" v ${v}) SET(${VERSION} ${v} PARENT_SCOPE) ENDFUNCTION() # For convenience: SET(MAJVER "${Python_FIND_VERSION_MAJOR}") SET(MINVER "${Python_FIND_VERSION_MINOR}") GET_LIBRARY_PATH(LIBPATH) UNSET(EXEVER) # Python interpreter version to search UNSET(LIBVER) # Python library version to search # Set up EXEVER/LIBVER from Python_FIND_VERSION et al.: IF(NOT DEFINED Python_FIND_VERSION_COUNT) SET(EXEVER "") # Search for unversioned interpreter. IF(NOT PYTHON_NATIVE) # Search most recent libraries w/o querying: GET_PYTHON_VERSION(VERSION *.* ${LIBPATH}) IF(VERSION) SET(LIBVER ${VERSION}) ENDIF() ENDIF() ELSEIF(Python_FIND_VERSION_COUNT EQUAL 1) # EXACT doesn't matter here. GET_PYTHON_VERSION(VERSION ${MAJVER}.* ${LIBPATH}) IF(VERSION) SET(EXEVER ${VERSION}) IF(NOT PYTHON_NATIVE) SET(LIBVER ${EXEVER}) ENDIF() ENDIF() ELSE() IF(Python_FIND_VERSION_EXACT) GET_PYTHON_VERSION(VERSION ${MAJVER}.${MINVER} ${LIBPATH}) IF(VERSION AND (Python_FIND_VERSION_COUNT EQUAL 2 OR PYTHON_NATIVE)) SET(EXEVER ${VERSION}) IF(NOT PYTHON_NATIVE) SET(LIBVER ${EXEVER}) ENDIF() # Else: Not found or unacceptable. ENDIF() ELSE() GET_PYTHON_VERSION(VERSION ${MAJVER}.* ${LIBPATH}) IF(VERSION AND (NOT VERSION VERSION_LESS Python_FIND_VERSION OR (VERSION VERSION_EQUAL ${MAJVER}.${MINVER} AND PYTHON_NATIVE))) SET(EXEVER ${VERSION}) IF(NOT PYTHON_NATIVE) SET(LIBVER ${EXEVER}) ENDIF() # Else: Not found or unacceptable. ENDIF() ENDIF() ENDIF() # Search interpreter: IF(DEFINED EXEVER) FIND_PROGRAM(PYTHON_EXECUTABLE python${EXEVER}) ENDIF() # Search library and include directory: IF(PYTHON_NATIVE AND PYTHON_EXECUTABLE) QUERY_PYTHON_LIBRARY(PATHS NAME ${PYTHON_EXECUTABLE}) FIND_LIBRARY(PYTHON_LIBRARY ${NAME} PATHS ${PATHS} NO_DEFAULT_PATH) QUERY_PYTHON_INCLUDE_DIR(PATH ${PYTHON_EXECUTABLE}) FIND_PATH(PYTHON_INCLUDE_DIR Python.h PATHS ${PATH} NO_DEFAULT_PATH) ELSEIF(DEFINED LIBVER) FIND_LIBRARY(PYTHON_LIBRARY python${LIBVER}) FIND_LIBRARY(PYTHON_LIBRARY python${LIBVER} PATH_SUFFIXES python${LIBVER}/config) FIND_PATH(PYTHON_INCLUDE_DIR Python.h PATH_SUFFIXES python${LIBVER}) ENDIF() # Check version: IF(PYTHON_EXECUTABLE AND Python_FIND_VERSION_COUNT GREATER 1) IF(Python_FIND_VERSION_EXACT) IF(Python_FIND_VERSION_COUNT GREATER 2) QUERY_PYTHON_VERSION(VERSION ${PYTHON_EXECUTABLE}) IF(NOT VERSION VERSION_EQUAL Python_FIND_VERSION) UNSET(PYTHON_EXECUTABLE CACHE) UNSET(PYTHON_EXECUTABLE) ENDIF() ENDIF() ELSE() IF(EXEVER VERSION_LESS Python_FIND_VERSION) QUERY_PYTHON_VERSION(VERSION ${PYTHON_EXECUTABLE}) IF(VERSION VERSION_LESS Python_FIND_VERSION) UNSET(PYTHON_EXECUTABLE CACHE) UNSET(PYTHON_EXECUTABLE) ENDIF() ENDIF() ENDIF() ENDIF() # Finish: INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS( PYTHON DEFAULT_MSG PYTHON_EXECUTABLE PYTHON_LIBRARY PYTHON_INCLUDE_DIR )
_______________________________________________ Powered by www.kitware.com Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ Follow this link to subscribe/unsubscribe: http://www.cmake.org/mailman/listinfo/cmake