decrypt drsuapi attributes
[wireshark-sm.git] / cmake / modules / FindPCAP.cmake
blobeb9565bc2f77871265764d7fb7588131ea4b3001
2 # - Find libpcap
3 # Find the native PCAP includes and library
5 #  PCAP_INCLUDE_DIRS - where to find pcap.h, etc.
6 #  PCAP_LIBRARIES    - List of libraries when using pcap.
7 #  PCAP_FOUND        - True if pcap found.
9 include(FindWSWinLibs)
10 FindWSWinLibs("libpcap-*" "PCAP_HINTS")
13 # First, try pkg-config on platforms other than Windows.
15 if(NOT USE_REPOSITORY)
16   find_package(PkgConfig)
17   pkg_search_module(PC_PCAP libpcap)
18 endif()
20 if(NOT PC_PCAP_FOUND AND NOT WIN32)
21   #
22   # That didn't work.  Try to retrieve hints from pcap-config.
23   # Do not use it on Windows as pcap-config is a shell script.
24   #
25   find_program(PCAP_CONFIG pcap-config)
26   if(PCAP_CONFIG)
27     #
28     # We have pcap-config; use it.
29     #
30     # First, get the include directory.
31     #
32     execute_process(COMMAND "${PCAP_CONFIG}" "--cflags"
33       RESULT_VARIABLE PCAP_CONFIG_RESULT
34       OUTPUT_VARIABLE PCAP_CONFIG_OUTPUT
35       OUTPUT_STRIP_TRAILING_WHITESPACE
36     )
37     if(NOT PCAP_CONFIG_RESULT EQUAL 0)
38       message(FATAL_ERROR "pcap-config --cflags failed")
39     endif()
40     #
41     # Assumes there's exactly one -I flag in the output
42     # of pcap-config --cflags.  That *should* be the case.
43     # Note that the hint might be bogus, on macOS it could be
44     # -I/usr/local/include even though the header isn't
45     # there (it may be under /usr/include or it may be
46     # buried in the Xcode app bundle).
47     #
48     string(REGEX REPLACE "^-I" "" PCAP_CONFIG_INCLUDE_DIRS "${PCAP_CONFIG_OUTPUT}")
50     # Now, get the library search path.
51     execute_process(COMMAND "${PCAP_CONFIG}" "--libs"
52       RESULT_VARIABLE PCAP_CONFIG_RESULT
53       OUTPUT_VARIABLE PCAP_CONFIG_OUTPUT
54       OUTPUT_STRIP_TRAILING_WHITESPACE
55     )
56     if(NOT PCAP_CONFIG_RESULT EQUAL 0)
57       message(FATAL_ERROR "pcap-config --libs failed")
58     endif()
59     separate_arguments(LIBS_LIST UNIX_COMMAND ${PCAP_CONFIG_OUTPUT})
60     set(PCAP_CONFIG_LIBRARY_DIRS "")
61     foreach(_arg IN LISTS LIBS_LIST)
62       # At most one -L path is expected for -lpcap.
63       if(_arg MATCHES "^-L")
64         string(REGEX REPLACE "^-L" "" _dir ${_arg})
65         list(APPEND PCAP_CONFIG_LIBRARY_DIRS ${_dir})
66       endif()
67     endforeach()
69     if(UNIX AND CMAKE_FIND_LIBRARY_SUFFIXES STREQUAL ".a")
70       # Now, get the library directories and libraries for static linking.
71       # (XXX - what about AIX?)
72       execute_process(COMMAND "${PCAP_CONFIG}" "--libs" "--static"
73         RESULT_VARIABLE PCAP_CONFIG_RESULT
74         OUTPUT_VARIABLE PCAP_CONFIG_OUTPUT
75       )
76       if(NOT PCAP_CONFIG_RESULT EQUAL 0)
77         message(FATAL_ERROR "pcap-config --libs --static failed")
78       endif()
79       separate_arguments(LIBS_LIST UNIX_COMMAND ${PCAP_CONFIG_OUTPUT})
80       set(PCAP_CONFIG_STATIC_LIBRARY_DIRS "")
81       set(PCAP_CONFIG_STATIC_LIBRARIES "")
82       foreach(_arg IN LISTS LIBS_LIST)
83         if(_arg MATCHES "^-L")
84           # Add this directory to the library directory hints.
85           string(REGEX REPLACE "^-L" "" _dir ${_arg})
86           list(APPEND PCAP_CONFIG_STATIC_LIBRARY_DIRS ${_dir})
87         elseif(_arg MATCHES "^-l")
88           # Add this library to the requirements for static linking.
89           string(REGEX REPLACE "^-l" "" _lib ${_arg})
90           list(APPEND PCAP_CONFIG_STATIC_LIBRARIES ${_lib})
91         endif()
92       endforeach()
93     endif()
94   endif()
95 endif()
98 # Locate the actual include directory. For pkg-config the
99 # PC_PCAP_INCLUDE_DIRS variable could be empty if the default
100 # header search path is sufficient to locate the header file.
101 # For macOS, the directory returned by pcap-config is wrong, so
102 # this will make sure to find a valid path.
104 find_path(PCAP_INCLUDE_DIR
105   NAMES
106     pcap/pcap.h
107     pcap.h
108   PATH_SUFFIXES
109     wpcap
110   HINTS
111     ${PC_PCAP_INCLUDE_DIRS}
112     ${PCAP_CONFIG_INCLUDE_DIRS}
113     "${PCAP_HINTS}/Include"
116 # On Windows we load wpcap.dll explicitly and probe its functions in
117 # capture\capture-wpcap.c. We don't want to link with pcap.lib since
118 # that would bring in the non-capturing (null) pcap.dll from the vcpkg
119 # library.
120 if(WIN32 AND NOT CMAKE_CROSSCOMPILING)
121   set(_pkg_required_vars PCAP_INCLUDE_DIR)
122 else()
123   find_library(PCAP_LIBRARY
124     NAMES
125       pcap
126       wpcap
127     HINTS
128       ${PC_PCAP_LIBRARY_DIRS}
129       ${PCAP_CONFIG_LIBRARY_DIRS}
130   )
131   set(_pkg_required_vars PCAP_LIBRARY PCAP_INCLUDE_DIR)
132 endif()
134 if(UNIX AND CMAKE_FIND_LIBRARY_SUFFIXES STREQUAL ".a")
135   # Try to find the static library (XXX - what about AIX?)
136   if(PC_PCAP_FOUND)
137     set(_pcap_static_libraries ${PC_PCAP_STATIC_LIBRARIES})
138   elseif(PCAP_CONFIG)
139     set(_pcap_static_libraries ${PCAP_CONFIG_STATIC_LIBRARIES})
140   else()
141     #
142     # No pkg-config nor pcap-config found, hope that this single library is
143     # sufficient for static linking.
144     #
145     set(_pcap_static_libraries pcap)
146   endif()
148   set(PCAP_STATIC_LIBRARIES "")
149   foreach(_lib IN LISTS _pcap_static_libraries)
150     #
151     # Try to find that library, so we get its full path, as
152     # we do with dynamic libraries.
153     #
154     string(MAKE_C_IDENTIFIER "PCAP_STATIC_${_lib}_LIBRARY" _libvar)
155     find_library(${_libvar} ${_lib}
156       HINTS
157       ${PC_PCAP_STATIC_LIBRARY_DIRS}
158       ${PCAP_CONFIG_STATIC_LIBRARY_DIRS}
159     )
160     set(_libpath ${${_libvar}})
161     if(_libpath)
162       list(APPEND PCAP_STATIC_LIBRARIES ${_libpath})
163     endif()
164   endforeach()
165 endif()
167 include(FindPackageHandleStandardArgs)
168 find_package_handle_standard_args(PCAP DEFAULT_MSG ${_pkg_required_vars})
169 mark_as_advanced(${_pkg_required_vars})
171 if(PCAP_FOUND)
172   set(PCAP_INCLUDE_DIRS ${PCAP_INCLUDE_DIR})
173   if(UNIX AND CMAKE_FIND_LIBRARY_SUFFIXES STREQUAL ".a")
174     # Link with static libpcap and its transitive dependencies.
175     set(PCAP_LIBRARIES ${PCAP_STATIC_LIBRARIES})
176   else()
177     set(PCAP_LIBRARIES ${PCAP_LIBRARY})
178   endif()
180   #Functions
181   include( CMakePushCheckState )
182   include( CheckFunctionExists )
183   include( CheckVariableExists )
185   cmake_push_check_state()
186   set( CMAKE_REQUIRED_INCLUDES ${PCAP_INCLUDE_DIRS} )
187   set( CMAKE_REQUIRED_LIBRARIES ${PCAP_LIBRARIES} )
189   include(CheckSymbolExists)
191   if(WIN32 AND NOT CMAKE_CROSSCOMPILING)
192     #
193     # Prepopulate some values. WinPcap 3.1 and later, and Npcap, have these
194     # in their SDK, and compilation checks on Windows can be slow.  We check
195     # whether they're present at run time, when we load wpcap.dll, and work
196     # around their absence or report an error.
197     #
198     set(HAVE_PCAP_FREECODE TRUE)
199     set(HAVE_PCAP_CREATE TRUE)
200     set(HAVE_PCAP_FREE_DATALINKS TRUE)
201     set(HAVE_PCAP_OPEN TRUE)
202     set(HAVE_PCAP_SETSAMPLING TRUE)
203     set(HAVE_PCAP_SET_TSTAMP_PRECISION TRUE)
204     set(HAVE_PCAP_SET_TSTAMP_TYPE TRUE)
205   else(WIN32)
206     #
207     # Make sure we have at least libpcap 0.8, because we require at
208     # least libpcap 0.8's APIs.
209     #
210     # We check whether pcap_lib_version is defined in the pcap header,
211     # using it as a proxy for all the 0.8 API's.  if not, we fail.
212     #
213     check_symbol_exists( pcap_lib_version ${PCAP_INCLUDE_DIR}/pcap.h HAVE_PCAP_LIB_VERSION )
214     if( NOT HAVE_PCAP_LIB_VERSION )
215       message(FATAL_ERROR "You need libpcap 0.8 or later")
216     endif( NOT HAVE_PCAP_LIB_VERSION )
218     check_function_exists( "pcap_freecode" HAVE_PCAP_FREECODE )
219     check_function_exists( "pcap_create" HAVE_PCAP_CREATE )
220     check_function_exists( "pcap_free_datalinks" HAVE_PCAP_FREE_DATALINKS )
221     #
222     # macOS Sonoma's libpcap includes stub versions of the remote-
223     # capture APIs.  They are exported as "weakly linked symbols".
224     #
225     # Xcode 15 offers only a macOS Sonoma SDK, which has a .tbd
226     # file for libpcap that claims it includes those APIs.  (Newer
227     # versions of macOS don't provide the system shared libraries,
228     # they only provide the dyld shared cache containing those
229     # libraries, so the OS provides SDKs that include a .tbd file
230     # to use when linking.)
231     #
232     # This means that check_function_exists() will think that
233     # the remote-capture APIs are present, including pcap_open().
234     #
235     # However, they are *not* present in macOS Ventura and earlier,
236     # which means that building on Ventura with Xcode 15 produces
237     # executables that fail to start because one of those APIs
238     # isn't found in the system libpcap.
239     #
240     # Protecting calls to those APIs with __builtin_available()
241     # does not prevent this, because the libpcap header files
242     # in the Sonoma SDK mark them as being first available
243     # in macOS 10.13, just like all the other routines introduced
244     # in libpcap 1.9, even though they're only available if libpcap
245     # is built with remote capture enabled or stub routines are
246     # provided.  (A fix to enable this has been checked into the
247     # libpcap repository, and may end up in a later version of
248     # the SDK.)
249     #
250     # Given all that, and given that the versions of the
251     # remote-capture APIs in Sonoma are stubs that always fail,
252     # there doesn't seem to be any point in checking for pcap_open()
253     # if we're linking against the Apple libpcap.
254     #
255     # However, if we're *not* linking against the Apple libpcap,
256     # we should check for it, so that we can use it if it's present.
257     #
258     # So we check for pcap_open if 1) this isn't macOS or 2) the
259     # the libpcap we found is not a system library, meaning that
260     # its path begins neither with /usr/lib (meaning it's a system
261     # dylib) nor /Application/Xcode.app (meaning it's a file in
262     # the Xcode SDK).
263     #
264     if( NOT APPLE OR NOT
265        (PCAP_LIBRARY MATCHES "/usr/lib/.*" OR
266         PCAP_LIBRARY MATCHES "/Application/Xcode.app/.*"))
267       check_function_exists( "pcap_open" HAVE_PCAP_OPEN )
268     endif()
269     if( HAVE_PCAP_OPEN )
270       #
271       # XXX - this *should* be checked for independently of checking
272       # for pcap_open(), as you might have pcap_setsampling() without
273       # remote capture support.
274       #
275       # However, 1) the sampling options are treated as remote options
276       # in the GUI and 2) having pcap_setsampling() doesn't mean
277       # you have sampling support.  libpcap needs a way to indicate
278       # whether a given device supports sampling, and the GUI should
279       # be changed to decouple them.
280       #
281       # (Actually, libpcap needs a general mechanism to offer options
282       # for particular devices, and Wireshark needs to use that
283       # mechanism.  The former is a work in progress.)
284       #
285       # (Note: another work in progress is support for remote
286       # capturing using pcap_create()/pcap_activate(), which we
287       # also need to support once it's available.)
288       #
289       check_function_exists( "pcap_setsampling" HAVE_PCAP_SETSAMPLING )
290     endif( HAVE_PCAP_OPEN )
291   endif()
293   if( HAVE_PCAP_CREATE )
294     #
295     # If we have pcap_create(), we have pcap_set_buffer_size(), and
296     # can set the capture buffer size.
297     #
298     # Otherwise, if this is Windows, we have pcap_setbuff(), and can
299     # set the capture buffer size.
300     #
301     set( CAN_SET_CAPTURE_BUFFER_SIZE TRUE )
302   endif()
303   check_function_exists( "pcap_set_tstamp_precision" HAVE_PCAP_SET_TSTAMP_PRECISION )
304   check_function_exists( "pcap_set_tstamp_type" HAVE_PCAP_SET_TSTAMP_TYPE )
305   # Remote pcap checks
306   if( HAVE_PCAP_OPEN )
307     set( HAVE_PCAP_REMOTE 1 )
308   endif()
310   check_symbol_exists(PCAP_ERROR_PROMISC_PERM_DENIED ${PCAP_INCLUDE_DIR}/pcap.h HAVE_PCAP_ERROR_PROMISC_PERM_DENIED)
311   check_symbol_exists(PCAP_WARNING_TSTAMP_TYPE_NOTSUP ${PCAP_INCLUDE_DIR}/pcap.h HAVE_PCAP_WARNING_TSTAMP_TYPE_NOTSUP)
313   cmake_pop_check_state()
314 endif()
316 if(PCAP_FOUND AND NOT TARGET pcap::pcap)
317   if(WIN32)
318     add_library(pcap::pcap INTERFACE IMPORTED)
319     set_target_properties(pcap::pcap PROPERTIES
320       INTERFACE_INCLUDE_DIRECTORIES "${PCAP_INCLUDE_DIRS}"
321     )
322   else()
323     add_library(pcap::pcap UNKNOWN IMPORTED)
324     set_target_properties(pcap::pcap PROPERTIES
325       IMPORTED_LOCATION "${PCAP_LIBRARIES}"
326       INTERFACE_INCLUDE_DIRECTORIES "${PCAP_INCLUDE_DIRS}"
327     )
328   endif()
329 endif()