| [cdd8fca] | 1 | # Version 2.2 |
|---|
| 2 | # Public Domain, originally written by Lasse KÀrkkÀinen <tronic> |
|---|
| 3 | # Maintained at https://github.com/Tronic/cmake-modules |
|---|
| 4 | # Please send your improvements as pull requests on Github. |
|---|
| 5 | |
|---|
| 6 | # Find another package and make it a dependency of the current package. |
|---|
| 7 | # This also automatically forwards the "REQUIRED" argument. |
|---|
| 8 | # Usage: libfind_package(<prefix> <another package> [extra args to find_package]) |
|---|
| 9 | macro (libfind_package PREFIX PKG) |
|---|
| 10 | set(${PREFIX}_args ${PKG} ${ARGN}) |
|---|
| 11 | if (${PREFIX}_FIND_REQUIRED) |
|---|
| 12 | set(${PREFIX}_args ${${PREFIX}_args} REQUIRED) |
|---|
| 13 | endif() |
|---|
| 14 | find_package(${${PREFIX}_args}) |
|---|
| 15 | set(${PREFIX}_DEPENDENCIES ${${PREFIX}_DEPENDENCIES};${PKG}) |
|---|
| 16 | unset(${PREFIX}_args) |
|---|
| 17 | endmacro() |
|---|
| 18 | |
|---|
| 19 | # A simple wrapper to make pkg-config searches a bit easier. |
|---|
| 20 | # Works the same as CMake's internal pkg_check_modules but is always quiet. |
|---|
| 21 | macro (libfind_pkg_check_modules) |
|---|
| 22 | find_package(PkgConfig QUIET) |
|---|
| 23 | if (PKG_CONFIG_FOUND) |
|---|
| 24 | pkg_check_modules(${ARGN} QUIET) |
|---|
| 25 | endif() |
|---|
| 26 | endmacro() |
|---|
| 27 | |
|---|
| 28 | # Avoid useless copy&pasta by doing what most simple libraries do anyway: |
|---|
| 29 | # pkg-config, find headers, find library. |
|---|
| 30 | # Usage: libfind_pkg_detect(<prefix> <pkg-config args> FIND_PATH <name> [other args] FIND_LIBRARY <name> [other args]) |
|---|
| 31 | # E.g. libfind_pkg_detect(SDL2 sdl2 FIND_PATH SDL.h PATH_SUFFIXES SDL2 FIND_LIBRARY SDL2) |
|---|
| 32 | function (libfind_pkg_detect PREFIX) |
|---|
| 33 | # Parse arguments |
|---|
| 34 | set(argname pkgargs) |
|---|
| 35 | foreach (i ${ARGN}) |
|---|
| 36 | if ("${i}" STREQUAL "FIND_PATH") |
|---|
| 37 | set(argname pathargs) |
|---|
| 38 | elseif ("${i}" STREQUAL "FIND_LIBRARY") |
|---|
| 39 | set(argname libraryargs) |
|---|
| 40 | else() |
|---|
| 41 | set(${argname} ${${argname}} ${i}) |
|---|
| 42 | endif() |
|---|
| 43 | endforeach() |
|---|
| 44 | if (NOT pkgargs) |
|---|
| 45 | message(FATAL_ERROR "libfind_pkg_detect requires at least a pkg_config package name to be passed.") |
|---|
| 46 | endif() |
|---|
| 47 | # Find library |
|---|
| 48 | libfind_pkg_check_modules(${PREFIX}_PKGCONF ${pkgargs}) |
|---|
| 49 | if (pathargs) |
|---|
| 50 | find_path(${PREFIX}_INCLUDE_DIR NAMES ${pathargs} HINTS ${${PREFIX}_PKGCONF_INCLUDE_DIRS}) |
|---|
| 51 | endif() |
|---|
| 52 | if (libraryargs) |
|---|
| 53 | find_library(${PREFIX}_LIBRARY NAMES ${libraryargs} HINTS ${${PREFIX}_PKGCONF_LIBRARY_DIRS}) |
|---|
| 54 | endif() |
|---|
| 55 | endfunction() |
|---|
| 56 | |
|---|
| 57 | # Extracts a version #define from a version.h file, output stored to <PREFIX>_VERSION. |
|---|
| 58 | # Usage: libfind_version_header(Foobar foobar/version.h FOOBAR_VERSION_STR) |
|---|
| 59 | # Fourth argument "QUIET" may be used for silently testing different define names. |
|---|
| 60 | # This function does nothing if the version variable is already defined. |
|---|
| 61 | function (libfind_version_header PREFIX VERSION_H DEFINE_NAME) |
|---|
| 62 | # Skip processing if we already have a version or if the include dir was not found |
|---|
| 63 | if (${PREFIX}_VERSION OR NOT ${PREFIX}_INCLUDE_DIR) |
|---|
| 64 | return() |
|---|
| 65 | endif() |
|---|
| 66 | set(quiet ${${PREFIX}_FIND_QUIETLY}) |
|---|
| 67 | # Process optional arguments |
|---|
| 68 | foreach(arg ${ARGN}) |
|---|
| 69 | if (arg STREQUAL "QUIET") |
|---|
| 70 | set(quiet TRUE) |
|---|
| 71 | else() |
|---|
| 72 | message(AUTHOR_WARNING "Unknown argument ${arg} to libfind_version_header ignored.") |
|---|
| 73 | endif() |
|---|
| 74 | endforeach() |
|---|
| 75 | # Read the header and parse for version number |
|---|
| 76 | set(filename "${${PREFIX}_INCLUDE_DIR}/${VERSION_H}") |
|---|
| 77 | if (NOT EXISTS ${filename}) |
|---|
| 78 | if (NOT quiet) |
|---|
| 79 | message(AUTHOR_WARNING "Unable to find ${${PREFIX}_INCLUDE_DIR}/${VERSION_H}") |
|---|
| 80 | endif() |
|---|
| 81 | return() |
|---|
| 82 | endif() |
|---|
| 83 | file(READ "${filename}" header) |
|---|
| 84 | string(REGEX REPLACE ".*#[ \t]*define[ \t]*${DEFINE_NAME}[ \t]*\"([^\n]*)\".*" "\\1" match "${header}") |
|---|
| 85 | # No regex match? |
|---|
| 86 | if (match STREQUAL header) |
|---|
| 87 | if (NOT quiet) |
|---|
| 88 | message(AUTHOR_WARNING "Unable to find \#define ${DEFINE_NAME} \"<version>\" from ${${PREFIX}_INCLUDE_DIR}/${VERSION_H}") |
|---|
| 89 | endif() |
|---|
| 90 | return() |
|---|
| 91 | endif() |
|---|
| 92 | # Export the version string |
|---|
| 93 | set(${PREFIX}_VERSION "${match}" PARENT_SCOPE) |
|---|
| 94 | endfunction() |
|---|
| 95 | |
|---|
| 96 | # Do the final processing once the paths have been detected. |
|---|
| 97 | # If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain |
|---|
| 98 | # all the variables, each of which contain one include directory. |
|---|
| 99 | # Ditto for ${PREFIX}_PROCESS_LIBS and library files. |
|---|
| 100 | # Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES. |
|---|
| 101 | # Also handles errors in case library detection was required, etc. |
|---|
| 102 | function (libfind_process PREFIX) |
|---|
| 103 | # Skip processing if already processed during this configuration run |
|---|
| 104 | if (${PREFIX}_FOUND) |
|---|
| 105 | return() |
|---|
| 106 | endif() |
|---|
| 107 | |
|---|
| 108 | set(found TRUE) # Start with the assumption that the package was found |
|---|
| 109 | |
|---|
| 110 | # Did we find any files? Did we miss includes? These are for formatting better error messages. |
|---|
| 111 | set(some_files FALSE) |
|---|
| 112 | set(missing_headers FALSE) |
|---|
| 113 | |
|---|
| 114 | # Shorthands for some variables that we need often |
|---|
| 115 | set(quiet ${${PREFIX}_FIND_QUIETLY}) |
|---|
| 116 | set(required ${${PREFIX}_FIND_REQUIRED}) |
|---|
| 117 | set(exactver ${${PREFIX}_FIND_VERSION_EXACT}) |
|---|
| 118 | set(findver "${${PREFIX}_FIND_VERSION}") |
|---|
| 119 | set(version "${${PREFIX}_VERSION}") |
|---|
| 120 | |
|---|
| 121 | # Lists of config option names (all, includes, libs) |
|---|
| 122 | unset(configopts) |
|---|
| 123 | set(includeopts ${${PREFIX}_PROCESS_INCLUDES}) |
|---|
| 124 | set(libraryopts ${${PREFIX}_PROCESS_LIBS}) |
|---|
| 125 | |
|---|
| 126 | # Process deps to add to |
|---|
| 127 | foreach (i ${PREFIX} ${${PREFIX}_DEPENDENCIES}) |
|---|
| 128 | if (DEFINED ${i}_INCLUDE_OPTS OR DEFINED ${i}_LIBRARY_OPTS) |
|---|
| 129 | # The package seems to export option lists that we can use, woohoo! |
|---|
| 130 | list(APPEND includeopts ${${i}_INCLUDE_OPTS}) |
|---|
| 131 | list(APPEND libraryopts ${${i}_LIBRARY_OPTS}) |
|---|
| 132 | else() |
|---|
| 133 | # If plural forms don't exist or they equal singular forms |
|---|
| 134 | if ((NOT DEFINED ${i}_INCLUDE_DIRS AND NOT DEFINED ${i}_LIBRARIES) OR |
|---|
| 135 | ({i}_INCLUDE_DIR STREQUAL ${i}_INCLUDE_DIRS AND ${i}_LIBRARY STREQUAL ${i}_LIBRARIES)) |
|---|
| 136 | # Singular forms can be used |
|---|
| 137 | if (DEFINED ${i}_INCLUDE_DIR) |
|---|
| 138 | list(APPEND includeopts ${i}_INCLUDE_DIR) |
|---|
| 139 | endif() |
|---|
| 140 | if (DEFINED ${i}_LIBRARY) |
|---|
| 141 | list(APPEND libraryopts ${i}_LIBRARY) |
|---|
| 142 | endif() |
|---|
| 143 | else() |
|---|
| 144 | # Oh no, we don't know the option names |
|---|
| 145 | message(FATAL_ERROR "We couldn't determine config variable names for ${i} includes and libs. Aieeh!") |
|---|
| 146 | endif() |
|---|
| 147 | endif() |
|---|
| 148 | endforeach() |
|---|
| 149 | |
|---|
| 150 | if (includeopts) |
|---|
| 151 | list(REMOVE_DUPLICATES includeopts) |
|---|
| 152 | endif() |
|---|
| 153 | |
|---|
| 154 | if (libraryopts) |
|---|
| 155 | list(REMOVE_DUPLICATES libraryopts) |
|---|
| 156 | endif() |
|---|
| 157 | |
|---|
| 158 | string(REGEX REPLACE ".*[ ;]([^ ;]*(_INCLUDE_DIRS|_LIBRARIES))" "\\1" tmp "${includeopts} ${libraryopts}") |
|---|
| 159 | if (NOT tmp STREQUAL "${includeopts} ${libraryopts}") |
|---|
| 160 | message(AUTHOR_WARNING "Plural form ${tmp} found in config options of ${PREFIX}. This works as before but is now deprecated. Please only use singular forms INCLUDE_DIR and LIBRARY, and update your find scripts for LibFindMacros > 2.0 automatic dependency system (most often you can simply remove the PROCESS variables entirely).") |
|---|
| 161 | endif() |
|---|
| 162 | |
|---|
| 163 | # Include/library names separated by spaces (notice: not CMake lists) |
|---|
| 164 | unset(includes) |
|---|
| 165 | unset(libs) |
|---|
| 166 | |
|---|
| 167 | # Process all includes and set found false if any are missing |
|---|
| 168 | foreach (i ${includeopts}) |
|---|
| 169 | list(APPEND configopts ${i}) |
|---|
| 170 | if (NOT "${${i}}" STREQUAL "${i}-NOTFOUND") |
|---|
| 171 | list(APPEND includes "${${i}}") |
|---|
| 172 | else() |
|---|
| 173 | set(found FALSE) |
|---|
| 174 | set(missing_headers TRUE) |
|---|
| 175 | endif() |
|---|
| 176 | endforeach() |
|---|
| 177 | |
|---|
| 178 | # Process all libraries and set found false if any are missing |
|---|
| 179 | foreach (i ${libraryopts}) |
|---|
| 180 | list(APPEND configopts ${i}) |
|---|
| 181 | if (NOT "${${i}}" STREQUAL "${i}-NOTFOUND") |
|---|
| 182 | list(APPEND libs "${${i}}") |
|---|
| 183 | else() |
|---|
| 184 | set (found FALSE) |
|---|
| 185 | endif() |
|---|
| 186 | endforeach() |
|---|
| 187 | |
|---|
| 188 | # Version checks |
|---|
| 189 | if (found AND findver) |
|---|
| 190 | if (NOT version) |
|---|
| 191 | message(WARNING "The find module for ${PREFIX} does not provide version information, so we'll just assume that it is OK. Please fix the module or remove package version requirements to get rid of this warning.") |
|---|
| 192 | elseif (version VERSION_LESS findver OR (exactver AND NOT version VERSION_EQUAL findver)) |
|---|
| 193 | set(found FALSE) |
|---|
| 194 | set(version_unsuitable TRUE) |
|---|
| 195 | endif() |
|---|
| 196 | endif() |
|---|
| 197 | |
|---|
| 198 | # If all-OK, hide all config options, export variables, print status and exit |
|---|
| 199 | if (found) |
|---|
| 200 | foreach (i ${configopts}) |
|---|
| 201 | mark_as_advanced(${i}) |
|---|
| 202 | endforeach() |
|---|
| 203 | if (NOT quiet) |
|---|
| 204 | message(STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}") |
|---|
| 205 | if (LIBFIND_DEBUG) |
|---|
| 206 | message(STATUS " ${PREFIX}_DEPENDENCIES=${${PREFIX}_DEPENDENCIES}") |
|---|
| 207 | message(STATUS " ${PREFIX}_INCLUDE_OPTS=${includeopts}") |
|---|
| 208 | message(STATUS " ${PREFIX}_INCLUDE_DIRS=${includes}") |
|---|
| 209 | message(STATUS " ${PREFIX}_LIBRARY_OPTS=${libraryopts}") |
|---|
| 210 | message(STATUS " ${PREFIX}_LIBRARIES=${libs}") |
|---|
| 211 | endif() |
|---|
| 212 | set (${PREFIX}_INCLUDE_OPTS ${includeopts} PARENT_SCOPE) |
|---|
| 213 | set (${PREFIX}_LIBRARY_OPTS ${libraryopts} PARENT_SCOPE) |
|---|
| 214 | set (${PREFIX}_INCLUDE_DIRS ${includes} PARENT_SCOPE) |
|---|
| 215 | set (${PREFIX}_LIBRARIES ${libs} PARENT_SCOPE) |
|---|
| 216 | set (${PREFIX}_FOUND TRUE PARENT_SCOPE) |
|---|
| 217 | endif() |
|---|
| 218 | return() |
|---|
| 219 | endif() |
|---|
| 220 | |
|---|
| 221 | # Format messages for debug info and the type of error |
|---|
| 222 | set(vars "Relevant CMake configuration variables:\n") |
|---|
| 223 | foreach (i ${configopts}) |
|---|
| 224 | mark_as_advanced(CLEAR ${i}) |
|---|
| 225 | set(val ${${i}}) |
|---|
| 226 | if ("${val}" STREQUAL "${i}-NOTFOUND") |
|---|
| 227 | set (val "<not found>") |
|---|
| 228 | elseif (val AND NOT EXISTS ${val}) |
|---|
| 229 | set (val "${val} (does not exist)") |
|---|
| 230 | else() |
|---|
| 231 | set(some_files TRUE) |
|---|
| 232 | endif() |
|---|
| 233 | set(vars "${vars} ${i}=${val}\n") |
|---|
| 234 | endforeach() |
|---|
| 235 | set(vars "${vars}You may use CMake GUI, cmake -D or ccmake to modify the values. Delete CMakeCache.txt to discard all values and force full re-detection if necessary.\n") |
|---|
| 236 | if (version_unsuitable) |
|---|
| 237 | set(msg "${PREFIX} ${${PREFIX}_VERSION} was found but") |
|---|
| 238 | if (exactver) |
|---|
| 239 | set(msg "${msg} only version ${findver} is acceptable.") |
|---|
| 240 | else() |
|---|
| 241 | set(msg "${msg} version ${findver} is the minimum requirement.") |
|---|
| 242 | endif() |
|---|
| 243 | else() |
|---|
| 244 | if (missing_headers) |
|---|
| 245 | set(msg "We could not find development headers for ${PREFIX}. Do you have the necessary dev package installed?") |
|---|
| 246 | elseif (some_files) |
|---|
| 247 | set(msg "We only found some files of ${PREFIX}, not all of them. Perhaps your installation is incomplete or maybe we just didn't look in the right place?") |
|---|
| 248 | if(findver) |
|---|
| 249 | set(msg "${msg} This could also be caused by incompatible version (if it helps, at least ${PREFIX} ${findver} should work).") |
|---|
| 250 | endif() |
|---|
| 251 | else() |
|---|
| 252 | set(msg "We were unable to find package ${PREFIX}.") |
|---|
| 253 | endif() |
|---|
| 254 | endif() |
|---|
| 255 | |
|---|
| 256 | # Fatal error out if REQUIRED |
|---|
| 257 | if (required) |
|---|
| 258 | set(msg "REQUIRED PACKAGE NOT FOUND\n${msg} This package is REQUIRED and you need to install it or adjust CMake configuration in order to continue building ${CMAKE_PROJECT_NAME}.") |
|---|
| 259 | message(FATAL_ERROR "${msg}\n${vars}") |
|---|
| 260 | endif() |
|---|
| 261 | # Otherwise just print a nasty warning |
|---|
| 262 | if (NOT quiet) |
|---|
| 263 | message(WARNING "WARNING: MISSING PACKAGE\n${msg} This package is NOT REQUIRED and you may ignore this warning but by doing so you may miss some functionality of ${CMAKE_PROJECT_NAME}. \n${vars}") |
|---|
| 264 | endif() |
|---|
| 265 | endfunction() |
|---|