Problems using SNMP++/Agent++ from another CMakeLists.txt

Good day!

I have to start saying that building and installing SNMP++ and AGENT++ works as expected without any issue.

That said, I have to build a simple SNMP Agent and I have mainly 2 requirements: 1) Do not install any file in the system, 2) Use CMake self contained build.

I have a folder structure and CMakeLists.txt as follows:

* MySnmpAgent
    - snmppp ---> SNMP++ sources
    - agentpp ---> Agent++ sources

My CMakeLists.txt

cmake_minimum_required(VERSION 3.25)

project(MySnmpAgent)

add_executable(MySnmpAgent
    src/main.cpp
    )

add_subdirectory(snmppp)
add_subdirectory(agentpp)


target_link_libraries(MySnmpAgent PUBLIC
    snmp++_static
    agent++_static
    )

I have found 2 issues.

The first one, I receive a build error:

libsnmp.h:268:11: fatal error: iostream.h: No such file or directory

This error is caused by the following line in both snmp++ and agent++ CMakeLists.txt:

check_include_files ("iostream" CNF_HAVE_IOSTREAM)

Since “iostream” is a C++ header file, the line would be:

include (CheckIncludeFileCXX)

...

check_include_file_cxx ("iostream" CNF_HAVE_IOSTREAM)

Probably the same fix needs to be applied to the line:

check_include_files ("cctype;cerrno;climits;csignal;cstddef;cstdio;cstdlib;cstring;ctime" CNF_STDCXX_98_HEADERS)

This solves the issue. It would be nice to have this fix applied for the next release.

So far so good.

The second issue is not that straightforward. Agent++ complains about SNMP++ root dir. The issue goes away if I precompile SNMP++ and provide SNMP_PP_ROOT_DIR but does not look to me like the CMake-ish way of building the code. I would like to be able to just do (example):

cmake <path-to-my-CMakeLists.txt> [-DCMAKE_BUILD_TYPE=Debug]

And then build both SNMP++ and AGENT++ in the following make step:

make

I can probably solve the issue by issuing something like:

execute_command(
    COMMAND "cmake <path_to_snmppp>"
    WORKING DIRECTORY ${SNMP_BUILD_DIR}
    )

Would certainly work if there is no other option, but it is not what I am looking for since that would trigger the build of SNMP++ when the cmake command is triggered for my CMakeLists.txt

Is there a way of building both SNMP++ and AGENT++ in the ‘make’ step following to CMake command?

Thanks in advance

Hi,

it is easy to replace check_include_files with check_include_file_cxx for the single include, but I will have to think about the second usage with multiple files.

The module cmake/modules/Findsnmp_pp.cmake requires that the snmp++ library exists. I’m wondering how other multi library projects are doing this.
I could think of the following solution: Define the needed variables in your CMakeLists.txt and adapt Findsnmp_pp.cmake to just use the provided values instead of searching for the library.

Kind regards,
Jochen

Hi Jochen,

thank you for your response.

I get the point. Thanks for considering it.

If Snmp++ is already included in the project using its CMakeLists.txt via add_subdirectory(), the targets defined for Snmp++ will be there and it can be checked by (Example):

if (TARGET snmp++)
  # Snmp++ target is already defined
  # target_link_libraries will make available all public include directories, include files, and so on
  target_link_libraries(agent++ snmp++)
  target_link_libraries(agent++_static snmp++_static)
endif()

If you are fine with, I can make some changes to the CMakeLists.txt / find_snmppp.cmake and send you the code for your consideration.

My proposal will be 100% backwards compatible and work in the provided scenario.

Regards

That would be great. Thanks in advance and best regards,
Jochen

