├── LibFindMacros.cmake └── README.md /LibFindMacros.cmake: -------------------------------------------------------------------------------- 1 | # Version 2.4 2 | # Public Domain, originally written by Lasse Kärkkäinen 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( [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( FIND_PATH [other args] FIND_LIBRARY [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 | # Read pkg-config version 56 | if (${PREFIX}_PKGCONF_VERSION) 57 | set(${PREFIX}_VERSION ${${PREFIX}_PKGCONF_VERSION} PARENT_SCOPE) 58 | endif() 59 | endfunction() 60 | 61 | # Extracts a version #define from a version.h file, output stored to _VERSION. 62 | # Usage: libfind_version_header(Foobar foobar/version.h FOOBAR_VERSION_STR) 63 | # Fourth argument "QUIET" may be used for silently testing different define names. 64 | # This function does nothing if the version variable is already defined. 65 | function (libfind_version_header PREFIX VERSION_H DEFINE_NAME) 66 | # Skip processing if we already have a version or if the include dir was not found 67 | if (${PREFIX}_VERSION OR NOT ${PREFIX}_INCLUDE_DIR) 68 | return() 69 | endif() 70 | set(quiet ${${PREFIX}_FIND_QUIETLY}) 71 | # Process optional arguments 72 | foreach(arg ${ARGN}) 73 | if (arg STREQUAL "QUIET") 74 | set(quiet TRUE) 75 | else() 76 | message(AUTHOR_WARNING "Unknown argument ${arg} to libfind_version_header ignored.") 77 | endif() 78 | endforeach() 79 | # Read the header and parse for version number 80 | set(filename "${${PREFIX}_INCLUDE_DIR}/${VERSION_H}") 81 | if (NOT EXISTS ${filename}) 82 | if (NOT quiet) 83 | message(AUTHOR_WARNING "Unable to find ${${PREFIX}_INCLUDE_DIR}/${VERSION_H}") 84 | endif() 85 | return() 86 | endif() 87 | file(READ "${filename}" header) 88 | string(REGEX REPLACE ".*#[ \t]*define[ \t]*${DEFINE_NAME}[ \t]*\"([^\n]*)\".*" "\\1" match "${header}") 89 | # No regex match? 90 | if (match STREQUAL header) 91 | if (NOT quiet) 92 | message(AUTHOR_WARNING "Unable to find \#define ${DEFINE_NAME} \"\" from ${${PREFIX}_INCLUDE_DIR}/${VERSION_H}") 93 | endif() 94 | return() 95 | endif() 96 | # Export the version string 97 | set(${PREFIX}_VERSION "${match}" PARENT_SCOPE) 98 | endfunction() 99 | 100 | # Do the final processing once the paths have been detected. 101 | # If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain 102 | # all the variables, each of which contain one include directory. 103 | # Ditto for ${PREFIX}_PROCESS_LIBS and library files. 104 | # Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES. 105 | # Also handles errors in case library detection was required, etc. 106 | function (libfind_process PREFIX) 107 | # Skip processing if already processed during this configuration run 108 | if (${PREFIX}_FOUND) 109 | return() 110 | endif() 111 | 112 | set(found TRUE) # Start with the assumption that the package was found 113 | 114 | # Did we find any files? Did we miss includes? These are for formatting better error messages. 115 | set(some_files FALSE) 116 | set(missing_headers FALSE) 117 | 118 | # Shorthands for some variables that we need often 119 | set(quiet ${${PREFIX}_FIND_QUIETLY}) 120 | set(required ${${PREFIX}_FIND_REQUIRED}) 121 | set(exactver ${${PREFIX}_FIND_VERSION_EXACT}) 122 | set(findver "${${PREFIX}_FIND_VERSION}") 123 | set(version "${${PREFIX}_VERSION}") 124 | 125 | # Lists of config option names (all, includes, libs) 126 | unset(configopts) 127 | set(includeopts ${${PREFIX}_PROCESS_INCLUDES}) 128 | set(libraryopts ${${PREFIX}_PROCESS_LIBS}) 129 | 130 | # Process deps to add to 131 | foreach (i ${PREFIX} ${${PREFIX}_DEPENDENCIES}) 132 | if (DEFINED ${i}_INCLUDE_OPTS) 133 | # The package seems to export option lists that we can use, woohoo! 134 | list(APPEND includeopts ${${i}_INCLUDE_OPTS}) 135 | else() 136 | if (DEFINED ${i}_INCLUDE_DIR) 137 | # Singular forms can be used 138 | list(APPEND includeopts ${i}_INCLUDE_DIR) 139 | else() 140 | if (DEFINED ${i}_INCLUDE_DIRS) 141 | # Plural forms can be used 142 | list(APPEND includeopts ${i}_INCLUDE_DIRS) 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. Aieeh!") 146 | endif() 147 | endif() 148 | endif() 149 | 150 | if (DEFINED ${i}_LIBRARY_OPTS) 151 | # The package seems to export option lists that we can use, woohoo! 152 | list(APPEND includeopts ${${i}_LIBRARY_OPTS}) 153 | else() 154 | if (DEFINED ${i}_LIBRARY) 155 | # Singular forms can be used 156 | list(APPEND includeopts ${i}_LIBRARY) 157 | else() 158 | if (DEFINED ${i}_LIBRARIES) 159 | # Plural forms can be used 160 | list(APPEND includeopts ${i}_LIBRARIES) 161 | else() 162 | # Oh no, we don't know the option names 163 | message(FATAL_ERROR "We couldn't determine config variable names for ${i} libraries. Aieeh!") 164 | endif() 165 | endif() 166 | endif() 167 | endforeach() 168 | 169 | if (includeopts) 170 | list(REMOVE_DUPLICATES includeopts) 171 | endif() 172 | 173 | if (libraryopts) 174 | list(REMOVE_DUPLICATES libraryopts) 175 | endif() 176 | 177 | string(REGEX REPLACE ".*[ ;]([^ ;]*(_INCLUDE_DIRS|_LIBRARIES))" "\\1" tmp "${includeopts} ${libraryopts}") 178 | if (NOT tmp STREQUAL "${includeopts} ${libraryopts}") 179 | 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).") 180 | endif() 181 | 182 | # Include/library names separated by spaces (notice: not CMake lists) 183 | unset(includes) 184 | unset(libs) 185 | 186 | # Process all includes and set found false if any are missing 187 | foreach (i ${includeopts}) 188 | list(APPEND configopts ${i}) 189 | if (NOT "${${i}}" STREQUAL "${i}-NOTFOUND") 190 | list(APPEND includes "${${i}}") 191 | else() 192 | set(found FALSE) 193 | set(missing_headers TRUE) 194 | endif() 195 | endforeach() 196 | 197 | # Process all libraries and set found false if any are missing 198 | foreach (i ${libraryopts}) 199 | list(APPEND configopts ${i}) 200 | if (NOT "${${i}}" STREQUAL "${i}-NOTFOUND") 201 | list(APPEND libs "${${i}}") 202 | else() 203 | set (found FALSE) 204 | endif() 205 | endforeach() 206 | 207 | # Version checks 208 | if (found AND findver) 209 | if (NOT version) 210 | 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.") 211 | elseif (version VERSION_LESS findver OR (exactver AND NOT version VERSION_EQUAL findver)) 212 | set(found FALSE) 213 | set(version_unsuitable TRUE) 214 | endif() 215 | endif() 216 | 217 | # If all-OK, hide all config options, export variables, print status and exit 218 | if (found) 219 | foreach (i ${configopts}) 220 | mark_as_advanced(${i}) 221 | endforeach() 222 | if (NOT quiet) 223 | message(STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}") 224 | if (LIBFIND_DEBUG) 225 | message(STATUS " ${PREFIX}_DEPENDENCIES=${${PREFIX}_DEPENDENCIES}") 226 | message(STATUS " ${PREFIX}_INCLUDE_OPTS=${includeopts}") 227 | message(STATUS " ${PREFIX}_INCLUDE_DIRS=${includes}") 228 | message(STATUS " ${PREFIX}_LIBRARY_OPTS=${libraryopts}") 229 | message(STATUS " ${PREFIX}_LIBRARIES=${libs}") 230 | endif() 231 | endif() 232 | set (${PREFIX}_INCLUDE_OPTS ${includeopts} PARENT_SCOPE) 233 | set (${PREFIX}_LIBRARY_OPTS ${libraryopts} PARENT_SCOPE) 234 | set (${PREFIX}_INCLUDE_DIRS ${includes} PARENT_SCOPE) 235 | set (${PREFIX}_LIBRARIES ${libs} PARENT_SCOPE) 236 | set (${PREFIX}_FOUND TRUE PARENT_SCOPE) 237 | return() 238 | endif() 239 | 240 | # Format messages for debug info and the type of error 241 | set(vars "Relevant CMake configuration variables:\n") 242 | foreach (i ${configopts}) 243 | mark_as_advanced(CLEAR ${i}) 244 | set(val ${${i}}) 245 | if ("${val}" STREQUAL "${i}-NOTFOUND") 246 | set (val "") 247 | elseif (val AND NOT EXISTS ${val}) 248 | set (val "${val} (does not exist)") 249 | else() 250 | set(some_files TRUE) 251 | endif() 252 | set(vars "${vars} ${i}=${val}\n") 253 | endforeach() 254 | 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") 255 | if (version_unsuitable) 256 | set(msg "${PREFIX} ${${PREFIX}_VERSION} was found but") 257 | if (exactver) 258 | set(msg "${msg} only version ${findver} is acceptable.") 259 | else() 260 | set(msg "${msg} version ${findver} is the minimum requirement.") 261 | endif() 262 | else() 263 | if (missing_headers) 264 | set(msg "We could not find development headers for ${PREFIX}. Do you have the necessary dev package installed?") 265 | elseif (some_files) 266 | 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?") 267 | if(findver) 268 | set(msg "${msg} This could also be caused by incompatible version (if it helps, at least ${PREFIX} ${findver} should work).") 269 | endif() 270 | else() 271 | set(msg "We were unable to find package ${PREFIX}.") 272 | endif() 273 | endif() 274 | 275 | # Fatal error out if REQUIRED 276 | if (required) 277 | 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}.") 278 | message(FATAL_ERROR "${msg}\n${vars}") 279 | endif() 280 | # Otherwise just print a nasty warning 281 | if (NOT quiet) 282 | 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}") 283 | endif() 284 | endfunction() 285 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | cmake-modules 2 | ============= 3 | 4 | LibFindMacros development repository and other cool CMake stuff 5 | 6 | This project is Public Domain. 7 | --------------------------------------------------------------------------------