]> The Tcpdump Group git mirrors - tcpdump/blob - cmake/Modules/FindPCAP.cmake
CMake: add stuff from CMAKE_PREFIX_PATH to PKG_CONFIG_PATH.
[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 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)