# This file is part of Projecteur - https://github.com/jahnf/projecteur - See LICENSE.md and README.md cmake_minimum_required(VERSION 3.6) include(LinuxDistributionInfo) set(_LinuxPackaging_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}") set(_LinuxPackaging_cpack_template "LinuxPkgCPackConfig.cmake.in") list(APPEND _LinuxPackaging_MAP_dist_pkgtype "debian::DEB" "ubuntu::DEB" "opensuse::RPM" "opensuse-leap::RPM" "fedora::RPM" "centos::RPM" "rhel::RPM" "arch::PKGBUILD" "archlinux::PKGBUILD" ) set(_LinuxPackaging_default_pkgtype "TGZ") # Function that adds 'dist-package' target # Arguments: # PROJECT : Project name to package # TARGET : Main executable target with version information # DESCRIPTION_BRIEF : Brief package description. # DESCRIPTION_FULL : Full package description. # CONTACT : Package maintainer/contact. # HOMEAPGE : The project homepage # DEBIAN_SECTION.....: A valid debian package section (default=devel) function(add_dist_package_target) set(oneValueArgs PROJECT # project name to package TARGET # main executable build target that has version information attached to it DESCRIPTION_BRIEF DESCRIPTION_FULL CONTACT # Maintainer / contact person HOMEPAGE DEBIAN_SECTION PREINST_SCRIPT POSTINST_SCRIPT PRERM_SCRIPT POSTRM_SCRIPT ) set(requiredArgs PROJECT TARGET) cmake_parse_arguments(PKG "" "${oneValueArgs}" "" ${ARGN}) foreach(arg IN LISTS requiredArgs) if("${PKG_${arg}}" STREQUAL "") message(FATAL_ERROR "Required argument '${arg}' is not set.") endif() endforeach() if(NOT TARGET ${PKG_TARGET}) message(FATAL_ERROR "Argument 'TARGET' needs to be a valid target.") endif() get_target_property(PKG_VERSION_STRING_FULL ${PKG_TARGET} VERSION_STRING_FULL) get_target_property(PKG_VERSION_STRING ${PKG_TARGET} VERSION_STRING) get_target_property(PKG_VERSION_MAJOR ${PKG_TARGET} VERSION_MAJOR) get_target_property(PKG_VERSION_MINOR ${PKG_TARGET} VERSION_MINOR) get_target_property(PKG_VERSION_PATCH ${PKG_TARGET} VERSION_PATCH) get_target_property(PKG_VERSION_FLAG ${PKG_TARGET} VERSION_FLAG) get_target_property(PKG_VERSION_DISTANCE ${PKG_TARGET} VERSION_DISTANCE) get_target_property(PKG_VERSION_BRANCH ${PKG_TARGET} VERSION_BRANCH) if("${PKG_VERSION_MAJOR}" STREQUAL "") set(PKG_VERSION_MAJOR 0) endif() if("${PKG_VERSION_MINOR}" STREQUAL "") set(PKG_VERSION_MINOR 0) endif() if("${PKG_VERSION_PATCH}" STREQUAL "") set(PKG_VERSION_PATCH 0) endif() set(PKG_VERSION_STRING_BASE "${PKG_VERSION_MAJOR}.${PKG_VERSION_MINOR}.${PKG_VERSION_PATCH}") if("${PKG_VERSION_FLAG}" STREQUAL "") set(PKG_VERSION_IDENTIFIERS "1") else() set(PKG_VERSION_IDENTIFIERS "0${PKG_VERSION_FLAG}.${PKG_VERSION_DISTANCE}") endif() # Set defaults if not set if("${PKG_CONTACT}" STREQUAL "") set(PKG_CONTACT "Generic Maintainer ") endif() if("${PKG_DEBIAN_SECTION}" STREQUAL "") set(PKG_DEBIAN_SECTION "devel") endif() find_program(CPACK_COMMAND cpack) if(NOT CPACK_COMMAND) message(FATAL_ERROR "CPack command was not found.") endif() get_linux_distribution(LINUX_DIST_NAME LINUX_DIST_VERSION) # Get the package type to be generated by the target from our map variable set(PKG_TYPE "${_LinuxPackaging_default_pkgtype}") set(PKG_TYPE_FOUND 0) foreach(v "${LINUX_DIST_NAME}-${LINUX_DIST_VERSION}" "${LINUX_DIST_NAME}") foreach(pair ${_LinuxPackaging_MAP_dist_pkgtype}) if( "${pair}" MATCHES "${v}::(.*)") set(PKG_TYPE "${CMAKE_MATCH_1}") set(PKG_TYPE_FOUND 1) break() endif() endforeach() if(PKG_TYPE_FOUND) break() endif() endforeach() # Check if project package dependencies exist include(PkgDependencies${PKG_PROJECT} OPTIONAL RESULT_VARIABLE INCLUDED_PROJECT_DEPENDENCIES) if(INCLUDED_PROJECT_DEPENDENCIES AND PkgDependencies_MAP_${PKG_PROJECT}) set(PKG_DEPENDENCY_FOUND 0) # Find dependencies for Linux distribution (and version) foreach(v "${LINUX_DIST_NAME}-${LINUX_DIST_VERSION}" "${LINUX_DIST_NAME}") foreach(pair ${PkgDependencies_MAP_${PKG_PROJECT}}) if( "${pair}" MATCHES "${v}::(.*)") if("${PKG_TYPE}" STREQUAL "PKGBUILD") unset(_install_deps) foreach(_dep ${${CMAKE_MATCH_1}}) list(APPEND _install_deps "'${_dep}'") endforeach() string(REPLACE ";" " " PKG_DEPENDENCIES "${_install_deps}") else() string(REPLACE ";" ", " PKG_DEPENDENCIES "${${CMAKE_MATCH_1}}") endif() set(PKG_DEPENDENCY_FOUND 1) break() endif() endforeach() if(PKG_DEPENDENCY_FOUND) break() endif() endforeach() endif() if(INCLUDED_PROJECT_DEPENDENCIES AND PkgDependenciesMake_MAP_${PKG_PROJECT}) set(PKG_BUILD_DEPENDENCY_FOUND 0) # Find dependencies for Linux distribution (and version) foreach(v "${LINUX_DIST_NAME}-${LINUX_DIST_VERSION}" "${LINUX_DIST_NAME}") foreach(pair ${PkgDependenciesMake_MAP_${PKG_PROJECT}}) if( "${pair}" MATCHES "${v}::(.*)") if("${PKG_TYPE}" STREQUAL "PKGBUILD") unset(_install_deps) foreach(_dep ${${CMAKE_MATCH_1}}) list(APPEND _install_deps "'${_dep}'") endforeach() string(REPLACE ";" " " PKG_BUILD_DEPENDENCIES "${_install_deps}") else() string(REPLACE ";" ", " PKG_BUILD_DEPENDENCIES "${${CMAKE_MATCH_1}}") endif() set(PKG_BUILD_DEPENDENCY_FOUND 1) break() endif() endforeach() if(PKG_BUILD_DEPENDENCY_FOUND) break() endif() endforeach() endif() string(TOLOWER "${PKG_PROJECT}" PKG_NAME) set(PKG_LICENSE "MIT") set(PKG_DIST "${LINUX_DIST_NAME}-${LINUX_DIST_VERSION}") string(TIMESTAMP PKG_DATE "%Y-%m-%d") if("${PKG_TYPE}" STREQUAL "PKGBUILD") _makepkg_packaging() else() _cpack_default_packaging() endif() configure_file( "${_LinuxPackaging_DIRECTORY}/travis-ci-bintray-deploy.json.in" "${CMAKE_CURRENT_BINARY_DIR}/travis-ci-bintray-deploy.json" @ONLY) message(STATUS "Configured target 'dist-package' with Linux '${PKG_DIST}' and package type '${PKG_TYPE}'") # Make some information available to parent scope set(PKG_DIST "${PKG_DIST}" PARENT_SCOPE) set(PKG_TYPE "${PKG_TYPE}" PARENT_SCOPE) endfunction() # makepg packaging (arch linux/pacman) function(_makepkg_packaging) get_target_property(PKG_SOURCE_ARCHIVE_PATH source-archive OUTPUT_ARCHIVE) get_filename_component(PKG_SOURCE_ARCHIVE_DIR "${PKG_SOURCE_ARCHIVE_PATH}" DIRECTORY) get_filename_component(PKG_SOURCE_ARCHIVE_FILE "${PKG_SOURCE_ARCHIVE_PATH}" NAME) set(PKG_PKGBUILD_PKGREL 1) set(PKG_PKGBUILD_ARCH "${CMAKE_SYSTEM_PROCESSOR}") set(PKG_PKGBUILD_INSTALL_FILE "${PKG_NAME}.install") set(PKG_PKGBUILD_INSTALL_FILE_PATH "${PKG_SOURCE_ARCHIVE_DIR}/${PKG_PKGBUILD_INSTALL_FILE}") file(MAKE_DIRECTORY "${PKG_SOURCE_ARCHIVE_DIR}") file(WRITE "${PKG_PKGBUILD_INSTALL_FILE_PATH}" "# generated install file\n\n") if(PKG_PREINST_SCRIPT) file(READ "${PKG_PREINST_SCRIPT}" _pkg_preinst_script_content) file(APPEND "${PKG_PKGBUILD_INSTALL_FILE_PATH}" "pre_install() {\n" " : # null operation in case the preinst file is empty\n" " ${_pkg_preinst_script_content}" "}\n\n" "pre_upgrade() {\n" " : # null operation in case the preinst file is empty\n" " ${_pkg_preinst_script_content}" "}\n\n" ) endif() if(PKG_POSTINST_SCRIPT) file(READ "${PKG_POSTINST_SCRIPT}" _pkg_postinst_script_content) file(APPEND "${PKG_PKGBUILD_INSTALL_FILE_PATH}" "post_install() {\n" " : # null operation in case the preinst file is empty\n" " ${_pkg_postinst_script_content}" "}\n\n" "post_upgrade() {\n" " : # null operation in case the preinst file is empty\n" " ${_pkg_postinst_script_content}" "}\n\n" ) endif() if(PKG_PRERM_SCRIPT) file(READ "${PKG_PRERM_SCRIPT}" _pkg_prerm_script_content) file(APPEND "${PKG_PKGBUILD_INSTALL_FILE_PATH}" "pre_remove() {\n" " : # null operation in case the preinst file is empty\n" " ${_pkg_prerm_script_content}" "}\n\n" ) endif() if(PKG_POSTRM_SCRIPT) file(READ "${PKG_POSTRM_SCRIPT}" _pkg_postrm_script_content) file(APPEND "${PKG_PKGBUILD_INSTALL_FILE_PATH}" "post_remove() {\n" " : # null operation in case the preinst file is empty\n" " ${_pkg_postrm_script_content}" "}\n\n" ) endif() # makepkg: '-' is not allowed in version number string(REPLACE "-" "" PKG_PKGBUILD_VER "${PKG_VERSION_STRING_FULL}") set(PKG_CONFIG_TEMPLATE "${_LinuxPackaging_DIRECTORY}/PKGBUILD.in") set(PKG_CONFIG_FILE "${PKG_SOURCE_ARCHIVE_DIR}/PKGBUILD") configure_file("${PKG_CONFIG_TEMPLATE}" "${PKG_CONFIG_FILE}" @ONLY) find_program(MAKEPKG_EXECUTABLE makepkg) set(PKGBUILD_OUTPUT_FILE "${PKG_NAME}-${PKG_PKGBUILD_VER}-${PKG_PKGBUILD_PKGREL}-${PKG_PKGBUILD_ARCH}.pkg.tar.xz") set(PKGBUILD_OUTPUT_PATH "${PKG_SOURCE_ARCHIVE_DIR}/${PKGBUILD_OUTPUT_FILE}") set(PKGBUILD_FINAL_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/dist-pkg") set(PKGBUILD_FINAL_FILE "${PKG_NAME}-${PKG_PKGBUILD_VER}-${PKG_PKGBUILD_PKGREL}_${LINUX_DIST_NAME}-${PKG_PKGBUILD_ARCH}.pkg.tar.xz") add_custom_target(dist-package COMMAND ${MAKEPKG_EXECUTABLE} -f --log --skipinteg WORKING_DIRECTORY "${PKG_SOURCE_ARCHIVE_DIR}" VERBATIM ) add_custom_command(TARGET dist-package PRE_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E make_directory "${PKGBUILD_FINAL_OUTPUT_DIR}" ) add_custom_command(TARGET dist-package POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different "${PKGBUILD_OUTPUT_PATH}" "${PKGBUILD_FINAL_OUTPUT_DIR}/${PKGBUILD_FINAL_FILE}" ) add_dependencies(dist-package source-archive) endfunction() # Default cpack packaging (DEB, RPM, TGZ) function(_cpack_default_packaging) set(PKG_CPACK_PKG_FILENAME "${PKG_NAME}-${PKG_VERSION_STRING}_${PKG_DIST}-${CMAKE_SYSTEM_PROCESSOR}") set(PKG_CPACK_PKG_FILE_PREFIX "dist-pkg") set(PKG_CONFIG_TEMPLATE "${_LinuxPackaging_DIRECTORY}/LinuxPkgCPackConfig.cmake.in") set(PKG_CONFIG_FILE "${CMAKE_CURRENT_BINARY_DIR}/CPackConfig-${PKG_TYPE}.cmake") configure_file("${PKG_CONFIG_TEMPLATE}" "${PKG_CONFIG_FILE}" @ONLY) add_custom_target(dist-package COMMAND ${CPACK_COMMAND} --config "${PKG_CONFIG_FILE}" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} VERBATIM ) endfunction() ## Add 'source-archive' target function(add_source_archive_target target) find_package(Git) find_program(TAR_EXECUTABLE tar) find_program(GZIP_EXECUTABLE gzip) if(GIT_FOUND) get_target_property(VERSION_STRING ${target} VERSION_STRING) execute_process(COMMAND ${GIT_EXECUTABLE} describe --always RESULT_VARIABLE result OUTPUT_VARIABLE GIT_TREEISH ERROR_VARIABLE error_out OUTPUT_STRIP_TRAILING_WHITESPACE WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} ) if(NOT result EQUAL 0) set(GIT_TREEISH "HEAD") endif() # Write set(ARCHIVE_STAGE_DIR "${PROJECT_BINARY_DIR}/archive_stage") set(FILE_BASENAME "${target}-${VERSION_STRING}_source") set(GIT_TAR_FILE_PATH "${ARCHIVE_STAGE_DIR}/${FILE_BASENAME}.git-stage.tar") add_custom_command(OUTPUT "${GIT_TAR_FILE_PATH}" COMMAND ${CMAKE_COMMAND} ARGS -E make_directory "${ARCHIVE_STAGE_DIR}" COMMAND ${GIT_EXECUTABLE} ARGS archive --format=tar --prefix=${target}-${VERSION_STRING}/ --output="${GIT_TAR_FILE_PATH}" ${GIT_TREEISH} WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMENT "Running git archive (${target})..." ) set(ARCHIVE_OUTPUT_DIR "${PROJECT_BINARY_DIR}/archive_output") set(TAR_FILE_PATH "${ARCHIVE_OUTPUT_DIR}/${FILE_BASENAME}.tar") set(TARGZ_FILE_PATH "${TAR_FILE_PATH}.gz") set(TARGZ_FILE_NAME "${FILE_BASENAME}.tar.gz") set(TAR_APPEND_DIR "${PROJECT_BINARY_DIR}/archive_append") add_custom_command(OUTPUT "${TARGZ_FILE_PATH}" DEPENDS "${GIT_TAR_FILE_PATH}" COMMAND ${CMAKE_COMMAND} ARGS -E copy "${GIT_TAR_FILE_PATH}" "${TAR_FILE_PATH}" COMMAND ${CMAKE_COMMAND} ARGS -E create_symlink "${PROJECT_BINARY_DIR}/archive_append" "${ARCHIVE_STAGE_DIR}/${target}-${VERSION_STRING}" COMMAND ${TAR_EXECUTABLE} ARGS -rf "${TAR_FILE_PATH}" "${target}-${VERSION_STRING}/*" COMMAND ${GZIP_EXECUTABLE} ARGS -9f "${TAR_FILE_PATH}" WORKING_DIRECTORY ${ARCHIVE_STAGE_DIR} COMMENT "Add version information to git archive (${target})..." ) set(ARCHIVE_FINAL_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/dist-pkg") add_custom_target(source-archive DEPENDS "${TARGZ_FILE_PATH}") set_target_properties(source-archive PROPERTIES OUTPUT_ARCHIVE "${TARGZ_FILE_PATH}") add_custom_command(TARGET source-archive PRE_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E make_directory "${ARCHIVE_FINAL_OUTPUT_DIR}") add_custom_command(TARGET source-archive POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different "${TARGZ_FILE_PATH}" "${ARCHIVE_FINAL_OUTPUT_DIR}/${TARGZ_FILE_NAME}") else() message(STATUS "Cannot add 'source-archive' target, git not found.") endif() endfunction()