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 11if(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 65 # 66 # We need to look for wpcap.dll in \Windows\System32\Npcap first, 67 # as either: 68 # 69 # 1) WinPcap isn't installed and Npcap isn't installed in "WinPcap 70 # API-compatible Mode", so there's no wpcap.dll in 71 # \Windows\System32, only in \Windows\System32\Npcap; 72 # 73 # 2) WinPcap is installed and Npcap isn't installed in "WinPcap 74 # API-compatible Mode", so the wpcap.dll in \Windows\System32 75 # is a WinPcap DLL, but we'd prefer an Npcap DLL (we should 76 # work with either one if we're configured against WinPcap, 77 # and we'll probably require Npcap if we're configured against 78 # it), and that's in \Windows\System32\Npcap; 79 # 80 # 3) Npcap is installed in "WinPcap API-compatible Mode", so both 81 # \Windows\System32 and \Windows\System32\Npcap have an Npcap 82 # wpcap.dll. 83 # 84 # Unfortunately, Windows has no notion of an rpath, so we can't 85 # set the rpath to include \Windows\System32\Npcap at link time; 86 # what we need to do is to link wpcap as a delay-load DLL and 87 # add \Windows\System32\Npcap to the DLL search path early in 88 # main() with a call to SetDllDirectory(). 89 # 90 # We add /delayload:wpcap.dll to the linker options here. 91 # 92 # See https://npcap.com/guide/npcap-devguide.html#npcap-feature-native-dll-implicitly 93 # 94 set(PCAP_LINK_FLAGS /delayload:wpcap.dll) 95 96 # 97 # Delay-loading libraries means we need to link with delayimp.lib. 98 # 99 set(PCAP_LIBRARIES ${PCAP_LIBRARIES} delayimp.lib) 100 endif() 101else(WIN32) 102 # 103 # Building for UN*X. 104 # 105 # See whether we were handed a QUIET argument, so we can pass it on 106 # to pkg_search_module. Do *NOT* pass on the REQUIRED argument, 107 # because, if pkg-config isn't found, or it is but it has no .pc 108 # files for libpcap, that is *not* necessarily an indication that 109 # libpcap isn't available - not all systems ship pkg-config, and 110 # libpcap didn't have .pc files until libpcap 1.9.0. 111 # 112 if(PCAP_FIND_QUIETLY) 113 set(_quiet "QUIET") 114 endif() 115 116 # 117 # First, try pkg-config. 118 # Before doing so, set the PKG_CONFIG_PATH environment variable 119 # to include all the directories in CMAKE_PREFIX_PATH. 120 # 121 # *If* we were to require CMake 3.1 or later on UN*X, 122 # pkg_search_module() would do this for us, but, for now, 123 # we're not doing that, in case somebody's building with 124 # CMake on some "long-term support" version, predating 125 # CMake 3.1, of an OS that supplies an earlier 126 # version as a package. 127 # 128 # If we ever set a minimum of 3.1 or later on UN*X, we should 129 # remove the environment variable changes. 130 # 131 # This is based on code in the CMake 3.12.4 FindPkgConfig.cmake, 132 # which is "Distributed under the OSI-approved BSD 3-Clause License." 133 # 134 find_package(PkgConfig) 135 136 # 137 # Get the current PKG_CONFIG_PATH setting. 138 # 139 set(_pkg_config_path "$ENV{PKG_CONFIG_PATH}") 140 141 # 142 # Save it, so we can restore it after we run pkg-config. 143 # 144 set(_saved_pkg_config_path "${_pkg_config_path}") 145 146 if(NOT "${CMAKE_PREFIX_PATH}" STREQUAL "") 147 # 148 # Convert it to a CMake-style path, before we add additional 149 # values to it. 150 # 151 if(NOT "${_pkg_config_path}" STREQUAL "") 152 file(TO_CMAKE_PATH "${_pkg_config_path}" _pkg_config_path) 153 endif() 154 155 # 156 # Turn CMAKE_PREFIX_PATH into a list of extra paths to add 157 # to _pkg_config_path. 158 # 159 set(_extra_paths "") 160 list(APPEND _extra_paths ${CMAKE_PREFIX_PATH}) 161 162 # Create a list of the possible pkgconfig subfolder (depending on 163 # the system 164 set(_lib_dirs) 165 if(NOT DEFINED CMAKE_SYSTEM_NAME 166 OR (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU)$" 167 AND NOT CMAKE_CROSSCOMPILING)) 168 if(EXISTS "/etc/debian_version") # is this a debian system ? 169 if(CMAKE_LIBRARY_ARCHITECTURE) 170 list(APPEND _lib_dirs "lib/${CMAKE_LIBRARY_ARCHITECTURE}/pkgconfig") 171 endif() 172 else() 173 # not debian, check the FIND_LIBRARY_USE_LIB32_PATHS and FIND_LIBRARY_USE_LIB64_PATHS properties 174 get_property(uselib32 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB32_PATHS) 175 if(uselib32 AND CMAKE_SIZEOF_VOID_P EQUAL 4) 176 list(APPEND _lib_dirs "lib32/pkgconfig") 177 endif() 178 get_property(uselib64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS) 179 if(uselib64 AND CMAKE_SIZEOF_VOID_P EQUAL 8) 180 list(APPEND _lib_dirs "lib64/pkgconfig") 181 endif() 182 get_property(uselibx32 GLOBAL PROPERTY FIND_LIBRARY_USE_LIBX32_PATHS) 183 if(uselibx32 AND CMAKE_INTERNAL_PLATFORM_ABI STREQUAL "ELF X32") 184 list(APPEND _lib_dirs "libx32/pkgconfig") 185 endif() 186 endif() 187 endif() 188 if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" AND NOT CMAKE_CROSSCOMPILING) 189 list(APPEND _lib_dirs "libdata/pkgconfig") 190 endif() 191 list(APPEND _lib_dirs "lib/pkgconfig") 192 list(APPEND _lib_dirs "share/pkgconfig") 193 194 # Check if directories exist and eventually append them to the 195 # pkgconfig path list 196 foreach(_prefix_dir ${_extra_paths}) 197 foreach(_lib_dir ${_lib_dirs}) 198 if(EXISTS "${_prefix_dir}/${_lib_dir}") 199 list(APPEND _pkg_config_path "${_prefix_dir}/${_lib_dir}") 200 list(REMOVE_DUPLICATES _pkg_config_path) 201 endif() 202 endforeach() 203 endforeach() 204 205 if(NOT "${_pkg_config_path}" STREQUAL "") 206 # remove empty values from the list 207 list(REMOVE_ITEM _pkg_config_path "") 208 file(TO_NATIVE_PATH "${_pkg_config_path}" _pkg_config_path) 209 if(UNIX) 210 string(REPLACE ";" ":" _pkg_config_path "${_pkg_config_path}") 211 string(REPLACE "\\ " " " _pkg_config_path "${_pkg_config_path}") 212 endif() 213 set(ENV{PKG_CONFIG_PATH} "${_pkg_config_path}") 214 endif() 215 endif() 216 pkg_search_module(CONFIG_PCAP ${_quiet} libpcap) 217 set(ENV{PKG_CONFIG_PATH} "${_saved_pkg_config_path}") 218 219 if(NOT CONFIG_PCAP_FOUND) 220 # 221 # That didn't work. Try pcap-config. 222 # 223 find_program(PCAP_CONFIG pcap-config) 224 if(PCAP_CONFIG) 225 # 226 # We have pcap-config; use it. 227 # 228 if(NOT "${_quiet}" STREQUAL "QUIET") 229 message(STATUS "Found pcap-config") 230 endif() 231 232 # 233 # If this is a vendor-supplied pcap-config, which we define as 234 # being "a pcap-config in /usr/bin or /usr/ccs/bin" (the latter 235 # is for Solaris and Sun/Oracle Studio), there are some issues. 236 # Work around them. 237 # 238 if("${PCAP_CONFIG}" STREQUAL /usr/bin/pcap-config OR 239 "${PCAP_CONFIG}" STREQUAL /usr/ccs/bin/pcap-config) 240 # 241 # It's vendor-supplied. 242 # 243 if(APPLE) 244 # 245 # This is macOS or another Darwin-based OS. 246 # 247 # That means that /usr/bin/pcap-config it may provide 248 # -I/usr/local/include with --cflags and -L/usr/local/lib 249 # with --libs; if there's no pcap installed under /usr/local, 250 # that will cause the build to fail, and if there is a pcap 251 # installed there, you'll get that pcap even if you don't 252 # want it. Remember that, so we ignore those values. 253 # 254 set(_broken_apple_pcap_config TRUE) 255 elseif(CMAKE_SYSTEM_NAME STREQUAL "SunOS" AND CMAKE_SYSTEM_VERSION MATCHES "5[.][0-9.]*") 256 # 257 # This is Solaris 2 or later, i.e. SunOS 5.x. 258 # 259 # At least on Solaris 11; there's /usr/bin/pcap-config, which 260 # reports -L/usr/lib with --libs, causing the 32-bit libraries 261 # to be found, and there's /usr/bin/{64bitarch}/pcap-config, 262 # where {64bitarch} is a name for the 64-bit version of the 263 # instruction set, which reports -L /usr/lib/{64bitarch}, 264 # causing the 64-bit libraries to be found. 265 # 266 # So if we're building 64-bit targets, we replace PCAP_CONFIG 267 # with /usr/bin/{64bitarch}; we get {64bitarch} as the 268 # output of "isainfo -n". 269 # 270 if(CMAKE_SIZEOF_VOID_P EQUAL 8) 271 execute_process(COMMAND "isainfo" "-n" 272 RESULT_VARIABLE ISAINFO_RESULT 273 OUTPUT_VARIABLE ISAINFO_OUTPUT 274 OUTPUT_STRIP_TRAILING_WHITESPACE 275 ) 276 if(ISAINFO_RESULT EQUAL 0) 277 # 278 # Success - change PCAP_CONFIG. 279 # 280 string(REPLACE "/bin/" "/bin/${ISAINFO_OUTPUT}/" PCAP_CONFIG "${PCAP_CONFIG}") 281 endif() 282 endif() 283 endif() 284 endif() 285 286 # 287 # Now get the include directories. 288 # 289 execute_process(COMMAND "${PCAP_CONFIG}" "--cflags" 290 RESULT_VARIABLE PCAP_CONFIG_RESULT 291 OUTPUT_VARIABLE PCAP_CONFIG_OUTPUT 292 OUTPUT_STRIP_TRAILING_WHITESPACE 293 ) 294 if(NOT PCAP_CONFIG_RESULT EQUAL 0) 295 message(FATAL_ERROR "pcap-config --cflags failed") 296 endif() 297 separate_arguments(CFLAGS_LIST UNIX_COMMAND ${PCAP_CONFIG_OUTPUT}) 298 set(CONFIG_PCAP_INCLUDE_DIRS "") 299 foreach(_arg IN LISTS CFLAGS_LIST) 300 if(_arg MATCHES "^-I") 301 # 302 # Extract the directory by removing the -I. 303 # 304 string(REGEX REPLACE "-I" "" _dir ${_arg}) 305 # 306 # Work around macOS (and probably other Darwin) brokenness, 307 # by not adding /usr/local/include if it's from the broken 308 # Apple pcap-config. 309 # 310 if(NOT _broken_apple_pcap_config OR 311 NOT "${_dir}" STREQUAL /usr/local/include) 312 # Add it to CONFIG_PCAP_INCLUDE_DIRS 313 list(APPEND CONFIG_PCAP_INCLUDE_DIRS ${_dir}) 314 endif() 315 endif() 316 endforeach() 317 318 # 319 # Now, get the library directories and libraries for dynamic linking. 320 # 321 execute_process(COMMAND "${PCAP_CONFIG}" "--libs" 322 RESULT_VARIABLE PCAP_CONFIG_RESULT 323 OUTPUT_VARIABLE PCAP_CONFIG_OUTPUT 324 OUTPUT_STRIP_TRAILING_WHITESPACE 325 ) 326 if(NOT PCAP_CONFIG_RESULT EQUAL 0) 327 message(FATAL_ERROR "pcap-config --libs failed") 328 endif() 329 separate_arguments(LIBS_LIST UNIX_COMMAND ${PCAP_CONFIG_OUTPUT}) 330 set(CONFIG_PCAP_LIBRARY_DIRS "") 331 set(CONFIG_PCAP_LIBRARIES "") 332 foreach(_arg IN LISTS LIBS_LIST) 333 if(_arg MATCHES "^-L") 334 # 335 # Extract the directory by removing the -L. 336 # 337 string(REGEX REPLACE "-L" "" _dir ${_arg}) 338 # 339 # Work around macOS (and probably other Darwin) brokenness, 340 # by not adding /usr/local/lib if it's from the broken 341 # Apple pcap-config. 342 # 343 if(NOT _broken_apple_pcap_config OR 344 NOT "${_dir}" STREQUAL /usr/local/lib) 345 # Add this directory to CONFIG_PCAP_LIBRARY_DIRS 346 list(APPEND CONFIG_PCAP_LIBRARY_DIRS ${_dir}) 347 endif() 348 elseif(_arg MATCHES "^-l") 349 string(REGEX REPLACE "-l" "" _lib ${_arg}) 350 list(APPEND CONFIG_PCAP_LIBRARIES ${_lib}) 351 endif() 352 endforeach() 353 354 # 355 # Now, get the library directories and libraries for static linking. 356 # 357 execute_process(COMMAND "${PCAP_CONFIG}" "--libs" "--static" 358 RESULT_VARIABLE PCAP_CONFIG_RESULT 359 OUTPUT_VARIABLE PCAP_CONFIG_OUTPUT 360 ) 361 if(NOT PCAP_CONFIG_RESULT EQUAL 0) 362 message(FATAL_ERROR "pcap-config --libs --static failed") 363 endif() 364 separate_arguments(LIBS_LIST UNIX_COMMAND ${PCAP_CONFIG_OUTPUT}) 365 set(CONFIG_PCAP_STATIC_LIBRARY_DIRS "") 366 set(CONFIG_PCAP_STATIC_LIBRARIES "") 367 foreach(_arg IN LISTS LIBS_LIST) 368 if(_arg MATCHES "^-L") 369 # 370 # Extract the directory by removing the -L. 371 # 372 string(REGEX REPLACE "-L" "" _dir ${_arg}) 373 # 374 # Work around macOS (and probably other Darwin) brokenness, 375 # by not adding /usr/local/lib if it's from the broken 376 # Apple pcap-config. 377 # 378 if(NOT _broken_apple_pcap_config OR 379 NOT "${_dir}" STREQUAL /usr/local/lib) 380 # Add this directory to CONFIG_PCAP_STATIC_LIBRARY_DIRS 381 list(APPEND CONFIG_PCAP_STATIC_LIBRARY_DIRS ${_dir}) 382 endif() 383 elseif(_arg MATCHES "^-l") 384 string(REGEX REPLACE "-l" "" _lib ${_arg}) 385 # 386 # Try to find that library, so we get its full path, as 387 # we do with dynamic libraries. 388 # 389 list(APPEND CONFIG_PCAP_STATIC_LIBRARIES ${_lib}) 390 endif() 391 endforeach() 392 393 # 394 # We've set CONFIG_PCAP_INCLUDE_DIRS, CONFIG_PCAP_LIBRARIES, and 395 # CONFIG_PCAP_STATIC_LIBRARIES above; set CONFIG_PCAP_FOUND. 396 # 397 set(CONFIG_PCAP_FOUND YES) 398 endif() 399 endif() 400 401 # 402 # If CONFIG_PCAP_FOUND is set, we have information from pkg-config and 403 # pcap-config; we need to convert library names to library full paths. 404 # 405 # If it's not set, we have to look for the libpcap headers and library 406 # ourselves. 407 # 408 if(CONFIG_PCAP_FOUND) 409 # 410 # Use CONFIG_PCAP_INCLUDE_DIRS as the value for PCAP_INCLUDE_DIRS. 411 # 412 set(PCAP_INCLUDE_DIRS "${CONFIG_PCAP_INCLUDE_DIRS}") 413 414 # 415 # CMake *really* doesn't like the notion of specifying 416 # "here are the directories in which to look for libraries" 417 # except in find_library() calls; it *really* prefers using 418 # full paths to library files, rather than library names. 419 # 420 foreach(_lib IN LISTS CONFIG_PCAP_LIBRARIES) 421 find_library(_libfullpath ${_lib} HINTS ${CONFIG_PCAP_LIBRARY_DIRS}) 422 list(APPEND PCAP_LIBRARIES ${_libfullpath}) 423 # 424 # Remove that from the cache; we're using it as a local variable, 425 # but find_library insists on making it a cache variable. 426 # 427 unset(_libfullpath CACHE) 428 endforeach() 429 430 # 431 # Now do the same for the static libraries. 432 # 433 set(SAVED_CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_FIND_LIBRARY_SUFFIXES}") 434 set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") 435 foreach(_lib IN LISTS CONFIG_PCAP_STATIC_LIBRARIES) 436 find_library(_libfullpath ${_lib} HINTS ${CONFIG_PCAP_LIBRARY_DIRS}) 437 list(APPEND PCAP_STATIC_LIBRARIES ${_libfullpath}) 438 # 439 # Remove that from the cache; we're using it as a local variable, 440 # but find_library insists on making it a cache variable. 441 # 442 unset(_libfullpath CACHE) 443 endforeach() 444 set(CMAKE_FIND_LIBRARY_SUFFIXES "${SAVED_CMAKE_FIND_LIBRARY_SUFFIXES}") 445 446 # 447 # We found libpcap using pkg-config or pcap-config. 448 # 449 set(PCAP_FOUND YES) 450 else(CONFIG_PCAP_FOUND) 451 # 452 # We didn't have pkg-config, or we did but it didn't have .pc files 453 # for libpcap, and we don't have pkg-config, so we have to look for 454 # the headers and libraries ourself. 455 # 456 # We don't directly set PCAP_INCLUDE_DIRS or PCAP_LIBRARIES, as 457 # they're not supposed to be cache entries, and find_path() and 458 # find_library() set cache entries. 459 # 460 # Try to find the header file. 461 # 462 find_path(PCAP_INCLUDE_DIR pcap.h) 463 464 # 465 # Try to find the library 466 # 467 find_library(PCAP_LIBRARY pcap) 468 469 # Try to find the static library (XXX - what about AIX?) 470 set(SAVED_CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_FIND_LIBRARY_SUFFIXES}") 471 set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") 472 find_library(PCAP_STATIC_LIBRARY pcap) 473 set(CMAKE_FIND_LIBRARY_SUFFIXES "${SAVED_CMAKE_FIND_LIBRARY_SUFFIXES}") 474 475 # 476 # This will fail if REQUIRED is set and PCAP_INCLUDE_DIR or 477 # PCAP_LIBRARY aren't set. 478 # 479 include(FindPackageHandleStandardArgs) 480 find_package_handle_standard_args(PCAP 481 DEFAULT_MSG 482 PCAP_INCLUDE_DIR 483 PCAP_LIBRARY 484 ) 485 486 mark_as_advanced( 487 PCAP_INCLUDE_DIR 488 PCAP_LIBRARY 489 PCAP_STATIC_LIBRARY 490 ) 491 492 if(PCAP_FOUND) 493 set(PCAP_INCLUDE_DIRS ${PCAP_INCLUDE_DIR}) 494 set(PCAP_LIBRARIES ${PCAP_LIBRARY}) 495 set(PCAP_STATIC_LIBRARIES ${PCAP_STATIC_LIBRARY}) 496 endif(PCAP_FOUND) 497 endif(CONFIG_PCAP_FOUND) 498endif(WIN32) 499