diff options
-rw-r--r-- | docs/writing-find-modules.md | 163 | ||||
-rw-r--r-- | find-modules/FindWayland.cmake | 236 | ||||
-rw-r--r-- | find-modules/FindXCB.cmake | 427 | ||||
-rw-r--r-- | modules/ECMFindModuleHelpers.cmake | 227 |
4 files changed, 471 insertions, 582 deletions
diff --git a/docs/writing-find-modules.md b/docs/writing-find-modules.md index 1ab6566f..2130a43a 100644 --- a/docs/writing-find-modules.md +++ b/docs/writing-find-modules.md @@ -197,7 +197,7 @@ download it. include(FeatureSummary) set_package_properties(Foo PROPERTIES - URL http://www.foo.example.com/ + URL "http://www.foo.example.com/" DESCRIPTION "A library for doing useful things") Most of the cache variables should be hidden in the `ccmake` interface unless @@ -225,146 +225,69 @@ Components ---------- If your find module has multiple components, such as a package that provides -multiple libraries, the following pattern can be helpful. First (after the -version checks), define what components are available: +multiple libraries, the ECMFindModulesHelpers module can do a lot of the work +for you. First, you need to include the module, and perform the version check. +ECMFindModuleHelpers provides its own version check macro, which specifies the +minimum required CMake version for the other macros in that module. - set(knownComponents - Bar - Baz - ) - -Determine which components we need to find. Note that `Foo_FIND_COMPONENTS` is -defined if `find_package` was passed the `COMPONENTS` option. - - if (Foo_FIND_COMPONENTS) - set(requiredComponents ${Foo_FIND_COMPONENTS}) - else() - set(requiredComponents ${knownComponents}) - endif() - -Translate component names into names to pass to `pkg-config`, and check for any -unknown components: - - unset(unknownComponents) - foreach(comp ${requiredComponents}) - list(FIND knownComponents ${comp} index) - if("${index}" STREQUAL "-1") - list(APPEND unknownComponents "${comp}") - endif() - endforeach() - - if(DEFINED unknownComponents) - set(msgType STATUS) - if(Foo_FIND_REQUIRED) - set(msgType FATAL_ERROR) - endif() - if(NOT Foo_FIND_QUIETLY) - message(${msgType} "Foo: requested unknown components ${unknownComponents}") - endif() - return() - endif() + include(ECMFindModuleHelpers) + ecm_find_package_version_check(Foo) -Now we create a macro to handle each component. The logic is very similar to -that of a Find module without components; in fact, most of it could be replaced -with `find_package` calls that use either other `Find*.cmake` files or -`*Config.make` files. +The important macros are `ecm_find_package_parse_components` and +`ecm_find_package_handle_library_components`. These take a list of components, +and query other variables you provide to find out the information they require. +The documentation for ECMFindModuleHelpers provides more information, but a +simple setup might look like - include(FindPackageHandleStandardArgs) - find_package(PkgConfig) + set(Foo_known_components Bar Baz) + set(Foo_Bar_pkg_config "foo-bar") + set(Foo_Bar_lib "bar") + set(Foo_Bar_header "foo/bar.h") + set(Foo_Bar_pkg_config "foo-baz") + set(Foo_Baz_lib "baz") + set(Foo_Baz_header "foo/baz.h") - macro(_foo_handle_component _comp) - set(_header) - set(_lib) - set(_pkgconfig_module) - if("${_comp}" STREQUAL "Bar") - set(_header "Foo/bar.h") - set(_lib "bar") - set(_pkgconfig_module "foo-bar") - elseif("${_comp}" STREQUAL "Baz") - set(_header "Foo/baz.h") - set(_lib "baz") - set(_pkgconfig_module "foo-baz") - endif() - - pkg_check_modules(PC_Foo_${_comp} QUIET ${_pkgconfig_module}) - - find_path(Foo_${_comp}_INCLUDE_DIR - NAMES ${_header} - HINTS ${PC_Foo_${_comp}_INCLUDE_DIRS} - ) - find_library(Foo_${_comp}_LIBRARY - NAMES ${_lib} - HINTS ${PC_Foo_${_comp}_LIBRARY_DIRS} - ) - set(Foo_${_comp}_DEFINITIONS ${Foo_${_comp}_CFLAGS_OTHER}) - - # compatibility variables - if(Foo_${_comp}_INCLUDE_DIR AND Foo_${_comp}_LIBRARY) - list(APPEND Foo_DEFINITIONS ${Foo_${_comp}_DEFINITIONS}) - list(APPEND Foo_INCLUDE_DIRS ${Foo_${_comp}_INCLUDE_DIR}) - list(APPEND Foo_LIBRARIES ${Foo_${_comp}_LIBRARY}) - endif() - - set(Foo_${_comp}_VERSION "${PC_Foo_${_comp}_VERSION}") - if(NOT Foo_VERSION) - set(Foo_VERSION ${Foo_${_comp}_VERSION}) - endif() - - find_package_handle_standard_args(Foo_${_comp} - FOUND_VAR - Foo_${_comp}_FOUND - REQUIRED_VARS - Foo_${_comp}_LIBRARY - Foo_${_comp}_INCLUDE_DIR - VERSION_VAR - Foo_${_comp}_VERSION - ) +If `Baz` depends on `Bar`, for example, you can specify this with - mark_as_advanced( - Foo_${_comp}_LIBRARY - Foo_${_comp}_INCLUDE_DIR - ) + set(Foo_Baz_component_deps "Bar") - if(Foo_${_comp}_FOUND AND NOT TARGET Foo::${_comp}) - add_library(Foo::${_comp} UNKNOWN IMPORTED) - set_target_properties(Foo::${_comp} PROPERTIES - IMPORTED_LOCATION "${Foo_${_comp}_LIBRARY}" - INTERFACE_COMPILE_OPTIONS "${Foo_${_comp}_DEFINITIONS}" - INTERFACE_INCLUDE_DIRECTORIES "${Foo_${_comp}_INCLUDE_DIR}" - ) - endif() - endmacro() +Then call the macros: -And finish off with everything else: + ecm_find_package_parse_components(Foo + RESULT_VAR Foo_components + KNOWN_COMPONENTS ${Foo_known_components} + ) + ecm_find_package_handle_library_components(Foo + COMPONENTS ${Foo_components} + ) - foreach(comp ${requiredComponents}) - _foo_handle_component(${comp}) - endforeach() +Of course, if your components need unusual handling, you may want to replace +`ecm_find_package_handle_library_components` with, for example, a `foreach` loop +over the components (the body of which should implement most of what a normal +find module does, including setting `Foo_<component>_FOUND`). - # compatibility variables - if (Foo_INCLUDE_DIRS) - list(REMOVE_DUPLICATES Foo_INCLUDE_DIRS) - endif() - if (Foo_DEFINITIONS) - list(REMOVE_DUPLICATES Foo_DEFINITIONS) - endif() - set(Foo_VERSION_STRING ${Foo_VERSION}) +At this point, you should set `Foo_VERSION` using whatever information you have +available (such as from parsing header files). Note that +`ecm_find_package_handle_library_components` will set it to the version reported +by pkg-config of the first component found, but this depends on the presence of +pkg-config files, and the version of a component may not be the same as the +version of the whole package. After that, finish off with + include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Foo FOUND_VAR Foo_FOUND REQUIRED_VARS Foo_LIBRARIES - Foo_INCLUDE_DIRS VERSION_VAR Foo_VERSION HANDLE_COMPONENTS ) - + include(FeatureSummary) set_package_properties(Foo PROPERTIES - URL http://www.foo.example.com/ - DESCRIPTION "A set of libraries for doing useful things") + URL "http://www.foo.example.com/" + DESCRIPTION "A library for doing useful things") Other Macros diff --git a/find-modules/FindWayland.cmake b/find-modules/FindWayland.cmake index a121de9f..c7c599c2 100644 --- a/find-modules/FindWayland.cmake +++ b/find-modules/FindWayland.cmake @@ -1,180 +1,95 @@ # Try to find Wayland on a Unix system # -# This will define: +# This is a component-based find module, which makes use of the COMPONENTS +# and OPTIONAL_COMPONENTS arguments to find_module. The following components +# are available: # -# Wayland_FOUND - True if Wayland is available -# Wayland_LIBRARIES - Link these to use Wayland -# Wayland_INCLUDE_DIRS - Include directory for Wayland -# Wayland_DEFINITIONS - Compiler flags for using Wayland -# Wayland_VERSION_STRING - Found Wayland version +# Client Server Cursor Egl # -# In addition the following more fine grained variables will be defined: +# If no components are specified, this module will act as though all components +# were passed to OPTIONAL_COMPONENTS. # -# Wayland_Client_FOUND Wayland_Client_INCLUDE_DIR Wayland_Client_LIBRARY Wayland_Client_VERSION_STRING -# Wayland_Server_FOUND Wayland_Server_INCLUDE_DIR Wayland_Server_LIBRARY Wayland_Server_VERSION_STRING -# Wayland_Cursor_FOUND Wayland_Cursor_INCLUDE_DIR Wayland_Cursor_LIBRARY Wayland_Cursor_VERSION_STRING -# Wayland_Egl_FOUND Wayland_Egl_INCLUDE_DIR Wayland_Egl_LIBRARY Wayland_Egl_VERSION_STRING +# This module will define the following variables, independently of the +# components searched for or found: # -# Additionally, the following imported targets will be defined: +# Wayland_FOUND - True if (the requestion version of) Wayland is available +# Wayland_VERSION - Found Wayland version # -# Wayland::Client -# Wayland::Server -# Wayland::Cursor -# Wayland::Egl +# For each searched-for components, Wayland_<component>_FOUND will be set to true +# if the corresponding Wayland library was found, and false otherwise. If +# Wayland_<component>_FOUND is true, the imported target Wayland::<component> will be +# defined. This module will also attempt to determine Wayland_*_VERSION variables +# for each imported target, although Wayland_VERSION should normally be sufficient. # -# Copyright (c) 2014 Martin Gräßlin <mgraesslin@kde.org> +# The following variable will also be defined for convenience, and for +# compatibility with old-style find module conventions: # -# Redistribution and use is allowed according to the terms of the BSD license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. - -if(CMAKE_VERSION VERSION_LESS 2.8.12) - message(FATAL_ERROR "CMake 2.8.12 is required by FindWayland.cmake") -endif() -if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.12) - message(AUTHOR_WARNING "Your project should require at least CMake 2.8.12 to use FindWayland.cmake") -endif() - -set(knownComponents Client - Server - Cursor - Egl - ) - -unset(unknownComponents) - -set(pkgConfigModules) - -if (Wayland_FIND_COMPONENTS) - set(comps ${Wayland_FIND_COMPONENTS}) -else() - set(comps ${knownComponents}) -endif() - -# iterate through the list of requested components, and check that we know them all. -# If not, fail. -foreach(comp ${comps}) - list(FIND knownComponents ${comp} index ) - if("${index}" STREQUAL "-1") - list(APPEND unknownComponents "${comp}") - else() - if("${comp}" STREQUAL "Client") - list(APPEND pkgConfigModules "wayland-client") - elseif("${comp}" STREQUAL "Server") - list(APPEND pkgConfigModules "wayland-server") - elseif("${comp}" STREQUAL "Cursor") - list(APPEND pkgConfigModules "wayland-cursor") - elseif("${comp}" STREQUAL "Egl") - list(APPEND pkgConfigModules "wayland-egl") - endif() - endif() -endforeach() +# Wayland_LIBRARIES - A list of all Wayland imported targets +#============================================================================= +# Copyright 2014 Martin Gräßlin <mgraesslin@kde.org> +# Copyright 2014 Alex Merry <alex.merry@kde.org> +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file COPYING-CMAKE-SCRIPTS for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of extra-cmake-modules, substitute the full +# License text for the above reference.) -if(DEFINED unknownComponents) - set(msgType STATUS) - if(Wayland_FIND_REQUIRED) - set(msgType FATAL_ERROR) - endif() - if(NOT Wayland_FIND_QUIETLY) - message(${msgType} "Wayland: requested unknown components ${unknownComponents}") - endif() - return() -endif() +include(${CMAKE_CURRENT_LIST_DIR}/../modules/ECMFindModuleHelpers.cmake) -macro(_wayland_handle_component _comp) - set(_header ) - set(_lib ) - set(_pkgconfig_module_var) - if("${_comp}" STREQUAL "Client") - set(_header "wayland-client.h") - set(_lib "wayland-client") - set(_pkgconfig_module_var "wayland-client") - elseif("${_comp}" STREQUAL "Server") - set(_header "wayland-server.h") - set(_lib "wayland-server") - set(_pkgconfig_module_var "wayland-server") - elseif("${_comp}" STREQUAL "Cursor") - set(_header "wayland-cursor.h") - set(_lib "wayland-cursor") - set(_pkgconfig_module_var "wayland-cursor") - elseif("${_comp}" STREQUAL "Egl") - set(_header "wayland-egl.h") - set(_lib "wayland-egl") - set(_pkgconfig_module_var "wayland-egl") - endif() +ecm_find_package_version_check(Wayland) - find_path(Wayland_${_comp}_INCLUDE_DIR - NAMES ${_header} - HINTS ${PKG_Wayland_INCLUDE_DIRS} - ) - find_library(Wayland_${_comp}_LIBRARY - NAMES ${_lib} - HINTS ${PKG_Wayland_LIBRARY_DIRS} +if(NOT WIN32) + set(Wayland_known_components + Client + Server + Cursor + Egl ) + foreach(_comp ${Wayland_known_components}) + string(TOLOWER "${_comp}" _lc_comp) + set(Wayland_${_comp}_component_deps) + set(Wayland_${_comp}_pkg_config "wayland-${_lc_comp}") + set(Wayland_${_comp}_lib "wayland-${_lc_comp}") + set(Wayland_${_comp}_header "wayland-${_lc_comp}.h") + endforeach() + set(Wayland_Egl_component_deps Client) - if(Wayland_${_comp}_INCLUDE_DIR AND Wayland_${_comp}_LIBRARY) - list(APPEND Wayland_INCLUDE_DIRS ${Wayland_${_comp}_INCLUDE_DIR}) - list(APPEND Wayland_LIBRARIES ${Wayland_${_comp}_LIBRARY}) - endif() - - if(PKG_Wayland_VERSION AND NOT PKG_Wayland_${_pkgconfig_module_var}_VERSION) - # this is what gets set if we only search for one module - set(Wayland_${_comp}_VERSION_STRING "${PKG_Wayland_VERSION}") - else() - set(Wayland_${_comp}_VERSION_STRING "${PKG_Wayland_${_pkgconfig_module_var}_VERSION}") - endif() - - if(NOT Wayland_VERSION_STRING) - set(Wayland_VERSION_STRING ${Wayland_${_comp}_VERSION_STRING}) - endif() - - set(Wayland_${_comp}_FIND_VERSION "${Wayland_FIND_VERSION}") - find_package_handle_standard_args(Wayland_${_comp} - FOUND_VAR - Wayland_${_comp}_FOUND - REQUIRED_VARS - Wayland_${_comp}_LIBRARY - Wayland_${_comp}_INCLUDE_DIR - VERSION_VAR - Wayland_${_comp}_VERSION_STRING - ) - - mark_as_advanced( - Wayland_${_comp}_LIBRARY - Wayland_${_comp}_INCLUDE_DIR + ecm_find_package_parse_components(Wayland + RESULT_VAR Wayland_components + KNOWN_COMPONENTS ${Wayland_known_components} + ) + ecm_find_package_handle_library_components(Wayland + COMPONENTS ${Wayland_components} ) - if(Wayland_${_comp}_FOUND AND NOT TARGET Wayland::${_comp}) - add_library(Wayland::${_comp} UNKNOWN IMPORTED) - set_target_properties(Wayland::${_comp} PROPERTIES - IMPORTED_LOCATION "${Wayland_${_comp}_LIBRARY}" - INTERFACE_COMPILE_OPTIONS "${Wayland_DEFINITIONS}" - INTERFACE_INCLUDE_DIRECTORIES "${Wayland_${_comp}_INCLUDE_DIR}" + # If pkg-config didn't provide us with version information, + # try to extract it from wayland-version.h + # (Note that the version from wayland-egl.pc will probably be + # the Mesa version, rather than the Wayland version, but that + # version will be ignored as we always find wayland-client.pc + # first). + if(NOT Wayland_VERSION) + find_file(Wayland_VERSION_HEADER + NAMES wayland-version.h + HINTS ${Wayland_INCLUDE_DIRS} ) - endif() -endmacro() - -if(NOT WIN32) - include(FindPackageHandleStandardArgs) - # Use pkg-config to get the directories and then use these values - # in the FIND_PATH() and FIND_LIBRARY() calls - find_package(PkgConfig) - # Invoke pkg_check_modules() in a loop because if we call it like this: - # pkg_check_modules(PKG_Wayland QUIET ${pkgConfigModules}) - # and one of the components cannot be found, then it won't set any variable - # at all. - foreach(comp ${pkgConfigModules}) - pkg_check_modules(PKG_Wayland_${comp} QUIET ${comp}) - endforeach() - - set(Wayland_DEFINITIONS ${PKG_Wayland_CFLAGS_OTHER}) - - foreach(comp ${comps}) - _wayland_handle_component(${comp}) - endforeach() - - if(Wayland_INCLUDE_DIRS) - list(REMOVE_DUPLICATES Wayland_INCLUDE_DIRS) + mark_as_advanced(Wayland_VERSION_HEADER) + if(Wayland_VERSION_HEADER) + file(READ ${Wayland_VERSION_HEADER} _wayland_version_header_contents) + string(REGEX REPLACE + "^.*[ \\t]+WAYLAND_VERSION[ \\t]+\"([0-9.]*)\".*$" + "\\1" + Wayland_VERSION + "${_wayland_version_header_contents}" + ) + unset(_wayland_version_header_contents) + endif() endif() find_package_handle_standard_args(Wayland @@ -182,9 +97,8 @@ if(NOT WIN32) Wayland_FOUND REQUIRED_VARS Wayland_LIBRARIES - Wayland_INCLUDE_DIRS VERSION_VAR - Wayland_VERSION_STRING + Wayland_VERSION HANDLE_COMPONENTS ) diff --git a/find-modules/FindXCB.cmake b/find-modules/FindXCB.cmake index eb307588..a900a624 100644 --- a/find-modules/FindXCB.cmake +++ b/find-modules/FindXCB.cmake @@ -1,325 +1,150 @@ # Try to find XCB on a Unix system # -# This will define: +# This is a component-based find module, which makes use of the COMPONENTS +# and OPTIONAL_COMPONENTS arguments to find_module. The following components +# are available: # -# XCB_FOUND - True if xcb is available -# XCB_LIBRARIES - Link these to use xcb -# XCB_INCLUDE_DIRS - Include directory for xcb -# XCB_DEFINITIONS - Compiler flags for using xcb +# XCB +# ATOM AUX COMPOSITE CURSOR DAMAGE +# DPMS DRI2 DRI3 EVENT EWMH +# GLX ICCCM IMAGE KEYSYMS PRESENT +# RANDR RECORD RENDER RENDERUTIL RES +# SCREENSAVER SHAPE SHM SYNC UTIL +# XEVIE XF86DRI XFIXES XINERAMA XINPUT +# XKB XPRINT XTEST XV XVMC # -# In addition the following more fine grained variables will be defined: +# If no components are specified, this module will act as though all components +# were passed to OPTIONAL_COMPONENTS. # -# XCB_XCB_FOUND XCB_XCB_INCLUDE_DIR XCB_XCB_LIBRARY -# XCB_UTIL_FOUND XCB_UTIL_INCLUDE_DIR XCB_UTIL_LIBRARY -# XCB_COMPOSITE_FOUND XCB_COMPOSITE_INCLUDE_DIR XCB_COMPOSITE_LIBRARY -# XCB_DAMAGE_FOUND XCB_DAMAGE_INCLUDE_DIR XCB_DAMAGE_LIBRARY -# XCB_XFIXES_FOUND XCB_XFIXES_INCLUDE_DIR XCB_XFIXES_LIBRARY -# XCB_RENDER_FOUND XCB_RENDER_INCLUDE_DIR XCB_RENDER_LIBRARY -# XCB_RANDR_FOUND XCB_RANDR_INCLUDE_DIR XCB_RANDR_LIBRARY -# XCB_SHAPE_FOUND XCB_SHAPE_INCLUDE_DIR XCB_SHAPE_LIBRARY -# XCB_DRI2_FOUND XCB_DRI2_INCLUDE_DIR XCB_DRI2_LIBRARY -# XCB_GLX_FOUND XCB_GLX_INCLUDE_DIR XCB_GLX_LIBRARY -# XCB_SHM_FOUND XCB_SHM_INCLUDE_DIR XCB_SHM_LIBRARY -# XCB_XV_FOUND XCB_XV_INCLUDE_DIR XCB_XV_LIBRARY -# XCB_SYNC_FOUND XCB_SYNC_INCLUDE_DIR XCB_SYNC_LIBRARY -# XCB_XTEST_FOUND XCB_XTEST_INCLUDE_DIR XCB_XTEST_LIBRARY -# XCB_ICCCM_FOUND XCB_ICCCM_INCLUDE_DIR XCB_ICCCM_LIBRARY -# XCB_EWMH_FOUND XCB_EWMH_INCLUDE_DIR XCB_EWMH_LIBRARY -# XCB_IMAGE_FOUND XCB_IMAGE_INCLUDE_DIR XCB_IMAGE_LIBRARY -# XCB_RENDERUTIL_FOUND XCB_RENDERUTIL_INCLUDE_DIR XCB_RENDERUTIL_LIBRARY -# XCB_KEYSYMS_FOUND XCB_KEYSYMS_INCLUDE_DIR XCB_KEYSYMS_LIBRARY +# This module will define the following variables, independently of the +# components searched for or found: # -# Additionally, the following imported targets will be defined: +# XCB_FOUND - True if (the requestion version of) xcb is available +# XCB_VERSION - Found xcb version # -# XCB::XCB -# XCB::COMPOSITE -# XCB::DAMAGE -# XCB::DRI2 -# XCB::EWMH -# XCB::GLX -# XCB::ICCCM -# XCB::IMAGE -# XCB::KEYSYMS -# XCB::RANDR -# XCB::RENDER -# XCB::RENDERUTIL -# XCB::SHAPE -# XCB::SHM -# XCB::SYNC -# XCB::UTIL -# XCB::XFIXES -# XCB::XTEST -# XCB::XV +# For each searched-for components, XCB_<component>_FOUND will be set to true +# if the corresponding xcb library was found, and false otherwise. If +# XCB_<component>_FOUND is true, the imported target XCB::<component> will be +# defined. This module will also attempt to determine XCB_*_VERSION variables +# for each imported target, although XCB_VERSION should normally be sufficient. # -# Copyright (c) 2011 Fredrik Höglund <fredrik@kde.org> -# Copyright (c) 2013 Martin Gräßlin <mgraesslin@kde.org> +# The following variable will also be defined for convenience, and for +# compatibility with old-style find module conventions: # -# Redistribution and use is allowed according to the terms of the BSD license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# XCB_LIBRARIES - A list of all XCB imported targets -if(CMAKE_VERSION VERSION_LESS 2.8.12) - message(FATAL_ERROR "CMake 2.8.12 is required by FindXCB.cmake") -endif() -if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.12) - message(AUTHOR_WARNING "Your project should require at least CMake 2.8.12 to use FindXCB.cmake") -endif() - -set(knownComponents XCB - COMPOSITE - DAMAGE - DRI2 - EWMH - GLX - ICCCM - IMAGE - KEYSYMS - RANDR - RENDER - RENDERUTIL - SHAPE - SHM - SYNC - UTIL - XFIXES - XTEST - XV) - -unset(unknownComponents) - -set(pkgConfigModules) - -if (XCB_FIND_COMPONENTS) - set(comps ${XCB_FIND_COMPONENTS}) -else() - set(comps ${knownComponents}) -endif() - -# iterate through the list of requested components, and check that we know them all. -# If not, fail. -foreach(comp ${comps}) - list(FIND knownComponents ${comp} index ) - if("${index}" STREQUAL "-1") - list(APPEND unknownComponents "${comp}") - else() - if("${comp}" STREQUAL "XCB") - list(APPEND pkgConfigModules "xcb") - elseif("${comp}" STREQUAL "COMPOSITE") - list(APPEND pkgConfigModules "xcb-composite") - elseif("${comp}" STREQUAL "DAMAGE") - list(APPEND pkgConfigModules "xcb-damage") - elseif("${comp}" STREQUAL "DRI2") - list(APPEND pkgConfigModules "xcb-dri2") - elseif("${comp}" STREQUAL "EWMH") - list(APPEND pkgConfigModules "xcb-ewmh") - elseif("${comp}" STREQUAL "GLX") - list(APPEND pkgConfigModules "xcb-glx") - elseif("${comp}" STREQUAL "ICCCM") - list(APPEND pkgConfigModules "xcb-icccm") - elseif("${comp}" STREQUAL "IMAGE") - list(APPEND pkgConfigModules "xcb-image") - elseif("${comp}" STREQUAL "KEYSYMS") - list(APPEND pkgConfigModules "xcb-keysyms") - elseif("${comp}" STREQUAL "RANDR") - list(APPEND pkgConfigModules "xcb-randr") - elseif("${comp}" STREQUAL "RENDER") - list(APPEND pkgConfigModules "xcb-render") - elseif("${comp}" STREQUAL "RENDERUTIL") - list(APPEND pkgConfigModules "xcb-renderutil") - elseif("${comp}" STREQUAL "SHAPE") - list(APPEND pkgConfigModules "xcb-shape") - elseif("${comp}" STREQUAL "SHM") - list(APPEND pkgConfigModules "xcb-shm") - elseif("${comp}" STREQUAL "SYNC") - list(APPEND pkgConfigModules "xcb-sync") - elseif("${comp}" STREQUAL "UTIL") - list(APPEND pkgConfigModules "xcb-util") - elseif("${comp}" STREQUAL "XFIXES") - list(APPEND pkgConfigModules "xcb-xfixes") - elseif("${comp}" STREQUAL "XTEST") - list(APPEND pkgConfigModules "xcb-xtest") - elseif("${comp}" STREQUAL "XV") - list(APPEND pkgConfigModules "xcb-xv") - endif() - endif() -endforeach() - - -if(DEFINED unknownComponents) - set(msgType STATUS) - if(XCB_FIND_REQUIRED) - set(msgType FATAL_ERROR) - endif() - if(NOT XCB_FIND_QUIETLY) - message(${msgType} "XCB: requested unknown components ${unknownComponents}") - endif() - return() -endif() - -macro(_XCB_HANDLE_COMPONENT _comp) - set(_header ) - set(_lib ) - set(_pkgconfig_module_var) - if("${_comp}" STREQUAL "XCB") - set(_header "xcb/xcb.h") - set(_lib "xcb") - set(_pkgconfig_module_var "xcb") - elseif("${_comp}" STREQUAL "COMPOSITE") - set(_header "xcb/composite.h") - set(_lib "xcb-composite") - set(_pkgconfig_module_var "xcb-composite") - elseif("${_comp}" STREQUAL "DAMAGE") - set(_header "xcb/damage.h") - set(_lib "xcb-damage") - set(_pkgconfig_module_var "xcb-damage") - elseif("${_comp}" STREQUAL "DRI2") - set(_header "xcb/dri2.h") - set(_lib "xcb-dri2") - set(_pkgconfig_module_var "xcb-dri2") - elseif("${_comp}" STREQUAL "EWMH") - set(_header "xcb/xcb_ewmh.h") - set(_lib "xcb-ewmh") - set(_pkgconfig_module_var "xcb-ewmh") - elseif("${_comp}" STREQUAL "GLX") - set(_header "xcb/glx.h") - set(_lib "xcb-glx") - set(_pkgconfig_module_var "xcb-glx") - elseif("${_comp}" STREQUAL "ICCCM") - set(_header "xcb/xcb_icccm.h") - set(_lib "xcb-icccm") - set(_pkgconfig_module_var "xcb-icccm") - elseif("${_comp}" STREQUAL "IMAGE") - set(_header "xcb/xcb_image.h") - set(_lib "xcb-image") - set(_pkgconfig_module_var "xcb-image") - elseif("${_comp}" STREQUAL "KEYSYMS") - set(_header "xcb/xcb_keysyms.h") - set(_lib "xcb-keysyms") - set(_pkgconfig_module_var "xcb-keysyms") - elseif("${_comp}" STREQUAL "RANDR") - set(_header "xcb/randr.h") - set(_lib "xcb-randr") - set(_pkgconfig_module_var "xcb-randr") - elseif("${_comp}" STREQUAL "RENDER") - set(_header "xcb/render.h") - set(_lib "xcb-render") - set(_pkgconfig_module_var "xcb-render") - elseif("${_comp}" STREQUAL "RENDERUTIL") - set(_header "xcb/xcb_renderutil.h") - set(_lib "xcb-render-util") - set(_pkgconfig_module_var "xcb-renderutil") - elseif("${_comp}" STREQUAL "SHAPE") - set(_header "xcb/shape.h") - set(_lib "xcb-shape") - set(_pkgconfig_module_var "xcb-shape") - elseif("${_comp}" STREQUAL "SHM") - set(_header "xcb/shm.h") - set(_lib "xcb-shm") - set(_pkgconfig_module_var "xcb-shm") - elseif("${_comp}" STREQUAL "SYNC") - set(_header "xcb/sync.h") - set(_lib "xcb-sync") - set(_pkgconfig_module_var "xcb-sync") - elseif("${_comp}" STREQUAL "UTIL") - set(_header "xcb/xcb_util.h") - set(_lib "xcb-util") - set(_pkgconfig_module_var "xcb-util") - elseif("${_comp}" STREQUAL "XFIXES") - set(_header "xcb/xfixes.h") - set(_lib "xcb-xfixes") - set(_pkgconfig_module_var "xcb-xfixes") - elseif("${_comp}" STREQUAL "XTEST") - set(_header "xcb/xtest.h") - set(_lib "xcb-xtest") - set(_pkgconfig_module_var "xcb-xtest") - elseif("${_comp}" STREQUAL "XV") - set(_header "xcb/xv.h") - set(_lib "xcb-xv") - set(_pkgconfig_module_var "xcb-xv") - endif() - - find_path(XCB_${_comp}_INCLUDE_DIR - NAMES ${_header} - HINTS ${PKG_XCB_INCLUDE_DIRS} +#============================================================================= +# Copyright 2011 Fredrik Höglund <fredrik@kde.org> +# Copyright 2013 Martin Gräßlin <mgraesslin@kde.org> +# Copyright 2014 Alex Merry <alex.merry@kde.org> +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file COPYING-CMAKE-SCRIPTS for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of extra-cmake-modules, substitute the full +# License text for the above reference.) + +include(${CMAKE_CURRENT_LIST_DIR}/../modules/ECMFindModuleHelpers.cmake) + +ecm_find_package_version_check(XCB) + +if(NOT WIN32) + # Note that this list needs to be ordered such that any component + # appears after its dependencies + set(XCB_known_components + XCB + RENDER + SHAPE + XFIXES + SHM + ATOM + AUX + COMPOSITE + CURSOR + DAMAGE + DPMS + DRI2 + DRI3 + EVENT + EWMH + GLX + ICCCM + IMAGE + KEYSYMS + PRESENT + RANDR + RECORD + RENDERUTIL + RES + SCREENSAVER + SYNC + UTIL + XEVIE + XF86DRI + XINERAMA + XINPUT + XKB + XPRINT + XTEST + XV + XVMC) + # default component info: xcb components have fairly predictable + # header files, library names and pkg-config names + foreach(_comp ${XCB_known_components}) + string(TOLOWER "${_comp}" _lc_comp) + set(XCB_${_comp}_component_deps XCB) + set(XCB_${_comp}_pkg_config "xcb-${_lc_comp}") + set(XCB_${_comp}_lib "xcb-${_lc_comp}") + set(XCB_${_comp}_header "xcb/${_lc_comp}.h") + endforeach() + # exceptions + set(XCB_XCB_component_deps) + set(XCB_COMPOSITE_component_deps XCB XFIXES) + set(XCB_DAMAGE_component_deps XCB XFIXES) + set(XCB_IMAGE_component_deps XCB SHM) + set(XCB_RENDERUTIL_component_deps XCB RENDER) + set(XCB_XFIXES_component_deps XCB RENDER SHAPE) + set(XCB_XVMC_component_deps XCB XV) + set(XCB_XV_component_deps XCB SHM) + set(XCB_XCB_pkg_config "xcb") + set(XCB_XCB_lib "xcb") + set(XCB_ATOM_header "xcb/xcb_atom.h") + set(XCB_ATOM_lib "xcb-util") + set(XCB_AUX_header "xcb/xcb_aux.h") + set(XCB_AUX_lib "xcb-util") + set(XCB_CURSOR_header "xcb/xcb_cursor.h") + set(XCB_EVENT_header "xcb/xcb_event.h") + set(XCB_EVENT_lib "xcb-util") + set(XCB_EWMH_header "xcb/xcb_ewmh.h") + set(XCB_ICCCM_header "xcb/xcb_icccm.h") + set(XCB_IMAGE_header "xcb/xcb_image.h") + set(XCB_KEYSYMS_header "xcb/xcb_keysyms.h") + set(XCB_PIXEL_header "xcb/xcb_pixel.h") + set(XCB_RENDERUTIL_header "xcb/xcb_renderutil.h") + set(XCB_RENDERUTIL_lib "xcb-render-util") + set(XCB_UTIL_header "xcb/xcb_util.h") + + ecm_find_package_parse_components(XCB + RESULT_VAR XCB_components + KNOWN_COMPONENTS ${XCB_known_components} ) - find_library(XCB_${_comp}_LIBRARY - NAMES ${_lib} - HINTS ${PKG_XCB_LIBRARY_DIRS} + ecm_find_package_handle_library_components(XCB + COMPONENTS ${XCB_components} ) - if(XCB_${_comp}_INCLUDE_DIR AND XCB_${_comp}_LIBRARY) - list(APPEND XCB_INCLUDE_DIRS ${XCB_${_comp}_INCLUDE_DIR}) - list(APPEND XCB_LIBRARIES ${XCB_${_comp}_LIBRARY}) - endif() - - if(PKG_XCB_VERSION AND NOT PKG_XCB_${_pkgconfig_module_var}_VERSION) - # this is what gets set if we only search for one module - set(XCB_${_comp}_VERSION_STRING "${PKG_XCB_VERSION}") - else() - set(XCB_${_comp}_VERSION_STRING "${PKG_XCB_${_pkgconfig_module_var}_VERSION}") - endif() - - if(NOT XCB_VERSION_STRING) - set(XCB_VERSION_STRING ${XCB_${_comp}_VERSION_STRING}) - endif() - - find_package_handle_standard_args(XCB_${_comp} - FOUND_VAR - XCB_${_comp}_FOUND - REQUIRED_VARS - XCB_${_comp}_LIBRARY - XCB_${_comp}_INCLUDE_DIR - VERSION_VAR - XCB_${_comp}_VERSION_STRING - ) - - mark_as_advanced(XCB_${_comp}_LIBRARY XCB_${_comp}_INCLUDE_DIR) - - if(XCB_${_comp}_FOUND AND NOT TARGET XCB::${_comp}) - add_library(XCB::${_comp} UNKNOWN IMPORTED) - set_target_properties(XCB::${_comp} PROPERTIES - IMPORTED_LOCATION "${XCB_${_comp}_LIBRARY}" - INTERFACE_COMPILE_OPTIONS "${XCB_DEFINITIONS}" - INTERFACE_INCLUDE_DIRECTORIES "${XCB_${_comp}_INCLUDE_DIR}" - ) - endif() - - # compatibility for old variable naming - set(XCB_${_comp}_INCLUDE_DIRS ${XCB_${_comp}_INCLUDE_DIR}) - set(XCB_${_comp}_LIBRARIES ${XCB_${_comp}_LIBRARY}) -endmacro() - -IF (NOT WIN32) - include(FindPackageHandleStandardArgs) - # Use pkg-config to get the directories and then use these values - # in the FIND_PATH() and FIND_LIBRARY() calls - find_package(PkgConfig) - pkg_check_modules(PKG_XCB QUIET ${pkgConfigModules}) - - set(XCB_DEFINITIONS ${PKG_XCB_CFLAGS}) - - foreach(comp ${comps}) - _xcb_handle_component(${comp}) - endforeach() - - if(XCB_INCLUDE_DIRS) - list(REMOVE_DUPLICATES XCB_INCLUDE_DIRS) - endif() - - find_package_handle_standard_args(XCB FOUND_VAR XCB_FOUND REQUIRED_VARS XCB_LIBRARIES - XCB_INCLUDE_DIRS VERSION_VAR - XCB_VERSION_STRING + XCB_VERSION HANDLE_COMPONENTS ) - - # compatibility for old variable naming - set(XCB_INCLUDE_DIR ${XCB_INCLUDE_DIRS}) - else() message(STATUS "XCB is not available on Windows.") set(XCB_FOUND FALSE) diff --git a/modules/ECMFindModuleHelpers.cmake b/modules/ECMFindModuleHelpers.cmake new file mode 100644 index 00000000..cf2f7e61 --- /dev/null +++ b/modules/ECMFindModuleHelpers.cmake @@ -0,0 +1,227 @@ +# Helper macros for find modules +# +# ecm_find_package_version_check(<name>) +# +# Prints warnings if the CMake version or the project's required CMake version +# is older than that required by extra-cmake-modules. +# +# ecm_find_package_parse_components(<name> +# RESULT_VAR <variable> +# KNOWN_COMPONENTS <component> [<component>]* +# [SKIP_DEPENDENCY_HANDLING]) +# +# This macro will populate <variable> with a list of components found in +# <name>_FIND_COMPONENTS, after checking that all those components are in the +# list of KNOWN_COMPONENTS; if there are any unknown components, it will print +# an error or warning (depending on the value of <name>_FIND_REQUIRED) and call +# return(). +# +# The order of components in <variable> is guaranteed to match the order they +# are listed in the KNOWN_COMPONENTS argument. +# +# If SKIP_DEPENDENCY_HANDLING is not set, for each component the variable +# <name>_<component>_component_deps will be checked for dependent components. +# If <component> is listed in <name>_FIND_COMPONENTS, then all its (transitive) +# dependencies will also be added to <variable>. +# +# ecm_find_package_handle_library_components(<name> +# COMPONENTS <component> [<component>]* +# [SKIP_DEPENDENCY_HANDLING]) +# [SKIP_PKG_CONFIG]) +# +# Creates an imported library target for each component. The operation of this +# macro depends on the presence of a number of CMake variables. +# +# The <name>_<component>_lib variable should contain the name of this library, +# and <name>_<component>_header variable should contain the name of a header +# file associated with it (whatever relative path is normally passed to +# '#include'). ecm_find_package_components() will then search for the library +# and include directory (creating appropriate cache variables) and create an +# imported library target named <name>::<component>. +# +# Additional variables can be used to provide additional information: +# +# If SKIP_PKG_CONFIG, the <name>_<component>_pkg_config variable is set, and +# pkg-config is found, the pkg-config module given by +# <name>_<component>_pkg_config will be searched for and used to help locate the +# library and header file. It will also be used to set +# <name>_<component>_VERSION. +# +# Note that if version information is found via pkg-config, +# <name>_<component>_FIND_VERSION can be set to require a particular version +# for each component. +# +# If SKIP_DEPENDENCY_HANDLING is not set, the INTERFACE_LINK_LIBRARIES property +# of the imported target for <component> will be set to contain the imported +# targets for the components listed in <name>_<component>_component_deps. +# <component>_FOUND will also be set to false if any of the compoments in +# <name>_<component>_component_deps are not found. This requires the components +# in <name>_<component>_component_deps to be listed before <component> in the +# COMPONENTS argument. +# +# <name>_LIBRARIES will list the imported targets. +# +# <name>_VERSION will be set to the same as <name>_<component>_VERSION for +# the component that is searched for first (note that components are searched +# for in the order they are passed to the macro). + +#============================================================================= +# Copyright 2014 Alex Merry <alex.merry@kde.org> +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file COPYING-CMAKE-SCRIPTS for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of extra-cmake-modules, substitute the full +# License text for the above reference.) + +include(CMakeParseArguments) + +macro(ecm_find_package_version_check module_name) + if(CMAKE_VERSION VERSION_LESS 2.8.12) + message(FATAL_ERROR "CMake 2.8.12 is required by Find${module_name}.cmake") + endif() + if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.12) + message(AUTHOR_WARNING "Your project should require at least CMake 2.8.12 to use Find${module_name}.cmake") + endif() +endmacro() + +macro(ecm_find_package_parse_components module_name) + set(ecm_fppc_options SKIP_DEPENDENCY_HANDLING) + set(ecm_fppc_oneValueArgs RESULT_VAR) + set(ecm_fppc_multiValueArgs KNOWN_COMPONENTS) + cmake_parse_arguments(ECM_FPPC "${ecm_fppc_options}" "${ecm_fppc_oneValueArgs}" "${ecm_fppc_multiValueArgs}" ${ARGN}) + + if(ECM_FPPC_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unexpected arguments to ecm_find_package_parse_components: ${ECM_FPPC_UNPARSED_ARGUMENTS}") + endif() + if(NOT ECM_FPPC_RESULT_VAR) + message(FATAL_ERROR "Missing RESULT_VAR argument to ecm_find_package_parse_components") + endif() + if(NOT ECM_FPPC_KNOWN_COMPONENTS) + message(FATAL_ERROR "Missing KNOWN_COMPONENTS argument to ecm_find_package_parse_components") + endif() + + if(${module_name}_FIND_COMPONENTS) + set(ecm_fppc_requestedComps ${${module_name}_FIND_COMPONENTS}) + + if(NOT ECM_FPPC_SKIP_DEPENDENCY_HANDLING) + # Make sure deps are included + foreach(ecm_fppc_comp ${ecm_fppc_requestedComps}) + foreach(ecm_fppc_dep_comp ${${module_name}_${ecm_fppc_comp}_component_deps}) + list(FIND ecm_fppc_requestedComps "${ecm_fppc_dep_comp}" ecm_fppc_index) + if("${ecm_fppc_index}" STREQUAL "-1") + if(NOT ${module_name}_FIND_QUIETLY) + message(STATUS "Wayland: ${ecm_fppc_comp} requires ${${module_name}_${ecm_fppc_comp}_component_deps}") + endif() + list(APPEND ecm_fppc_requestedComps "${ecm_fppc_dep_comp}") + endif() + endforeach() + endforeach() + else() + message(STATUS "Skipping dependency handling for ${module_name}") + endif() + list(REMOVE_DUPLICATES ecm_fppc_requestedComps) + + # This makes sure components are listed in the same order as + # KNOWN_COMPONENTS (potentially important for inter-dependencies) + set(${ECM_FPPC_RESULT_VAR}) + foreach(ecm_fppc_comp ${ECM_FPPC_KNOWN_COMPONENTS}) + list(FIND ecm_fppc_requestedComps "${ecm_fppc_comp}" ecm_fppc_index) + if(NOT "${ecm_fppc_index}" STREQUAL "-1") + list(APPEND ${ECM_FPPC_RESULT_VAR} "${ecm_fppc_comp}") + list(REMOVE_AT ecm_fppc_requestedComps ${ecm_fppc_index}) + endif() + endforeach() + # if there are any left, they are unknown components + if(ecm_fppc_requestedComps) + set(ecm_fppc_msgType STATUS) + if(${module_name}_FIND_REQUIRED) + set(ecm_fppc_msgType FATAL_ERROR) + endif() + if(NOT ${module_name}_FIND_QUIETLY) + message(${ecm_fppc_msgType} "${module_name}: requested unknown components ${ecm_fppc_requestedComps}") + endif() + return() + endif() + else() + set(${ECM_FPPC_RESULT_VAR} ${ECM_FPPC_KNOWN_COMPONENTS}) + endif() +endmacro() + +macro(ecm_find_package_handle_library_components module_name) + set(ecm_fpwc_options SKIP_PKG_CONFIG SKIP_DEPENDENCY_HANDLING) + set(ecm_fpwc_oneValueArgs) + set(ecm_fpwc_multiValueArgs COMPONENTS) + cmake_parse_arguments(ECM_FPWC "${ecm_fpwc_options}" "${ecm_fpwc_oneValueArgs}" "${ecm_fpwc_multiValueArgs}" ${ARGN}) + + if(ECM_FPWC_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unexpected arguments to ecm_find_package_handle_components: ${ECM_FPWC_UNPARSED_ARGUMENTS}") + endif() + if(NOT ECM_FPWC_COMPONENTS) + message(FATAL_ERROR "Missing COMPONENTS argument to ecm_find_package_handle_components") + endif() + + include(FindPackageHandleStandardArgs) + find_package(PkgConfig) + foreach(ecm_fpwc_comp ${ECM_FPWC_COMPONENTS}) + set(ecm_fpwc_dep_vars) + set(ecm_fpwc_dep_libs) + if(NOT SKIP_DEPENDENCY_HANDLING) + foreach(ecm_fpwc_dep ${${module_name}_${ecm_fpwc_comp}_component_deps}) + list(APPEND ecm_fpwc_dep_vars "${module_name}_${ecm_fpwc_dep}_FOUND") + list(APPEND ecm_fpwc_dep_libs "${module_name}::${ecm_fpwc_dep}") + endforeach() + endif() + + if(NOT ECM_FPWC_SKIP_PKG_CONFIG AND ${module_name}_${ecm_fpwc_comp}_pkg_config) + pkg_check_modules(PKG_${module_name}_${ecm_fpwc_comp} QUIET + ${${module_name}_${ecm_fpwc_comp}_pkg_config}) + endif() + + find_path(${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR + NAMES ${${module_name}_${ecm_fpwc_comp}_header} + HINTS ${PKG_${module_name}_${ecm_fpwc_comp}_INCLUDE_DIRS} + ) + find_library(${module_name}_${ecm_fpwc_comp}_LIBRARY + NAMES ${${module_name}_${ecm_fpwc_comp}_lib} + HINTS ${PKG_${module_name}_${ecm_fpwc_comp}_LIBRARY_DIRS} + ) + + set(${module_name}_${ecm_fpwc_comp}_VERSION "${PKG_${module_name}_${ecm_fpwc_comp}_VERSION}") + if(NOT ${module_name}_VERSION) + set(${module_name}_VERSION ${${module_name}_${ecm_fpwc_comp}_VERSION}) + endif() + + find_package_handle_standard_args(${module_name}_${ecm_fpwc_comp} + FOUND_VAR + ${module_name}_${ecm_fpwc_comp}_FOUND + REQUIRED_VARS + ${module_name}_${ecm_fpwc_comp}_LIBRARY + ${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR + ${ecm_fpwc_dep_vars} + VERSION_VAR + ${module_name}_${ecm_fpwc_comp}_VERSION + ) + + mark_as_advanced( + ${module_name}_${ecm_fpwc_comp}_LIBRARY + ${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR + ) + + if(${module_name}_${ecm_fpwc_comp}_FOUND AND NOT TARGET ${module_name}::${ecm_fpwc_comp}) + add_library(${module_name}::${ecm_fpwc_comp} UNKNOWN IMPORTED) + set_target_properties(${module_name}::${ecm_fpwc_comp} PROPERTIES + IMPORTED_LOCATION "${${module_name}_${ecm_fpwc_comp}_LIBRARY}" + INTERFACE_COMPILE_OPTIONS "${PKG_${module_name}_${ecm_fpwc_comp}_DEFINITIONS}" + INTERFACE_INCLUDE_DIRECTORIES "${${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR}" + INTERFACE_LINK_LIBRARIES "${ecm_fpwc_dep_libs}" + ) + list(APPEND ${module_name}_LIBRARIES "${module_name}::${ecm_fpwc_comp}") + endif() + endforeach() +endmacro() + |