| Elliott Hughes | 820eced | 2021-08-20 18:00:50 -0700 | [diff] [blame] | 1 | # |
| 2 | # Try to find libpcap. |
| 3 | # |
| 4 | # To tell this module where to look, a user may set the environment variable |
| 5 | # PCAP_ROOT to point cmake to the *root* of a directory with include and |
| 6 | # lib subdirectories for pcap.dll (e.g WpdPack or npcap-sdk). |
| 7 | # Alternatively, PCAP_ROOT may also be set from cmake command line or GUI |
| 8 | # (e.g cmake -DPCAP_ROOT=C:\path\to\pcap [...]) |
| 9 | # |
| 10 | |
| 11 | if(WIN32) |
| 12 | # |
| 13 | # Building for Windows. |
| 14 | # |
| 15 | # libpcap isn't set up to install .pc files or pcap-config on Windows, |
| 16 | # and it's not clear that either of them would work without a lot |
| 17 | # of additional effort. WinPcap doesn't supply them, and neither |
| 18 | # does Npcap. |
| 19 | # |
| 20 | # So just search for them directly. Look for both pcap and wpcap. |
| 21 | # Don't bother looking for static libraries; unlike most UN*Xes |
| 22 | # (with the exception of AIX), where different extensions are used |
| 23 | # for shared and static, Windows uses .lib both for import libraries |
| 24 | # for DLLs and for static libraries. |
| 25 | # |
| 26 | # We don't directly set PCAP_INCLUDE_DIRS or PCAP_LIBRARIES, as |
| 27 | # they're not supposed to be cache entries, and find_path() and |
| 28 | # find_library() set cache entries. |
| 29 | # |
| 30 | find_path(PCAP_INCLUDE_DIR pcap.h) |
| 31 | |
| 32 | # The 64-bit Packet.lib is located under /x64 |
| 33 | if(CMAKE_SIZEOF_VOID_P EQUAL 8) |
| 34 | # |
| 35 | # For the WinPcap and Npcap SDKs, the Lib subdirectory of the top-level |
| 36 | # directory contains 32-bit libraries; the 64-bit libraries are in the |
| 37 | # Lib/x64 directory. |
| 38 | # |
| 39 | # The only way to *FORCE* CMake to look in the Lib/x64 directory |
| 40 | # without searching in the Lib directory first appears to be to set |
| 41 | # CMAKE_LIBRARY_ARCHITECTURE to "x64". |
| 42 | # |
| 43 | set(CMAKE_LIBRARY_ARCHITECTURE "x64") |
| 44 | endif() |
| 45 | find_library(PCAP_LIBRARY NAMES pcap wpcap) |
| 46 | |
| 47 | # |
| 48 | # Do the standard arg processing, including failing if it's a |
| 49 | # required package. |
| 50 | # |
| 51 | include(FindPackageHandleStandardArgs) |
| 52 | find_package_handle_standard_args(PCAP |
| 53 | DEFAULT_MSG |
| 54 | PCAP_INCLUDE_DIR |
| 55 | PCAP_LIBRARY |
| 56 | ) |
| 57 | mark_as_advanced( |
| 58 | PCAP_INCLUDE_DIR |
| 59 | PCAP_LIBRARY |
| 60 | ) |
| 61 | if(PCAP_FOUND) |
| 62 | set(PCAP_LIBRARIES ${PCAP_LIBRARY}) |
| 63 | set(PCAP_INCLUDE_DIRS ${PCAP_INCLUDE_DIR}) |
| 64 | endif() |
| 65 | else(WIN32) |
| 66 | # |
| 67 | # Building for UN*X. |
| 68 | # |
| 69 | # See whether we were handed a QUIET argument, so we can pass it on |
| 70 | # to pkg_search_module. Do *NOT* pass on the REQUIRED argument, |
| 71 | # because, if pkg-config isn't found, or it is but it has no .pc |
| 72 | # files for libpcap, that is *not* necessarily an indication that |
| 73 | # libpcap isn't available - not all systems ship pkg-config, and |
| 74 | # libpcap didn't have .pc files until libpcap 1.9.0. |
| 75 | # |
| 76 | if(PCAP_FIND_QUIETLY) |
| 77 | set(_quiet "QUIET") |
| 78 | endif() |
| 79 | |
| 80 | # |
| 81 | # First, try pkg-config. |
| 82 | # Before doing so, set the PKG_CONFIG_PATH environment variable |
| 83 | # to include all the directories in CMAKE_PREFIX_PATH. |
| 84 | # |
| 85 | # *If* we were to require CMake 3.1 or later on UN*X, |
| 86 | # pkg_search_module() would do this for us, but, for now, |
| 87 | # we're not doing that, in case somebody's building with |
| 88 | # CMake on some "long-term support" version, predating |
| 89 | # CMake 3.1, of an OS that that supplies an earlier |
| 90 | # version as a package. |
| 91 | # |
| 92 | # If we ever set a minimum of 3.1 or later on UN*X, we should |
| 93 | # remove the environment variable changes. |
| 94 | # |
| 95 | # This is based on code in the CMake 3.12.4 FindPkgConfig.cmake, |
| 96 | # which is "Distributed under the OSI-approved BSD 3-Clause License." |
| 97 | # |
| 98 | find_package(PkgConfig) |
| 99 | |
| 100 | # |
| 101 | # Get the current PKG_CONFIG_PATH setting. |
| 102 | # |
| 103 | set(_pkg_config_path "$ENV{PKG_CONFIG_PATH}") |
| 104 | |
| 105 | # |
| 106 | # Save it, so we can restore it after we run pkg-config. |
| 107 | # |
| 108 | set(_saved_pkg_config_path "${_pkg_config_path}") |
| 109 | |
| 110 | if(NOT "${CMAKE_PREFIX_PATH}" STREQUAL "") |
| 111 | # |
| 112 | # Convert it to a CMake-style path, before we add additional |
| 113 | # values to it. |
| 114 | # |
| 115 | if(NOT "${_pkg_config_path}" STREQUAL "") |
| 116 | file(TO_CMAKE_PATH "${_pkg_config_path}" _pkg_config_path) |
| 117 | endif() |
| 118 | |
| 119 | # |
| 120 | # Turn CMAKE_PREFIX_PATH into a list of extra paths to add |
| 121 | # to _pkg_config_path. |
| 122 | # |
| 123 | set(_extra_paths "") |
| 124 | list(APPEND _extra_paths ${CMAKE_PREFIX_PATH}) |
| 125 | |
| 126 | # Create a list of the possible pkgconfig subfolder (depending on |
| 127 | # the system |
| 128 | set(_lib_dirs) |
| 129 | if(NOT DEFINED CMAKE_SYSTEM_NAME |
| 130 | OR (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU)$" |
| 131 | AND NOT CMAKE_CROSSCOMPILING)) |
| 132 | if(EXISTS "/etc/debian_version") # is this a debian system ? |
| 133 | if(CMAKE_LIBRARY_ARCHITECTURE) |
| 134 | list(APPEND _lib_dirs "lib/${CMAKE_LIBRARY_ARCHITECTURE}/pkgconfig") |
| 135 | endif() |
| 136 | else() |
| 137 | # not debian, check the FIND_LIBRARY_USE_LIB32_PATHS and FIND_LIBRARY_USE_LIB64_PATHS properties |
| 138 | get_property(uselib32 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB32_PATHS) |
| 139 | if(uselib32 AND CMAKE_SIZEOF_VOID_P EQUAL 4) |
| 140 | list(APPEND _lib_dirs "lib32/pkgconfig") |
| 141 | endif() |
| 142 | get_property(uselib64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS) |
| 143 | if(uselib64 AND CMAKE_SIZEOF_VOID_P EQUAL 8) |
| 144 | list(APPEND _lib_dirs "lib64/pkgconfig") |
| 145 | endif() |
| 146 | get_property(uselibx32 GLOBAL PROPERTY FIND_LIBRARY_USE_LIBX32_PATHS) |
| 147 | if(uselibx32 AND CMAKE_INTERNAL_PLATFORM_ABI STREQUAL "ELF X32") |
| 148 | list(APPEND _lib_dirs "libx32/pkgconfig") |
| 149 | endif() |
| 150 | endif() |
| 151 | endif() |
| 152 | if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" AND NOT CMAKE_CROSSCOMPILING) |
| 153 | list(APPEND _lib_dirs "libdata/pkgconfig") |
| 154 | endif() |
| 155 | list(APPEND _lib_dirs "lib/pkgconfig") |
| 156 | list(APPEND _lib_dirs "share/pkgconfig") |
| 157 | |
| 158 | # Check if directories exist and eventually append them to the |
| 159 | # pkgconfig path list |
| 160 | foreach(_prefix_dir ${_extra_paths}) |
| 161 | foreach(_lib_dir ${_lib_dirs}) |
| 162 | if(EXISTS "${_prefix_dir}/${_lib_dir}") |
| 163 | list(APPEND _pkg_config_path "${_prefix_dir}/${_lib_dir}") |
| 164 | list(REMOVE_DUPLICATES _pkg_config_path) |
| 165 | endif() |
| 166 | endforeach() |
| 167 | endforeach() |
| 168 | |
| 169 | if(NOT "${_pkg_config_path}" STREQUAL "") |
| 170 | # remove empty values from the list |
| 171 | list(REMOVE_ITEM _pkg_config_path "") |
| 172 | file(TO_NATIVE_PATH "${_pkg_config_path}" _pkg_config_path) |
| 173 | if(UNIX) |
| 174 | string(REPLACE ";" ":" _pkg_config_path "${_pkg_config_path}") |
| 175 | string(REPLACE "\\ " " " _pkg_config_path "${_pkg_config_path}") |
| 176 | endif() |
| 177 | set(ENV{PKG_CONFIG_PATH} "${_pkg_config_path}") |
| 178 | endif() |
| 179 | endif() |
| 180 | pkg_search_module(CONFIG_PCAP ${_quiet} libpcap) |
| 181 | set(ENV{PKG_CONFIG_PATH} "${_saved_pkg_config_path}") |
| 182 | |
| 183 | if(NOT CONFIG_PCAP_FOUND) |
| 184 | # |
| 185 | # That didn't work. Try pcap-config. |
| 186 | # |
| 187 | find_program(PCAP_CONFIG pcap-config) |
| 188 | if(PCAP_CONFIG) |
| 189 | # |
| 190 | # We have pcap-config; use it. |
| 191 | # |
| 192 | if(NOT "${_quiet}" STREQUAL "QUIET") |
| 193 | message(STATUS "Found pcap-config") |
| 194 | endif() |
| 195 | |
| 196 | # |
| 197 | # if this is macOS or some other Darwin-based OS, check whether |
| 198 | # it's the system-supplied one. |
| 199 | # |
| 200 | if(APPLE AND "${PCAP_CONFIG}" STREQUAL /usr/bin/pcap-config) |
| 201 | # |
| 202 | # It is - remember that, so that if it provides -I/usr/local/include |
| 203 | # with --cflags, or -L/usr/local/lib with --libs, we ignore it; |
| 204 | # the macOS pcap-config does that even though the headers aren't |
| 205 | # under /usr/local/include and the library isn't in /usr/local/lib. |
| 206 | # |
| 207 | set(_broken_apple_pcap_config TRUE) |
| 208 | endif() |
| 209 | |
| 210 | # |
| 211 | # Now get the include directories. |
| 212 | # |
| 213 | execute_process(COMMAND "${PCAP_CONFIG}" "--cflags" |
| 214 | RESULT_VARIABLE PCAP_CONFIG_RESULT |
| 215 | OUTPUT_VARIABLE PCAP_CONFIG_OUTPUT |
| 216 | OUTPUT_STRIP_TRAILING_WHITESPACE |
| 217 | ) |
| 218 | if(NOT PCAP_CONFIG_RESULT EQUAL 0) |
| 219 | message(FATAL_ERROR "pcap-config --cflags failed") |
| 220 | endif() |
| 221 | separate_arguments(CFLAGS_LIST UNIX_COMMAND ${PCAP_CONFIG_OUTPUT}) |
| 222 | set(CONFIG_PCAP_INCLUDE_DIRS "") |
| 223 | foreach(_arg IN LISTS CFLAGS_LIST) |
| 224 | if(_arg MATCHES "^-I") |
| 225 | # |
| 226 | # Extract the directory by removing the -I. |
| 227 | # |
| 228 | string(REGEX REPLACE "-I" "" _dir ${_arg}) |
| 229 | # |
| 230 | # Work around macOS (and probably other Darwin) brokenness, |
| 231 | # by not adding /usr/local/include if it's from the broken |
| 232 | # Apple pcap-config. |
| 233 | # |
| 234 | if(NOT _broken_apple_pcap_config OR |
| 235 | NOT "${_dir}" STREQUAL /usr/local/include) |
| 236 | # Add it to CONFIG_PCAP_INCLUDE_DIRS |
| 237 | list(APPEND CONFIG_PCAP_INCLUDE_DIRS ${_dir}) |
| 238 | endif() |
| 239 | endif() |
| 240 | endforeach() |
| 241 | |
| 242 | # |
| 243 | # Now, get the library directories and libraries for dynamic linking. |
| 244 | # |
| 245 | execute_process(COMMAND "${PCAP_CONFIG}" "--libs" |
| 246 | RESULT_VARIABLE PCAP_CONFIG_RESULT |
| 247 | OUTPUT_VARIABLE PCAP_CONFIG_OUTPUT |
| 248 | OUTPUT_STRIP_TRAILING_WHITESPACE |
| 249 | ) |
| 250 | if(NOT PCAP_CONFIG_RESULT EQUAL 0) |
| 251 | message(FATAL_ERROR "pcap-config --libs failed") |
| 252 | endif() |
| 253 | separate_arguments(LIBS_LIST UNIX_COMMAND ${PCAP_CONFIG_OUTPUT}) |
| 254 | set(CONFIG_PCAP_LIBRARY_DIRS "") |
| 255 | set(CONFIG_PCAP_LIBRARIES "") |
| 256 | foreach(_arg IN LISTS LIBS_LIST) |
| 257 | if(_arg MATCHES "^-L") |
| 258 | # |
| 259 | # Extract the directory by removing the -L. |
| 260 | # |
| 261 | string(REGEX REPLACE "-L" "" _dir ${_arg}) |
| 262 | # |
| 263 | # Work around macOS (and probably other Darwin) brokenness, |
| 264 | # by not adding /usr/local/lib if it's from the broken |
| 265 | # Apple pcap-config. |
| 266 | # |
| 267 | if(NOT _broken_apple_pcap_config OR |
| 268 | NOT "${_dir}" STREQUAL /usr/local/lib) |
| 269 | # Add this directory to CONFIG_PCAP_LIBRARY_DIRS |
| 270 | list(APPEND CONFIG_PCAP_LIBRARY_DIRS ${_dir}) |
| 271 | endif() |
| 272 | elseif(_arg MATCHES "^-l") |
| 273 | string(REGEX REPLACE "-l" "" _lib ${_arg}) |
| 274 | list(APPEND CONFIG_PCAP_LIBRARIES ${_lib}) |
| 275 | endif() |
| 276 | endforeach() |
| 277 | |
| 278 | # |
| 279 | # Now, get the library directories and libraries for static linking. |
| 280 | # |
| 281 | execute_process(COMMAND "${PCAP_CONFIG}" "--libs" "--static" |
| 282 | RESULT_VARIABLE PCAP_CONFIG_RESULT |
| 283 | OUTPUT_VARIABLE PCAP_CONFIG_OUTPUT |
| 284 | ) |
| 285 | if(NOT PCAP_CONFIG_RESULT EQUAL 0) |
| 286 | message(FATAL_ERROR "pcap-config --libs --static failed") |
| 287 | endif() |
| 288 | separate_arguments(LIBS_LIST UNIX_COMMAND ${PCAP_CONFIG_OUTPUT}) |
| 289 | set(CONFIG_PCAP_STATIC_LIBRARY_DIRS "") |
| 290 | set(CONFIG_PCAP_STATIC_LIBRARIES "") |
| 291 | foreach(_arg IN LISTS LIBS_LIST) |
| 292 | if(_arg MATCHES "^-L") |
| 293 | # |
| 294 | # Extract the directory by removing the -L. |
| 295 | # |
| 296 | string(REGEX REPLACE "-L" "" _dir ${_arg}) |
| 297 | # |
| 298 | # Work around macOS (and probably other Darwin) brokenness, |
| 299 | # by not adding /usr/local/lib if it's from the broken |
| 300 | # Apple pcap-config. |
| 301 | # |
| 302 | if(NOT _broken_apple_pcap_config OR |
| 303 | NOT "${_dir}" STREQUAL /usr/local/lib) |
| 304 | # Add this directory to CONFIG_PCAP_STATIC_LIBRARY_DIRS |
| 305 | list(APPEND CONFIG_PCAP_STATIC_LIBRARY_DIRS ${_dir}) |
| 306 | endif() |
| 307 | elseif(_arg MATCHES "^-l") |
| 308 | string(REGEX REPLACE "-l" "" _lib ${_arg}) |
| 309 | # |
| 310 | # Try to find that library, so we get its full path, as |
| 311 | # we do with dynamic libraries. |
| 312 | # |
| 313 | list(APPEND CONFIG_PCAP_STATIC_LIBRARIES ${_lib}) |
| 314 | endif() |
| 315 | endforeach() |
| 316 | |
| 317 | # |
| 318 | # We've set CONFIG_PCAP_INCLUDE_DIRS, CONFIG_PCAP_LIBRARIES, and |
| 319 | # CONFIG_PCAP_STATIC_LIBRARIES above; set CONFIG_PCAP_FOUND. |
| 320 | # |
| 321 | set(CONFIG_PCAP_FOUND YES) |
| 322 | endif() |
| 323 | endif() |
| 324 | |
| 325 | # |
| 326 | # If CONFIG_PCAP_FOUND is set, we have information from pkg-config and |
| 327 | # pcap-config; we need to convert library names to library full paths. |
| 328 | # |
| 329 | # If it's not set, we have to look for the libpcap headers and library |
| 330 | # ourselves. |
| 331 | # |
| 332 | if(CONFIG_PCAP_FOUND) |
| 333 | # |
| 334 | # Use CONFIG_PCAP_INCLUDE_DIRS as the value for PCAP_INCLUDE_DIRS. |
| 335 | # |
| 336 | set(PCAP_INCLUDE_DIRS "${CONFIG_PCAP_INCLUDE_DIRS}") |
| 337 | |
| 338 | # |
| 339 | # CMake *really* doesn't like the notion of specifying |
| 340 | # "here are the directories in which to look for libraries" |
| 341 | # except in find_library() calls; it *really* prefers using |
| 342 | # full paths to library files, rather than library names. |
| 343 | # |
| 344 | foreach(_lib IN LISTS CONFIG_PCAP_LIBRARIES) |
| 345 | find_library(_libfullpath ${_lib} HINTS ${CONFIG_PCAP_LIBRARY_DIRS}) |
| 346 | list(APPEND PCAP_LIBRARIES ${_libfullpath}) |
| 347 | # |
| 348 | # Remove that from the cache; we're using it as a local variable, |
| 349 | # but find_library insists on making it a cache variable. |
| 350 | # |
| 351 | unset(_libfullpath CACHE) |
| 352 | endforeach() |
| 353 | |
| 354 | # |
| 355 | # Now do the same for the static libraries. |
| 356 | # |
| 357 | set(SAVED_CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_FIND_LIBRARY_SUFFIXES}") |
| 358 | set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") |
| 359 | foreach(_lib IN LISTS CONFIG_PCAP_STATIC_LIBRARIES) |
| 360 | find_library(_libfullpath ${_lib} HINTS ${CONFIG_PCAP_LIBRARY_DIRS}) |
| 361 | list(APPEND PCAP_STATIC_LIBRARIES ${_libfullpath}) |
| 362 | # |
| 363 | # Remove that from the cache; we're using it as a local variable, |
| 364 | # but find_library insists on making it a cache variable. |
| 365 | # |
| 366 | unset(_libfullpath CACHE) |
| 367 | endforeach() |
| 368 | set(CMAKE_FIND_LIBRARY_SUFFIXES "${SAVED_CMAKE_FIND_LIBRARY_SUFFIXES}") |
| 369 | |
| 370 | # |
| 371 | # We found libpcap using pkg-config or pcap-config. |
| 372 | # |
| 373 | set(PCAP_FOUND YES) |
| 374 | else(CONFIG_PCAP_FOUND) |
| 375 | # |
| 376 | # We didn't have pkg-config, or we did but it didn't have .pc files |
| 377 | # for libpcap, and we don't have pkg-config, so we have to look for |
| 378 | # the headers and libraries ourself. |
| 379 | # |
| 380 | # We don't directly set PCAP_INCLUDE_DIRS or PCAP_LIBRARIES, as |
| 381 | # they're not supposed to be cache entries, and find_path() and |
| 382 | # find_library() set cache entries. |
| 383 | # |
| 384 | # Try to find the header file. |
| 385 | # |
| 386 | find_path(PCAP_INCLUDE_DIR pcap.h) |
| 387 | |
| 388 | # |
| 389 | # Try to find the library |
| 390 | # |
| 391 | find_library(PCAP_LIBRARY pcap) |
| 392 | |
| 393 | # Try to find the static library (XXX - what about AIX?) |
| 394 | set(SAVED_CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_FIND_LIBRARY_SUFFIXES}") |
| 395 | set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") |
| 396 | find_library(PCAP_STATIC_LIBRARY pcap) |
| 397 | set(CMAKE_FIND_LIBRARY_SUFFIXES "${SAVED_CMAKE_FIND_LIBRARY_SUFFIXES}") |
| 398 | |
| 399 | # |
| 400 | # This will fail if REQUIRED is set and PCAP_INCLUDE_DIR or |
| 401 | # PCAP_LIBRARY aren't set. |
| 402 | # |
| 403 | include(FindPackageHandleStandardArgs) |
| 404 | find_package_handle_standard_args(PCAP |
| 405 | DEFAULT_MSG |
| 406 | PCAP_INCLUDE_DIR |
| 407 | PCAP_LIBRARY |
| 408 | ) |
| 409 | |
| 410 | mark_as_advanced( |
| 411 | PCAP_INCLUDE_DIR |
| 412 | PCAP_LIBRARY |
| 413 | PCAP_STATIC_LIBRARY |
| 414 | ) |
| 415 | |
| 416 | if(PCAP_FOUND) |
| 417 | set(PCAP_INCLUDE_DIRS ${PCAP_INCLUDE_DIR}) |
| 418 | set(PCAP_LIBRARIES ${PCAP_LIBRARY}) |
| 419 | set(PCAP_STATIC_LIBRARIES ${PCAP_STATIC_LIBRARY}) |
| 420 | endif(PCAP_FOUND) |
| 421 | endif(CONFIG_PCAP_FOUND) |
| 422 | endif(WIN32) |