Home | History | Annotate | Line # | Download | only in Modules
FindPCAP.cmake revision 1.1
      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 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 a vendor-supplied pcap-config, which we define as
    198       # being "a pcap-config in /usr/bin or /usr/ccs/bin" (the latter
    199       # is for Solaris and Sun/Oracle Studio), there are some issues.
    200       # Work around them.
    201       #
    202       if("${PCAP_CONFIG}" STREQUAL /usr/bin/pcap-config OR
    203          "${PCAP_CONFIG}" STREQUAL /usr/ccs/bin/pcap-config)
    204         #
    205         # It's vendor-supplied.
    206         #
    207         if(APPLE)
    208           #
    209           # This is macOS or another Darwin-based OS.
    210           #
    211           # That means that /usr/bin/pcap-config it may provide
    212           # -I/usr/local/include with --cflags and -L/usr/local/lib
    213           # with --libs; if there's no pcap installed under /usr/local,
    214           # that will cause the build to fail, and if there is a pcap
    215           # installed there, you'll get that pcap even if you don't
    216           # want it.  Remember that, so we ignore those values.
    217           #
    218           set(_broken_apple_pcap_config TRUE)
    219         elseif(CMAKE_SYSTEM_NAME STREQUAL "SunOS" AND CMAKE_SYSTEM_VERSION MATCHES "5[.][0-9.]*")
    220           #
    221           # This is Solaris 2 or later, i.e. SunOS 5.x.
    222           #
    223           # At least on Solaris 11; there's /usr/bin/pcap-config, which
    224           # reports -L/usr/lib with --libs, causing the 32-bit libraries
    225           # to be found, and there's /usr/bin/{64bitarch}/pcap-config,
    226           # where {64bitarch} is a name for the 64-bit version of the
    227           # instruction set, which reports -L /usr/lib/{64bitarch},
    228           # causing the 64-bit libraries to be found.
    229           #
    230           # So if we're building 64-bit targets, we replace PCAP_CONFIG
    231           # with /usr/bin/{64bitarch}; we get {64bitarch} as the
    232           # output of "isainfo -n".
    233           #
    234           if(CMAKE_SIZEOF_VOID_P EQUAL 8)
    235             execute_process(COMMAND "isainfo" "-n"
    236               RESULT_VARIABLE ISAINFO_RESULT
    237               OUTPUT_VARIABLE ISAINFO_OUTPUT
    238               OUTPUT_STRIP_TRAILING_WHITESPACE
    239             )
    240             if(ISAINFO_RESULT EQUAL 0)
    241               #
    242               # Success - change PCAP_CONFIG.
    243               #
    244               string(REPLACE "/bin/" "/bin/${ISAINFO_OUTPUT}/" PCAP_CONFIG "${PCAP_CONFIG}")
    245             endif()
    246           endif()
    247         endif()
    248       endif()
    249 
    250       #
    251       # Now get the include directories.
    252       #
    253       execute_process(COMMAND "${PCAP_CONFIG}" "--cflags"
    254         RESULT_VARIABLE PCAP_CONFIG_RESULT
    255         OUTPUT_VARIABLE PCAP_CONFIG_OUTPUT
    256         OUTPUT_STRIP_TRAILING_WHITESPACE
    257       )
    258       if(NOT PCAP_CONFIG_RESULT EQUAL 0)
    259         message(FATAL_ERROR "pcap-config --cflags failed")
    260       endif()
    261       separate_arguments(CFLAGS_LIST UNIX_COMMAND ${PCAP_CONFIG_OUTPUT})
    262       set(CONFIG_PCAP_INCLUDE_DIRS "")
    263       foreach(_arg IN LISTS CFLAGS_LIST)
    264         if(_arg MATCHES "^-I")
    265           #
    266           # Extract the directory by removing the -I.
    267           #
    268           string(REGEX REPLACE "-I" "" _dir ${_arg})
    269           #
    270           # Work around macOS (and probably other Darwin) brokenness,
    271           # by not adding /usr/local/include if it's from the broken
    272           # Apple pcap-config.
    273           #
    274           if(NOT _broken_apple_pcap_config OR
    275              NOT "${_dir}" STREQUAL /usr/local/include)
    276             # Add it to CONFIG_PCAP_INCLUDE_DIRS
    277             list(APPEND CONFIG_PCAP_INCLUDE_DIRS ${_dir})
    278           endif()
    279         endif()
    280       endforeach()
    281 
    282       #
    283       # Now, get the library directories and libraries for dynamic linking.
    284       #
    285       execute_process(COMMAND "${PCAP_CONFIG}" "--libs"
    286         RESULT_VARIABLE PCAP_CONFIG_RESULT
    287         OUTPUT_VARIABLE PCAP_CONFIG_OUTPUT
    288         OUTPUT_STRIP_TRAILING_WHITESPACE
    289       )
    290       if(NOT PCAP_CONFIG_RESULT EQUAL 0)
    291         message(FATAL_ERROR "pcap-config --libs failed")
    292       endif()
    293       separate_arguments(LIBS_LIST UNIX_COMMAND ${PCAP_CONFIG_OUTPUT})
    294       set(CONFIG_PCAP_LIBRARY_DIRS "")
    295       set(CONFIG_PCAP_LIBRARIES "")
    296       foreach(_arg IN LISTS LIBS_LIST)
    297         if(_arg MATCHES "^-L")
    298           #
    299           # Extract the directory by removing the -L.
    300           #
    301           string(REGEX REPLACE "-L" "" _dir ${_arg})
    302           #
    303           # Work around macOS (and probably other Darwin) brokenness,
    304           # by not adding /usr/local/lib if it's from the broken
    305           # Apple pcap-config.
    306           #
    307           if(NOT _broken_apple_pcap_config OR
    308              NOT "${_dir}" STREQUAL /usr/local/lib)
    309             # Add this directory to CONFIG_PCAP_LIBRARY_DIRS
    310             list(APPEND CONFIG_PCAP_LIBRARY_DIRS ${_dir})
    311           endif()
    312         elseif(_arg MATCHES "^-l")
    313           string(REGEX REPLACE "-l" "" _lib ${_arg})
    314           list(APPEND CONFIG_PCAP_LIBRARIES ${_lib})
    315         endif()
    316       endforeach()
    317 
    318       #
    319       # Now, get the library directories and libraries for static linking.
    320       #
    321       execute_process(COMMAND "${PCAP_CONFIG}" "--libs" "--static"
    322         RESULT_VARIABLE PCAP_CONFIG_RESULT
    323         OUTPUT_VARIABLE PCAP_CONFIG_OUTPUT
    324       )
    325       if(NOT PCAP_CONFIG_RESULT EQUAL 0)
    326         message(FATAL_ERROR "pcap-config --libs --static failed")
    327       endif()
    328       separate_arguments(LIBS_LIST UNIX_COMMAND ${PCAP_CONFIG_OUTPUT})
    329       set(CONFIG_PCAP_STATIC_LIBRARY_DIRS "")
    330       set(CONFIG_PCAP_STATIC_LIBRARIES "")
    331       foreach(_arg IN LISTS LIBS_LIST)
    332         if(_arg MATCHES "^-L")
    333           #
    334           # Extract the directory by removing the -L.
    335           #
    336           string(REGEX REPLACE "-L" "" _dir ${_arg})
    337           #
    338           # Work around macOS (and probably other Darwin) brokenness,
    339           # by not adding /usr/local/lib if it's from the broken
    340           # Apple pcap-config.
    341           #
    342           if(NOT _broken_apple_pcap_config OR
    343              NOT "${_dir}" STREQUAL /usr/local/lib)
    344             # Add this directory to CONFIG_PCAP_STATIC_LIBRARY_DIRS
    345             list(APPEND CONFIG_PCAP_STATIC_LIBRARY_DIRS ${_dir})
    346           endif()
    347         elseif(_arg MATCHES "^-l")
    348           string(REGEX REPLACE "-l" "" _lib ${_arg})
    349           #
    350           # Try to find that library, so we get its full path, as
    351           # we do with dynamic libraries.
    352           #
    353           list(APPEND CONFIG_PCAP_STATIC_LIBRARIES ${_lib})
    354         endif()
    355       endforeach()
    356 
    357       #
    358       # We've set CONFIG_PCAP_INCLUDE_DIRS, CONFIG_PCAP_LIBRARIES, and
    359       # CONFIG_PCAP_STATIC_LIBRARIES above; set CONFIG_PCAP_FOUND.
    360       #
    361       set(CONFIG_PCAP_FOUND YES)
    362     endif()
    363   endif()
    364 
    365   #
    366   # If CONFIG_PCAP_FOUND is set, we have information from pkg-config and
    367   # pcap-config; we need to convert library names to library full paths.
    368   #
    369   # If it's not set, we have to look for the libpcap headers and library
    370   # ourselves.
    371   #
    372   if(CONFIG_PCAP_FOUND)
    373     #
    374     # Use CONFIG_PCAP_INCLUDE_DIRS as the value for PCAP_INCLUDE_DIRS.
    375     #
    376     set(PCAP_INCLUDE_DIRS "${CONFIG_PCAP_INCLUDE_DIRS}")
    377 
    378     #
    379     # CMake *really* doesn't like the notion of specifying
    380     # "here are the directories in which to look for libraries"
    381     # except in find_library() calls; it *really* prefers using
    382     # full paths to library files, rather than library names.
    383     #
    384     foreach(_lib IN LISTS CONFIG_PCAP_LIBRARIES)
    385       find_library(_libfullpath ${_lib} HINTS ${CONFIG_PCAP_LIBRARY_DIRS})
    386       list(APPEND PCAP_LIBRARIES ${_libfullpath})
    387       #
    388       # Remove that from the cache; we're using it as a local variable,
    389       # but find_library insists on making it a cache variable.
    390       #
    391       unset(_libfullpath CACHE)
    392    endforeach()
    393 
    394     #
    395     # Now do the same for the static libraries.
    396     #
    397     set(SAVED_CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_FIND_LIBRARY_SUFFIXES}")
    398     set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
    399     foreach(_lib IN LISTS CONFIG_PCAP_STATIC_LIBRARIES)
    400       find_library(_libfullpath ${_lib} HINTS ${CONFIG_PCAP_LIBRARY_DIRS})
    401       list(APPEND PCAP_STATIC_LIBRARIES ${_libfullpath})
    402       #
    403       # Remove that from the cache; we're using it as a local variable,
    404       # but find_library insists on making it a cache variable.
    405       #
    406       unset(_libfullpath CACHE)
    407     endforeach()
    408     set(CMAKE_FIND_LIBRARY_SUFFIXES "${SAVED_CMAKE_FIND_LIBRARY_SUFFIXES}")
    409 
    410     #
    411     # We found libpcap using pkg-config or pcap-config.
    412     #
    413     set(PCAP_FOUND YES)
    414   else(CONFIG_PCAP_FOUND)
    415     #
    416     # We didn't have pkg-config, or we did but it didn't have .pc files
    417     # for libpcap, and we don't have pkg-config, so we have to look for
    418     # the headers and libraries ourself.
    419     #
    420     # We don't directly set PCAP_INCLUDE_DIRS or PCAP_LIBRARIES, as
    421     # they're not supposed to be cache entries, and find_path() and
    422     # find_library() set cache entries.
    423     #
    424     # Try to find the header file.
    425     #
    426     find_path(PCAP_INCLUDE_DIR pcap.h)
    427 
    428     #
    429     # Try to find the library
    430     #
    431     find_library(PCAP_LIBRARY pcap)
    432 
    433     # Try to find the static library (XXX - what about AIX?)
    434     set(SAVED_CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_FIND_LIBRARY_SUFFIXES}")
    435     set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
    436     find_library(PCAP_STATIC_LIBRARY pcap)
    437     set(CMAKE_FIND_LIBRARY_SUFFIXES "${SAVED_CMAKE_FIND_LIBRARY_SUFFIXES}")
    438 
    439     #
    440     # This will fail if REQUIRED is set and PCAP_INCLUDE_DIR or
    441     # PCAP_LIBRARY aren't set.
    442     #
    443     include(FindPackageHandleStandardArgs)
    444     find_package_handle_standard_args(PCAP
    445       DEFAULT_MSG
    446       PCAP_INCLUDE_DIR
    447       PCAP_LIBRARY
    448     )
    449 
    450     mark_as_advanced(
    451       PCAP_INCLUDE_DIR
    452       PCAP_LIBRARY
    453       PCAP_STATIC_LIBRARY
    454     )
    455 
    456     if(PCAP_FOUND)
    457       set(PCAP_INCLUDE_DIRS ${PCAP_INCLUDE_DIR})
    458       set(PCAP_LIBRARIES ${PCAP_LIBRARY})
    459       set(PCAP_STATIC_LIBRARIES ${PCAP_STATIC_LIBRARY})
    460     endif(PCAP_FOUND)
    461   endif(CONFIG_PCAP_FOUND)
    462 endif(WIN32)
    463