cmake_minimum_required(VERSION 3.18) project(rpm VERSION 4.20.1 DESCRIPTION "The RPM Package Manager" HOMEPAGE_URL "http://rpm.org" LANGUAGES C ) # user configurable stuff option(ENABLE_CUTF8 "Enable C.UTF-8 as default locale" ON) option(ENABLE_NLS "Enable native language support" ON) option(ENABLE_OPENMP "Enable OpenMP threading support" ON) option(ENABLE_PYTHON "Enable Python bindings" ON) option(ENABLE_PLUGINS "Enable plugin support" ON) option(ENABLE_WERROR "Stop build on warnings" OFF) option(ENABLE_SQLITE "Enable sqlite rpmdb support" ON) option(ENABLE_NDB "Enable ndb rpmdb support" ON) option(ENABLE_BDB_RO "Enable read-only Berkeley DB rpmdb support (EXPERIMENTAL)" OFF) option(ENABLE_TESTSUITE "Enable test-suite" OFF) option(ENABLE_ASAN "Enable address-sanitizer" OFF) option(ENABLE_UBSAN "Enable undefined behavior-sanitizer" OFF) option(WITH_CAP "Build with capability support" ON) option(WITH_ACL "Build with ACL support" ON) option(WITH_SELINUX "Build with SELinux support" ON) option(WITH_DBUS "Build with DBUS support" ON) option(WITH_AUDIT "Build with audit support" ON) option(WITH_FSVERITY "Build with fsverity support" OFF) option(WITH_IMAEVM "Build with IMA support" OFF) option(WITH_FAPOLICYD "Build with fapolicyd support" ON) option(WITH_SEQUOIA "Build with Sequoia OpenPGP support" ON) option(WITH_OPENSSL "Use openssl instead of libgcrypt for internal crypto" OFF) option(WITH_READLINE "Build with readline support" ON) option(WITH_BZIP2 "Build with bzip2 support" ON) option(WITH_ICONV "Build with iconv support" ON) option(WITH_ZSTD "Build with zstd support" ON) option(WITH_LIBDW "Build with libdw support" ON) option(WITH_LIBELF "Build with libelf support" ON) option(WITH_LIBLZMA "Build with liblzma support" ON) option(WITH_DOXYGEN "Build API docs with doxygen" OFF) set(RPM_CONFIGDIR "${CMAKE_INSTALL_PREFIX}/lib/rpm" CACHE PATH "rpm home") set(RPM_MACROSDIR "${RPM_CONFIGDIR}/macros.d") set(RPM_VENDOR "vendor" CACHE STRING "rpm vendor string") # Emulate libtool versioning. Before a public release: # - increment micro version whenever there are code changes # - increment minor version whenever there are added interfaces # - increment major version whenever there are removed interfaces # - incrementing a more significant version segment resets changes to # any less significant segments set(RPM_SOVERSION 10) set(RPM_LIBVERSION ${RPM_SOVERSION}.2.1) set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS ON) set(CMAKE_SHARED_LIBRARY_PREFIX "") set(CMAKE_SHARED_MODULE_PREFIX "") set(CMAKE_POSITION_INDEPENDENT_CODE ON) include(GNUInstallDirs) include(CheckSymbolExists) add_compile_definitions(_GNU_SOURCE) add_definitions(-D_FILE_OFFSET_BITS=64) # Find a (system) utility in canonical FHS paths, excluding $PATH. Useful for # when the path is to be used at RPM runtime, such as in the macro files. The # MYPATH environment variable can be used to augment these paths. function(findutil UTIL TRY) list(GET TRY 0 util) find_program(${UTIL} NAMES ${TRY} PATHS ENV MYPATH PATHS /usr/local/bin /usr/bin /bin PATHS /usr/local/sbin /usr/sbin /sbin NO_DEFAULT_PATH ) if (NOT ${UTIL}) list(GET TRY 0 util) message(DEBUG "${util} not found, assuming /usr/bin/${util}") set(${UTIL} /usr/bin/${util} PARENT_SCOPE) endif() mark_as_advanced(${UTIL}) endfunction() function(makemacros) set(prefix ${CMAKE_INSTALL_PREFIX}) set(exec_prefix "\${prefix}") set(bindir "\${exec_prefix}/${CMAKE_INSTALL_BINDIR}") set(sbindir "\${exec_prefix}/${CMAKE_INSTALL_SBINDIR}") set(libexecdir "\${exec_prefix}/${CMAKE_INSTALL_LIBEXECDIR}") set(datarootdir "\${prefix}/${CMAKE_INSTALL_DATAROOTDIR}") set(datadir "\${datarootdir}") set(sysconfdir "${CMAKE_INSTALL_FULL_SYSCONFDIR}") set(sharedstatedir "${CMAKE_INSTALL_FULL_SHAREDSTATEDIR}") set(localstatedir "${CMAKE_INSTALL_FULL_LOCALSTATEDIR}") set(libdir "\${prefix}/=LIB=") set(includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}") set(oldincludedir "${CMAKE_INSTALL_FULL_OLDINCLUDEDIR}") set(infodir "\${prefix}/${CMAKE_INSTALL_INFODIR}") set(mandir "\${prefix}/${CMAKE_INSTALL_MANDIR}") set(rundir /run) pkg_get_variable(sysusersdir systemd sysusersdir) if (NOT sysusersdir) set(sysusersdir /usr/lib/sysusers.d) endif() findutil(__7ZIP "7za;7z") findutil(__BZIP2 bzip2) findutil(__CAT cat) findutil(__CHMOD chmod) findutil(__CHOWN chown) findutil(__CP cp) findutil(__CURL curl) findutil(__FILE file) findutil(__GPG gpg) findutil(__GREP grep) findutil(__GZIP gzip) findutil(__ID id) findutil(__CC cc) findutil(__LN ln) findutil(__INSTALL install) findutil(__LRZIP lrzip) findutil(__LZIP lzip) findutil(__XZ xz) findutil(__MAKE make) findutil(__MKDIR mkdir) findutil(__MV mv) findutil(__PATCH patch) findutil(__RM rm) findutil(__SED sed) findutil(__TAR tar) findutil(__UNZIP unzip) findutil(__ZSTD zstd) findutil(__GEM gem) findutil(__GIT git) findutil(__HG hg) findutil(__BZR bzr) findutil(__QUILT quilt) findutil(__LD ld) findutil(__OBJDUMP objdump) findutil(__STRIP strip) findutil(__SYSTEMD_SYSUSERS systemd-sysusers) findutil(__FIND_DEBUGINFO find-debuginfo) findutil(__AWK awk) findutil(__AR ar) findutil(__AS as) findutil(__CPP cpp) findutil(__CXX c++) list(GET db_backends 0 DB_BACKEND) set(host_cpu ${CMAKE_HOST_SYSTEM_PROCESSOR}) string(TOLOWER ${CMAKE_HOST_SYSTEM_NAME} host_os) set(host_vendor ${RPM_VENDOR}) set(host ${host_cpu}-${host_vendor}-${host_os}) set(RPMCANONVENDOR ${host_vendor}) set(RPMCANONOS ${host_os}) set(RPMCANONGNU -gnu) configure_file(platform.in platform @ONLY) configure_file(rpmrc.in rpmrc @ONLY) configure_file(macros.in macros @ONLY) configure_file(rpmpopt.in rpmpopt-${PROJECT_VERSION} @ONLY) configure_file(rpm.pc.in rpm.pc @ONLY) install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E env pkglibdir=${RPM_CONFIGDIR} ${CMAKE_SOURCE_DIR}/installplatform rpmrc platform macros ${RPMCANONVENDOR} ${RPMCANONOS} ${RPMCANONGNU} WORKING_DIRECTORY ${CMAKE_BINARY_DIR})" ) endfunction() include(CheckLibraryExists) include(CheckFunctionExists) include(CheckIncludeFile) include(CheckCCompilerFlag) include(CheckVariableExists) set(OPTFUNCS stpcpy stpncpy putenv mempcpy fdatasync lutimes mergesort getauxval setprogname __progname syncfs sched_getaffinity unshare secure_getenv __secure_getenv mremap strchrnul ) set(REQFUNCS mkstemp getcwd basename dirname realpath setenv unsetenv regcomp utimes getline localtime_r statvfs getaddrinfo openat mkdirat fstatat linkat symlinkat mkfifoat mknodat unlinkat renameat utimensat fchmodat fchownat stpcpy stpncpy ) find_package(PkgConfig REQUIRED) find_package(Lua 5.2 REQUIRED) find_package(ZLIB REQUIRED) if (WITH_BZIP2) find_package(BZip2 REQUIRED) endif() if (WITH_ICONV) find_package(Iconv REQUIRED) endif() pkg_check_modules(POPT REQUIRED IMPORTED_TARGET popt) if (WITH_READLINE) pkg_check_modules(READLINE REQUIRED IMPORTED_TARGET readline) endif() if (WITH_ZSTD) pkg_check_modules(ZSTD REQUIRED IMPORTED_TARGET libzstd>=1.3.8) endif() if (WITH_LIBELF) pkg_check_modules(LIBELF REQUIRED IMPORTED_TARGET libelf) endif() if (WITH_LIBDW) pkg_check_modules(LIBDW REQUIRED IMPORTED_TARGET libdw) endif() if (WITH_LIBLZMA) pkg_check_modules(LIBLZMA REQUIRED IMPORTED_TARGET liblzma>=5.2.0) endif() pkg_check_modules(LIBARCHIVE REQUIRED IMPORTED_TARGET libarchive) # Lua module does not ship an IMPORTED target, define our own add_library(LUA::LUA INTERFACE IMPORTED) set_target_properties(LUA::LUA PROPERTIES INTERFACE_LINK_LIBRARIES "${LUA_LIBRARIES}" INTERFACE_INCLUDE_DIRECTORIES "${LUA_INCLUDE_DIR}") # file >= 5.39 ships a pkg-config, may move to that later add_library(MAGIC::MAGIC UNKNOWN IMPORTED) find_library(MAGIC_LIBRARY NAMES magic REQUIRED) find_path(MAGIC_INCLUDE_DIR NAMES magic.h REQUIRED) mark_as_advanced(MAGIC_LIBRARY) mark_as_advanced(MAGIC_INCLUDE_DIR) set_target_properties(MAGIC::MAGIC PROPERTIES IMPORTED_LOCATION "${MAGIC_LIBRARY}") target_include_directories(MAGIC::MAGIC INTERFACE "${MAGIC_INCLUDE_DIR}") if (ENABLE_OPENMP) find_package(OpenMP 4.5 REQUIRED) endif() if (ENABLE_NLS) find_package(Intl REQUIRED) check_variable_exists(_nl_msg_cat_cntr HAVE_NL_MSG_CAT_CNTR) endif() if (ENABLE_SQLITE) pkg_check_modules(SQLITE REQUIRED IMPORTED_TARGET sqlite3>=3.22) list(APPEND db_backends sqlite) endif() if (ENABLE_NDB) list(APPEND db_backends ndb) endif() if (ENABLE_BDB_RO) list(APPEND db_backends bdb_ro) endif() list(APPEND db_backends dummy) if (ENABLE_PYTHON) find_package(Python3 3.7 COMPONENTS Interpreter Development REQUIRED) endif() if (WITH_CAP) pkg_check_modules(LIBCAP REQUIRED IMPORTED_TARGET libcap) endif() if (WITH_ACL) pkg_check_modules(LIBACL REQUIRED IMPORTED_TARGET libacl) endif() if (WITH_AUDIT) pkg_check_modules(AUDIT REQUIRED IMPORTED_TARGET audit) endif() if (WITH_SELINUX) pkg_check_modules(SELINUX REQUIRED IMPORTED_TARGET libselinux) endif() if (WITH_FSVERITY) pkg_check_modules(FSVERITY REQUIRED IMPORTED_TARGET libfsverity) endif() if (WITH_IMAEVM) list(APPEND REQFUNCS lsetxattr) check_library_exists(imaevm imaevm_signhash "" HAVE_IMAEVM_SIGNHASH) add_library(IMA::IMA UNKNOWN IMPORTED) find_path(IMA_INCLUDE_DIR NAMES imaevm.h REQUIRED) find_library(IMA_LIBRARY NAMES imaevm REQUIRED) mark_as_advanced(IMA_INCLUDE_DIR) mark_as_advanced(IMA_LIBRARY) set_target_properties(IMA::IMA PROPERTIES IMPORTED_LOCATION "${IMA_LIBRARY}") target_include_directories(IMA::IMA INTERFACE "${IMA_INCLUDE_DIR}") endif() find_program(AWK gawk mawk nawk awk REQUIRED) mark_as_advanced(AWK) find_program(FIND_DEBUGINFO find-debuginfo) mark_as_advanced(FIND_DEBUGINFO) function(chkdef func req) string(TOUPPER ${func} FUNC) set(HAVENAME HAVE_${FUNC}) check_function_exists(${func} ${HAVENAME}) if (${req} AND NOT ${HAVENAME}) message(FATAL_ERROR "required function ${func} not found") endif() endfunction() foreach(f ${OPTFUNCS}) chkdef(${f} FALSE) endforeach() foreach(f ${REQFUNCS}) chkdef(${f} TRUE) endforeach() function(chkhdr inc req) string(MAKE_C_IDENTIFIER ${inc} ID) string(TOUPPER ${ID} INC) set(HAVENAME HAVE_${INC}) check_include_file(${inc} ${HAVENAME}) if (${req} AND NOT ${HAVENAME}) message(FATAL_ERROR "required include ${inc} not found") endif() endfunction() set(OPTINCS unistd.h limits.h getopt.h sys/utsname.h sys/systemcfg.h sys/param.h sys/auxv.h ) foreach(f ${OPTINCS}) chkhdr(${f} FALSE) endforeach() function(id0name var file) execute_process(COMMAND ${AWK} -F: "$3==0 {print $1;exit}" ${file} OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE name) if ("${name}" STREQUAL "") set(name root) endif() set(${var} ${name} PARENT_SCOPE) endfunction() id0name(UID_0_USER /etc/passwd) id0name(GID_0_GROUP /etc/group) # map module/package findings to config.h if (BZIP2_FOUND) set(HAVE_BZLIB_H 1) endif() if (LIBLZMA_FOUND) set(HAVE_LZMA_H 1) endif() if (Iconv_FOUND) set(HAVE_ICONV 1) endif() if (ZSTD_FOUND) set(HAVE_ZSTD 1) endif() if (READLINE_FOUND) set(HAVE_READLINE 1) endif() if (LIBELF_FOUND) set(HAVE_LIBELF 1) endif() if (LIBDW_FOUND) set(HAVE_LIBDW 1) check_library_exists(dw dwelf_elf_begin "" HAVE_DWELF_ELF_BEGIN) endif() check_symbol_exists(GLOB_ONLYDIR "glob.h" HAVE_GLOB_ONLYDIR) check_symbol_exists(major "sys/sysmacros.h" MAJOR_IN_SYSMACROS) if (NOT MAJOR_IN_SYSMACROS) check_symbol_exists(major "sys/mkdev.h" MAJOR_IN_MKDEV) endif() if (ENABLE_CUTF8) set(C_LOCALE "C.UTF-8") else() set(C_LOCALE "C") endif() message(INFO " using ${C_LOCALE} as default locale") configure_file(config.h.in config.h) add_compile_definitions(HAVE_CONFIG_H) add_compile_options(-Wall -Wpointer-arith -Wmissing-prototypes -Wstrict-prototypes -Wempty-body -Wformat-security) if (ENABLE_WERROR) add_compile_options(-Werror) endif() if (ENABLE_ASAN) add_compile_options(-fsanitize=address) add_link_options(-fsanitize=address) endif() if (ENABLE_UBSAN) add_compile_options(-fsanitize=undefined) add_link_options(-fsanitize=undefined) endif() if (ENABLE_ASAN OR ENABLE_UBSAN) add_compile_options(-fno-omit-frame-pointer) endif() # try to ensure some compiler sanity and hardening options where supported foreach (flag -fno-strict-overflow -fno-delete-null-pointer-checks -fhardened) check_c_compiler_flag(${flag} found) if (found) add_compile_options(${flag}) endif() unset(found) endforeach() # generated sources include_directories(${CMAKE_BINARY_DIR}) # global private includes include_directories(${CMAKE_SOURCE_DIR}/misc) # public headers include_directories(${CMAKE_SOURCE_DIR}/include) add_subdirectory(docs) add_subdirectory(include/rpm) add_subdirectory(misc) add_subdirectory(rpmio) add_subdirectory(lib) add_subdirectory(build) add_subdirectory(sign) add_subdirectory(tools) if (EXISTS ${CMAKE_SOURCE_DIR}/po/rpm.pot) add_subdirectory(po) endif() if (ENABLE_PYTHON) add_subdirectory(python) endif() set(RPM_PLUGINDIR ${CMAKE_INSTALL_FULL_LIBDIR}/rpm-plugins CACHE PATH "rpm plugin directory") if (ENABLE_PLUGINS) add_subdirectory(plugins) endif() add_subdirectory(fileattrs) add_subdirectory(scripts) makemacros() foreach(f macros rpmrc rpmpopt-${PROJECT_VERSION}) install(FILES ${CMAKE_BINARY_DIR}/${f} DESTINATION ${RPM_CONFIGDIR}) endforeach() if (ENABLE_TESTSUITE) add_subdirectory(tests) endif() install(FILES ${CMAKE_CURRENT_BINARY_DIR}/rpm.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) install(DIRECTORY DESTINATION ${RPM_CONFIGDIR}/lua) install(DIRECTORY DESTINATION ${RPM_CONFIGDIR}/macros.d) install(FILES CONTRIBUTING.md COPYING CREDITS INSTALL README TYPE DOC) add_custom_target(ChangeLog WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND git log --no-merges --no-decorate --output=${CMAKE_BINARY_DIR}/ChangeLog ) add_custom_command(OUTPUT po/rpm.pot COMMAND git submodule update --init) function(add_tarball targetname namever treeish) set(distfmt tar) set(tarname ${namever}.${distfmt}) set(distname ${tarname}.bz2) set(docname ${namever}-doc.${distfmt}) add_custom_target(${docname} DEPENDS man apidoc COMMAND tar -C ${CMAKE_BINARY_DIR} --transform 's:^:${namever}/:' -cf ${docname} docs/man/*.[1-8] docs/html/ ) add_custom_target(${distname} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} VERBATIM DEPENDS ChangeLog ${docname} po/rpm.pot COMMAND git archive --format=${distfmt} --output=${CMAKE_BINARY_DIR}/${tarname} --prefix=${namever}/ --add-file=${CMAKE_BINARY_DIR}/ChangeLog ${treeish} COMMAND git submodule foreach --quiet "git archive --prefix=${namever}/$sm_path/ \ --output=${CMAKE_BINARY_DIR}/$sha1.tar HEAD \ && tar --concatenate \ --file=${CMAKE_BINARY_DIR}/${tarname} \ ${CMAKE_BINARY_DIR}/$sha1.tar \ && rm -f ${CMAKE_BINARY_DIR}/$sha1.tar" COMMAND tar --concatenate --file=${CMAKE_BINARY_DIR}/${tarname} ${CMAKE_BINARY_DIR}/${docname} COMMAND bzip2 -f ${CMAKE_BINARY_DIR}/${tarname} ) add_custom_target(${targetname} DEPENDS ${distname}) endfunction() add_tarball(dist ${PROJECT_NAME}-${PROJECT_VERSION} HEAD) if (EXISTS ${CMAKE_SOURCE_DIR}/.git) execute_process(COMMAND git rev-list --count HEAD WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE gitcount OUTPUT_STRIP_TRAILING_WHITESPACE) add_tarball(snapshot ${PROJECT_NAME}-${PROJECT_VERSION}-git${gitcount} HEAD) endif() # Voodoo rites to make our libraries cmake find_package() importable include(CMakePackageConfigHelpers) configure_package_config_file( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/rpm-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/rpm-config.cmake INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/rpm ) write_basic_package_version_file( ${CMAKE_CURRENT_BINARY_DIR}/rpm-config-version.cmake COMPATIBILITY SameMinorVersion ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/rpm-config.cmake ${CMAKE_CURRENT_BINARY_DIR}/rpm-config-version.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/rpm ) export(TARGETS librpm librpmio librpmbuild librpmsign FILE rpm-targets.cmake NAMESPACE rpm:: ) install(EXPORT rpm-targets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${CMAKE_PROJECT_NAME} NAMESPACE rpm:: )