Skip to content

Commit

Permalink
Overhaul Python structure, better support Python 2+3 builds
Browse files Browse the repository at this point in the history
* Copy in CMake 3.16 Python CMake scripts, does the work for us
* Fix OS X and most MinGW builds
* Closes #380
* See: pothosware/homebrew-pothos#59
  • Loading branch information
ncorgan committed May 8, 2023
1 parent 2e5fe3e commit 1e25695
Show file tree
Hide file tree
Showing 13 changed files with 3,199 additions and 655 deletions.
224 changes: 145 additions & 79 deletions .github/workflows/ci.yml

Large diffs are not rendered by default.

13 changes: 0 additions & 13 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -141,21 +141,8 @@ add_subdirectory(docs)
########################################################################
# Python support (optional)
########################################################################
message(STATUS "")
message(STATUS "#############################################")
message(STATUS "## Begin configuration for Python support...")
message(STATUS "#############################################")
message(STATUS "Enabling optional Python bindings if possible...")
add_subdirectory(python)

message(STATUS "")
message(STATUS "#############################################")
message(STATUS "## Begin configuration for Python3 support...")
message(STATUS "#############################################")
message(STATUS "Enabling optional Python3 bindings if possible...")
add_subdirectory(python3)


########################################################################
# uninstall target
########################################################################
Expand Down
225 changes: 92 additions & 133 deletions python/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
########################################################################
# Project setup
########################################################################
cmake_minimum_required(VERSION 2.8)
cmake_minimum_required(VERSION 3.3)
project(SoapySDRPython CXX)
enable_testing()

Expand All @@ -14,81 +14,14 @@ find_package(SWIG)
message(STATUS "SWIG_FOUND: ${SWIG_FOUND} - ${SWIG_VERSION}")

########################################################################
# Find python interp
# Find Python
########################################################################
find_package(PythonInterp)
message(STATUS "PYTHONINTERP_FOUND: ${PYTHONINTERP_FOUND} - ${PYTHON_VERSION_STRING}")
message(STATUS "PYTHON_EXECUTABLE: ${PYTHON_EXECUTABLE}")

#help find_package(PythonLibs) by setting Python_ADDITIONAL_VERSIONS from PYTHON_VERSION_STRING
if(PYTHONINTERP_FOUND AND DEFINED PYTHON_VERSION_STRING AND NOT DEFINED Python_ADDITIONAL_VERSIONS)
string(SUBSTRING "${PYTHON_VERSION_STRING}" 0 3 Python_ADDITIONAL_VERSIONS)
endif()

########################################################################
# Determine install directory
########################################################################
execute_process(
COMMAND ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/get_python_lib.py" "${CMAKE_INSTALL_PREFIX}"
OUTPUT_STRIP_TRAILING_WHITESPACE
OUTPUT_VARIABLE PYTHON_INSTALL_DIR_SYSCONF
)
set(PYTHON_INSTALL_DIR "${PYTHON_INSTALL_DIR_SYSCONF}" CACHE STRING "python install prefix")
message(STATUS "PYTHON_INSTALL_DIR: \${prefix}/${PYTHON_INSTALL_DIR}")

########################################################################
# Find Python libs
########################################################################
option(USE_PYTHON_CONFIG "use python-config to locate development files" TRUE)
set(PYTHON_CONFIG_EXECUTABLE ${PYTHON_EXECUTABLE}-config
CACHE FILEPATH "Path to python-config executable")
if (USE_PYTHON_CONFIG AND EXISTS ${PYTHON_CONFIG_EXECUTABLE})
execute_process(
COMMAND ${PYTHON_CONFIG_EXECUTABLE} --includes
OUTPUT_STRIP_TRAILING_WHITESPACE
OUTPUT_VARIABLE PYTHON_INCLUDE_DIRS)
string(REGEX REPLACE "^[-I]" "" PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIRS}")
string(REGEX REPLACE "[ ]-I" " " PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIRS}")
separate_arguments(PYTHON_INCLUDE_DIRS)
execute_process(
COMMAND ${PYTHON_CONFIG_EXECUTABLE} --ldflags
OUTPUT_STRIP_TRAILING_WHITESPACE
OUTPUT_VARIABLE PYTHON_LIBRARIES)
string(STRIP "${PYTHON_LIBRARIES}" PYTHON_LIBRARIES)
set(PYTHONLIBS_VERSION_STRING ${PYTHON_VERSION_STRING})
set(PYTHONLIBS_FOUND TRUE)
else()
find_package(PythonLibs)
endif()

message(STATUS "PYTHONLIBS_FOUND: ${PYTHONLIBS_FOUND} - ${PYTHONLIBS_VERSION_STRING}")
message(STATUS "PYTHON_INCLUDE_DIRS: ${PYTHON_INCLUDE_DIRS}")
message(STATUS "PYTHON_LIBRARIES: ${PYTHON_LIBRARIES}")

