]> The Tcpdump Group git mirrors - tcpdump/blob - cmake/Modules/FindPCAP.cmake
Fix a few typos in comments
[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 # 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()
101 else(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)
498 endif(WIN32)