mirror of https://github.com/zeromq/pyzmq.git
431 lines
15 KiB
CMake
431 lines
15 KiB
CMake
cmake_minimum_required(VERSION 3.14...3.28)
|
|
project(${SKBUILD_PROJECT_NAME} LANGUAGES C CXX)
|
|
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
|
|
|
|
list(PREPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
|
find_package(
|
|
Python
|
|
COMPONENTS Interpreter Development.Module
|
|
REQUIRED)
|
|
|
|
# Python_SOABI isn't always right when cross-compiling
|
|
# SKBUILD_SOABI seems to be
|
|
if (DEFINED SKBUILD_SOABI AND NOT "${SKBUILD_SOABI}" STREQUAL "${Python_SOABI}")
|
|
message(WARNING "SKBUILD_SOABI=${SKBUILD_SOABI} != Python_SOABI=${Python_SOABI}; likely cross-compiling, using SOABI=${SKBUILD_SOABI} from scikit-build")
|
|
set(Python_SOABI "${SKBUILD_SOABI}")
|
|
endif()
|
|
|
|
# legacy pyzmq env options, no PYZMQ_ prefix
|
|
set(ZMQ_PREFIX "auto" CACHE STRING "libzmq installation prefix or 'bundled'")
|
|
option(ZMQ_DRAFT_API "whether to build the libzmq draft API" OFF)
|
|
option(PYZMQ_LIBZMQ_RPATH "Add $ZMQ_PREFIX/lib to $RPATH (true by default). Set to false if libzmq will be bundled or relocated and RPATH is handled separately" ON)
|
|
|
|
# anything new should start with PYZMQ_
|
|
option(PYZMQ_LIBZMQ_NO_BUNDLE "Prohibit building bundled libzmq. Useful for repackaging, to allow default search for libzmq and requiring it to succeed." OFF)
|
|
set(PYZMQ_LIBZMQ_VERSION "4.3.5" CACHE STRING "libzmq version when bundling")
|
|
set(PYZMQ_LIBSODIUM_VERSION "1.0.20" CACHE STRING "libsodium version when bundling")
|
|
set(PYZMQ_LIBZMQ_URL "" CACHE STRING "full URL to download bundled libzmq")
|
|
set(PYZMQ_LIBSODIUM_URL "" CACHE STRING "full URL to download bundled libsodium")
|
|
set(PYZMQ_LIBSODIUM_CONFIGURE_ARGS "" CACHE STRING "semicolon-separated list of arguments to pass to ./configure for bundled libsodium")
|
|
set(PYZMQ_LIBSODIUM_MSBUILD_ARGS "" CACHE STRING "semicolon-separated list of arguments to pass to msbuild for bundled libsodium")
|
|
set(PYZMQ_LIBSODIUM_VS_VERSION "" CACHE STRING "Visual studio solution version for bundled libsodium (default: detect from MSVC_VERSION)")
|
|
|
|
if (NOT CMAKE_BUILD_TYPE)
|
|
# default to Release
|
|
set(CMAKE_BUILD_TYPE "Release")
|
|
endif()
|
|
|
|
# get options from env
|
|
|
|
# handle booleans
|
|
foreach(_optname ZMQ_DRAFT_API PYZMQ_NO_BUNDLE PYZMQ_LIBZMQ_RPATH)
|
|
if (DEFINED ENV{${_optname}})
|
|
if ("$ENV{${_optname}}" STREQUAL "1" OR "$ENV{${_optname}}" STREQUAL "ON")
|
|
set(${_optname} TRUE)
|
|
else()
|
|
set(${_optname} FALSE)
|
|
endif()
|
|
endif()
|
|
endforeach()
|
|
|
|
foreach(_optname
|
|
ZMQ_PREFIX
|
|
PYZMQ_LIBZMQ_VERSION
|
|
PYZMQ_LIBZMQ_URL
|
|
PYZMQ_LIBSODIUM_VERSION
|
|
PYZMQ_LIBSODIUM_URL
|
|
PYZMQ_LIBSODIUM_CONFIGURE_ARGS
|
|
PYZMQ_LIBSODIUM_MSBUILD_ARGS
|
|
PYZMQ_LIBSODIUM_VS_VERSION
|
|
)
|
|
if (DEFINED ENV{${_optname}})
|
|
if (_optname MATCHES ".*_ARGS")
|
|
# if it's an _ARGS, split "-a -b" into "-a" "-b"
|
|
# use native CMake lists for cmake args,
|
|
# native command-line strings for env variables
|
|
separate_arguments(${_optname} NATIVE_COMMAND "$ENV{${_optname}}")
|
|
else()
|
|
set(${_optname} "$ENV{${_optname}}")
|
|
endif()
|
|
endif()
|
|
endforeach()
|
|
|
|
if(ZMQ_DRAFT_API)
|
|
message(STATUS "enabling ZMQ_DRAFT_API")
|
|
add_compile_definitions(ZMQ_BUILD_DRAFT_API=1)
|
|
endif()
|
|
|
|
if (PYZMQ_LIBSODIUM_VERSION AND NOT PYZMQ_LIBSODIUM_URL)
|
|
set(PYZMQ_LIBSODIUM_URL "https://github.com/jedisct1/libsodium/releases/download/${PYZMQ_LIBSODIUM_VERSION}-RELEASE/libsodium-${PYZMQ_LIBSODIUM_VERSION}.tar.gz")
|
|
endif()
|
|
|
|
if (PYZMQ_LIBZMQ_VERSION AND NOT PYZMQ_LIBZMQ_URL)
|
|
set(PYZMQ_LIBZMQ_URL "https://github.com/zeromq/libzmq/releases/download/v${PYZMQ_LIBZMQ_VERSION}/zeromq-${PYZMQ_LIBZMQ_VERSION}.tar.gz")
|
|
endif()
|
|
|
|
#------- bundle libzmq ------
|
|
|
|
if (NOT ZMQ_PREFIX)
|
|
# empty string is the same as 'auto'
|
|
set(ZMQ_PREFIX "auto")
|
|
endif()
|
|
|
|
# default search paths:
|
|
|
|
foreach(prefix $ENV{PREFIX} "/opt/homebrew" "/opt/local" "/usr/local" "/usr")
|
|
if (IS_DIRECTORY "${prefix}")
|
|
list(APPEND CMAKE_PREFIX_PATH "${prefix}")
|
|
endif()
|
|
endforeach()
|
|
|
|
if (ZMQ_PREFIX STREQUAL "auto")
|
|
message(CHECK_START "Looking for libzmq")
|
|
find_package(ZeroMQ QUIET)
|
|
if (ZeroMQ_FOUND AND TARGET libzmq)
|
|
set(libzmq_target "libzmq")
|
|
get_target_property(_ZMQ_LOCATION libzmq IMPORTED_LOCATION)
|
|
message(CHECK_PASS "Found with cmake: ${_ZMQ_LOCATION}")
|
|
endif()
|
|
|
|
if (NOT ZeroMQ_FOUND)
|
|
find_package(PkgConfig QUIET)
|
|
if (PkgConfig_FOUND)
|
|
message(CHECK_START "Looking for libzmq with pkg-config")
|
|
pkg_check_modules(libzmq libzmq IMPORTED_TARGET)
|
|
if (TARGET PkgConfig::libzmq)
|
|
set(ZeroMQ_FOUND TRUE)
|
|
set(libzmq_target "PkgConfig::libzmq")
|
|
message(CHECK_PASS "found: -L${libzmq_LIBRARY_DIRS} -l${libzmq_LIBRARIES}")
|
|
if (PYZMQ_LIBZMQ_RPATH)
|
|
foreach(LIBZMQ_LIB_DIR IN LISTS libzmq_LIBRARY_DIRS)
|
|
message(STATUS " Adding ${LIBZMQ_LIB_DIR} to RPATH, set PYZMQ_LIBZMQ_RPATH=OFF if this is not what you want.")
|
|
list(APPEND CMAKE_INSTALL_RPATH "${LIBZMQ_LIB_DIR}")
|
|
endforeach()
|
|
endif()
|
|
else()
|
|
message(CHECK_FAIL "no")
|
|
endif()
|
|
endif()
|
|
endif()
|
|
|
|
if (NOT ZeroMQ_FOUND)
|
|
message(STATUS " Fallback: looking for libzmq in ${CMAKE_PREFIX_PATH}")
|
|
find_library(LIBZMQ_LIBRARY NAMES zmq)
|
|
find_path(LIBZMQ_INCLUDE_DIR "zmq.h")
|
|
|
|
# check if found
|
|
if (LIBZMQ_LIBRARY AND LIBZMQ_INCLUDE_DIR)
|
|
set(ZeroMQ_FOUND TRUE)
|
|
message(CHECK_PASS "${LIBZMQ_LIBRARY}")
|
|
# NOTE: we _could_ set RPATH here. Should we? Unclear.
|
|
if (PYZMQ_LIBZMQ_RPATH)
|
|
get_filename_component(LIBZMQ_LIB_DIR "${LIBZMQ_LIBRARY}" DIRECTORY)
|
|
message(STATUS " Adding ${LIBZMQ_LIB_DIR} to RPATH, set PYZMQ_LIBZMQ_RPATH=OFF if this is not what you want.")
|
|
list(APPEND CMAKE_INSTALL_RPATH "${LIBZMQ_LIB_DIR}")
|
|
endif()
|
|
endif()
|
|
endif()
|
|
|
|
if (NOT ZeroMQ_FOUND)
|
|
if (PYZMQ_NO_BUNDLE)
|
|
message(CHECK_FAIL "libzmq not found")
|
|
message(FATAL_ERROR "aborting because bundled libzmq is disabled")
|
|
else()
|
|
message(CHECK_FAIL "libzmq not found, will bundle libzmq and libsodium")
|
|
set(ZMQ_PREFIX "bundled")
|
|
endif()
|
|
endif()
|
|
elseif (NOT ZMQ_PREFIX STREQUAL "bundled")
|
|
message(CHECK_START "Looking for libzmq in ${ZMQ_PREFIX}")
|
|
find_path(
|
|
LIBZMQ_INCLUDE_DIR zmq.h
|
|
PATHS "${ZMQ_PREFIX}/include"
|
|
NO_DEFAULT_PATH
|
|
)
|
|
find_library(
|
|
LIBZMQ_LIBRARY
|
|
NAMES zmq
|
|
PATHS "${ZMQ_PREFIX}/lib"
|
|
NO_DEFAULT_PATH
|
|
)
|
|
if (LIBZMQ_LIBRARY AND LIBZMQ_INCLUDE_DIR)
|
|
message(CHECK_PASS "${LIBZMQ_LIBRARY}")
|
|
if (PYZMQ_LIBZMQ_RPATH)
|
|
# add prefix to RPATH
|
|
message(STATUS " Adding ${ZMQ_PREFIX}/lib to RPATH, set PYZMQ_LIBZMQ_RPATH=OFF if this is not what you want.")
|
|
list(APPEND CMAKE_INSTALL_RPATH "${ZMQ_PREFIX}/lib")
|
|
endif()
|
|
else()
|
|
message(CHECK_FAIL "no")
|
|
message(FATAL_ERROR "libzmq not found in ZMQ_PREFIX=${ZMQ_PREFIX}")
|
|
endif()
|
|
else()
|
|
# bundled
|
|
endif()
|
|
|
|
if (ZMQ_PREFIX STREQUAL "bundled")
|
|
message(STATUS "Bundling libzmq and libsodium")
|
|
include(FetchContent)
|
|
add_compile_definitions(ZMQ_STATIC=1)
|
|
set(BUNDLE_DIR "${CMAKE_CURRENT_BINARY_DIR}/bundled")
|
|
file(MAKE_DIRECTORY "${BUNDLE_DIR}/lib")
|
|
include_directories(${BUNDLE_DIR}/include)
|
|
list(PREPEND CMAKE_PREFIX_PATH ${BUNDLE_DIR})
|
|
|
|
set(LICENSE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/licenses")
|
|
file(MAKE_DIRECTORY "${LICENSE_DIR}")
|
|
|
|
# libsodium
|
|
|
|
if (MSVC)
|
|
set(libsodium_lib "${BUNDLE_DIR}/lib/libsodium.lib")
|
|
else()
|
|
set(libsodium_lib "${BUNDLE_DIR}/lib/libsodium.a")
|
|
endif()
|
|
|
|
FetchContent_Declare(bundled_libsodium
|
|
URL ${PYZMQ_LIBSODIUM_URL}
|
|
PREFIX ${BUNDLE_DIR}
|
|
)
|
|
FetchContent_MakeAvailable(bundled_libsodium)
|
|
configure_file("${bundled_libsodium_SOURCE_DIR}/LICENSE" "${LICENSE_DIR}/LICENSE.libsodium.txt" COPYONLY)
|
|
# run libsodium build explicitly here, so it's available to libzmq next
|
|
set(bundled_libsodium_include "${bundled_libsodium_SOURCE_DIR}/src/libsodium/include")
|
|
|
|
if(${bundled_libsodium_POPULATED} AND NOT EXISTS "${libsodium_lib}")
|
|
message(STATUS "building bundled libsodium")
|
|
if (MSVC)
|
|
# select vs build solution by msvc version number
|
|
if (NOT PYZMQ_LIBSODIUM_VS_VERSION)
|
|
if(MSVC_VERSION GREATER_EQUAL 1940)
|
|
message(STATUS "Unrecognized MSVC_VERSION=${MSVC_VERSION}")
|
|
set(MSVC_VERSION 1939)
|
|
endif()
|
|
|
|
if(MSVC_VERSION GREATER_EQUAL 1930)
|
|
set(PYZMQ_LIBSODIUM_VS_VERSION "2022")
|
|
elseif(MSVC_VERSION GREATER_EQUAL 1920)
|
|
set(PYZMQ_LIBSODIUM_VS_VERSION "2019")
|
|
elseif(MSVC_VERSION GREATER_EQUAL 1910)
|
|
set(PYZMQ_LIBSODIUM_VS_VERSION "2017")
|
|
else()
|
|
message(FATAL_ERROR "unsupported bundling libsodium for MSVC_VERSION=${MSVC_VERSION} (need at least VS2017)")
|
|
endif()
|
|
endif()
|
|
find_package(Vcvars REQUIRED)
|
|
list(APPEND libsodium_build
|
|
${Vcvars_LAUNCHER}
|
|
"msbuild"
|
|
"/m"
|
|
"/v:n"
|
|
"/p:Configuration=Static${CMAKE_BUILD_TYPE}"
|
|
"/p:Platform=${CMAKE_GENERATOR_PLATFORM}"
|
|
"builds/msvc/vs${PYZMQ_LIBSODIUM_VS_VERSION}/libsodium.sln"
|
|
)
|
|
list(APPEND libsodium_build ${PYZMQ_LIBSODIUM_MSBUILD_ARGS})
|
|
execute_process(
|
|
COMMAND ${libsodium_build}
|
|
WORKING_DIRECTORY ${bundled_libsodium_SOURCE_DIR}
|
|
COMMAND_ECHO STDOUT
|
|
# COMMAND_ERROR_IS_FATAL ANY
|
|
RESULT_VARIABLE _status
|
|
)
|
|
if (_status)
|
|
message(FATAL_ERROR "failed to build libsodium")
|
|
endif()
|
|
file(GLOB_RECURSE BUILT_LIB "${bundled_libsodium_SOURCE_DIR}/**/libsodium.lib")
|
|
message(STATUS "copy ${BUILT_LIB} ${libsodium_lib}")
|
|
configure_file(${BUILT_LIB} ${libsodium_lib} COPYONLY)
|
|
else()
|
|
list(APPEND libsodium_configure
|
|
./configure
|
|
--prefix=${BUNDLE_DIR}
|
|
--with-pic
|
|
--disable-dependency-tracking
|
|
--disable-shared
|
|
--enable-static
|
|
)
|
|
list(APPEND libsodium_configure ${PYZMQ_LIBSODIUM_CONFIGURE_ARGS})
|
|
execute_process(
|
|
COMMAND ${libsodium_configure}
|
|
WORKING_DIRECTORY ${bundled_libsodium_SOURCE_DIR}
|
|
COMMAND_ECHO STDOUT
|
|
# COMMAND_ERROR_IS_FATAL ANY
|
|
RESULT_VARIABLE _status
|
|
)
|
|
# COMMAND_ERROR_IS_FATAL requires cmake 3.19, ubuntu 20.04 has 3.16
|
|
if (_status)
|
|
message(FATAL_ERROR "failed to configure libsodium")
|
|
endif()
|
|
execute_process(
|
|
COMMAND make
|
|
WORKING_DIRECTORY ${bundled_libsodium_SOURCE_DIR}
|
|
COMMAND_ECHO STDOUT
|
|
# COMMAND_ERROR_IS_FATAL ANY
|
|
RESULT_VARIABLE _status
|
|
)
|
|
if (_status)
|
|
message(FATAL_ERROR "failed to build libsodium")
|
|
endif()
|
|
execute_process(
|
|
COMMAND make install
|
|
WORKING_DIRECTORY ${bundled_libsodium_SOURCE_DIR}
|
|
COMMAND_ECHO STDOUT
|
|
# COMMAND_ERROR_IS_FATAL ANY
|
|
RESULT_VARIABLE _status
|
|
)
|
|
if (_status)
|
|
message(FATAL_ERROR "failed to install libsodium")
|
|
endif()
|
|
endif()
|
|
endif()
|
|
|
|
# use libzmq's own cmake, so we can import the libzmq-static target
|
|
set(ENABLE_CURVE ON)
|
|
set(ENABLE_DRAFTS ${ZMQ_DRAFT_API})
|
|
set(ENABLE_LIBSODIUM_RANDOMBYTES_CLOSE "OFF")
|
|
set(WITH_LIBSODIUM ON)
|
|
set(WITH_LIBSODIUM_STATIC ON)
|
|
set(LIBZMQ_PEDANTIC OFF)
|
|
set(LIBZMQ_WERROR OFF)
|
|
set(WITH_DOC OFF)
|
|
set(WITH_DOCS OFF)
|
|
set(BUILD_TESTS OFF)
|
|
set(BUILD_SHARED OFF)
|
|
set(BUILD_STATIC ON)
|
|
|
|
if(NOT MSVC)
|
|
# backport check for kqueue, which is wrong in libzmq 4.3.5
|
|
# libzmq's cmake will proceed with the rest
|
|
# https://github.com/zeromq/libzmq/pull/4659
|
|
include(CheckCXXSymbolExists)
|
|
set(POLLER
|
|
""
|
|
CACHE STRING "Choose polling system for I/O threads. valid values are
|
|
kqueue, epoll, devpoll, pollset, poll or select [default=autodetect]")
|
|
if(POLLER STREQUAL "")
|
|
check_cxx_symbol_exists(kqueue "sys/types.h;sys/event.h;sys/time.h" HAVE_KQUEUE)
|
|
if(HAVE_KQUEUE)
|
|
set(POLLER "kqueue")
|
|
endif()
|
|
endif()
|
|
endif()
|
|
|
|
if(MSVC)
|
|
set(API_POLLER "select" CACHE STRING "Set API Poller (default: select)")
|
|
endif()
|
|
|
|
FetchContent_Declare(bundled_libzmq
|
|
URL ${PYZMQ_LIBZMQ_URL}
|
|
PREFIX ${BUNDLE_DIR}
|
|
)
|
|
FetchContent_MakeAvailable(bundled_libzmq)
|
|
configure_file("${bundled_libzmq_SOURCE_DIR}/LICENSE" "${LICENSE_DIR}/LICENSE.zeromq.txt" COPYONLY)
|
|
|
|
# target for libzmq static
|
|
if (TARGET libzmq-static)
|
|
set(libzmq_target "libzmq-static")
|
|
else()
|
|
message(FATAL_ERROR "libzmq-static target not found in bundled libzmq")
|
|
endif()
|
|
endif()
|
|
|
|
if (NOT TARGET "${libzmq_target}" AND LIBZMQ_LIBRARY AND LIBZMQ_INCLUDE_DIR)
|
|
set(libzmq_target "libzmq")
|
|
# construct target from find_library results
|
|
# what if it was static?
|
|
add_library(libzmq SHARED IMPORTED)
|
|
set_property(TARGET libzmq PROPERTY IMPORTED_LOCATION ${LIBZMQ_LIBRARY})
|
|
set_property(TARGET libzmq PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${LIBZMQ_INCLUDE_DIR})
|
|
endif()
|
|
|
|
#------- building pyzmq itself -------
|
|
|
|
message(STATUS "Using Python ${Python_INTERPRETER_ID} ${Python_EXECUTABLE}")
|
|
|
|
set(EXT_SRC_DIR "${CMAKE_CURRENT_BINARY_DIR}/_src")
|
|
set(ZMQ_BUILDUTILS "${CMAKE_CURRENT_SOURCE_DIR}/buildutils")
|
|
file(MAKE_DIRECTORY "${EXT_SRC_DIR}")
|
|
|
|
if(Python_INTERPRETER_ID STREQUAL "PyPy")
|
|
message(STATUS "Building CFFI backend")
|
|
set(ZMQ_EXT_NAME "_cffi")
|
|
|
|
set(ZMQ_BACKEND_DEST "zmq/backend/cffi")
|
|
set(ZMQ_C "${EXT_SRC_DIR}/${ZMQ_EXT_NAME}.c")
|
|
|
|
add_custom_command(
|
|
OUTPUT ${ZMQ_C}
|
|
VERBATIM
|
|
COMMAND "${Python_EXECUTABLE}"
|
|
"${ZMQ_BUILDUTILS}/build_cffi.py"
|
|
"${ZMQ_C}"
|
|
)
|
|
else()
|
|
message(STATUS "Building Cython backend")
|
|
find_program(CYTHON "cython")
|
|
|
|
set(ZMQ_BACKEND_DEST "zmq/backend/cython")
|
|
set(ZMQ_EXT_NAME "_zmq")
|
|
set(ZMQ_C "${EXT_SRC_DIR}/${ZMQ_EXT_NAME}.c")
|
|
set(ZMQ_PYX "${CMAKE_CURRENT_SOURCE_DIR}/zmq/backend/cython/${ZMQ_EXT_NAME}.py")
|
|
add_custom_command(
|
|
OUTPUT ${ZMQ_C}
|
|
DEPENDS ${ZMQ_PYX}
|
|
VERBATIM
|
|
COMMAND "${Python_EXECUTABLE}"
|
|
-mcython
|
|
--3str
|
|
--output-file ${ZMQ_C}
|
|
--module-name "zmq.backend.cython._zmq"
|
|
${ZMQ_PYX}
|
|
)
|
|
endif()
|
|
|
|
file(MAKE_DIRECTORY ${ZMQ_BACKEND_DEST})
|
|
|
|
python_add_library(
|
|
${ZMQ_EXT_NAME} MODULE
|
|
WITH_SOABI
|
|
${ZMQ_C}
|
|
)
|
|
|
|
if (TARGET ${libzmq_target})
|
|
message(STATUS "Linking libzmq target ${libzmq_target}")
|
|
target_link_libraries(${ZMQ_EXT_NAME} PUBLIC ${libzmq_target})
|
|
if ("${libzmq_target}" STREQUAL "libzmq-static" AND NOT MSVC)
|
|
# seem to need stdc++ for static libzmq on non-Windows
|
|
# not sure if/when this should be libc++ or how to know
|
|
target_link_libraries(${ZMQ_EXT_NAME} PUBLIC stdc++)
|
|
endif()
|
|
else()
|
|
message(FATAL_ERROR "should have a libzmq target ${libzmq_target} to link to...")
|
|
endif()
|
|
|
|
target_include_directories(${ZMQ_EXT_NAME} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/zmq/utils")
|
|
install(TARGETS ${ZMQ_EXT_NAME} DESTINATION "${ZMQ_BACKEND_DEST}" COMPONENT pyzmq)
|
|
|
|
# add custom target so we exclude bundled targets from installation
|
|
# only need this because the extension name is different for cff/cython
|
|
add_custom_target(pyzmq DEPENDS ${ZMQ_EXT_NAME})
|