Skip to content

File tree

2 files changed

+470
-0
lines changed

2 files changed

+470
-0
lines changed

cmake/ECMFindModuleHelpers.cmake

Lines changed: 300 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
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 components 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 <[email protected]>
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+
macro(ecm_find_package_version_check module_name)
127+
if(CMAKE_VERSION VERSION_LESS 2.8.12)
128+
message(FATAL_ERROR "CMake 2.8.12 is required by Find${module_name}.cmake")
129+
endif()
130+
if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.12)
131+
message(AUTHOR_WARNING "Your project should require at least CMake 2.8.12 to use Find${module_name}.cmake")
132+
endif()
133+
endmacro()
134+
135+
macro(ecm_find_package_parse_components module_name)
136+
set(ecm_fppc_options SKIP_DEPENDENCY_HANDLING)
137+
set(ecm_fppc_oneValueArgs RESULT_VAR)
138+
set(ecm_fppc_multiValueArgs KNOWN_COMPONENTS DEFAULT_COMPONENTS)
139+
cmake_parse_arguments(ECM_FPPC "${ecm_fppc_options}" "${ecm_fppc_oneValueArgs}" "${ecm_fppc_multiValueArgs}" ${ARGN})
140+
141+
if(ECM_FPPC_UNPARSED_ARGUMENTS)
142+
message(FATAL_ERROR "Unexpected arguments to ecm_find_package_parse_components: ${ECM_FPPC_UNPARSED_ARGUMENTS}")
143+
endif()
144+
if(NOT ECM_FPPC_RESULT_VAR)
145+
message(FATAL_ERROR "Missing RESULT_VAR argument to ecm_find_package_parse_components")
146+
endif()
147+
if(NOT ECM_FPPC_KNOWN_COMPONENTS)
148+
message(FATAL_ERROR "Missing KNOWN_COMPONENTS argument to ecm_find_package_parse_components")
149+
endif()
150+
if(NOT ECM_FPPC_DEFAULT_COMPONENTS)
151+
set(ECM_FPPC_DEFAULT_COMPONENTS ${ECM_FPPC_KNOWN_COMPONENTS})
152+
endif()
153+
154+
if(${module_name}_FIND_COMPONENTS)
155+
set(ecm_fppc_requestedComps ${${module_name}_FIND_COMPONENTS})
156+
157+
if(NOT ECM_FPPC_SKIP_DEPENDENCY_HANDLING)
158+
# Make sure deps are included
159+
foreach(ecm_fppc_comp ${ecm_fppc_requestedComps})
160+
foreach(ecm_fppc_dep_comp ${${module_name}_${ecm_fppc_comp}_component_deps})
161+
list(FIND ecm_fppc_requestedComps "${ecm_fppc_dep_comp}" ecm_fppc_index)
162+
if("${ecm_fppc_index}" STREQUAL "-1")
163+
if(NOT ${module_name}_FIND_QUIETLY)
164+
message(STATUS "${module_name}: ${ecm_fppc_comp} requires ${${module_name}_${ecm_fppc_comp}_component_deps}")
165+
endif()
166+
list(APPEND ecm_fppc_requestedComps "${ecm_fppc_dep_comp}")
167+
endif()
168+
endforeach()
169+
endforeach()
170+
else()
171+
message(STATUS "Skipping dependency handling for ${module_name}")
172+
endif()
173+
list(REMOVE_DUPLICATES ecm_fppc_requestedComps)
174+
175+
# This makes sure components are listed in the same order as
176+
# KNOWN_COMPONENTS (potentially important for inter-dependencies)
177+
set(${ECM_FPPC_RESULT_VAR})
178+
foreach(ecm_fppc_comp ${ECM_FPPC_KNOWN_COMPONENTS})
179+
list(FIND ecm_fppc_requestedComps "${ecm_fppc_comp}" ecm_fppc_index)
180+
if(NOT "${ecm_fppc_index}" STREQUAL "-1")
181+
list(APPEND ${ECM_FPPC_RESULT_VAR} "${ecm_fppc_comp}")
182+
list(REMOVE_AT ecm_fppc_requestedComps ${ecm_fppc_index})
183+
endif()
184+
endforeach()
185+
# if there are any left, they are unknown components
186+
if(ecm_fppc_requestedComps)
187+
set(ecm_fppc_msgType STATUS)
188+
if(${module_name}_FIND_REQUIRED)
189+
set(ecm_fppc_msgType FATAL_ERROR)
190+
endif()
191+
if(NOT ${module_name}_FIND_QUIETLY)
192+
message(${ecm_fppc_msgType} "${module_name}: requested unknown components ${ecm_fppc_requestedComps}")
193+
endif()
194+
return()
195+
endif()
196+
else()
197+
set(${ECM_FPPC_RESULT_VAR} ${ECM_FPPC_DEFAULT_COMPONENTS})
198+
endif()
199+
endmacro()
200+
201+
macro(ecm_find_package_handle_library_components module_name)
202+
set(ecm_fpwc_options SKIP_PKG_CONFIG SKIP_DEPENDENCY_HANDLING)
203+
set(ecm_fpwc_oneValueArgs)
204+
set(ecm_fpwc_multiValueArgs COMPONENTS)
205+
cmake_parse_arguments(ECM_FPWC "${ecm_fpwc_options}" "${ecm_fpwc_oneValueArgs}" "${ecm_fpwc_multiValueArgs}" ${ARGN})
206+
207+
if(ECM_FPWC_UNPARSED_ARGUMENTS)
208+
message(FATAL_ERROR "Unexpected arguments to ecm_find_package_handle_components: ${ECM_FPWC_UNPARSED_ARGUMENTS}")
209+
endif()
210+
if(NOT ECM_FPWC_COMPONENTS)
211+
message(FATAL_ERROR "Missing COMPONENTS argument to ecm_find_package_handle_components")
212+
endif()
213+
214+
include(FindPackageHandleStandardArgs)
215+
find_package(PkgConfig QUIET)
216+
foreach(ecm_fpwc_comp ${ECM_FPWC_COMPONENTS})
217+
set(ecm_fpwc_dep_vars)
218+
set(ecm_fpwc_dep_targets)
219+
if(NOT SKIP_DEPENDENCY_HANDLING)
220+
foreach(ecm_fpwc_dep ${${module_name}_${ecm_fpwc_comp}_component_deps})
221+
list(APPEND ecm_fpwc_dep_vars "${module_name}_${ecm_fpwc_dep}_FOUND")
222+
list(APPEND ecm_fpwc_dep_targets "${module_name}::${ecm_fpwc_dep}")
223+
endforeach()
224+
endif()
225+
226+
if(NOT ECM_FPWC_SKIP_PKG_CONFIG AND ${module_name}_${ecm_fpwc_comp}_pkg_config)
227+
pkg_check_modules(PKG_${module_name}_${ecm_fpwc_comp} QUIET
228+
${${module_name}_${ecm_fpwc_comp}_pkg_config})
229+
endif()
230+
231+
find_path(${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR
232+
NAMES ${${module_name}_${ecm_fpwc_comp}_header}
233+
HINTS ${PKG_${module_name}_${ecm_fpwc_comp}_INCLUDE_DIRS}
234+
PATH_SUFFIXES ${${module_name}_${ecm_fpwc_comp}_header_subdir}
235+
)
236+
find_library(${module_name}_${ecm_fpwc_comp}_LIBRARY
237+
NAMES ${${module_name}_${ecm_fpwc_comp}_lib}
238+
HINTS ${PKG_${module_name}_${ecm_fpwc_comp}_LIBRARY_DIRS}
239+
)
240+
241+
set(${module_name}_${ecm_fpwc_comp}_VERSION "${PKG_${module_name}_${ecm_fpwc_comp}_VERSION}")
242+
if(NOT ${module_name}_VERSION)
243+
set(${module_name}_VERSION ${${module_name}_${ecm_fpwc_comp}_VERSION})
244+
endif()
245+
246+
set(_name_mismatched_arg)
247+
if(NOT CMAKE_VERSION VERSION_LESS 3.17)
248+
set(_name_mismatched_arg NAME_MISMATCHED)
249+
endif()
250+
find_package_handle_standard_args(${module_name}_${ecm_fpwc_comp}
251+
FOUND_VAR
252+
${module_name}_${ecm_fpwc_comp}_FOUND
253+
REQUIRED_VARS
254+
${module_name}_${ecm_fpwc_comp}_LIBRARY
255+
${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR
256+
${ecm_fpwc_dep_vars}
257+
VERSION_VAR
258+
${module_name}_${ecm_fpwc_comp}_VERSION
259+
${_name_mismatched_arg}
260+
)
261+
262+
mark_as_advanced(
263+
${module_name}_${ecm_fpwc_comp}_LIBRARY
264+
${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR
265+
)
266+
267+
if(${module_name}_${ecm_fpwc_comp}_FOUND)
268+
list(APPEND ${module_name}_LIBRARIES
269+
"${${module_name}_${ecm_fpwc_comp}_LIBRARY}")
270+
list(APPEND ${module_name}_INCLUDE_DIRS
271+
"${${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR}")
272+
set(${module_name}_DEFINITIONS
273+
${${module_name}_DEFINITIONS}
274+
${PKG_${module_name}_${ecm_fpwc_comp}_DEFINITIONS})
275+
if(NOT TARGET ${module_name}::${ecm_fpwc_comp})
276+
add_library(${module_name}::${ecm_fpwc_comp} UNKNOWN IMPORTED)
277+
set_target_properties(${module_name}::${ecm_fpwc_comp} PROPERTIES
278+
IMPORTED_LOCATION "${${module_name}_${ecm_fpwc_comp}_LIBRARY}"
279+
INTERFACE_COMPILE_OPTIONS "${PKG_${module_name}_${ecm_fpwc_comp}_DEFINITIONS}"
280+
INTERFACE_INCLUDE_DIRECTORIES "${${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR}"
281+
INTERFACE_LINK_LIBRARIES "${ecm_fpwc_dep_targets}"
282+
)
283+
endif()
284+
list(APPEND ${module_name}_TARGETS
285+
"${module_name}::${ecm_fpwc_comp}")
286+
endif()
287+
endforeach()
288+
if(${module_name}_LIBRARIES)
289+
list(REMOVE_DUPLICATES ${module_name}_LIBRARIES)
290+
endif()
291+
if(${module_name}_INCLUDE_DIRS)
292+
list(REMOVE_DUPLICATES ${module_name}_INCLUDE_DIRS)
293+
endif()
294+
if(${module_name}_DEFINITIONS)
295+
list(REMOVE_DUPLICATES ${module_name}_DEFINITIONS)
296+
endif()
297+
if(${module_name}_TARGETS)
298+
list(REMOVE_DUPLICATES ${module_name}_TARGETS)
299+
endif()
300+
endmacro()

0 commit comments

Comments
 (0)