• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  endif()
65else(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)
422endif(WIN32)
423