1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
|
cmake_minimum_required(VERSION 3.6)
include(ExternalProject)
# searches for absolute paths of libraries, applying LIBRARY_DIRS
# CMake prefers absolute paths of libraries in non-standard locations, apparently
# see FindPkgConfig.cmake's _pkg_find_libs for more information
#
# positional parameters:
# - libraries: name of variable containing list of libraries
# - library_dirs
function(apply_library_dirs libraries library_dirs)
foreach(library ${${libraries}})
find_library(${library}_path ${library} PATHS ${${library_dirs}} NO_DEFAULT_PATH)
if(NOT ${library}_path)
list(APPEND new_libraries ${library})
else()
list(APPEND new_libraries ${${library}_path})
endif()
endforeach()
set(${libraries} ${new_libraries} PARENT_SCOPE)
unset(new_libraries)
endfunction()
# imports a library from the standard set of variables CMake creates when using its pkg-config module or find_package
# this is code shared by import_pkgconfig_target and import_external_project, hence it's been extracted into a separate
# CMake function
#
# partly inspired by https://github.com/Kitware/CMake/blob/master/Modules/FindPkgConfig.cmake#L187
#
# positional parameters:
# - target_name: name of the target that should be created
# - variable_prefix: prefix of the variable that should be used to create the target from
function(import_library_from_prefix target_name variable_prefix)
if(TARGET ${target_name})
message(WARNING "Target exists already, skipping")
return()
endif()
add_library(${target_name} INTERFACE IMPORTED GLOBAL)
if(${variable_prefix}_INCLUDE_DIRS)
# need to create directories before setting INTERFACE_INCLUDE_DIRECTORIES, otherwise CMake will complain
# possibly related: https://cmake.org/Bug/view.php?id=15052
foreach(dir ${${variable_prefix}_INCLUDE_DIRS})
if(NOT EXISTS ${dir})
if(${dir} MATCHES ${CMAKE_BINARY_DIR})
file(MAKE_DIRECTORY ${dir})
list(APPEND include_dirs ${dir})
endif()
else()
list(APPEND include_dirs ${dir})
endif()
endforeach()
set_property(TARGET ${target_name} PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${include_dirs})
unset(include_dirs)
endif()
# if library dirs are set, figure out absolute paths to libraries, like CMake's FindPkgConfig module does
if(${variable_prefix}_LIBRARY_DIRS)
apply_library_dirs(${variable_prefix}_LIBRARIES ${variable_prefix}_LIBRARY_DIRS)
endif()
set_property(TARGET ${target_name} PROPERTY INTERFACE_LINK_LIBRARIES ${${variable_prefix}_LIBRARIES})
if(${variable_prefix}_CFLAGS_OTHER)
set_property(TARGET ${target_name} PROPERTY INTERFACE_COMPILE_OPTIONS ${${variable_prefix}_CFLAGS_OTHER})
endif()
# export some of the imported properties with the target name as prefix
# this is necessary to allow the other external projects, which are not built with CMake or not within the same
# CMake context, to link to the libraries built as external projects (or the system ones, depending on the build
# configuration)
set(${target_name}_INCLUDE_DIRS ${${variable_prefix}_INCLUDE_DIRS} CACHE INTERNAL "")
set(${target_name}_LIBRARIES ${${variable_prefix}_LIBRARIES} CACHE INTERNAL "")
set(${target_name}_LIBRARY_DIRS ${${variable_prefix}_LIBRARY_DIRS} CACHE INTERNAL "")
# TODO: the following might not always apply
set(${target_name}_PREFIX ${CMAKE_INSTALL_PREFIX}/lib CACHE INTERNAL "")
endfunction()
# imports a library using pkg-config
#
# positional parameters:
# - target_name: name of the target that we shall create for you
# - pkg_config_target: librar(y name to pass to pkg-config (may include a version)
function(import_pkgconfig_target)
set(keywords STATIC OPTIONAL)
set(oneValueArgs TARGET_NAME PKGCONFIG_TARGET)
cmake_parse_arguments(IMPORT_PKGCONFIG_TARGET "${keywords}" "${oneValueArgs}" "" "${ARGN}")
# check whether parameters have been set
if(NOT IMPORT_PKGCONFIG_TARGET_TARGET_NAME)
message(FATAL_ERROR "TARGET_NAME parameter missing, but is required")
endif()
if(NOT IMPORT_PKGCONFIG_TARGET_PKGCONFIG_TARGET)
message(FATAL_ERROR "PKGCONFIG_TARGET parameter missing, but is required")
endif()
find_package(PkgConfig REQUIRED)
set(type "shared")
if(IMPORT_PKGCONFIG_TARGET_STATIC)
set(type "static")
endif()
message(STATUS "Importing target ${IMPORT_PKGCONFIG_TARGET_TARGET_NAME} via pkg-config (${IMPORT_PKGCONFIG_TARGET_PKGCONFIG_TARGET}, ${type})")
if(NOT IMPORT_PKGCONFIG_TARGET_OPTIONAL)
set(extra_args REQUIRED)
endif()
pkg_check_modules(${IMPORT_PKGCONFIG_TARGET_TARGET_NAME}-IMPORTED ${IMPORT_PKGCONFIG_TARGET_PKGCONFIG_TARGET} ${extra_args})
if(NOT ${IMPORT_PKGCONFIG_TARGET_TARGET_NAME}-IMPORTED_FOUND AND IMPORT_PKGCONFIG_TARGET_OPTIONAL)
return()
endif()
if(IMPORT_PKGCONFIG_TARGET_STATIC)
set(prefix ${IMPORT_PKGCONFIG_TARGET_TARGET_NAME}-IMPORTED_STATIC)
else()
set(prefix ${IMPORT_PKGCONFIG_TARGET_TARGET_NAME}-IMPORTED)
endif()
import_library_from_prefix(${IMPORT_PKGCONFIG_TARGET_TARGET_NAME} ${prefix})
endfunction()
function(import_find_pkg_target target_name pkg_name variable_prefix)
message(STATUS "Importing target ${target_name} via find_package (${pkg_name})")
find_package(${pkg_name})
if(NOT ${variable_prefix}_FOUND)
message(FATAL_ERROR "${pkg_name} could not be found on the system. You will have to either install it, or use the bundled package.")
endif()
import_library_from_prefix(${target_name} ${variable_prefix})
endfunction()
# imports a library from an existing external project
#
# required parameters:
# - TARGET_NAME:
function(import_external_project)
set(oneValueArgs TARGET_NAME EXT_PROJECT_NAME)
set(multiValueArgs LIBRARIES INCLUDE_DIRS LIBRARY_DIRS)
cmake_parse_arguments(IMPORT_EXTERNAL_PROJECT "" "${oneValueArgs}" "${multiValueArgs}" "${ARGN}")
# check whether parameters have been set
if(NOT IMPORT_EXTERNAL_PROJECT_TARGET_NAME)
message(FATAL_ERROR "TARGET_NAME parameter missing, but is required")
endif()
if(NOT IMPORT_EXTERNAL_PROJECT_EXT_PROJECT_NAME)
message(FATAL_ERROR "EXT_PROJECT_NAME parameter missing, but is required")
endif()
if(NOT IMPORT_EXTERNAL_PROJECT_LIBRARIES)
message(FATAL_ERROR "LIBRARIES parameter missing, but is required")
endif()
if(NOT IMPORT_EXTERNAL_PROJECT_INCLUDE_DIRS)
message(FATAL_ERROR "INCLUDE_DIRS parameter missing, but is required")
endif()
if(TARGET ${target_name})
message(WARNING "Target exists already, skipping")
return()
endif()
add_library(${IMPORT_EXTERNAL_PROJECT_TARGET_NAME} INTERFACE IMPORTED GLOBAL)
ExternalProject_Get_Property(${IMPORT_EXTERNAL_PROJECT_EXT_PROJECT_NAME} SOURCE_DIR)
ExternalProject_Get_Property(${IMPORT_EXTERNAL_PROJECT_EXT_PROJECT_NAME} INSTALL_DIR)
ExternalProject_Get_Property(${IMPORT_EXTERNAL_PROJECT_EXT_PROJECT_NAME} BINARY_DIR)
# "evaluate" patterns in the passed arguments by using some string replacing magic
# this makes it easier to use this function, as some external project properties don't need to be evaluated and
# passed beforehand, and should reduce the amount of duplicate code in this file
foreach(item ITEMS
IMPORT_EXTERNAL_PROJECT_EXT_PROJECT_NAME
IMPORT_EXTERNAL_PROJECT_LIBRARIES
IMPORT_EXTERNAL_PROJECT_INCLUDE_DIRS
IMPORT_EXTERNAL_PROJECT_LIBRARY_DIRS)
# create new variable with fixed string...
string(REPLACE "<SOURCE_DIR>" "${SOURCE_DIR}" "${item}-out" "${${item}}")
# ... and set the original value to the new value
set(${item} "${${item}-out}")
# create new variable with fixed string...
string(REPLACE "<INSTALL_DIR>" "${INSTALL_DIR}" "${item}-out" "${${item}}")
# ... and set the original value to the new value
set(${item} "${${item}-out}")
# create new variable with fixed string...
string(REPLACE "<BINARY_DIR>" "${BINARY_DIR}" "${item}-out" "${${item}}")
# ... and set the original value to the new value
set(${item} "${${item}-out}")
endforeach()
# if library dirs are set, figure out absolute paths to libraries, like CMake's FindPkgConfig module does
if(${IMPORT_EXTERNAL_PROJECT_LIBRARY_DIRS})
apply_library_dirs(IMPORT_EXTERNAL_PROJECT_LIBRARIES IMPORT_EXTERNAL_PROJECT_LIBRARY_DIRS)
endif()
set_property(TARGET ${IMPORT_EXTERNAL_PROJECT_TARGET_NAME} PROPERTY INTERFACE_LINK_LIBRARIES "${IMPORT_EXTERNAL_PROJECT_LIBRARIES}")
if(IMPORT_EXTERNAL_PROJECT_INCLUDE_DIRS)
# need to create directories before setting INTERFACE_INCLUDE_DIRECTORIES, otherwise CMake will complain
# possibly related: https://cmake.org/Bug/view.php?id=15052
foreach(dir ${IMPORT_EXTERNAL_PROJECT_INCLUDE_DIRS})
if(NOT EXISTS ${dir})
if(${dir} MATCHES ${CMAKE_BINARY_DIR})
file(MAKE_DIRECTORY ${dir})
list(APPEND include_dirs ${dir})
endif()
else()
list(APPEND include_dirs ${dir})
endif()
endforeach()
set_property(TARGET ${IMPORT_EXTERNAL_PROJECT_TARGET_NAME} PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${include_dirs})
unset(include_dirs)
endif()
# finally, add a depenceny on the external project to make sure it's built
add_dependencies(${IMPORT_EXTERNAL_PROJECT_TARGET_NAME} "${IMPORT_EXTERNAL_PROJECT_EXT_PROJECT_NAME}")
# read external project properties, and export them with the target name as prefix
# this is necessary to allow the other external projects, which are not built with CMake or not within the same
# CMake context, to link to the libraries built as external projects (or the system ones, depending on the build
# configuration)
set(${IMPORT_EXTERNAL_PROJECT_TARGET_NAME}_INCLUDE_DIRS "${IMPORT_EXTERNAL_PROJECT_INCLUDE_DIRS}" CACHE INTERNAL "")
set(${IMPORT_EXTERNAL_PROJECT_TARGET_NAME}_LIBRARIES "${IMPORT_EXTERNAL_PROJECT_LIBRARIES}" CACHE INTERNAL "")
set(${IMPORT_EXTERNAL_PROJECT_TARGET_NAME}_LIBRARY_DIRS "${IMPORT_EXTERNAL_PROJECT_LIBRARY_DIRS}" CACHE INTERNAL "")
set(${IMPORT_EXTERNAL_PROJECT_TARGET_NAME}_PREFIX ${INSTALL_DIR} CACHE INTERNAL "")
endfunction()
# @brief Configure a libappimage module by setting
#
# Sets set to the given <target> the public headers, the compile definitions and the include directories. Which are
# common to all modules.
function(configure_libappimage_module target)
# targets are called lib* already, so CMake shouldn't add another lib prefix to the actual files
set_target_properties(${target}
PROPERTIES PREFIX ""
POSITION_INDEPENDENT_CODE ON
)
target_compile_definitions(${target}
# Support Large Files
PRIVATE -D_FILE_OFFSET_BITS=64
PRIVATE -D_LARGEFILE_SOURCE
PRIVATE -DGIT_COMMIT="${GIT_COMMIT}"
PRIVATE -DENABLE_BINRELOC
)
target_include_directories(${target}
PUBLIC $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include/>
PRIVATE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src/libappimage>
INTERFACE $<INSTALL_INTERFACE:include/>
)
endfunction()
|