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