cmake_minimum_required(VERSION 3.16.5)
project(plpython CXX)
option(ENABLE_PYTHON_EMBED "Install Python runtime into PG directory (non-standard)" OFF)
set(3RD_PATH_PY "$ENV{THIRD_BIN_PATH}/kernel/platform/python3.7/")
message("3RD_PATH_PY is ${3RD_PATH_PY}")
if(IS_DIRECTORY ${3RD_PATH_PY})
message("${3RD_PATH_PY} is found")
set(Python3_ROOT_DIR ${3RD_PATH_PY})
set(Python3_EXECUTABLE "${3RD_PATH_PY}/bin/python3")
set(Python3_LIBRARY "${3RD_PATH_PY}/lib/libpython3.7m.so")
endif()
find_package(Python3 3.7 REQUIRED COMPONENTS Interpreter Development)
set(PYTHON_MAJOR_VERSION ${Python3_VERSION_MAJOR})
set(PYTHON_VERSION ${Python3_VERSION})
set(PYTHON_INCLUDE_SPEC -I${Python3_INCLUDE_DIRS})
set(PYTHON_LIB_DIR ${Python3_LIBRARY_DIRS})
set(PLPYTHON_NAME "plpython${PYTHON_MAJOR_VERSION}")
message(NOTICE "Python3_LIBRARY = ${Python3_LIBRARY}")
message(NOTICE "Python3_LIBRARY_DIRS = ${Python3_LIBRARY_DIRS}")
message(NOTICE "Python3_INCLUDE_DIRS = ${Python3_INCLUDE_DIRS}")
set(SHARED_LIBPYTHON FALSE)
if(NOT Python3_LIBRARY MATCHES "\\.(a|lib)$")
set(SHARED_LIBPYTHON TRUE)
endif()
if(WIN32)
set(SHARED_LIBPYTHON TRUE)
string(REPLACE "\\" "/" PYTHON_INCLUDE_SPEC "${PYTHON_INCLUDE_SPEC}")
endif()
if(APPLE)
set(SHARED_LIBPYTHON TRUE)
endif()
if(NOT SHARED_LIBPYTHON)
message(FATAL_ERROR "Cannot build PL/Python because libpython is not a shared library. You might have to rebuild your Python installation.")
endif()
set(PLPYTHON_SRCS
plpy_cursorobject.cpp
plpy_elog.cpp
plpy_exec.cpp
plpy_main.cpp
plpy_planobject.cpp
plpy_plpymodule.cpp
plpy_procedure.cpp
plpy_resultobject.cpp
plpy_spi.cpp
plpy_subxactobject.cpp
plpy_typeio.cpp
plpy_util.cpp
)
if(WIN32 AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
string(REPLACE "." "" PYTVERSTR "${PYTHON_VERSION}")
set(PYTHON_DEF_FILE "python${PYTVERSTR}.def")
set(PYTHON_IMPORT_LIB "libpython${PYTVERSTR}.a")
get_filename_component(PYTHON_BIN_DIR ${Python3_EXECUTABLE} DIRECTORY)
find_file(PYTHON_DLL_PATH NAMES python${PYTVERSTR}.dll PATHS ${PYTHON_BIN_DIR} $ENV{WINDIR}/System32)
if(PYTHON_DLL_PATH)
add_custom_command(
OUTPUT ${PYTHON_DEF_FILE}
COMMAND pexports ${PYTHON_DLL_PATH} > ${PYTHON_DEF_FILE}
DEPENDS ${PYTHON_DLL_PATH}
COMMENT "Generating python.def from python.dll"
)
add_custom_command(
OUTPUT ${PYTHON_IMPORT_LIB}
COMMAND dlltool --dllname python${PYTVERSTR}.dll --def ${PYTHON_DEF_FILE} --output-lib ${PYTHON_IMPORT_LIB}
DEPENDS ${PYTHON_DEF_FILE}
COMMENT "Generating libpython.a import library"
)
list(APPEND PLPYTHON_SRCS ${PYTHON_IMPORT_LIB})
set(PYTHON_LIB_SPEC "")
else()
message(WARNING "Could not find python.dll for import lib generation. Standard linking will be attempted.")
set(PYTHON_LIB_SPEC ${Python3_LIBRARIES})
endif()
else()
set(PYTHON_LIB_SPEC ${Python3_LIBRARIES})
endif()
find_package(Perl REQUIRED)
set(ERRCODES_TXT "${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/common/backend/utils/errcodes.txt")
set(GEN_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/generate-spiexceptions.pl")
if(EXISTS ${ERRCODES_TXT} AND EXISTS ${GEN_SCRIPT})
add_custom_command(
OUTPUT spiexceptions.h
COMMAND ${PERL_EXECUTABLE} ${GEN_SCRIPT} ${ERRCODES_TXT} > ${CMAKE_CURRENT_SOURCE_DIR}/spiexceptions.h
DEPENDS ${ERRCODES_TXT} ${GEN_SCRIPT}
COMMENT "Generating spiexceptions.h"
)
set(GENERATED_HEADERS spiexceptions.h)
else()
message(WARNING "spiexceptions.h generation sources not found. Assuming pre-generated or system provided.")
set(GENERATED_HEADERS "")
endif()
add_library(${PLPYTHON_NAME} MODULE ${PLPYTHON_SRCS} ${GENERATED_HEADERS})
set(TGT_INC
${PROJECT_SRC_DIR}/include
${PROJECT_SRC_DIR}/include/nodes
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_INCLUDE_PATH}
)
target_compile_definitions(${PLPYTHON_NAME} PRIVATE
-DPLPYTHON_NAME="${PLPYTHON_NAME}"
PGXC
_REENTRANT
_THREAD_SAFE
_POSIX_PTHREAD_SEMANTICS
USE_SPQ
)
target_include_directories(${PLPYTHON_NAME} PRIVATE ${TGT_INC})
target_link_libraries(${PLPYTHON_NAME} PRIVATE
Python3::Python -ldl -lm
)
set_target_properties(${PLPYTHON_NAME} PROPERTIES
PREFIX ""
OUTPUT_NAME ${PLPYTHON_NAME}
)
set_target_properties(${PLPYTHON_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON)
if(APPLE)
set_target_properties(${PLPYTHON_NAME} PROPERTIES
LINK_FLAGS "-framework Python"
)
endif()
set(PLPYTHON_DATA
"${PLPYTHON_NAME}u.control"
"${PLPYTHON_NAME}u--1.0.sql"
"${PLPYTHON_NAME}u--unpackaged--1.0.sql"
)
set(TARGET_FILE "${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/test/regress/parallel_schedule0A")
set(MARKER_LINE "#support plpython3u")
set(CONTENT_TO_APPEND "\n${MARKER_LINE}
test: plpython3u/plpython_schema
test: plpython3u/plpython_populate
test: plpython3u/plpython_test
test: plpython3u/plpython_do
test: plpython3u/plpython_global
test: plpython3u/plpython_global_session
test: plpython3u/plpython_import
test: plpython3u/plpython_spi
test: plpython3u/plpython_newline plpython3u/plpython_void plpython3u/plpython_params plpython3u/plpython_setof plpython3u/plpython_record
test: plpython3u/plpython_types
test: plpython3u/plpython_error
test: plpython3u/plpython_unicode plpython3u/plpython_quote
test: plpython3u/plpython_composite
test: plpython3u/plpython_subtransaction
test: plpython3u/plpython_gms_xslprocessor plpython3u/plpython_gms_xmldom
test: plpython3u/plpython_drop")
if(EXISTS "${TARGET_FILE}")
file(READ "${TARGET_FILE}" FILE_CONTENT)
string(FIND "${FILE_CONTENT}" "${MARKER_LINE}" MARKER_POS)
if(MARKER_POS EQUAL -1)
file(APPEND "${TARGET_FILE}" "${CONTENT_TO_APPEND}")
message(STATUS "ppended plpython3u support content to ${TARGET_FILE}")
else()
message(STATUS "Marker '${MARKER_LINE}' already exists in the file, skipping append")
endif()
else()
message(FATAL_ERROR "Target file does not exist, please check the path: ${TARGET_FILE}")
endif()
if(FALSE)
find_program(PG_REGRESS pg_regress PATHS ${PG_BIN_DIR})
set(TEST_SQL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/sql")
set(TEST_EXPECTED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/expected")
set(TEST_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/python3")
file(MAKE_DIRECTORY "${TEST_BUILD_DIR}/sql")
file(MAKE_DIRECTORY "${TEST_BUILD_DIR}/expected")
find_program(SED_EXECUTABLE NAMES sed gsed)
find_program(SHELL_EXECUTABLE NAMES sh bash)
if(SED_EXECUTABLE AND SHELL_EXECUTABLE)
set(PREP_SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/prep_tests.sh")
file(WRITE ${PREP_SCRIPT}
"#!/bin/sh\n"
"mkdir -p ${TEST_BUILD_DIR}/sql ${TEST_BUILD_DIR}/expected\n"
"for file in ${TEST_SQL_DIR}/*.sql ${TEST_EXPECTED_DIR}/*.out; do\n"
" if [ -f \"$file\" ]; then\n"
" outfile=\"${TEST_BUILD_DIR}/$file\"\n"
" mkdir -p $(dirname \"$outfile\")\n"
" sed -e 's/except \\([[:alpha:]][[:alpha:].]*\\), *\\([[:alpha:]][[:alpha:]]*\\):/except \\1 as \\2:/g' \\\n"
" -e \"s/<type 'exceptions\\.\\([[:alpha:]]*\\)'>/<class '\\1'>/g\" \\\n"
" -e \"s/<type 'long'>/<class 'int'>/g\" \\\n"
" -e \"s/\\([0-9][0-9]*\\)L/\\1/g\" \\\n"
" -e 's/\\([ [{]\\)u\"/\\1\"/g' \\\n"
" -e \"s/\\([ [{]\\)u'/\\1'/g\" \\\n"
" -e \"s/def next/def __next__/g\" \\\n"
" -e \"s/LANGUAGE plpythonu/LANGUAGE ${PLPYTHON_NAME}/g\" \\\n"
" -e \"s/LANGUAGE plpython2u/LANGUAGE ${PLPYTHON_NAME}/g\" \\\n"
" -e \"s/EXTENSION plpythonu/EXTENSION ${PLPYTHON_NAME}/g\" \\\n"
" -e \"s/EXTENSION plpython2u/EXTENSION ${PLPYTHON_NAME}/g\" \\\n"
" \"$file\" > \"$outfile\"\n"
" fi\n"
"done\n"
)
add_custom_target(prep3
COMMAND ${SHELL_EXECUTABLE} ${PREP_SCRIPT}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Preparing Python 3 regression tests"
)
add_test(NAME plpython_regress
COMMAND ${PG_REGRESS} --inputdir=./python3 --outputdir=./python3 --dbname=postgres ${PLPYTHON_NAME}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
set_tests_properties(plpython_regress PROPERTIES
DEPENDS prep3
)
else()
message(WARNING "sed or shell not found. Regression test preparation skipped.")
endif()
endif()
install(TARGETS ${PLPYTHON_NAME}
LIBRARY DESTINATION lib/postgresql/
)
install(FILES ${PLPYTHON_DATA}
DESTINATION share/postgresql/extension/
)
if(ENABLE_PYTHON3)
get_filename_component(PYTHON_BIN_DIR ${Python3_EXECUTABLE} DIRECTORY)
get_filename_component(PYTHON_LIB_DIR ${Python3_LIBRARY} DIRECTORY)
set(PYTHON_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/python")
message(NOTICE "PYTHON_PARENT_DIR = ${PYTHON_PARENT_DIR}")
file(GLOB python_bins "${PYTHON_BIN_DIR}/python*")
file(GLOB python_libs "${PYTHON_LIB_DIR}/libpython3.*")
file(GLOB python_lib_dirs LIST_DIRECTORIES true "${PYTHON_LIB_DIR}/python3.*")
message(NOTICE "python_bins = ${python_bins}")
message(NOTICE "python_libs = ${python_libs}")
message(NOTICE "python_lib_dirs = ${python_lib_dirs}")
install(DIRECTORY DESTINATION "${PYTHON_INSTALL_DIR}/bin")
install(DIRECTORY DESTINATION "${PYTHON_INSTALL_DIR}/lib64")
install(FILES ${python_bins} DESTINATION "${PYTHON_INSTALL_DIR}/bin")
install(FILES ${python_libs} DESTINATION "${PYTHON_INSTALL_DIR}/lib64")
install(DIRECTORY ${python_lib_dirs} DESTINATION "${PYTHON_INSTALL_DIR}/lib64")
endif()
set_directory_properties(PROPERTIES
ADDITIONAL_CLEAN_FILES
"spiexceptions.h;${TEST_BUILD_DIR};python*.def;libpython*;${PREP_SCRIPT}"
)