#on windows, we require a pythonxx_d.lib in debug mode
#require that the PYTHON_DEBUG_LIBRARY flag is set
#or the build assumes that the debug library DNE
set(PYTHON_DEBUG_OK TRUE)
if(WIN32 AND NOT PYTHON_DEBUG_LIBRARY AND "${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
message(WARNING "WIN32 Debug mode requires PYTHON_DEBUG_LIBRARY")
set(PYTHON_DEBUG_OK FALSE)
endif()

########################################################################
# Python version check
########################################################################
set(PYTHON_VERSION_MATCH TRUE)
if (PYTHON_VERSION_STRING AND PYTHONLIBS_VERSION_STRING)
if(NOT "${PYTHON_VERSION_STRING}" VERSION_EQUAL "${PYTHONLIBS_VERSION_STRING}")
message(WARNING "Python interp and library version mismatch")
set(PYTHON_VERSION_MATCH FALSE)
endif()
endif()
list(PREPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)

########################################################################
## set the swig flags - shared with python3 build
## set the swig flags
########################################################################
set(CMAKE_SWIG_FLAGS -c++ -threads -I${SoapySDR_INCLUDE_DIRS})
set(CMAKE_SWIG_FLAGS -threads -I${SoapySDR_INCLUDE_DIRS})

#check for size_t issue on arm 32-bit platforms
include(CheckCXXSourceCompiles)
Expand All @@ -102,80 +35,106 @@ if (SIZE_T_IS_UNSIGNED_INT)
list(APPEND CMAKE_SWIG_FLAGS -DSIZE_T_IS_UNSIGNED_INT)
endif (SIZE_T_IS_UNSIGNED_INT)

########################################################################
## Export variables for python3 subdirectory
########################################################################

#this directory used as a stand-alone build since the library is pulled in externally
#set ENABLE_LIBRARY for cmake_dependent_option() used in the feature setup below
if ("${PROJECT_SOURCE_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}")
set(ENABLE_LIBRARY ${SoapySDR_FOUND})

#otherwise export enable and swig variables used in the python3 directory
else ()

#set once we know that executable and libs are found and match
#this tells the parent scope to build python3 when this is python2
if(PYTHON_VERSION_STRING AND "${PYTHON_VERSION_STRING}" VERSION_LESS "3.0")
set(BUILD_PYTHON3 TRUE PARENT_SCOPE)
endif()

#or enable search for python3 when this directory failed to find
#a full set of python interpreter and devel files of any version
if(NOT PYTHONINTERP_FOUND OR NOT PYTHONLIBS_FOUND)
set(BUILD_PYTHON3 TRUE PARENT_SCOPE)
endif()

set(CMAKE_SWIG_FLAGS ${CMAKE_SWIG_FLAGS} PARENT_SCOPE)

endif ()

########################################################################
## Feature registration
########################################################################
include(FeatureSummary)
include(CMakeDependentOption)
cmake_dependent_option(ENABLE_PYTHON "Enable python bindings" ON "ENABLE_LIBRARY;SWIG_FOUND;PYTHONINTERP_FOUND;PYTHONLIBS_FOUND;PYTHON_DEBUG_OK;PYTHON_VERSION_MATCH" OFF)
add_feature_info(Python ENABLE_PYTHON "python bindings v${PYTHON_VERSION_STRING}")
if (NOT ENABLE_PYTHON)
return()

# Note: for build script compatibility, still use ENABLE_PYTHON for Python 2
message(STATUS "")
message(STATUS "#############################################")
message(STATUS "## Begin configuration for Python 2 support...")
message(STATUS "#############################################")
message(STATUS "Enabling optional Python 2 bindings if possible...")
find_package(Python2 COMPONENTS Interpreter Development)
if(${Python2_FOUND})
message(STATUS " * Interpreter: ${Python2_EXECUTABLE} (${Python2_INTERPRETER_ID})")
message(STATUS " * Include: ${Python2_INCLUDE_DIRS}")
message(STATUS " * Library: ${Python2_LIBRARIES}")
endif()
cmake_dependent_option(ENABLE_PYTHON "Enable Python2 bindings" ON "ENABLE_LIBRARY;SWIG_FOUND;Python2_FOUND" OFF)
add_feature_info(Python2 ENABLE_PYTHON "Python2 bindings v${Python2_VERSION}")

message(STATUS "")
message(STATUS "#############################################")
message(STATUS "## Begin configuration for Python 3 support...")
message(STATUS "#############################################")
message(STATUS "Enabling optional Python 3 bindings if possible...")
find_package(Python3 COMPONENTS Interpreter Development)
if(${Python3_FOUND})
message(STATUS " * Interpreter: ${Python3_EXECUTABLE} (${Python3_INTERPRETER_ID})")
message(STATUS " * Include: ${Python3_INCLUDE_DIRS}")
message(STATUS " * Library: ${Python3_LIBRARIES}")
endif()
cmake_dependent_option(ENABLE_PYTHON3 "Enable Python3 bindings" ON "ENABLE_LIBRARY;SWIG_FOUND;Python3_FOUND" OFF)
add_feature_info(Python3 ENABLE_PYTHON3 "Python3 bindings v${Python3_VERSION}")

########################################################################
# Build Module
# Build and install module
########################################################################
include(UseSWIG)
set(SOAPYSDR_PYTHON_DIR ${CMAKE_CURRENT_SOURCE_DIR})

configure_file(
SoapySDR.in.i
${CMAKE_CURRENT_BINARY_DIR}/SoapySDR.i
@ONLY)
function(BUILD_PYTHON_MODULE PYTHON_VERSION)
configure_file(
${SOAPYSDR_PYTHON_DIR}/SoapySDR.in.i
${CMAKE_CURRENT_BINARY_DIR}/SoapySDR.i
@ONLY)
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/SoapySDR.i PROPERTIES CPLUSPLUS ON)

