# Copyright 2010-2011 Free Software Foundation, Inc. # # This file is part of GNU Radio # # GNU Radio is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3, or (at your option) # any later version. # # GNU Radio is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. if(DEFINED __INCLUDED_GR_PYTHON_CMAKE) return() endif() set(__INCLUDED_GR_PYTHON_CMAKE TRUE) ######################################################################## # Setup the python interpreter: # This allows the user to specify a specific interpreter, # or finds the interpreter via the built-in cmake module. ######################################################################## #this allows the user to override PYTHON_EXECUTABLE if(PYTHON_EXECUTABLE) set(PYTHONINTERP_FOUND TRUE) #otherwise if not set, try to automatically find it else(PYTHON_EXECUTABLE) #use the built-in find script find_package(PythonInterp) #and if that fails use the find program routine if(NOT PYTHONINTERP_FOUND) find_program(PYTHON_EXECUTABLE NAMES python python2.7 python2.6 python2.5) if(PYTHON_EXECUTABLE) set(PYTHONINTERP_FOUND TRUE) endif(PYTHON_EXECUTABLE) endif(NOT PYTHONINTERP_FOUND) endif(PYTHON_EXECUTABLE) #make the path to the executable appear in the cmake gui set(PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE} CACHE FILEPATH "python interpreter") #make sure we can use -B with python (introduced in 2.6) if(PYTHON_EXECUTABLE) execute_process( COMMAND ${PYTHON_EXECUTABLE} -B -c "" OUTPUT_QUIET ERROR_QUIET RESULT_VARIABLE PYTHON_HAS_DASH_B_RESULT ) if(PYTHON_HAS_DASH_B_RESULT EQUAL 0) set(PYTHON_DASH_B "-B") endif() endif(PYTHON_EXECUTABLE) ######################################################################## # Check for the existence of a python module: # - desc a string description of the check # - mod the name of the module to import # - cmd an additional command to run # - have the result variable to set ######################################################################## macro(GR_PYTHON_CHECK_MODULE desc mod cmd have) message(STATUS "") message(STATUS "Python checking for ${desc}") execute_process( COMMAND ${PYTHON_EXECUTABLE} -c " ######################################### try: import ${mod} assert ${cmd} except ImportError, AssertionError: exit(-1) except: pass #########################################" RESULT_VARIABLE ${have} ) if(${have} EQUAL 0) message(STATUS "Python checking for ${desc} - found") set(${have} TRUE) else(${have} EQUAL 0) message(STATUS "Python checking for ${desc} - not found") set(${have} FALSE) endif(${have} EQUAL 0) endmacro(GR_PYTHON_CHECK_MODULE) ######################################################################## # Sets the python installation directory GR_PYTHON_DIR ######################################################################## execute_process(COMMAND ${PYTHON_EXECUTABLE} -c " from distutils import sysconfig print sysconfig.get_python_lib(plat_specific=True, prefix='') " OUTPUT_VARIABLE GR_PYTHON_DIR OUTPUT_STRIP_TRAILING_WHITESPACE ) file(TO_CMAKE_PATH ${GR_PYTHON_DIR} GR_PYTHON_DIR) ######################################################################## # Create an always-built target with a unique name # Usage: GR_UNIQUE_TARGET( ) ######################################################################## function(GR_UNIQUE_TARGET desc) file(RELATIVE_PATH reldir ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}) execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import re, hashlib unique = hashlib.md5('${reldir}${ARGN}').hexdigest()[:5] print(re.sub('\\W', '_', '${desc} ${reldir} ' + unique))" OUTPUT_VARIABLE _target OUTPUT_STRIP_TRAILING_WHITESPACE) add_custom_target(${_target} ALL DEPENDS ${ARGN}) endfunction(GR_UNIQUE_TARGET) ######################################################################## # Install python sources (also builds and installs byte-compiled python) ######################################################################## function(GR_PYTHON_INSTALL) include(CMakeParseArgumentsCopy) CMAKE_PARSE_ARGUMENTS(GR_PYTHON_INSTALL "" "DESTINATION;COMPONENT" "FILES;PROGRAMS" ${ARGN}) #################################################################### if(GR_PYTHON_INSTALL_FILES) #################################################################### install(${ARGN}) #installs regular python files #create a list of all generated files unset(pysrcfiles) unset(pycfiles) unset(pyofiles) foreach(pyfile ${GR_PYTHON_INSTALL_FILES}) get_filename_component(pyfile ${pyfile} ABSOLUTE) list(APPEND pysrcfiles ${pyfile}) #determine if this file is in the source or binary directory file(RELATIVE_PATH source_rel_path ${CMAKE_CURRENT_SOURCE_DIR} ${pyfile}) string(LENGTH "${source_rel_path}" source_rel_path_len) file(RELATIVE_PATH binary_rel_path ${CMAKE_CURRENT_BINARY_DIR} ${pyfile}) string(LENGTH "${binary_rel_path}" binary_rel_path_len) #and set the generated path appropriately if(${source_rel_path_len} GREATER ${binary_rel_path_len}) set(pygenfile ${CMAKE_CURRENT_BINARY_DIR}/${binary_rel_path}) else() set(pygenfile ${CMAKE_CURRENT_BINARY_DIR}/${source_rel_path}) endif() list(APPEND pycfiles ${pygenfile}c) list(APPEND pyofiles ${pygenfile}o) #ensure generation path exists get_filename_component(pygen_path ${pygenfile} PATH) file(MAKE_DIRECTORY ${pygen_path}) endforeach(pyfile) #the command to generate the pyc files add_custom_command( DEPENDS ${pysrcfiles} OUTPUT ${pycfiles} COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_BINARY_DIR}/python_compile_helper.py ${pysrcfiles} ${pycfiles} ) #the command to generate the pyo files add_custom_command( DEPENDS ${pysrcfiles} OUTPUT ${pyofiles} COMMAND ${PYTHON_EXECUTABLE} -O ${CMAKE_BINARY_DIR}/python_compile_helper.py ${pysrcfiles} ${pyofiles} ) #create install rule and add generated files to target list set(python_install_gen_targets ${pycfiles} ${pyofiles}) install(FILES ${python_install_gen_targets} DESTINATION ${GR_PYTHON_INSTALL_DESTINATION} COMPONENT ${GR_PYTHON_INSTALL_COMPONENT} ) #################################################################### elseif(GR_PYTHON_INSTALL_PROGRAMS) #################################################################### file(TO_NATIVE_PATH ${PYTHON_EXECUTABLE} pyexe_native) if (CMAKE_CROSSCOMPILING) set(pyexe_native /usr/bin/env python) endif() foreach(pyfile ${GR_PYTHON_INSTALL_PROGRAMS}) get_filename_component(pyfile_name ${pyfile} NAME) get_filename_component(pyfile ${pyfile} ABSOLUTE) string(REPLACE "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" pyexefile "${pyfile}.exe") list(APPEND python_install_gen_targets ${pyexefile}) get_filename_component(pyexefile_path ${pyexefile} PATH) file(MAKE_DIRECTORY ${pyexefile_path}) add_custom_command( OUTPUT ${pyexefile} DEPENDS ${pyfile} COMMAND ${PYTHON_EXECUTABLE} -c \"open('${pyexefile}', 'w').write('\#!${pyexe_native}\\n'+open('${pyfile}').read())\" COMMENT "Shebangin ${pyfile_name}" ) #on windows, python files need an extension to execute get_filename_component(pyfile_ext ${pyfile} EXT) if(WIN32 AND NOT pyfile_ext) set(pyfile_name "${pyfile_name}.py") endif() install(PROGRAMS ${pyexefile} RENAME ${pyfile_name} DESTINATION ${GR_PYTHON_INSTALL_DESTINATION} COMPONENT ${GR_PYTHON_INSTALL_COMPONENT} ) endforeach(pyfile) endif() GR_UNIQUE_TARGET("pygen" ${python_install_gen_targets}) endfunction(GR_PYTHON_INSTALL) ######################################################################## # Write the python helper script that generates byte code files ######################################################################## file(WRITE ${CMAKE_BINARY_DIR}/python_compile_helper.py " import sys, py_compile files = sys.argv[1:] srcs, gens = files[:len(files)/2], files[len(files)/2:] for src, gen in zip(srcs, gens): py_compile.compile(file=src, cfile=gen, doraise=True) ")