# PostgreSQL 17 — Self-contained CMake build for FenrirOS (GNU-free, musl/LLVM) # # This CMakeLists.txt is fully self-contained: it runs configure (POSIX-sh probe), # generates parser files (bison/flex), generates catalog headers (perl), and then # builds the entire server + client suite with cmake/ninja. # # Requirements in PATH: # - C compiler (musl-clang via toolchain file) # - bison, flex (or /usr/bin/bison, /usr/bin/flex from Debian) # - perl (for catalog header generation) # - m4 (needed by flex at runtime) cmake_minimum_required(VERSION 3.16) project(PostgreSQL VERSION 17.0 LANGUAGES C) set(CMAKE_C_STANDARD 99) set(CMAKE_POSITION_INDEPENDENT_CODE ON) # PostgreSQL source needs these feature-test macros for Linux APIs add_compile_definitions( _GNU_SOURCE _POSIX_C_SOURCE=200809L ) # ── source root ────────────────────────────────────────────── set(PG_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src") # ══════════════════════════════════════════════════════════════ # Step 1: Run ./configure to generate pg_config.h (POSIX-sh probe) # ══════════════════════════════════════════════════════════════ if(NOT EXISTS "${PG_SRC}/include/pg_config.h") message(STATUS "Running ./configure to generate pg_config.h ...") execute_process( COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/configure --prefix=${CMAKE_INSTALL_PREFIX} --without-readline --without-zlib --without-icu --without-systemd WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} RESULT_VARIABLE _configure_result ) if(NOT _configure_result EQUAL 0) message(FATAL_ERROR "PostgreSQL ./configure failed (exit ${_configure_result})") endif() endif() # ══════════════════════════════════════════════════════════════ # Step 2: Pre-generate parser files (bison + flex) # ══════════════════════════════════════════════════════════════ find_program(BISON_EXECUTABLE bison PATHS /usr/bin /usr/local/bin) find_program(FLEX_EXECUTABLE flex PATHS /usr/local/bin /usr/bin) find_program(M4_EXECUTABLE m4 PATHS /usr/local/bin /usr/bin) if(NOT EXISTS "${PG_SRC}/backend/parser/gram.c") if(NOT BISON_EXECUTABLE) message(FATAL_ERROR "bison not found — needed to generate gram.c/gram.h") endif() message(STATUS "Generating gram.c/gram.h with bison ...") execute_process( COMMAND ${BISON_EXECUTABLE} -d -o gram.c gram.y WORKING_DIRECTORY ${PG_SRC}/backend/parser RESULT_VARIABLE _bison_result ) if(NOT _bison_result EQUAL 0) message(FATAL_ERROR "bison failed (exit ${_bison_result})") endif() endif() if(NOT EXISTS "${PG_SRC}/backend/parser/scan.c") if(NOT FLEX_EXECUTABLE) message(FATAL_ERROR "flex not found — needed to generate scan.c") endif() message(STATUS "Generating scan.c with flex ...") set(ENV{M4} "${M4_EXECUTABLE}") execute_process( COMMAND ${FLEX_EXECUTABLE} -o scan.c scan.l WORKING_DIRECTORY ${PG_SRC}/backend/parser RESULT_VARIABLE _flex_result ) if(NOT _flex_result EQUAL 0) message(FATAL_ERROR "flex failed (exit ${_flex_result})") endif() endif() # Also generate replication scanner/parser if missing if(NOT EXISTS "${PG_SRC}/backend/replication/repl_gram.c") if(BISON_EXECUTABLE) message(STATUS "Generating repl_gram.c with bison ...") execute_process( COMMAND ${BISON_EXECUTABLE} -d -o repl_gram.c repl_gram.y WORKING_DIRECTORY ${PG_SRC}/backend/replication RESULT_VARIABLE _repl_bison_result ) endif() endif() if(NOT EXISTS "${PG_SRC}/backend/replication/repl_scanner.c") if(FLEX_EXECUTABLE) message(STATUS "Generating repl_scanner.c with flex ...") set(ENV{M4} "${M4_EXECUTABLE}") execute_process( COMMAND ${FLEX_EXECUTABLE} -o repl_scanner.c repl_scanner.l WORKING_DIRECTORY ${PG_SRC}/backend/replication RESULT_VARIABLE _repl_flex_result ) endif() endif() # Generate other flex/bison outputs that may be missing # syncrep scanner/parser if(NOT EXISTS "${PG_SRC}/backend/replication/syncrep_scanner.c" AND EXISTS "${PG_SRC}/backend/replication/syncrep_scanner.l") if(FLEX_EXECUTABLE) message(STATUS "Generating syncrep_scanner.c with flex ...") set(ENV{M4} "${M4_EXECUTABLE}") execute_process( COMMAND ${FLEX_EXECUTABLE} -o syncrep_scanner.c syncrep_scanner.l WORKING_DIRECTORY ${PG_SRC}/backend/replication ) endif() endif() if(NOT EXISTS "${PG_SRC}/backend/replication/syncrep_gram.c" AND EXISTS "${PG_SRC}/backend/replication/syncrep_gram.y") if(BISON_EXECUTABLE) execute_process( COMMAND ${BISON_EXECUTABLE} -d -o syncrep_gram.c syncrep_gram.y WORKING_DIRECTORY ${PG_SRC}/backend/replication ) endif() endif() # bootstrap parser/scanner if(NOT EXISTS "${PG_SRC}/backend/bootstrap/bootparse.c" AND EXISTS "${PG_SRC}/backend/bootstrap/bootparse.y") if(BISON_EXECUTABLE) execute_process( COMMAND ${BISON_EXECUTABLE} -d -o bootparse.c bootparse.y WORKING_DIRECTORY ${PG_SRC}/backend/bootstrap ) endif() endif() if(NOT EXISTS "${PG_SRC}/backend/bootstrap/bootscanner.c" AND EXISTS "${PG_SRC}/backend/bootstrap/bootscanner.l") if(FLEX_EXECUTABLE) set(ENV{M4} "${M4_EXECUTABLE}") execute_process( COMMAND ${FLEX_EXECUTABLE} -o bootscanner.c bootscanner.l WORKING_DIRECTORY ${PG_SRC}/backend/bootstrap ) endif() endif() # GUC scanner if(NOT EXISTS "${PG_SRC}/backend/utils/misc/guc-file.c" AND EXISTS "${PG_SRC}/backend/utils/misc/guc-file.l") if(FLEX_EXECUTABLE) set(ENV{M4} "${M4_EXECUTABLE}") execute_process( COMMAND ${FLEX_EXECUTABLE} -o guc-file.c guc-file.l WORKING_DIRECTORY ${PG_SRC}/backend/utils/misc ) endif() endif() # pgbench expression parser/scanner if(NOT EXISTS "${PG_SRC}/bin/pgbench/exprparse.c" AND EXISTS "${PG_SRC}/bin/pgbench/exprparse.y") if(BISON_EXECUTABLE) execute_process( COMMAND ${BISON_EXECUTABLE} -d -o exprparse.c exprparse.y WORKING_DIRECTORY ${PG_SRC}/bin/pgbench ) endif() endif() if(NOT EXISTS "${PG_SRC}/bin/pgbench/exprscan.c" AND EXISTS "${PG_SRC}/bin/pgbench/exprscan.l") if(FLEX_EXECUTABLE) set(ENV{M4} "${M4_EXECUTABLE}") execute_process( COMMAND ${FLEX_EXECUTABLE} -o exprscan.c exprscan.l WORKING_DIRECTORY ${PG_SRC}/bin/pgbench ) endif() endif() # psql scanner if(NOT EXISTS "${PG_SRC}/fe_utils/psqlscan.c" AND EXISTS "${PG_SRC}/fe_utils/psqlscan.l") if(FLEX_EXECUTABLE) set(ENV{M4} "${M4_EXECUTABLE}") execute_process( COMMAND ${FLEX_EXECUTABLE} -o psqlscan.c psqlscan.l WORKING_DIRECTORY ${PG_SRC}/fe_utils ) endif() endif() # psql slash-command scanner if(NOT EXISTS "${PG_SRC}/bin/psql/psqlscanslash.c" AND EXISTS "${PG_SRC}/bin/psql/psqlscanslash.l") if(FLEX_EXECUTABLE) set(ENV{M4} "${M4_EXECUTABLE}") execute_process( COMMAND ${FLEX_EXECUTABLE} -o psqlscanslash.c psqlscanslash.l WORKING_DIRECTORY ${PG_SRC}/bin/psql ) endif() endif() # jsonpath parser/scanner if(NOT EXISTS "${PG_SRC}/backend/utils/adt/jsonpath_gram.c" AND EXISTS "${PG_SRC}/backend/utils/adt/jsonpath_gram.y") if(BISON_EXECUTABLE) execute_process( COMMAND ${BISON_EXECUTABLE} -d -o jsonpath_gram.c jsonpath_gram.y WORKING_DIRECTORY ${PG_SRC}/backend/utils/adt ) endif() endif() if(NOT EXISTS "${PG_SRC}/backend/utils/adt/jsonpath_scan.c" AND EXISTS "${PG_SRC}/backend/utils/adt/jsonpath_scan.l") if(FLEX_EXECUTABLE) set(ENV{M4} "${M4_EXECUTABLE}") execute_process( COMMAND ${FLEX_EXECUTABLE} -o jsonpath_scan.c jsonpath_scan.l WORKING_DIRECTORY ${PG_SRC}/backend/utils/adt ) endif() endif() # ══════════════════════════════════════════════════════════════ # Step 3: Pre-generate catalog headers (perl) # ══════════════════════════════════════════════════════════════ find_program(PERL_EXECUTABLE perl PATHS /usr/bin /usr/local/bin) if(NOT EXISTS "${PG_SRC}/include/catalog/pg_proc_d.h") if(NOT PERL_EXECUTABLE) message(FATAL_ERROR "perl not found — needed to generate catalog headers") endif() message(STATUS "Generating catalog headers with perl ...") # Use make to run the catalog generation targets (they invoke perl scripts) execute_process( COMMAND make -C src/backend/catalog generated-headers WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} RESULT_VARIABLE _cat_result ) if(NOT _cat_result EQUAL 0) message(FATAL_ERROR "Catalog header generation failed") endif() endif() # Generate errcodes.h if missing if(NOT EXISTS "${PG_SRC}/include/utils/errcodes.h") message(STATUS "Generating errcodes.h ...") execute_process( COMMAND make -C src/backend/utils errcodes.h WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) endif() # Generate fmgroids.h / fmgrprotos.h / fmgrtab.c if missing if(NOT EXISTS "${PG_SRC}/include/utils/fmgroids.h") message(STATUS "Generating fmgr files ...") execute_process( COMMAND make -C src/backend/utils fmgroids.h fmgrprotos.h fmgrtab.c WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) endif() # Generate schemapg.h if missing if(NOT EXISTS "${PG_SRC}/include/catalog/schemapg.h") message(STATUS "Generating schemapg.h ...") execute_process( COMMAND make -C src/include/catalog distprep WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) endif() # ── generate pg_config_paths.h ─────────────────────────────── set(PG_PREFIX "${CMAKE_INSTALL_PREFIX}") file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/pg_config_paths.h" "#define PGBINDIR \"${PG_PREFIX}/bin\" #define PGSHAREDIR \"${PG_PREFIX}/share/postgresql\" #define SYSCONFDIR \"${PG_PREFIX}/etc/postgresql\" #define INCLUDEDIR \"${PG_PREFIX}/include\" #define PKGINCLUDEDIR \"${PG_PREFIX}/include/postgresql\" #define INCLUDEDIRSERVER \"${PG_PREFIX}/include/postgresql/server\" #define LIBDIR \"${PG_PREFIX}/lib\" #define PKGLIBDIR \"${PG_PREFIX}/lib/postgresql\" #define LOCALEDIR \"${PG_PREFIX}/share/locale\" #define DOCDIR \"${PG_PREFIX}/share/doc/postgresql\" #define HTMLDIR \"${PG_PREFIX}/share/doc/postgresql\" #define MANDIR \"${PG_PREFIX}/share/man\" ") # ── common include dirs ───────────────────────────────────── set(PG_INCLUDE_DIRS ${PG_SRC}/include ${PG_SRC}/include/port/linux ${PG_SRC}/include/portability ${PG_SRC}/include/snowball # PG wrapper header.h (must come before libstemmer) ${PG_SRC}/port # pg_config_paths.h from prior build ${PG_SRC}/interfaces/libpq # libpq-fe.h for libpqwalreceiver ${PG_SRC}/backend ${PG_SRC}/backend/utils ${CMAKE_CURRENT_SOURCE_DIR} # for pg_config.h if at top level ${CMAKE_CURRENT_BINARY_DIR} # for generated pg_config_paths.h ) # ── options ────────────────────────────────────────────────── option(PG_USE_OPENSSL "Link with OpenSSL/LibreSSL" OFF) # ══════════════════════════════════════════════════════════════ # libpgcommon — common utility code shared by server and clients # ══════════════════════════════════════════════════════════════ file(GLOB PGCOMMON_SRCS "${PG_SRC}/common/*.c") # Remove test files and OS-specific files list(FILTER PGCOMMON_SRCS EXCLUDE REGEX ".*_test\\.c$") list(FILTER PGCOMMON_SRCS EXCLUDE REGEX ".*/norm_test\\.c$") list(FILTER PGCOMMON_SRCS EXCLUDE REGEX ".*/case_test\\.c$") list(FILTER PGCOMMON_SRCS EXCLUDE REGEX ".*/category_test\\.c$") # Remove OpenSSL files if not using it if(NOT PG_USE_OPENSSL) list(FILTER PGCOMMON_SRCS EXCLUDE REGEX ".*_openssl\\.c$") list(FILTER PGCOMMON_SRCS EXCLUDE REGEX ".*/protocol_openssl\\.c$") endif() # Remove fe_memutils (frontend only) and restricted_token (win32) list(FILTER PGCOMMON_SRCS EXCLUDE REGEX ".*/fe_memutils\\.c$") list(FILTER PGCOMMON_SRCS EXCLUDE REGEX ".*/restricted_token\\.c$") # Server copy: exclude logging.c (frontend-only, needs fe_memutils) set(PGCOMMON_SRV_SRCS ${PGCOMMON_SRCS}) list(FILTER PGCOMMON_SRV_SRCS EXCLUDE REGEX ".*/logging\\.c$") add_library(pgcommon_srv STATIC ${PGCOMMON_SRV_SRCS}) target_include_directories(pgcommon_srv PUBLIC ${PG_INCLUDE_DIRS}) # Server: do NOT define FRONTEND target_compile_definitions(pgcommon_srv PRIVATE _GNU_SOURCE _POSIX_C_SOURCE=200809L) # Frontend version (for client tools) set(PGCOMMON_FE_SRCS ${PGCOMMON_SRCS}) # Add frontend-only files list(APPEND PGCOMMON_FE_SRCS "${PG_SRC}/common/fe_memutils.c" "${PG_SRC}/common/restricted_token.c" "${PG_SRC}/common/logging.c" ) add_library(pgcommon_fe STATIC ${PGCOMMON_FE_SRCS}) target_include_directories(pgcommon_fe PUBLIC ${PG_INCLUDE_DIRS}) target_compile_definitions(pgcommon_fe PRIVATE FRONTEND) # ══════════════════════════════════════════════════════════════ # libpgport — portability functions # ══════════════════════════════════════════════════════════════ file(GLOB PGPORT_SRCS "${PG_SRC}/port/*.c") # Remove win32-specific files list(FILTER PGPORT_SRCS EXCLUDE REGEX ".*/win32.*\\.c$") # Remove dirent (POSIX already has it) list(FILTER PGPORT_SRCS EXCLUDE REGEX ".*/dirent\\.c$") # Remove inet_aton (musl has it) list(FILTER PGPORT_SRCS EXCLUDE REGEX ".*/inet_aton\\.c$") # Remove pthread_barrier_wait (musl already provides it) list(FILTER PGPORT_SRCS EXCLUDE REGEX ".*/pthread_barrier_wait\\.c$") # Remove CRC32C arch-specific files that need special compiler flags list(FILTER PGPORT_SRCS EXCLUDE REGEX ".*_armv8.*\\.c$") list(FILTER PGPORT_SRCS EXCLUDE REGEX ".*_loongarch.*\\.c$") # Remove CRC AVX512 (not needed, only ARM/LoongArch CRC variants removed) list(FILTER PGPORT_SRCS EXCLUDE REGEX ".*crc32c_.*avx512.*\\.c$") # SSE4.2 CRC files need special flags set(PG_CRC_SSE42_SRC "${PG_SRC}/port/pg_crc32c_sse42.c") if(EXISTS "${PG_CRC_SSE42_SRC}") set_source_files_properties(${PG_CRC_SSE42_SRC} PROPERTIES COMPILE_FLAGS "-msse4.2") endif() # AVX512 popcount files need special flags set(PG_POPCOUNT_AVX512_SRC "${PG_SRC}/port/pg_popcount_avx512.c") set(PG_POPCOUNT_AVX512_CHOOSE_SRC "${PG_SRC}/port/pg_popcount_avx512_choose.c") if(EXISTS "${PG_POPCOUNT_AVX512_SRC}") set_source_files_properties(${PG_POPCOUNT_AVX512_SRC} PROPERTIES COMPILE_FLAGS "-mavx512bw -mavx512vpopcntdq") endif() if(EXISTS "${PG_POPCOUNT_AVX512_CHOOSE_SRC}") set_source_files_properties(${PG_POPCOUNT_AVX512_CHOOSE_SRC} PROPERTIES COMPILE_FLAGS "-mxsave") endif() add_library(pgport_srv STATIC ${PGPORT_SRCS}) target_include_directories(pgport_srv PUBLIC ${PG_INCLUDE_DIRS}) # Server: do NOT define FRONTEND target_compile_definitions(pgport_srv PRIVATE _GNU_SOURCE _POSIX_C_SOURCE=200809L) add_library(pgport_fe STATIC ${PGPORT_SRCS}) target_include_directories(pgport_fe PUBLIC ${PG_INCLUDE_DIRS}) target_compile_definitions(pgport_fe PRIVATE FRONTEND) # ══════════════════════════════════════════════════════════════ # libpq — client library # ══════════════════════════════════════════════════════════════ file(GLOB LIBPQ_SRCS "${PG_SRC}/interfaces/libpq/*.c") # Remove win32-specific list(FILTER LIBPQ_SRCS EXCLUDE REGEX ".*/win32\\.c$") list(FILTER LIBPQ_SRCS EXCLUDE REGEX ".*/pthread-win32\\.c$") # Remove OpenSSL if not using if(NOT PG_USE_OPENSSL) list(FILTER LIBPQ_SRCS EXCLUDE REGEX ".*-openssl\\.c$") list(FILTER LIBPQ_SRCS EXCLUDE REGEX ".*fe-secure-openssl\\.c$") endif() # Remove GSSAPI list(FILTER LIBPQ_SRCS EXCLUDE REGEX ".*-gssapi.*\\.c$") add_library(pq SHARED ${LIBPQ_SRCS}) target_include_directories(pq PRIVATE ${PG_INCLUDE_DIRS} ${PG_SRC}/interfaces/libpq ) target_compile_definitions(pq PRIVATE FRONTEND) target_link_libraries(pq PRIVATE pgcommon_fe pgport_fe) if(PG_USE_OPENSSL) target_link_libraries(pq PRIVATE ssl crypto) endif() add_library(pq_static STATIC ${LIBPQ_SRCS}) target_include_directories(pq_static PRIVATE ${PG_INCLUDE_DIRS} ${PG_SRC}/interfaces/libpq ) target_compile_definitions(pq_static PRIVATE FRONTEND) set_target_properties(pq_static PROPERTIES OUTPUT_NAME pq) # ══════════════════════════════════════════════════════════════ # postgres — the server backend # ══════════════════════════════════════════════════════════════ # Collect ALL backend .c files recursively file(GLOB_RECURSE BACKEND_SRCS "${PG_SRC}/backend/*.c") # Remove win32-specific port files list(FILTER BACKEND_SRCS EXCLUDE REGEX ".*/port/win32.*\\.c$") list(FILTER BACKEND_SRCS EXCLUDE REGEX ".*/port/win32_sema\\.c$") list(FILTER BACKEND_SRCS EXCLUDE REGEX ".*/port/win32_shmem\\.c$") # Remove semaphore/shmem alternative implementations # pg_sema.c = posix_sema.c (copied by configure), exclude the others list(FILTER BACKEND_SRCS EXCLUDE REGEX ".*/port/sysv_sema\\.c$") list(FILTER BACKEND_SRCS EXCLUDE REGEX ".*/port/posix_sema\\.c$") # pg_shmem.c = sysv_shmem.c (copied by configure), exclude the source list(FILTER BACKEND_SRCS EXCLUDE REGEX ".*/port/sysv_shmem\\.c$") # Remove node fragment files (*.switch.c, *.funcs.c) — these are #included list(FILTER BACKEND_SRCS EXCLUDE REGEX ".*\\.switch\\.c$") list(FILTER BACKEND_SRCS EXCLUDE REGEX ".*\\.funcs\\.c$") # Remove regex fragment files — #included by regcomp.c / regexec.c list(FILTER BACKEND_SRCS EXCLUDE REGEX ".*/regc_.*\\.c$") list(FILTER BACKEND_SRCS EXCLUDE REGEX ".*/rege_.*\\.c$") # Remove other fragment .c files that are #included, not compiled standalone list(FILTER BACKEND_SRCS EXCLUDE REGEX ".*/levenshtein\\.c$") list(FILTER BACKEND_SRCS EXCLUDE REGEX ".*/like_match\\.c$") list(FILTER BACKEND_SRCS EXCLUDE REGEX ".*/pgstat_wait_event\\.c$") list(FILTER BACKEND_SRCS EXCLUDE REGEX ".*/wait_event_funcs_data\\.c$") # Remove standalone utility/test programs in utils/mb list(FILTER BACKEND_SRCS EXCLUDE REGEX ".*/utils/mb/iso\\.c$") list(FILTER BACKEND_SRCS EXCLUDE REGEX ".*/utils/mb/win1251\\.c$") list(FILTER BACKEND_SRCS EXCLUDE REGEX ".*/utils/mb/win866\\.c$") # Remove GSSAPI auth files list(FILTER BACKEND_SRCS EXCLUDE REGEX ".*be-gssapi-common\\.c$") list(FILTER BACKEND_SRCS EXCLUDE REGEX ".*be-secure-gssapi\\.c$") # Remove loadable modules (PG_MODULE_MAGIC) — they're built as .so separately list(FILTER BACKEND_SRCS EXCLUDE REGEX ".*/conversion_procs/.*\\.c$") list(FILTER BACKEND_SRCS EXCLUDE REGEX ".*/libpqwalreceiver/.*\\.c$") list(FILTER BACKEND_SRCS EXCLUDE REGEX ".*/pgoutput/.*\\.c$") list(FILTER BACKEND_SRCS EXCLUDE REGEX ".*/snowball/dict_snowball\\.c$") # Remove OpenSSL backend files if not enabled if(NOT PG_USE_OPENSSL) list(FILTER BACKEND_SRCS EXCLUDE REGEX ".*be-secure-openssl\\.c$") endif() # Remove JIT LLVM files (we don't use JIT) list(FILTER BACKEND_SRCS EXCLUDE REGEX ".*/jit/llvm.*\\.c$") # Remove parser .y and .l originals if they got picked up list(FILTER BACKEND_SRCS EXCLUDE REGEX ".*\\.y$") list(FILTER BACKEND_SRCS EXCLUDE REGEX ".*\\.l$") # Timezone library (needed by backend) file(GLOB TZ_SRCS "${PG_SRC}/timezone/*.c") list(FILTER TZ_SRCS EXCLUDE REGEX ".*/zic\\.c$") # zic is a standalone tool add_executable(postgres ${BACKEND_SRCS} ${TZ_SRCS}) target_include_directories(postgres PRIVATE ${PG_INCLUDE_DIRS} ${PG_SRC}/backend/utils ${PG_SRC}/backend/snowball/libstemmer ${PG_SRC}/timezone ) target_compile_definitions(postgres PRIVATE BUILDING_DLL ) # Allow multiple definitions — backend fd.c overrides file_utils.c versions target_link_options(postgres PRIVATE "LINKER:--allow-multiple-definition") target_link_libraries(postgres PRIVATE pgcommon_srv pgport_srv m dl pthread rt ) if(PG_USE_OPENSSL) target_link_libraries(postgres PRIVATE ssl crypto) endif() # Export dynamic symbols for loadable modules set_target_properties(postgres PROPERTIES ENABLE_EXPORTS TRUE) # ══════════════════════════════════════════════════════════════ # libfe_utils — frontend utility library (psql, pg_dump, etc.) # ══════════════════════════════════════════════════════════════ file(GLOB FE_UTILS_SRCS "${PG_SRC}/fe_utils/*.c") add_library(fe_utils STATIC ${FE_UTILS_SRCS}) target_include_directories(fe_utils PRIVATE ${PG_INCLUDE_DIRS}) target_compile_definitions(fe_utils PRIVATE FRONTEND) target_link_libraries(fe_utils PRIVATE pgcommon_fe) # ══════════════════════════════════════════════════════════════ # Client tools # ══════════════════════════════════════════════════════════════ set(CLIENT_LIBS fe_utils pq_static pgcommon_fe pgport_fe m pthread) set(CLIENT_DEFS FRONTEND) # ── psql ───────────────────────────────────────────────────── file(GLOB PSQL_SRCS "${PG_SRC}/bin/psql/*.c") list(FILTER PSQL_SRCS EXCLUDE REGEX ".*/t/.*") add_executable(psql ${PSQL_SRCS}) target_include_directories(psql PRIVATE ${PG_INCLUDE_DIRS} ${PG_SRC}/bin/psql) target_compile_definitions(psql PRIVATE ${CLIENT_DEFS}) target_link_libraries(psql PRIVATE ${CLIENT_LIBS}) # ── pg_dump / pg_dumpall / pg_restore ──────────────────────── # Shared object files for pg_dump and pg_restore (not pg_dumpall) set(PGDUMP_OBJS "${PG_SRC}/bin/pg_dump/compress_gzip.c" "${PG_SRC}/bin/pg_dump/compress_io.c" "${PG_SRC}/bin/pg_dump/compress_lz4.c" "${PG_SRC}/bin/pg_dump/compress_none.c" "${PG_SRC}/bin/pg_dump/compress_zstd.c" "${PG_SRC}/bin/pg_dump/dumputils.c" "${PG_SRC}/bin/pg_dump/filter.c" "${PG_SRC}/bin/pg_dump/parallel.c" "${PG_SRC}/bin/pg_dump/pg_backup_archiver.c" "${PG_SRC}/bin/pg_dump/pg_backup_custom.c" "${PG_SRC}/bin/pg_dump/pg_backup_db.c" "${PG_SRC}/bin/pg_dump/pg_backup_directory.c" "${PG_SRC}/bin/pg_dump/pg_backup_null.c" "${PG_SRC}/bin/pg_dump/pg_backup_tar.c" "${PG_SRC}/bin/pg_dump/pg_backup_utils.c" ) add_executable(pg_dump ${PGDUMP_OBJS} "${PG_SRC}/bin/pg_dump/pg_dump.c" "${PG_SRC}/bin/pg_dump/common.c" "${PG_SRC}/bin/pg_dump/pg_dump_sort.c" ) target_include_directories(pg_dump PRIVATE ${PG_INCLUDE_DIRS} ${PG_SRC}/bin/pg_dump) target_compile_definitions(pg_dump PRIVATE ${CLIENT_DEFS}) target_link_libraries(pg_dump PRIVATE ${CLIENT_LIBS}) add_executable(pg_dumpall "${PG_SRC}/bin/pg_dump/pg_dumpall.c" "${PG_SRC}/bin/pg_dump/dumputils.c" "${PG_SRC}/bin/pg_dump/filter.c" ) target_include_directories(pg_dumpall PRIVATE ${PG_INCLUDE_DIRS} ${PG_SRC}/bin/pg_dump) target_compile_definitions(pg_dumpall PRIVATE ${CLIENT_DEFS}) target_link_libraries(pg_dumpall PRIVATE ${CLIENT_LIBS}) add_executable(pg_restore ${PGDUMP_OBJS} "${PG_SRC}/bin/pg_dump/pg_restore.c" ) target_include_directories(pg_restore PRIVATE ${PG_INCLUDE_DIRS} ${PG_SRC}/bin/pg_dump) target_compile_definitions(pg_restore PRIVATE ${CLIENT_DEFS}) target_link_libraries(pg_restore PRIVATE ${CLIENT_LIBS}) # ── initdb ─────────────────────────────────────────────────── file(GLOB INITDB_SRCS "${PG_SRC}/bin/initdb/*.c") add_executable(initdb ${INITDB_SRCS}) target_include_directories(initdb PRIVATE ${PG_INCLUDE_DIRS} ${PG_SRC}/timezone) target_compile_definitions(initdb PRIVATE ${CLIENT_DEFS}) target_link_libraries(initdb PRIVATE ${CLIENT_LIBS}) # ── pg_ctl ─────────────────────────────────────────────────── add_executable(pg_ctl "${PG_SRC}/bin/pg_ctl/pg_ctl.c") target_include_directories(pg_ctl PRIVATE ${PG_INCLUDE_DIRS}) target_compile_definitions(pg_ctl PRIVATE ${CLIENT_DEFS}) target_link_libraries(pg_ctl PRIVATE ${CLIENT_LIBS}) # ── pg_config ──────────────────────────────────────────────── add_executable(pg_config_bin "${PG_SRC}/bin/pg_config/pg_config.c") target_include_directories(pg_config_bin PRIVATE ${PG_INCLUDE_DIRS}) target_compile_definitions(pg_config_bin PRIVATE ${CLIENT_DEFS}) target_link_libraries(pg_config_bin PRIVATE pgcommon_fe pgport_fe) set_target_properties(pg_config_bin PROPERTIES OUTPUT_NAME pg_config) # ── pg_controldata ─────────────────────────────────────────── add_executable(pg_controldata "${PG_SRC}/bin/pg_controldata/pg_controldata.c") target_include_directories(pg_controldata PRIVATE ${PG_INCLUDE_DIRS}) target_compile_definitions(pg_controldata PRIVATE ${CLIENT_DEFS}) target_link_libraries(pg_controldata PRIVATE pgcommon_fe pgport_fe m) # ── pg_checksums ───────────────────────────────────────────── add_executable(pg_checksums "${PG_SRC}/bin/pg_checksums/pg_checksums.c") target_include_directories(pg_checksums PRIVATE ${PG_INCLUDE_DIRS}) target_compile_definitions(pg_checksums PRIVATE ${CLIENT_DEFS}) target_link_libraries(pg_checksums PRIVATE fe_utils pgcommon_fe pgport_fe m) # ── pg_resetwal ────────────────────────────────────────────── add_executable(pg_resetwal "${PG_SRC}/bin/pg_resetwal/pg_resetwal.c") target_include_directories(pg_resetwal PRIVATE ${PG_INCLUDE_DIRS}) target_compile_definitions(pg_resetwal PRIVATE ${CLIENT_DEFS}) target_link_libraries(pg_resetwal PRIVATE fe_utils pgcommon_fe pgport_fe m) # ── pg_basebackup tools ────────────────────────────────────── file(GLOB PG_BASEBACKUP_SRCS "${PG_SRC}/bin/pg_basebackup/*.c") # Separate the entry point files set(PG_BASEBACKUP_COMMON_SRCS ${PG_BASEBACKUP_SRCS}) list(FILTER PG_BASEBACKUP_COMMON_SRCS EXCLUDE REGEX ".*/pg_basebackup\\.c$") list(FILTER PG_BASEBACKUP_COMMON_SRCS EXCLUDE REGEX ".*/pg_receivewal\\.c$") list(FILTER PG_BASEBACKUP_COMMON_SRCS EXCLUDE REGEX ".*/pg_recvlogical\\.c$") list(FILTER PG_BASEBACKUP_COMMON_SRCS EXCLUDE REGEX ".*/pg_createsubscriber\\.c$") add_executable(pg_basebackup ${PG_BASEBACKUP_COMMON_SRCS} "${PG_SRC}/bin/pg_basebackup/pg_basebackup.c") target_include_directories(pg_basebackup PRIVATE ${PG_INCLUDE_DIRS} ${PG_SRC}/bin/pg_basebackup) target_compile_definitions(pg_basebackup PRIVATE ${CLIENT_DEFS}) target_link_libraries(pg_basebackup PRIVATE ${CLIENT_LIBS}) # ── scripts (createdb, dropdb, etc.) ───────────────────────── set(SCRIPT_COMMON "${PG_SRC}/bin/scripts/common.c") foreach(tool IN ITEMS createdb createuser dropdb dropuser clusterdb reindexdb vacuumdb pg_isready) add_executable(${tool} "${PG_SRC}/bin/scripts/${tool}.c" ${SCRIPT_COMMON} ) target_include_directories(${tool} PRIVATE ${PG_INCLUDE_DIRS} ${PG_SRC}/bin/scripts) target_compile_definitions(${tool} PRIVATE ${CLIENT_DEFS}) target_link_libraries(${tool} PRIVATE ${CLIENT_LIBS}) endforeach() # ── pg_waldump ─────────────────────────────────────────────── file(GLOB PG_WALDUMP_SRCS "${PG_SRC}/bin/pg_waldump/*.c") add_executable(pg_waldump ${PG_WALDUMP_SRCS}) target_include_directories(pg_waldump PRIVATE ${PG_INCLUDE_DIRS}) target_compile_definitions(pg_waldump PRIVATE ${CLIENT_DEFS}) target_link_libraries(pg_waldump PRIVATE pgcommon_fe pgport_fe m) # ── pgbench ────────────────────────────────────────────────── file(GLOB PGBENCH_SRCS "${PG_SRC}/bin/pgbench/*.c") add_executable(pgbench ${PGBENCH_SRCS}) target_include_directories(pgbench PRIVATE ${PG_INCLUDE_DIRS} ${PG_SRC}/bin/pgbench) target_compile_definitions(pgbench PRIVATE ${CLIENT_DEFS}) target_link_libraries(pgbench PRIVATE ${CLIENT_LIBS}) # ══════════════════════════════════════════════════════════════ # Install # ══════════════════════════════════════════════════════════════ install(TARGETS postgres psql initdb pg_ctl pg_config_bin pg_dump pg_dumpall pg_restore pg_controldata pg_checksums pg_resetwal pg_basebackup pg_waldump pgbench createdb createuser dropdb dropuser clusterdb reindexdb vacuumdb pg_isready RUNTIME DESTINATION bin ) install(TARGETS pq LIBRARY DESTINATION lib ) install(TARGETS pq_static ARCHIVE DESTINATION lib ) # Install libpq headers install(FILES ${PG_SRC}/interfaces/libpq/libpq-fe.h ${PG_SRC}/include/libpq/libpq-fs.h ${PG_SRC}/include/pg_config_ext.h ${PG_SRC}/include/postgres_ext.h ${PG_SRC}/include/pg_config.h ${PG_SRC}/include/pg_config_manual.h ${PG_SRC}/include/pg_config_os.h DESTINATION include ) install(DIRECTORY ${PG_SRC}/include/libpq/ DESTINATION include/libpq FILES_MATCHING PATTERN "*.h" ) # Install server include files for extensions install(DIRECTORY ${PG_SRC}/include/ DESTINATION include/postgresql/server FILES_MATCHING PATTERN "*.h" ) # Install timezone data if(EXISTS "${PG_SRC}/timezone/data") install(DIRECTORY ${PG_SRC}/timezone/data/ DESTINATION share/postgresql/timezone ) endif()