I ran into the same issue. The following patch fixes it for me. It does two things:

  1. Add the optional LANGUAGE CXX to the check_include_files calls. The issue here was that otherwise, check_include_files prefers the C compiler if it is enabled. The including project might have done that for some other subdirectory, so the include test would run against C. And fail because of that.
  2. Add a CMake configuration file, so another CMake project can just use find_package(snmp++ REQUIRED).
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5a0343b..45cd6e9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -45,39 +45,39 @@ set (SNMP_PP_MICRO_VERSION ${PROJECT_VERSION_PATCH})
 
 message (STATUS "snmp++ Version ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
 
-check_include_files (sys/types.h CNF_HAVE_SYS_TYPES_H)
-check_include_files (sys/stat.h CNF_HAVE_SYS_STAT_H)
-check_include_files ("cctype;cerrno;climits;csignal;cstddef;cstdio;cstdlib;cstring;ctime" CNF_STDCXX_98_HEADERS)
-check_include_files ("iostream" CNF_HAVE_IOSTREAM)
-check_include_files ("stdlib.h;stddef.h" CNF_STDC_HEADERS)
-check_include_files (stdlib.h CNF_HAVE_STDLIB_H)
-check_include_files (string.h CNF_HAVE_STRING_H)
-check_include_files (memory.h CNF_HAVE_MEMORY_H)
-check_include_files (strings.h CNF_HAVE_STRINGS_H)
-check_include_files (inttypes.h CNF_HAVE_INTTYPES_H)
-check_include_files (ctype.h CNF_HAVE_CTYPE_H)
-check_include_files (signal.h CNF_HAVE_SIGNAL_H)
-check_include_files (errno.h CNF_HAVE_ERRNO_H)
-check_include_files (time.h CNF_HAVE_TIME_H)
-check_include_files (unistd.h CNF_HAVE_UNISTD_H)
-check_include_files (sys/unistd.h CNF_HAVE_SYS_UNISTD_H)
-check_include_files (stdint.h CNF_HAVE_STDINT_H)
-check_include_files (sys/time.h CNF_HAVE_SYS_TIME_H)
-check_include_files (sys/param.h CNF_HAVE_SYS_PARAM_H)
-check_include_files (sys/timeb.h CNF_HAVE_SYS_TIMEB_H)
-check_include_files (winsock2.h CNF_HAVE_WINSOCK2_H)
-check_include_files (ws2tcpip.h CNF_HAVE_WS2TCPIP_H)
-check_include_files (wspiapi.h CNF_HAVE_WSPIAPI_H)
-check_include_files (winsock.h CNF_HAVE_WINSOCK_H)
-check_include_files (netdb.h CNF_HAVE_NETDB_H)
-check_include_files (sys/socket.h CNF_HAVE_SYS_SOCKET_H)
-check_include_files (arpa/inet.h CNF_HAVE_ARPA_INET_H)
-check_include_files (netinet/in.h CNF_HAVE_NETINET_IN_H)
-check_include_files (poll.h CNF_HAVE_POLL_H)
-check_include_files (sys/select.h CNF_HAVE_SYS_SELECT_H)
-check_include_files (io.h CNF_HAVE_IO_H)
-check_include_files (process.h CNF_HAVE_PROCESS_H)
-check_include_files (pthread.h CNF_HAVE_PTHREAD_H)
+check_include_files (sys/types.h CNF_HAVE_SYS_TYPES_H LANGUAGE CXX)
+check_include_files (sys/stat.h CNF_HAVE_SYS_STAT_H LANGUAGE CXX)
+check_include_files ("cctype;cerrno;climits;csignal;cstddef;cstdio;cstdlib;cstring;ctime" CNF_STDCXX_98_HEADERS LANGUAGE CXX)
+check_include_files ("iostream" CNF_HAVE_IOSTREAM LANGUAGE CXX)
+check_include_files ("stdlib.h;stddef.h" CNF_STDC_HEADERS LANGUAGE CXX)
+check_include_files (stdlib.h CNF_HAVE_STDLIB_H LANGUAGE CXX)
+check_include_files (string.h CNF_HAVE_STRING_H LANGUAGE CXX)
+check_include_files (memory.h CNF_HAVE_MEMORY_H LANGUAGE CXX)
+check_include_files (strings.h CNF_HAVE_STRINGS_H LANGUAGE CXX)
+check_include_files (inttypes.h CNF_HAVE_INTTYPES_H LANGUAGE CXX)
+check_include_files (ctype.h CNF_HAVE_CTYPE_H LANGUAGE CXX)
+check_include_files (signal.h CNF_HAVE_SIGNAL_H LANGUAGE CXX)
+check_include_files (errno.h CNF_HAVE_ERRNO_H LANGUAGE CXX)
+check_include_files (time.h CNF_HAVE_TIME_H LANGUAGE CXX)
+check_include_files (unistd.h CNF_HAVE_UNISTD_H LANGUAGE CXX)
+check_include_files (sys/unistd.h CNF_HAVE_SYS_UNISTD_H LANGUAGE CXX)
+check_include_files (stdint.h CNF_HAVE_STDINT_H LANGUAGE CXX)
+check_include_files (sys/time.h CNF_HAVE_SYS_TIME_H LANGUAGE CXX)
+check_include_files (sys/param.h CNF_HAVE_SYS_PARAM_H LANGUAGE CXX)
+check_include_files (sys/timeb.h CNF_HAVE_SYS_TIMEB_H LANGUAGE CXX)
+check_include_files (winsock2.h CNF_HAVE_WINSOCK2_H LANGUAGE CXX)
+check_include_files (ws2tcpip.h CNF_HAVE_WS2TCPIP_H LANGUAGE CXX)
+check_include_files (wspiapi.h CNF_HAVE_WSPIAPI_H LANGUAGE CXX)
+check_include_files (winsock.h CNF_HAVE_WINSOCK_H LANGUAGE CXX)
+check_include_files (netdb.h CNF_HAVE_NETDB_H LANGUAGE CXX)
+check_include_files (sys/socket.h CNF_HAVE_SYS_SOCKET_H LANGUAGE CXX)
+check_include_files (arpa/inet.h CNF_HAVE_ARPA_INET_H LANGUAGE CXX)
+check_include_files (netinet/in.h CNF_HAVE_NETINET_IN_H LANGUAGE CXX)
+check_include_files (poll.h CNF_HAVE_POLL_H LANGUAGE CXX)
+check_include_files (sys/select.h CNF_HAVE_SYS_SELECT_H LANGUAGE CXX)
+check_include_files (io.h CNF_HAVE_IO_H LANGUAGE CXX)
+check_include_files (process.h CNF_HAVE_PROCESS_H LANGUAGE CXX)
+check_include_files (pthread.h CNF_HAVE_PTHREAD_H LANGUAGE CXX)
 check_function_exists ("strcasecmp" CNF_HAVE_STRCASECMP)
 check_function_exists ("stricmp" CNF_HAVE_STRICMP)
 check_function_exists ("getpid" CNF_HAVE_GETPID)
@@ -99,48 +99,48 @@ check_function_exists ("inet_aton" HAVE_INET_ATON)
 check_function_exists ("inet_ntoa" HAVE_INET_NTOA)
 check_function_exists ("inet_ntop" HAVE_INET_NTOP)
 check_function_exists ("inet_pton" HAVE_INET_PTON)
-check_include_files (inttypes.h HAVE_INTTYPES_H)
-check_include_files (io.h HAVE_IO_H)
+check_include_files (inttypes.h HAVE_INTTYPES_H LANGUAGE CXX)
+check_include_files (io.h HAVE_IO_H LANGUAGE CXX)
 check_function_exists ("isdigit" HAVE_ISDIGIT)
-check_include_files (limits.h HAVE_LIMITS_H)
+check_include_files (limits.h HAVE_LIMITS_H LANGUAGE CXX)
 check_function_exists ("localtime_r" HAVE_LOCALTIME_R)
 check_function_exists ("malloc" HAVE_MALLOC)
-check_include_files (memory.h HAVE_MEMORY_H)
+check_include_files (memory.h HAVE_MEMORY_H LANGUAGE CXX)
 check_function_exists ("memset" HAVE_MEMSET)
-check_include_files (netdb.h HAVE_NETDB_H)
-check_include_files (netinet/in.h HAVE_NETINET_IN_H)
+check_include_files (netdb.h HAVE_NETDB_H LANGUAGE CXX)
+check_include_files (netinet/in.h HAVE_NETINET_IN_H LANGUAGE CXX)
 check_function_exists ("poll" HAVE_POLL)
-check_include_files (poll.h HAVE_POLL_H)
-check_include_files (process.h HAVE_PROCESS_H)
-check_include_files (pthread.h HAVE_PTHREAD) # :-(
+check_include_files (poll.h HAVE_POLL_H LANGUAGE CXX)
+check_include_files (process.h HAVE_PROCESS_H LANGUAGE CXX)
+check_include_files (pthread.h HAVE_PTHREAD LANGUAGE CXX) # :-(
 check_function_exists ("realloc" HAVE_REALLOC)
 check_function_exists ("select" HAVE_SELECT)
-check_include_files (signal.h HAVE_SIGNAL_H)
+check_include_files (signal.h HAVE_SIGNAL_H LANGUAGE CXX)
 check_function_exists ("socket" HAVE_SOCKET)
-check_include_files (stdint.h HAVE_STDINT_H)
-check_include_files (stdio.h HAVE_STDIO_H)
-check_include_files (stdlib.h HAVE_STDLIB_H)
+check_include_files (stdint.h HAVE_STDINT_H LANGUAGE CXX)
+check_include_files (stdio.h HAVE_STDIO_H LANGUAGE CXX)
+check_include_files (stdlib.h HAVE_STDLIB_H LANGUAGE CXX)
 check_function_exists ("strcasecmp" HAVE_STRCASECMP)
 check_function_exists ("strchr" HAVE_STRCHR)
 check_function_exists ("strerror" HAVE_STRERROR)
 check_function_exists ("stricmp" HAVE_STRICMP)
-check_include_files (strings.h HAVE_STRINGS_H)
-check_include_files (string.h HAVE_STRING_H)
+check_include_files (strings.h HAVE_STRINGS_H LANGUAGE CXX)
+check_include_files (string.h HAVE_STRING_H LANGUAGE CXX)
 check_function_exists ("strstr" HAVE_STRSTR)
-check_include_files (sys/param.h HAVE_SYS_PARAM_H)
-check_include_files (sys/select.h HAVE_SYS_SELECT_H)
-check_include_files (sys/socket.h HAVE_SYS_SOCKET_H)
-check_include_files (sys/stat.h HAVE_SYS_STAT_H)
-check_include_files (sys/timeb.h HAVE_SYS_TIMEB_H)
-check_include_files (sys/time.h HAVE_SYS_TIME_H)
-check_include_files (sys/types.h HAVE_SYS_TYPES_H)
-check_include_files (sys/unistd.h HAVE_SYS_UNISTD_H)
-check_include_files (time.h HAVE_TIME_H)
-check_include_files (unistd.h HAVE_UNISTD_H)
-check_include_files (winsock2.h HAVE_WINSOCK2_H)
-check_include_files (winsock.h HAVE_WINSOCK_H)
-check_include_files (ws2tcpip.h HAVE_WS2TCPIP_H)
-check_include_files (wspiapi.h HAVE_WSPIAPI_H)
+check_include_files (sys/param.h HAVE_SYS_PARAM_H LANGUAGE CXX)
+check_include_files (sys/select.h HAVE_SYS_SELECT_H LANGUAGE CXX)
+check_include_files (sys/socket.h HAVE_SYS_SOCKET_H LANGUAGE CXX)
+check_include_files (sys/stat.h HAVE_SYS_STAT_H LANGUAGE CXX)
+check_include_files (sys/timeb.h HAVE_SYS_TIMEB_H LANGUAGE CXX)
+check_include_files (sys/time.h HAVE_SYS_TIME_H LANGUAGE CXX)
+check_include_files (sys/types.h HAVE_SYS_TYPES_H LANGUAGE CXX)
+check_include_files (sys/unistd.h HAVE_SYS_UNISTD_H LANGUAGE CXX)
+check_include_files (time.h HAVE_TIME_H LANGUAGE CXX)
+check_include_files (unistd.h HAVE_UNISTD_H LANGUAGE CXX)
+check_include_files (winsock2.h HAVE_WINSOCK2_H LANGUAGE CXX)
+check_include_files (winsock.h HAVE_WINSOCK_H LANGUAGE CXX)
+check_include_files (ws2tcpip.h HAVE_WS2TCPIP_H LANGUAGE CXX)
+check_include_files (wspiapi.h HAVE_WSPIAPI_H LANGUAGE CXX)
 check_function_exists ("_getpid" HAVE__GETPID)
 
 check_type_size ("int64_t" SIZEOF_INT64_T LANGUAGE CXX)
@@ -357,8 +357,8 @@ if (NOT HAVE_SIZE_T)
 endif ()
 
 
-check_include_files (malloc.h HAVE_MALLOC_H)
-check_include_files ("sys/param.h;sys/mount.h" HAVE_SYS_MOUNT_H)
+check_include_files (malloc.h HAVE_MALLOC_H LANGUAGE CXX)
+check_include_files ("sys/param.h;sys/mount.h" HAVE_SYS_MOUNT_H LANGUAGE CXX)
 check_function_exists ("strcasecmp" HAVE_STRCASECMP)
 
 configure_file (${CMAKE_CURRENT_SOURCE_DIR}/cmake_config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/config.h)
@@ -510,8 +510,17 @@ add_library (snmp++_static STATIC
   ${MY_SRC_FILES}
 )
 
-install (TARGETS snmp++ DESTINATION lib)
-install (TARGETS snmp++_static DESTINATION lib)
+install (TARGETS snmp++ EXPORT snmp++Config DESTINATION lib)
+install (TARGETS snmp++_static EXPORT snmp++Config DESTINATION lib)
 install (FILES ${MY_HEADER_LIB_FILES} DESTINATION include)
 install (FILES ${MY_HEADER_FILES} DESTINATION include/snmp_pp)
 
+include(GNUInstallDirs)
+export(
+    TARGETS snmp++ snmp++_static
+    FILE "${CMAKE_CURRENT_BINARY_DIR}/snmp++Config.cmake"
+)
+install(
+    EXPORT snmp++Config
+    DESTINATION "${CMAKE_INSTALL_DATADIR}/snmp++/cmake"
+)