ECMFindModuleHelpers.cmake (13540B)
1 #.rst: 2 # ECMFindModuleHelpers 3 # -------------------- 4 # 5 # Helper macros for find modules: ecm_find_package_version_check(), 6 # ecm_find_package_parse_components() and 7 # ecm_find_package_handle_library_components(). 8 # 9 # :: 10 # 11 # ecm_find_package_version_check(<name>) 12 # 13 # Prints warnings if the CMake version or the project's required CMake version 14 # is older than that required by extra-cmake-modules. 15 # 16 # :: 17 # 18 # ecm_find_package_parse_components(<name> 19 # RESULT_VAR <variable> 20 # KNOWN_COMPONENTS <component1> [<component2> [...]] 21 # [SKIP_DEPENDENCY_HANDLING]) 22 # 23 # This macro will populate <variable> with a list of components found in 24 # <name>_FIND_COMPONENTS, after checking that all those components are in the 25 # list of KNOWN_COMPONENTS; if there are any unknown components, it will print 26 # an error or warning (depending on the value of <name>_FIND_REQUIRED) and call 27 # return(). 28 # 29 # The order of components in <variable> is guaranteed to match the order they 30 # are listed in the KNOWN_COMPONENTS argument. 31 # 32 # If SKIP_DEPENDENCY_HANDLING is not set, for each component the variable 33 # <name>_<component>_component_deps will be checked for dependent components. 34 # If <component> is listed in <name>_FIND_COMPONENTS, then all its (transitive) 35 # dependencies will also be added to <variable>. 36 # 37 # :: 38 # 39 # ecm_find_package_handle_library_components(<name> 40 # COMPONENTS <component> [<component> [...]] 41 # [SKIP_DEPENDENCY_HANDLING]) 42 # [SKIP_PKG_CONFIG]) 43 # 44 # Creates an imported library target for each component. The operation of this 45 # macro depends on the presence of a number of CMake variables. 46 # 47 # The <name>_<component>_lib variable should contain the name of this library, 48 # and <name>_<component>_header variable should contain the name of a header 49 # file associated with it (whatever relative path is normally passed to 50 # '#include'). <name>_<component>_header_subdir variable can be used to specify 51 # which subdirectory of the include path the headers will be found in. 52 # ecm_find_package_components() will then search for the library 53 # and include directory (creating appropriate cache variables) and create an 54 # imported library target named <name>::<component>. 55 # 56 # Additional variables can be used to provide additional information: 57 # 58 # If SKIP_PKG_CONFIG, the <name>_<component>_pkg_config variable is set, and 59 # pkg-config is found, the pkg-config module given by 60 # <name>_<component>_pkg_config will be searched for and used to help locate the 61 # library and header file. It will also be used to set 62 # <name>_<component>_VERSION. 63 # 64 # Note that if version information is found via pkg-config, 65 # <name>_<component>_FIND_VERSION can be set to require a particular version 66 # for each component. 67 # 68 # If SKIP_DEPENDENCY_HANDLING is not set, the INTERFACE_LINK_LIBRARIES property 69 # of the imported target for <component> will be set to contain the imported 70 # targets for the components listed in <name>_<component>_component_deps. 71 # <component>_FOUND will also be set to false if any of the compoments in 72 # <name>_<component>_component_deps are not found. This requires the components 73 # in <name>_<component>_component_deps to be listed before <component> in the 74 # COMPONENTS argument. 75 # 76 # The following variables will be set: 77 # 78 # ``<name>_TARGETS`` 79 # the imported targets 80 # ``<name>_LIBRARIES`` 81 # the found libraries 82 # ``<name>_INCLUDE_DIRS`` 83 # the combined required include directories for the components 84 # ``<name>_DEFINITIONS`` 85 # the "other" CFLAGS provided by pkg-config, if any 86 # ``<name>_VERSION`` 87 # the value of ``<name>_<component>_VERSION`` for the first component that 88 # has this variable set (note that components are searched for in the order 89 # they are passed to the macro), although if it is already set, it will not 90 # be altered 91 # 92 # Note that these variables are never cleared, so if 93 # ecm_find_package_handle_library_components() is called multiple times with 94 # different components (typically because of multiple find_package() calls) then 95 # ``<name>_TARGETS``, for example, will contain all the targets found in any 96 # call (although no duplicates). 97 # 98 # Since pre-1.0.0. 99 100 #============================================================================= 101 # Copyright 2014 Alex Merry <alex.merry@kde.org> 102 # 103 # Redistribution and use in source and binary forms, with or without 104 # modification, are permitted provided that the following conditions 105 # are met: 106 # 107 # 1. Redistributions of source code must retain the copyright 108 # notice, this list of conditions and the following disclaimer. 109 # 2. Redistributions in binary form must reproduce the copyright 110 # notice, this list of conditions and the following disclaimer in the 111 # documentation and/or other materials provided with the distribution. 112 # 3. The name of the author may not be used to endorse or promote products 113 # derived from this software without specific prior written permission. 114 # 115 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 116 # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 117 # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 118 # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 119 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 120 # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 121 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 122 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 123 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 124 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 125 126 include(CMakeParseArguments) 127 128 macro(ecm_find_package_version_check module_name) 129 if(CMAKE_VERSION VERSION_LESS 2.8.12) 130 message(FATAL_ERROR "CMake 2.8.12 is required by Find${module_name}.cmake") 131 endif() 132 if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.12) 133 message(AUTHOR_WARNING "Your project should require at least CMake 2.8.12 to use Find${module_name}.cmake") 134 endif() 135 endmacro() 136 137 macro(ecm_find_package_parse_components module_name) 138 set(ecm_fppc_options SKIP_DEPENDENCY_HANDLING) 139 set(ecm_fppc_oneValueArgs RESULT_VAR) 140 set(ecm_fppc_multiValueArgs KNOWN_COMPONENTS DEFAULT_COMPONENTS) 141 cmake_parse_arguments(ECM_FPPC "${ecm_fppc_options}" "${ecm_fppc_oneValueArgs}" "${ecm_fppc_multiValueArgs}" ${ARGN}) 142 143 if(ECM_FPPC_UNPARSED_ARGUMENTS) 144 message(FATAL_ERROR "Unexpected arguments to ecm_find_package_parse_components: ${ECM_FPPC_UNPARSED_ARGUMENTS}") 145 endif() 146 if(NOT ECM_FPPC_RESULT_VAR) 147 message(FATAL_ERROR "Missing RESULT_VAR argument to ecm_find_package_parse_components") 148 endif() 149 if(NOT ECM_FPPC_KNOWN_COMPONENTS) 150 message(FATAL_ERROR "Missing KNOWN_COMPONENTS argument to ecm_find_package_parse_components") 151 endif() 152 if(NOT ECM_FPPC_DEFAULT_COMPONENTS) 153 set(ECM_FPPC_DEFAULT_COMPONENTS ${ECM_FPPC_KNOWN_COMPONENTS}) 154 endif() 155 156 if(${module_name}_FIND_COMPONENTS) 157 set(ecm_fppc_requestedComps ${${module_name}_FIND_COMPONENTS}) 158 159 if(NOT ECM_FPPC_SKIP_DEPENDENCY_HANDLING) 160 # Make sure deps are included 161 foreach(ecm_fppc_comp ${ecm_fppc_requestedComps}) 162 foreach(ecm_fppc_dep_comp ${${module_name}_${ecm_fppc_comp}_component_deps}) 163 list(FIND ecm_fppc_requestedComps "${ecm_fppc_dep_comp}" ecm_fppc_index) 164 if("${ecm_fppc_index}" STREQUAL "-1") 165 if(NOT ${module_name}_FIND_QUIETLY) 166 message(STATUS "${module_name}: ${ecm_fppc_comp} requires ${${module_name}_${ecm_fppc_comp}_component_deps}") 167 endif() 168 list(APPEND ecm_fppc_requestedComps "${ecm_fppc_dep_comp}") 169 endif() 170 endforeach() 171 endforeach() 172 else() 173 message(STATUS "Skipping dependency handling for ${module_name}") 174 endif() 175 list(REMOVE_DUPLICATES ecm_fppc_requestedComps) 176 177 # This makes sure components are listed in the same order as 178 # KNOWN_COMPONENTS (potentially important for inter-dependencies) 179 set(${ECM_FPPC_RESULT_VAR}) 180 foreach(ecm_fppc_comp ${ECM_FPPC_KNOWN_COMPONENTS}) 181 list(FIND ecm_fppc_requestedComps "${ecm_fppc_comp}" ecm_fppc_index) 182 if(NOT "${ecm_fppc_index}" STREQUAL "-1") 183 list(APPEND ${ECM_FPPC_RESULT_VAR} "${ecm_fppc_comp}") 184 list(REMOVE_AT ecm_fppc_requestedComps ${ecm_fppc_index}) 185 endif() 186 endforeach() 187 # if there are any left, they are unknown components 188 if(ecm_fppc_requestedComps) 189 set(ecm_fppc_msgType STATUS) 190 if(${module_name}_FIND_REQUIRED) 191 set(ecm_fppc_msgType FATAL_ERROR) 192 endif() 193 if(NOT ${module_name}_FIND_QUIETLY) 194 message(${ecm_fppc_msgType} "${module_name}: requested unknown components ${ecm_fppc_requestedComps}") 195 endif() 196 return() 197 endif() 198 else() 199 set(${ECM_FPPC_RESULT_VAR} ${ECM_FPPC_DEFAULT_COMPONENTS}) 200 endif() 201 endmacro() 202 203 macro(ecm_find_package_handle_library_components module_name) 204 set(ecm_fpwc_options SKIP_PKG_CONFIG SKIP_DEPENDENCY_HANDLING) 205 set(ecm_fpwc_oneValueArgs) 206 set(ecm_fpwc_multiValueArgs COMPONENTS) 207 cmake_parse_arguments(ECM_FPWC "${ecm_fpwc_options}" "${ecm_fpwc_oneValueArgs}" "${ecm_fpwc_multiValueArgs}" ${ARGN}) 208 209 if(ECM_FPWC_UNPARSED_ARGUMENTS) 210 message(FATAL_ERROR "Unexpected arguments to ecm_find_package_handle_components: ${ECM_FPWC_UNPARSED_ARGUMENTS}") 211 endif() 212 if(NOT ECM_FPWC_COMPONENTS) 213 message(FATAL_ERROR "Missing COMPONENTS argument to ecm_find_package_handle_components") 214 endif() 215 216 include(FindPackageHandleStandardArgs) 217 find_package(PkgConfig) 218 foreach(ecm_fpwc_comp ${ECM_FPWC_COMPONENTS}) 219 set(ecm_fpwc_dep_vars) 220 set(ecm_fpwc_dep_targets) 221 if(NOT SKIP_DEPENDENCY_HANDLING) 222 foreach(ecm_fpwc_dep ${${module_name}_${ecm_fpwc_comp}_component_deps}) 223 list(APPEND ecm_fpwc_dep_vars "${module_name}_${ecm_fpwc_dep}_FOUND") 224 list(APPEND ecm_fpwc_dep_targets "${module_name}::${ecm_fpwc_dep}") 225 endforeach() 226 endif() 227 228 if(NOT ECM_FPWC_SKIP_PKG_CONFIG AND ${module_name}_${ecm_fpwc_comp}_pkg_config) 229 pkg_check_modules(PKG_${module_name}_${ecm_fpwc_comp} QUIET 230 ${${module_name}_${ecm_fpwc_comp}_pkg_config}) 231 endif() 232 233 find_path(${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR 234 NAMES ${${module_name}_${ecm_fpwc_comp}_header} 235 HINTS ${PKG_${module_name}_${ecm_fpwc_comp}_INCLUDE_DIRS} 236 PATH_SUFFIXES ${${module_name}_${ecm_fpwc_comp}_header_subdir} 237 ) 238 find_library(${module_name}_${ecm_fpwc_comp}_LIBRARY 239 NAMES ${${module_name}_${ecm_fpwc_comp}_lib} 240 HINTS ${PKG_${module_name}_${ecm_fpwc_comp}_LIBRARY_DIRS} 241 ) 242 243 set(${module_name}_${ecm_fpwc_comp}_VERSION "${PKG_${module_name}_${ecm_fpwc_comp}_VERSION}") 244 if(NOT ${module_name}_VERSION) 245 set(${module_name}_VERSION ${${module_name}_${ecm_fpwc_comp}_VERSION}) 246 endif() 247 248 find_package_handle_standard_args(${module_name}_${ecm_fpwc_comp} 249 FOUND_VAR 250 ${module_name}_${ecm_fpwc_comp}_FOUND 251 REQUIRED_VARS 252 ${module_name}_${ecm_fpwc_comp}_LIBRARY 253 ${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR 254 ${ecm_fpwc_dep_vars} 255 VERSION_VAR 256 ${module_name}_${ecm_fpwc_comp}_VERSION 257 ) 258 259 mark_as_advanced( 260 ${module_name}_${ecm_fpwc_comp}_LIBRARY 261 ${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR 262 ) 263 264 if(${module_name}_${ecm_fpwc_comp}_FOUND) 265 list(APPEND ${module_name}_LIBRARIES 266 "${${module_name}_${ecm_fpwc_comp}_LIBRARY}") 267 list(APPEND ${module_name}_INCLUDE_DIRS 268 "${${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR}") 269 set(${module_name}_DEFINITIONS 270 ${${module_name}_DEFINITIONS} 271 ${PKG_${module_name}_${ecm_fpwc_comp}_DEFINITIONS}) 272 if(NOT TARGET ${module_name}::${ecm_fpwc_comp}) 273 add_library(${module_name}::${ecm_fpwc_comp} UNKNOWN IMPORTED) 274 set_target_properties(${module_name}::${ecm_fpwc_comp} PROPERTIES 275 IMPORTED_LOCATION "${${module_name}_${ecm_fpwc_comp}_LIBRARY}" 276 INTERFACE_COMPILE_OPTIONS "${PKG_${module_name}_${ecm_fpwc_comp}_DEFINITIONS}" 277 INTERFACE_INCLUDE_DIRECTORIES "${${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR}" 278 INTERFACE_LINK_LIBRARIES "${ecm_fpwc_dep_targets}" 279 ) 280 endif() 281 list(APPEND ${module_name}_TARGETS 282 "${module_name}::${ecm_fpwc_comp}") 283 endif() 284 endforeach() 285 if(${module_name}_LIBRARIES) 286 list(REMOVE_DUPLICATES ${module_name}_LIBRARIES) 287 endif() 288 if(${module_name}_INCLUDE_DIRS) 289 list(REMOVE_DUPLICATES ${module_name}_INCLUDE_DIRS) 290 endif() 291 if(${module_name}_DEFINITIONS) 292 list(REMOVE_DUPLICATES ${module_name}_DEFINITIONS) 293 endif() 294 if(${module_name}_TARGETS) 295 list(REMOVE_DUPLICATES ${module_name}_TARGETS) 296 endif() 297 endmacro()