BASIS  r3148
FindPythonModules.cmake
Go to the documentation of this file.
00001 ##############################################################################
00002 # @file  FindPythonModules.cmake
00003 # @brief Find Python modules.
00004 #
00005 # @par Input/Output variables:
00006 # <table border="0">
00007 #   <tr>
00008 #     @tp @b PythonModules_DIR @endtp
00009 #     <td>List of directories where Python modules are installed.</td>
00010 #   </tr>
00011 # </table>
00012 
00013 # @par Input variables:
00014 # <table border="0">
00015 #   <tr>
00016 #     @tp @b PythonModules_FIND_COMPONENTS @endtp
00017 #     <td>The @c COMPONENTS argument(s) of the find_package() command specifies
00018 #         the names of the Python modules to look for.</td>
00019 #   </tr>
00020 #   <tr>
00021 #     @tp @b PythonModules_FIND_OPTIONAL_COMPONENTS @endtp
00022 #     <td>The @c OPTIONAL_COMPONENTS argument(s) of the find_package() command
00023 #         specifies the names of the Python modules which are not necessarily
00024 #         required, but should be searched as well.</td>
00025 #   </tr>
00026 #   <tr>
00027 #     @tp @b PYTHON_EXECUTABLE @endtp
00028 #     <td>Path to the Python interpreter. Should be set by first looking
00029 #         for the Python interpreter, i.e., find_packages(PythonInterp).
00030 #         If set, this module first tries to execute the Python interpreter,
00031 #         import the respective Python module, and then derive the search path
00032 #         from the @c __file__ attribute of the loaded Python module.
00033 #         Otherwise, or if this fails, it looks either for a package
00034 #         @c __init__.py file inside a subdirectory named after the specified
00035 #         Python module or a @c .py module file in each directory listed in
00036 #         the @c PYTHONPATH.</td>
00037 #   </tr>
00038 #   <tr>
00039 #     @tp @b PYTHONPATH @endtp
00040 #     <td>Search path for Python modules. If this CMake variable is undefined,
00041 #         the corresponding environment variable is used instead if set.
00042 #         Only absolute paths in the @c PYTHONPATH are considered.</td>
00043 #   </tr>
00044 # </table>
00045 #
00046 # @par Output variables:
00047 # <table border="0">
00048 #   <tr>
00049 #     @tp @b PythonModules_FOUND @endtp
00050 #     <td>Whether all specified Python modules were found.</td>
00051 #   </tr>
00052 #   <tr>
00053 #     @tp @b PythonModules_&lt;module&gt;_FOUND @endtp
00054 #     <td>Whether the Python module &lt;module%gt; was found.</td>
00055 #   </tr>
00056 #   <tr>
00057 #     @tp @b PythonModules_&lt;module&gt;_PATH @endtp
00058 #     <td>Absolute path of the directory containing the Python module named &lt;module%gt;.</td>
00059 #   </tr>
00060 #   <tr>
00061 #     @tp @b PythonModules_&lt;module&gt; @endtp
00062 #     <td>Import target for module named &lt;module&gt;. The location of the
00063 #         target is @c PythonModules_&lt;module&gt_PATH.</tr>
00064 #   </tr>
00065 #   <tr>
00066 #     @tp @b PythonModules_PYTHONPATH @endtp
00067 #     <td>The @c PYTHONPATH setting required for the found Python module(s), i.e.,
00068 #         The directories that have to be added to the Python search path.
00069 #         To support the use of this CMake module more than once with different
00070 #         arguments to the find_package() command, e.g., with and without the
00071 #         @c REQUIRED argument, the directories containing the found Python
00072 #         modules are appended to any existing directories in
00073 #         @c PythonModules_PYTHONPATH if not already listed.</td>
00074 #   </tr>
00075 # </table>
00076 #
00077 # @ingroup CMakeFindModules
00078 ##############################################################################
00079 
00080 include (CMakeParseArguments)
00081 
00082 # ----------------------------------------------------------------------------
00083 ## @brief Find Python module.
00084 #
00085 # If the @c PYTHON_EXECUTABLE variable is set, this function at first tries
00086 # to launch the Python interpreter, import the named Python module, and then
00087 # determines the search path for the Python module from the @c __file__
00088 # attribute of the loaded module. Otherwise, or if this fails, it looks for
00089 # the Python module in the directories listed in the @c PYTHONPATH variable
00090 # if defined. If this variable is not defined, the @c PYTHONPATH environment
00091 # variable is used instead.
00092 #
00093 # @param [in] CACHEVAR Name of CMake cache variable which stores path of
00094 #                      directory of the Python module. If not set or if
00095 #                      the cache entry contains space characters only or
00096 #                      ends in the string NOTFOUND, this function looks for
00097 #                      the specified Python module. Otherwise, it does nothing
00098 #                      and leaves the cache entry unmodified.
00099 # @param [in] ARGN     The remaining arguments are parsed and the following
00100 #                      options extract:
00101 # @par
00102 # <table border=0>
00103 #   <tr>
00104 #     @tp @b NAME module @endtp
00105 #     <td>Name of the Python module.</td>
00106 #   </tr>
00107 #   <tr>
00108 #     @tp @b PYTHON_EXECUTABLE python @endtp
00109 #     <td>Full path of the Python interpreter executable. If not specified
00110 #         the global PYTHON_EXECUTABLE CMake variable/cache entry is used.</td>
00111 #   </tr>
00112 #   <tr>
00113 #     @tp @b PATH dir1 [dir2...] @endtp
00114 #     <td>Directories where to look for Python module.</td>
00115 #   </tr>
00116 #   <tr>
00117 #     @tp @b NO_PYTHONPATH @endtp
00118 #     <td>Do not consider the @c PYTHONPATH environment variable.</td>
00119 #   </tr>
00120 #   <tr>
00121 #     @tp @b NO_DEFAULT_PATH @endtp
00122 #     <td>Do not look in any default path such as the directories listed by the
00123 #         @c PYTHONPATH environment variable.</td>
00124 #   </tr>
00125 # </table>
00126 #
00127 # @returns Sets the named cache variable of type @c PATH to the absolute path
00128 #          of the directory containing the specified Python @p MODULE if found,
00129 #          or the string "&lt;MODULE%gt;-NOTFOUND" otherwise.
00130 function (basis_find_python_module CACHEVAR)
00131   # do nothing if path of module already known from previous run
00132   if (DEFINED ${CACHEVAR} AND NOT ${CACHEVAR} MATCHES "NOTFOUND$")
00133     return ()
00134   endif ()
00135   # parse arguments
00136   CMAKE_PARSE_ARGUMENTS (
00137     ARGN
00138       "NO_DEFAULT_PATH;NO_PYTHONPATH"
00139       "PYTHON_EXECUTABLE;NAME"
00140       "PATH"
00141       ${ARGN}
00142   )
00143   if (NOT ARGN_NAME)
00144     message ("basis_find_python_module(): Missing NAME argument!")
00145   endif ()
00146   if (ARGN_UNPARSED_ARGUMENTS)
00147     message ("basis_find_python_module(): Invalid arguments: ${ARGN_UNPARSED_ARGUMENTS}")
00148   endif ()
00149   if (NOT ARGN_PYTHON_EXECUTABLE)
00150     set (ARGN_PYTHON_EXECUTABLE "${PYTHON_EXECUTABLE}")
00151   endif ()
00152   if (ARGN_NO_DEFAULT_PATH)
00153     set (ARGN_NO_PYTHONPATH TRUE)
00154     set (ARGN_PYTHON_EXECUTABLE)
00155   endif ()
00156   # set initial value of cache entry
00157   if (${CACHEVAR} MATCHES "^ *$")
00158     set (${CACHEVAR} "${ARGN_NAME}-NOTFOUND" CACHE PATH "Directory containing ${ARGN_NAME} Python module/package." FORCE)
00159   else ()
00160     set (${CACHEVAR} "${ARGN_NAME}-NOTFOUND" CACHE PATH "Directory containing ${ARGN_NAME} Python module/package.")
00161   endif ()
00162   # 1. search specified paths
00163   foreach (P ${ARGN_PATH}) # ignore empty entries
00164     if (IS_ABSOLUTE "${P}")
00165       if (EXISTS "${P}/${ARGN_NAME}.py"  OR EXISTS "${P}/${ARGN_NAME}/__init__.py" OR
00166           EXISTS "${P}/${ARGN_NAME}.pyc" OR EXISTS "${P}/${ARGN_NAME}/__init__.pyc")
00167         set_property (CACHE ${CACHEVAR} PROPERTY VALUE "${P}")
00168         return ()
00169       endif ()
00170     endif ()
00171   endforeach ()
00172   # 2. get __file__ attribute of module loaded in Python
00173   if (ARGN_PYTHON_EXECUTABLE)
00174     set (IMPORT_SITE_ERROR FALSE)
00175     # 2a. try it with -E option -- the preferred way to run Python
00176     execute_process (
00177       COMMAND "${ARGN_PYTHON_EXECUTABLE}" -E -c "import ${ARGN_NAME}; print ${ARGN_NAME}.__file__"
00178       RESULT_VARIABLE STATUS
00179       OUTPUT_VARIABLE P
00180       ERROR_VARIABLE  ERROR
00181       OUTPUT_STRIP_TRAILING_WHITESPACE
00182     )
00183     if (ERROR MATCHES "'import site' failed|ImportError: No module named site")
00184       set (IMPORT_SITE_ERROR TRUE)
00185     endif ()
00186     # 2b. try it without -E option
00187     if (NOT STATUS EQUAL 0)
00188       execute_process (
00189         COMMAND "${ARGN_PYTHON_EXECUTABLE}" -c "import ${ARGN_NAME}; print ${ARGN_NAME}.__file__"
00190         RESULT_VARIABLE STATUS
00191         OUTPUT_VARIABLE P
00192         ERROR_VARIABLE  ERROR
00193         OUTPUT_STRIP_TRAILING_WHITESPACE
00194       )
00195       if (ERROR MATCHES "'import site' failed|ImportError: No module named site")
00196         set (IMPORT_SITE_ERROR TRUE)
00197       endif ()
00198       if (NOT STATUS EQUAL 0 AND ERROR MATCHES "ImportError: No module named site")
00199         set (PYTHONHOME "$ENV{PYTHONHOME}")
00200         unset (ENV{PYTHONHOME})
00201         execute_process (
00202           COMMAND "${ARGN_PYTHON_EXECUTABLE}" -c "import ${ARGN_NAME}; print ${ARGN_NAME}.__file__"
00203           RESULT_VARIABLE STATUS
00204           OUTPUT_VARIABLE P
00205           ERROR_VARIABLE  ERROR
00206           OUTPUT_STRIP_TRAILING_WHITESPACE
00207         )
00208         if (ERROR MATCHES "'import site' failed|ImportError: No module named site")
00209           set (IMPORT_SITE_ERROR TRUE)
00210         endif ()
00211         set (ENV{PYTHONHOME} "${PYTHONHOME}")
00212       endif ()
00213     endif ()
00214     if (STATUS EQUAL 0)
00215       if (P MATCHES "__init__\\.pyc?$")
00216         get_filename_component (P "${P}" PATH)
00217         get_filename_component (P "${P}" PATH)
00218       else ()
00219         get_filename_component (P "${P}" PATH)
00220       endif ()
00221       set_property (CACHE ${CACHEVAR} PROPERTY VALUE "${P}")
00222       return ()
00223     elseif (IMPORT_SITE_ERROR)
00224       message (WARNING "Import of site module failed when running Python interpreter ${ARGN_PYTHON_EXECUTABLE}"
00225                        " with and without -E option. Make sure that the Python interpreter is installed properly"
00226                        " and that the PYTHONHOME environment variable is either not set (recommended) or at"
00227                        " least set correctly for this Python installation. Maybe you need to enable this Python"
00228                        " version first somehow if more than one version of Python is installed on your system?"
00229                        " Otherwise, set PYTHON_EXECUTABLE to the right Python interpreter executable (python).")
00230     endif ()
00231   endif ()
00232   # 3. search PYTHONPATH
00233   if (NOT ARGN_NO_PYTHONPATH)
00234     string (REPLACE ":" ";" PYTHONPATH "$ENV{PYTHONPATH}")
00235     foreach (P ${PYTHONPATH}) # ignore empty entries
00236       if (IS_ABSOLUTE "${P}")
00237         if (EXISTS "${P}/${ARGN_NAME}.py"  OR EXISTS "${P}/${ARGN_NAME}/__init__.py" OR
00238             EXISTS "${P}/${ARGN_NAME}.pyc" OR EXISTS "${P}/${ARGN_NAME}/__init__.pyc")
00239           set_property (CACHE ${CACHEVAR} PROPERTY VALUE "${P}")
00240           return ()
00241         endif ()
00242       endif ()
00243     endforeach ()
00244   endif ()
00245 endfunction ()
00246 
00247 # ----------------------------------------------------------------------------
00248 # find Python modules
00249 if (NOT PythonModules_FIND_COMPONENTS AND NOT PythonModules_FIND_OPTIONAL_COMPONENTS)
00250   message (FATAL_ERROR "PythonModules: No (OPTIONAL_)COMPONENTS (i.e., Python module names) specified!")
00251 endif ()
00252 if (NOT DEFINED PythonModules_PYTHONPATH)
00253   set (PythonModules_PYTHONPATH) # PYTHONPATH of all found modules
00254 endif ()
00255 # helper macro
00256 macro (_PythonModules_find_python_modules ALL_FOUND)
00257   set (${ALL_FOUND} TRUE)
00258   foreach (_PythonModules_MODULE ${ARGN})
00259     set (_PythonModules_VAR "PythonModules_${_PythonModules_MODULE}_PATH")
00260     set (_PythonModules_TGT "PythonModules_${_PythonModules_MODULE}")
00261     if (PythonModules_DIR)
00262       basis_find_python_module (
00263         ${_PythonModules_VAR}
00264         NAME "${_PythonModules_MODULE}"
00265         PATH "${PythonModules_DIR}"
00266         NO_DEFAULT_PATH
00267       )
00268     else ()
00269       basis_find_python_module (
00270         ${_PythonModules_VAR}
00271         NAME "${_PythonModules_MODULE}"
00272         PATH "${PythonModules_DIR}"
00273       )
00274     endif ()
00275     mark_as_advanced (${_PythonModules_VAR})
00276     if (${_PythonModules_VAR} MATCHES "(^ *|NOTFOUND)$")
00277       set (${ALL_FOUND}                                 FALSE)
00278       set (PythonModules_${_PythonModules_MODULE}_FOUND FALSE)
00279     else ()
00280       if (NOT TARGET ${_PythonModules_TGT})
00281         add_library (${_PythonModules_TGT} UNKNOWN IMPORTED)
00282         set_target_properties (
00283           ${_PythonModules_TGT}
00284           PROPERTIES
00285             BASIS_TYPE        "SCRIPT_LIBRARY"
00286             IMPORTED_LOCATION "${${_PythonModules_VAR}}"
00287         )
00288       endif ()
00289       set (PythonModules_${_PythonModules_MODULE}_FOUND TRUE)
00290       list (APPEND PythonModules_PYTHONPATH "${${_PythonModules_VAR}}")
00291     endif ()
00292   endforeach ()
00293 endmacro ()
00294 # optional first, as PythonModules_FOUND shall be reset to TRUE afterwards
00295 _PythonModules_find_python_modules (PythonModules_FOUND ${PythonModules_FIND_OPTIONAL_COMPONENTS})
00296 _PythonModules_find_python_modules (PythonModules_FOUND ${PythonModules_FIND_COMPONENTS})
00297 # remove duplicate paths in PYTHONPATH
00298 if (PythonModules_PYTHONPATH)
00299   list (REMOVE_DUPLICATES PythonModules_PYTHONPATH)
00300 endif ()
00301 
00302 # ----------------------------------------------------------------------------
00303 # handle standard QUIET and REQUIRED arguments
00304 if (NOT PythonModules_FOUND)
00305   # list of modules that were not found
00306   set (_PythonModules_MISSING)
00307   foreach (_PythonModules_MODULE ${PythonModules_FIND_COMPONENTS})
00308     if (NOT PythonModules_${_PythonModules_MODULE}_FOUND)
00309       list (APPEND _PythonModules_MISSING "${_PythonModules_MODULE}")
00310     endif ()
00311   endforeach ()
00312   # hint on how to help finding the Python modules
00313   set (_PythonModules_HINT)
00314   if (PYTHON_EXECUTABLE)
00315     set (_PythonModules_HINT "Check if executing ${PYTHON_EXECUTABLE} -c \"import <module>\" works")
00316   else ()
00317     set (_PythonModules_HINT "Set PYTHON_EXECUTABLE, e.g., by searching for Python interpreter first")
00318   endif ()
00319   if (_PythonModules_HINT)
00320     set (_PythonModules_HINT "${_PythonModules_HINT} or set")
00321   else ()
00322     set (_PythonModules_HINT "Set")
00323   endif ()
00324   set (_PythonModules_HINT "${_PythonModules_HINT} the PythonModules_DIR variable. Alternatively,")
00325   set (_PythonModules_HINT "${_PythonModules_HINT} set the PythonModules_<module>_PATH variable(s)")
00326   set (_PythonModules_HINT "${_PythonModules_HINT} instead or the PYTHONPATH environment variable.")
00327   set (_PythonModules_HINT "${_PythonModules_HINT} Unset PythonModules_DIR if you chose an alternative")
00328   set (_PythonModules_HINT "${_PythonModules_HINT} option and before rerunning CMake again.")
00329   # error message
00330   string (REPLACE ";" ", " ${_PythonModules_MISSING} "${_PythonModules_MISSING}")
00331   message (FATAL_ERROR "Could NOT find the following Python modules:\n${_PythonModules_MISSING}\n${_PythonModules_HINT}")
00332 endif ()
00333 
00334 # ----------------------------------------------------------------------------
00335 # common <Pkg>_DIR variable
00336 if (NOT PythonModules_DIR)
00337   set (
00338     PythonModules_DIR
00339       "${PythonModules_PYTHONPATH}"
00340     CACHE PATH
00341       "Directory or list of directories separated by ; of installed Python modules."
00342     FORCE
00343   )
00344 endif ()
00345 
00346 # ----------------------------------------------------------------------------
00347 # clean up
00348 unset (_PythonModules_MODULE)
00349 unset (_PythonModules_VAR)
00350 unset (_PythonModules_VARS)