[CMake] check for modules/packages in python and R

Mark Moll mmoll at cs.rice.edu
Fri Jun 11 15:04:17 EDT 2010


Attached is my initial attempt to check for the existence of python modules and R packages. 

In the case of python, I need to be able to check for a specific version of python (find corresponding executable, libraries, and headers) and check for modules in that version of python. This is not possible with the FindPythonInterp.cmake and FindPythonLibs.cmake. The location of modules is returned. I also return the location where new modules should be installed. 

The FindR module is much simpler, mostly because I know much less about R. I did add a function to install an R module in the default location for a user’s R packages, if it’s not already installed.

I realize this code is somewhat UNIX-biased, but perhaps adding Windows support is not too difficult. If anyone has ideas to improve this code, please let me know.
-- 
Mark


# This code sets the following variables:
# PYTHON_EXEC         - path to python executable
# PYTHON_LIBRARIES    - path to the python library
# PYTHON_INCLUDE_DIRS - path to where Python.h is found
# PTYHON_SITE_MODULES - path to site-packages
# PYTHON_ARCH         - name of architecture to be used for platform-specific 
#                       binary modules
# PYTHON_VERSION      - version of python
#
# You can optionally include the version number when using this package 
# like so:
#	find_package(python 2.6)
#
# This code defines a helper function find_python_module(). It can be used 
# like so:
#	find_python_module(numpy)
# If numpy is found, the variable PY_NUMPY contains the location of the numpy 
# module. If the module is required add the keyword "REQUIRED":
#	find_python_module(numpy REQUIRED)

find_program(PYTHON_EXEC "python${Python_FIND_VERSION}" 
	DOC "Location of python executable to use")
string(REGEX REPLACE "/bin/python${Python_FIND_VERSION}$" "" PYTHON_PREFIX
	"${PYTHON_EXEC}")
execute_process(COMMAND "${PYTHON_EXEC}" "-c"
	"import sys; print '%d.%d' % (sys.version_info[0],sys.version_info[1])"
	OUTPUT_VARIABLE PYTHON_VERSION
	OUTPUT_STRIP_TRAILING_WHITESPACE)
find_library(PYTHON_LIBRARIES "python${PYTHON_VERSION}" PATHS "${PYTHON_PREFIX}" 
	PATH_SUFFIXES "lib" "lib/python${PYTHON_VERSION}/config" 
	DOC "Python libraries" NO_DEFAULT_PATH)
find_path(PYTHON_INCLUDE_DIRS "Python.h"
	PATHS "${PYTHON_PREFIX}/include/python${PYTHON_VERSION}"
	DOC "Python include directories" NO_DEFAULT_PATH)
execute_process(COMMAND "${PYTHON_EXEC}" "-c" 
	"from distutils.sysconfig import get_python_lib; print get_python_lib()"
	OUTPUT_VARIABLE PYTHON_SITE_MODULES
	OUTPUT_STRIP_TRAILING_WHITESPACE)

function(find_python_module module)
	string(TOUPPER ${module} module_upper)
	if(NOT PY_${module_upper})
		if(ARGC GREATER 1 AND ARGV1 STREQUAL "REQUIRED")
			set(${module}_FIND_REQUIRED TRUE)
		endif()
		# A module's location is usually a directory, but for binary modules
		# it's a .so file.
		execute_process(COMMAND "${PYTHON_EXEC}" "-c" 
			"import re, ${module}; print re.compile('/__init__.py.*').sub('',${module}.__file__)"
			RESULT_VARIABLE _${module}_status 
			OUTPUT_VARIABLE _${module}_location
			ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
		if(NOT _${module}_status)
			set(PY_${module_upper} ${_${module}_location} CACHE STRING 
				"Location of Python module ${module}")
		endif(NOT _${module}_status)
	endif(NOT PY_${module_upper})
	find_package_handle_standard_args(PY_${module} DEFAULT_MSG PY_${module_upper})
endfunction(find_python_module)

set(PYTHON_ARCH "unknown")
if(APPLE)
	set(PYTHON_ARCH "darwin")
else(APPLE)
	if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
		if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
			set(PYTHON_ARCH "linux2")
		else(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
			set(PYTHON_ARCH "linux")
		endif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
	else(CMAKE_SYSTEM_NAME STREQUAL "Linux")
		if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
			set(PYTHON_ARCH "windows")
		endif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
	endif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
endif(APPLE)

find_package_handle_standard_args(Python DEFAULT_MSG 
	PYTHON_LIBRARIES PYTHON_INCLUDE_DIRS PYTHON_SITE_MODULES)


===============================================================

# This code sets the following variables
# R_EXEC      - path to R executable
# R_LIBS_USER - path to directory of user's R packages (defined only if R is found) 
#
# It also defines the following help functions if R is found:
# FIND_R_PACKAGE(package)            - sets R_<PACKAGE> to ON if package is installed 
# INSTALL_R_PACKAGE(package)         - installs package in ${R_LIBS_USER}
# FIND_OR_INSTALL_R_PACKAGE(package) - finds package and installs it, if not found

find_program(R_EXEC R)

if(R_EXEC)
	# R_LIBS_USER is always defined within R, even if it is not explicitly set by the user
	execute_process(COMMAND "${R_EXEC}" "--slave" "-e" 
		"print(Sys.getenv(\"R_LIBS_USER\"))"
		OUTPUT_VARIABLE _rlibsuser
		OUTPUT_STRIP_TRAILING_WHITESPACE)
	string(REGEX REPLACE "[ ]*(R_LIBS_USER)[ ]*\n\"(.*)\"" "\\2"
		R_LIBS_USER ${_rlibsuser})
	
	function(find_r_package package)
		string(TOUPPER ${package} package_upper)
		if(NOT R_${package_upper})
			if(ARGC GREATER 1 AND ARGV1 STREQUAL "REQUIRED")
				set(${package}_FIND_REQUIRED TRUE)
			endif()
			execute_process(COMMAND "${R_EXEC}" "--slave" "-e" 
				"library('${package}')"
				RESULT_VARIABLE _${package}_status 
				ERROR_QUIET OUTPUT_QUIET)
			if(NOT _${package}_status)
				set(R_${package_upper} TRUE CACHE BOOL 
					"Whether the R package ${package} is installed")
			endif(NOT _${package}_status)
		endif(NOT R_${package_upper})
		find_package_handle_standard_args(R_${package} DEFAULT_MSG R_${package_upper})
	endfunction(find_r_package)
	
	function(install_r_package package)
		message(STATUS "Installing R package ${package}...")
		execute_process(COMMAND "${R_EXEC}" "--slave" "-e"
			"install.packages('${package}','${R_LIBS_USER}','http://cran.r-project.org')"
			ERROR_QUIET OUTPUT_QUIET)
		message(STATUS "R package ${package} has been installed in ${R_LIBS_USER}")
	endfunction(install_r_package)
	
	function(find_or_install_r_package package)
		find_r_package(${package})
		string(TOUPPER ${package} package_upper)
		if(NOT R_${package_upper})
			install_r_package(${package})
		endif()
	endfunction(find_or_install_r_package)
endif(R_EXEC)

find_package_handle_standard_args(R DEFAULT_MSG R_EXEC)

-- 
Mark





More information about the CMake mailing list