message(STATUS "CMAKE_SWIG_FLAGS=${CMAKE_SWIG_FLAGS}")
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/SoapySDR.i PROPERTIES CPLUSPLUS ON)
if(MINGW)
string(APPEND CMAKE_SHARED_LINKER_FLAGS " -static-libgcc -static-libstdc++")
endif()

if(${CMAKE_VERSION} VERSION_LESS "3.8")
SWIG_ADD_MODULE(SoapySDR python ${CMAKE_CURRENT_BINARY_DIR}/SoapySDR.i)
else()
SWIG_ADD_LIBRARY(SoapySDR LANGUAGE python SOURCES ${CMAKE_CURRENT_BINARY_DIR}/SoapySDR.i)
endif()
if(${CMAKE_VERSION} VERSION_LESS "3.8")
SWIG_ADD_MODULE(SoapySDR${PYTHON_VERSION} python ${CMAKE_CURRENT_BINARY_DIR}/SoapySDR.i)
else()
SWIG_ADD_LIBRARY(SoapySDR${PYTHON_VERSION} LANGUAGE python SOURCES ${CMAKE_CURRENT_BINARY_DIR}/SoapySDR.i)
endif()

if(APPLE)
list(APPEND PYTHON_LIBRARIES "-undefined dynamic_lookup")
endif()
set(python_includes ${SoapySDR_INCLUDE_DIRS})
set(python_libraries SoapySDR Python${PYTHON_VERSION}::Module)

target_include_directories(${SWIG_MODULE_SoapySDR_REAL_NAME} PRIVATE ${PYTHON_INCLUDE_DIRS})
SWIG_LINK_LIBRARIES(SoapySDR SoapySDR ${PYTHON_LIBRARIES})
set_target_properties(${SWIG_MODULE_SoapySDR${PYTHON_VERSION}_REAL_NAME} PROPERTIES OUTPUT_NAME _SoapySDR)

########################################################################
# Install Module
########################################################################
install(
TARGETS ${SWIG_MODULE_SoapySDR_REAL_NAME}
DESTINATION ${PYTHON_INSTALL_DIR}
)

install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/SoapySDR.py
DESTINATION ${PYTHON_INSTALL_DIR}
)
if(MINGW)
# https://stackoverflow.com/a/50792585
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
target_compile_definitions(${SWIG_MODULE_SoapySDR${PYTHON_VERSION}_REAL_NAME} PRIVATE -DMS_WIN64=1)
else()
target_compile_definitions(${SWIG_MODULE_SoapySDR${PYTHON_VERSION}_REAL_NAME} PRIVATE -DMS_WIN32=1)
endif()
endif()

target_include_directories(${SWIG_MODULE_SoapySDR${PYTHON_VERSION}_REAL_NAME} PRIVATE ${python_includes})
SWIG_LINK_LIBRARIES(SoapySDR${PYTHON_VERSION} ${python_libraries})

execute_process(
COMMAND ${Python${PYTHON_VERSION}_EXECUTABLE} ${SOAPYSDR_PYTHON_DIR}/get_python_lib.py ${CMAKE_INSTALL_PREFIX}
OUTPUT_STRIP_TRAILING_WHITESPACE
OUTPUT_VARIABLE PYTHON_INSTALL_DIR)

install(
TARGETS ${SWIG_MODULE_SoapySDR${PYTHON_VERSION}_REAL_NAME}
DESTINATION ${PYTHON_INSTALL_DIR}
)

install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/SoapySDR.py
DESTINATION ${PYTHON_INSTALL_DIR}
)
endfunction()

# TODO: Windows has full Python installations in different directories, so all Python
# versions install file in the same subpaths. CMake doesn't catch this for some reason,
# so should we error out if both Python versions are detected or prioritize one over the
# other with a warning?

if(ENABLE_PYTHON)
add_subdirectory(python2)
endif()

if(ENABLE_PYTHON3)
add_subdirectory(python3)
endif()
2 changes: 1 addition & 1 deletion python/apps/SimpleSiggen.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def siggen_app(
sdr = SoapySDR.Device(args)
#set clock rate first
if clock_rate is not None:
sdr.setMasterclock_rate(clock_rate)
sdr.setMasterClockRate(clock_rate)

#set sample rate
sdr.setSampleRate(SOAPY_SDR_TX, tx_chan, rate)
Expand Down
Loading

0 comments on commit 1e25695

Please sign in to comment.