diff options
Diffstat (limited to 'host/examples/rfnoc-example/cmake/Modules/UHDPython.cmake')
-rw-r--r-- | host/examples/rfnoc-example/cmake/Modules/UHDPython.cmake | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/host/examples/rfnoc-example/cmake/Modules/UHDPython.cmake b/host/examples/rfnoc-example/cmake/Modules/UHDPython.cmake new file mode 100644 index 000000000..4fdacc243 --- /dev/null +++ b/host/examples/rfnoc-example/cmake/Modules/UHDPython.cmake @@ -0,0 +1,370 @@ +# +# Copyright 2010-2011 Ettus Research LLC +# Copyright 2018 Ettus Research, a National Instruments Company +# Copyright 2019 Ettus Research, a National Instruments Company +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# Note: When modifying this file, check if the changes also need to go into +# host/examples/rfnoc-example/cmake/Modules/UHDPython.cmake. + +if (POLICY CMP0094) + # See https://cmake.org/cmake/help/v3.15/policy/CMP0094.html + # set Python3_FIND_STRATEGY to LOCATION - this ensures that Python from + # sysroot is used first when cross-compiling + # note: policy CMP0094 is available starting with CMake 3.15 + cmake_policy(SET CMP0094 NEW) +endif() + +if(NOT DEFINED INCLUDED_UHD_PYTHON_CMAKE) +set(INCLUDED_UHD_PYTHON_CMAKE TRUE) + +######################################################################## +# Setup Python Part 0: Pybind11 +# +# We do this first so it doesn't interfere with the other steps. In +# particular, searching for pybind11 will mess with PYTHON_VERSION. +######################################################################## +find_package(pybind11 ${PYBIND11_MIN_VERSION} QUIET) + +######################################################################## +# Setup Python Part 1: Find the interpreters +######################################################################## +message(STATUS "") +message(STATUS "Configuring the Python interpreter...") +#this allows the user to override PYTHON_EXECUTABLE +if(PYTHON_EXECUTABLE) + set(PYTHONINTERP_FOUND TRUE) +endif(PYTHON_EXECUTABLE) + +if(NOT PYTHONINTERP_FOUND) + find_package(Python3 ${PYTHON_MIN_VERSION} QUIET) + if(Python3_Interpreter_FOUND) + set(PYTHON_VERSION ${Python3_VERSION}) + set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE}) + set(PYTHONINTERP_FOUND TRUE) + endif(Python3_Interpreter_FOUND) +endif(NOT PYTHONINTERP_FOUND) + +if(NOT PYTHONINTERP_FOUND) + find_package(PythonInterp ${PYTHON_MIN_VERSION} QUIET) + if(PYTHONINTERP_FOUND) + set(PYTHON_VERSION ${PYTHON_VERSION_STRING}) + endif(PYTHONINTERP_FOUND) +endif(NOT PYTHONINTERP_FOUND) + +# If that fails, try using the build-in find program routine. +if(NOT PYTHONINTERP_FOUND) + message(STATUS "Attempting to find Python without CMake...") + find_program(PYTHON_EXECUTABLE NAMES python3 python3.6 python3.7 python3.8 python3.9) + if(PYTHON_EXECUTABLE) + set(PYTHONINTERP_FOUND TRUE) + endif(PYTHON_EXECUTABLE) +endif(NOT PYTHONINTERP_FOUND) + +if(NOT PYTHON_VERSION) + message(STATUS "Manually determining build Python version...") + execute_process(COMMAND ${PYTHON_EXECUTABLE} -c " +import sys +print('{}.{}.{}'.format( + sys.version_info.major, + sys.version_info.minor, + sys.version_info.micro))" + OUTPUT_VARIABLE PYTHON_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) +endif(NOT PYTHON_VERSION) + +# If we still haven't found a Python interpreter, then we're done. +if(NOT PYTHONINTERP_FOUND) + message(FATAL_ERROR "Error: Python interpreter required by the build system.") +endif(NOT PYTHONINTERP_FOUND) +if(NOT PYTHON_EXECUTABLE) + message(FATAL_ERROR "Error: Python interpreter required by the build system.") +endif(NOT PYTHON_EXECUTABLE) + +#make the path to the executable appear in the cmake gui +set(PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE} CACHE FILEPATH + "python buildtime interpreter") + +message(STATUS "Python interpreter: ${PYTHON_EXECUTABLE} Version: ${PYTHON_VERSION}") +message(STATUS "Override with: -DPYTHON_EXECUTABLE=<path-to-python>") + +#this allows the user to override RUNTIME_PYTHON_EXECUTABLE +if(NOT RUNTIME_PYTHON_EXECUTABLE) + if(CMAKE_CROSSCOMPILING) + message(STATUS "Cross compiling, setting python runtime to /usr/bin/python3") + message(STATUS "and interpreter to min. required version ${PYTHON_MIN_VERSION}") + message(STATUS "If this is not what you want, please set RUNTIME_PYTHON_EXECUTABLE") + message(STATUS "and RUNTIME_PYTHON_VERSION manually") + set(RUNTIME_PYTHON_EXECUTABLE "/usr/bin/python3") + set(RUNTIME_PYTHON_VERSION ${PYTHON_MIN_VERSION}) + set(EXACT_ARGUMENT "") + else(CMAKE_CROSSCOMPILING) + #default to the buildtime interpreter + set(RUNTIME_PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE}) + set(RUNTIME_PYTHON_VERSION ${PYTHON_VERSION}) + set(EXACT_ARGUMENT "EXACT") + endif(CMAKE_CROSSCOMPILING) +else(NOT RUNTIME_PYTHON_EXECUTABLE) + set(EXACT_ARGUMENT "EXACT") +endif(NOT RUNTIME_PYTHON_EXECUTABLE) + +if(NOT RUNTIME_PYTHON_VERSION) + message(STATUS "Manually determining runtime Python version...") + execute_process(COMMAND ${PYTHON_EXECUTABLE} -c " +from __future__ import print_function +import sys +print('{}.{}.{}'.format( + sys.version_info.major, + sys.version_info.minor, + sys.version_info.micro))" + OUTPUT_VARIABLE RUNTIME_PYTHON_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) +endif(NOT RUNTIME_PYTHON_VERSION) + +#make the path to the executable appear in the cmake gui +set(RUNTIME_PYTHON_EXECUTABLE ${RUNTIME_PYTHON_EXECUTABLE} CACHE FILEPATH + "python runtime interpreter") + +message(STATUS "Python runtime interpreter: ${RUNTIME_PYTHON_EXECUTABLE} Version: ${RUNTIME_PYTHON_VERSION}") +message(STATUS "Override with: -DRUNTIME_PYTHON_EXECUTABLE=<path-to-python>") + +############################################################################### +# Determine if a Python module is installed, or, more generally, determine +# if some condition that Python can report through a Boolean expression is +# met. This macro allows one or more modules to be imported and a Python +# Boolean expression to be evaluated. +# +# - desc: +# Description of what's being checked (for user feedback) +# - module: +# The module(s) to be passed to the `import` command +# - bool_expr: +# A Python expression to be evaluated that returns True or False based on +# the presence or absence of the module (or in the general case, the +# condition being checked) +# - have_ver: +# The variable name to be set to TRUE if the Python expression returns True, +# or FALSE otherwise +macro(PYTHON_CHECK_MODULE desc module bool_expr have_var) + message(STATUS "") + message(STATUS "Python checking for ${desc}") + execute_process( + COMMAND ${PYTHON_EXECUTABLE} -c " +######################################### +try: + import ${module} +except: + exit(1) +try: + assert ${bool_expr} +except: + exit(2) +exit(0) +#########################################" + RESULT_VARIABLE python_result + ) + if(python_result EQUAL 0) + message(STATUS "Python checking for ${desc} - found") + set(${have_var} TRUE) + elseif(python_result EQUAL 1) + message(STATUS "Python checking for ${desc} - \"import ${module}\" failed (is it installed?)") + set(${have_var} FALSE) + elseif(python_result EQUAL 2) + message(STATUS "Python checking for ${desc} - \"assert ${bool_expr}\" failed") + set(${have_var} FALSE) + else() + message(STATUS "Python checking for ${desc} - unknown error") + set(${have_var} FALSE) + endif() +endmacro(PYTHON_CHECK_MODULE) + + +############################################################################### +# Determine if a Python module is installed and if it meets a minimum required +# version. +# +# - desc: +# Description of what's being checked (for user feedback) +# - module: +# The module to be `import`ed +# - module_version_expr: +# A Python expression to be evaluated that returns the module version string +# (usually "module_name.__version__", but may be tailored for non-conformant +# modules, or other custom use cases) +# - min_module_version: +# The minimum version required of the module as a canonical Python version +# string ("major.minor.micro") as defined in PEP 440 +# - have_ver: +# The variable name to be set to TRUE if the module is present and meets +# the minimum version requirement or FALSE otherwise +macro(PYTHON_CHECK_MODULE_VERSION desc module module_version_expr min_module_version have_var) + message(STATUS "") + message(STATUS "Python checking for ${desc}") + execute_process( + COMMAND ${PYTHON_EXECUTABLE} -c " +######################################### +try: + import ${module} +except: + exit(1) +try: + version = ${module_version_expr} + print(version) +except: + exit(2) +exit(0) +#########################################" + RESULT_VARIABLE python_result + OUTPUT_VARIABLE version_output + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(python_result EQUAL 0) + if(${version_output} VERSION_GREATER_EQUAL ${min_module_version}) + message(STATUS "Python checking for ${desc} - ${version_output} satisfies minimum required version ${min_module_version}") + set(${have_var} TRUE) + else() + message(STATUS "Python checking for ${desc} - ${version_output} does not satisfy minimum required version ${min_module_version}") + set(${have_var} FALSE) + endif() + elseif(python_result EQUAL 1) + message(STATUS "Python checking for ${desc} - \"import ${module}\" failed (is it installed?)") + set(${have_var} FALSE) + elseif(python_result EQUAL 2) + message(STATUS "Python checking for ${desc} - evaluation of \"${module_version_expr}\" failed") + set(${have_var} FALSE) + else() + message(STATUS "Python checking for ${desc} - unknown error") + set(${have_var} FALSE) + endif() +endmacro(PYTHON_CHECK_MODULE_VERSION) + + +############################################################################### +# Install a Python module into a system/prefix/virtualenv location. +# +# - LIBTARGET: Is there a library target included in this module (e.g., pyuhd)? +# If so, state its name here. It will update RPATH on Linux/Unix +# systems. +# - MODULE: Name of module (e.g., 'uhd') +macro(PYTHON_INSTALL_MODULE) + cmake_parse_arguments( + _py_install_mod + "" "LIBTARGET;MODULE" "" + ${ARGN} + ) + + # Check if we're in a virtual environment -- the rules are a bit different + # there. + PYTHON_CHECK_MODULE( + "virtual environment" + "sys" + "sys.prefix != sys.base_prefix" + HAVE_PYTHON_VIRTUALENV + ) + + if(HAVE_PYTHON_VIRTUALENV) + message( + STATUS + "Python virtual environment detected -- Ignoring UHD_PYTHON_DIR.") + # In virtualenvs, let setuptools do its thing + install(CODE "message(\"Installing ${_py_install_mod_MODULE} Python module into venv via pip.\")") + install(CODE + "execute_process(COMMAND pip3 install . --force-reinstall WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})") + else() + # Otherwise, use sysconfig to determine the correct relative path for Python + # packages, and install to our prefix + if(NOT DEFINED UHD_PYTHON_DIR) + execute_process(COMMAND ${PYTHON_EXECUTABLE} -c + # Avoid the posix_local install scheme + "import os,sysconfig;\ + install_scheme = 'posix_user';\ + platlib = sysconfig.get_path('platlib', scheme=install_scheme);\ + prefix = sysconfig.get_config_var('prefix');\ + print(os.path.relpath(platlib, prefix));" + OUTPUT_VARIABLE UHD_PYTHON_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + endif(NOT DEFINED UHD_PYTHON_DIR) + file(TO_CMAKE_PATH ${UHD_PYTHON_DIR} UHD_PYTHON_DIR) + + message( + STATUS + "Installing '${_py_install_mod_MODULE}' Python module to: " + "${CMAKE_INSTALL_PREFIX}/${UHD_PYTHON_DIR}") + # We use sysconfig (above) to figure out the destination path, and then + # we simply copy this module recursively into its final destination. + install(DIRECTORY + ${CMAKE_CURRENT_BINARY_DIR}/${_py_install_mod_MODULE} + DESTINATION ${UHD_PYTHON_DIR} + COMPONENT pythonapi + ) + # On Linux/Unix systems, we must properly install the library file. + # install(DIRECTORY) will treat the .so file like any other file, which + # means it won't update its RPATH, and thus the RPATH would be stuck to the + # build directory. + if(UNIX AND _py_install_mod_LIBTARGET) + install(TARGETS ${_py_install_mod_LIBTARGET} + DESTINATION ${UHD_PYTHON_DIR}/${_py_install_mod_MODULE} + ) + endif() + endif(HAVE_PYTHON_VIRTUALENV) +endmacro(PYTHON_INSTALL_MODULE) + +############################################################################### +# Part 2: Python Libraries +############################################################################### +# The libraries must match the RUNTIME_PYTHON_EXECUTABLE's version. +# - Figure out version +# - See if Python3_LIBRARIES is already set (or Python2_LIBRARIES) +if(NOT PYTHON_LIBRARIES OR NOT PYTHON_INCLUDE_DIRS) + message(STATUS "Finding Python Libraries...") + find_package(PythonLibs ${RUNTIME_PYTHON_VERSION} ${EXACT_ARGUMENT} QUIET) + if(NOT RUNTIME_PYTHON_VERSION VERSION_LESS 3) + if(NOT PYTHON_LIBRARIES OR NOT PYTHON_INCLUDE_DIRS) + find_package(Python3 ${RUNTIME_PYTHON_VERSION} + ${EXACT_ARGUMENT} + QUIET + COMPONENTS Interpreter Development) + if(Python3_Development_FOUND) + set(PYTHON_LIBRARIES ${Python3_LIBRARIES}) + set(PYTHON_INCLUDE_DIRS ${Python3_INCLUDE_DIRS}) + endif(Python3_Development_FOUND) + endif(NOT PYTHON_LIBRARIES OR NOT PYTHON_INCLUDE_DIRS) + else(NOT RUNTIME_PYTHON_VERSION VERSION_LESS 3) + if(NOT PYTHON_LIBRARIES OR NOT PYTHON_INCLUDE_DIRS) + find_package(Python2 ${RUNTIME_PYTHON_VERSION} + ${EXACT_ARGUMENT} + QUIET + COMPONENTS Interpreter Development) + if(Python2_Development_FOUND) + set(PYTHON_LIBRARIES ${Python2_LIBRARIES}) + set(PYTHON_INCLUDE_DIRS ${Python2_INCLUDE_DIRS}) + endif(Python2_Development_FOUND) + endif(NOT PYTHON_LIBRARIES OR NOT PYTHON_INCLUDE_DIRS) + endif(NOT RUNTIME_PYTHON_VERSION VERSION_LESS 3) + if(NOT PYTHON_LIBRARIES OR NOT PYTHON_INCLUDE_DIRS) + message(STATUS "Could not find Python Libraries.") + endif(NOT PYTHON_LIBRARIES OR NOT PYTHON_INCLUDE_DIRS) +endif(NOT PYTHON_LIBRARIES OR NOT PYTHON_INCLUDE_DIRS) + +if(PYTHON_LIBRARIES AND PYTHON_INCLUDE_DIRS) + set(HAVE_PYTHON_LIBS TRUE) + message(STATUS "Python Libraries: ${PYTHON_LIBRARIES}") + message(STATUS "Python include directories: ${PYTHON_INCLUDE_DIRS}") +else(PYTHON_LIBRARIES AND PYTHON_INCLUDE_DIRS) + set(HAVE_PYTHON_LIBS FALSE) +endif(PYTHON_LIBRARIES AND PYTHON_INCLUDE_DIRS) + +if(NOT PYTHON_LIBRARY) + set(PYTHON_LIBRARIES ${PYTHON_LIBRARIES} CACHE FILEPATH + "Python libraries") + mark_as_advanced(PYTHON_LIBRARIES) +endif(NOT PYTHON_LIBRARY) +if(NOT PYTHON_INCLUDE_DIR) + set(PYTHON_INCLUDE_DIRS ${PYTHON_INCLUDE_DIRS} CACHE FILEPATH + "Python include dirs") + mark_as_advanced(PYTHON_INCLUDE_DIRS) +endif(NOT PYTHON_INCLUDE_DIR) + +endif(NOT DEFINED INCLUDED_UHD_PYTHON_CMAKE) |