
上QQ阅读APP看书,第一时间看更新
How to do it
This is a C project and we will use the C99 standard. We will build the CMakeLists.txt file step by step:
- We declare a C project and enforce compliance with the C99 standard:
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(recipe-10 LANGUAGES C)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_EXTENSIONS OFF)
set(CMAKE_C_STANDARD_REQUIRED ON)
- We append the current source directory, CMAKE_CURRENT_SOURCE_DIR, to the list of paths where CMake will look for modules, CMAKE_MODULE_PATH. This is where our own FindZeroMQ.cmake module is located:
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR})
- We will discuss FindZeroMQ.cmake later, but now that the FindZeroMQ.cmake module is available, we search for the library. This is a required dependency for our project. Since we did not use the QUIET option to find_package, status messages will be printed automatically when the library is found:
find_package(ZeroMQ REQUIRED)
- We proceed to add the hwserver executable target. The include directories and link libraries are specified using the ZeroMQ_INCLUDE_DIRS and ZeroMQ_LIBRARIES variables set by the successful find_package command:
add_executable(hwserver hwserver.c)
target_include_directories(hwserver
PRIVATE
${ZeroMQ_INCLUDE_DIRS}
)
target_link_libraries(hwserver
PRIVATE
${ZeroMQ_LIBRARIES}
)
- Finally, we do the same for the hwclient executable target:
add_executable(hwclient hwclient.c)
target_include_directories(hwclient
PRIVATE
${ZeroMQ_INCLUDE_DIRS}
)
target_link_libraries(hwclient
PRIVATE
${ZeroMQ_LIBRARIES}
)
The main CMakeLists.txt for this recipe differs from the one used in the previous recipe in the use of the FindZeroMQ.cmake module. This module searches for the ZeroMQ header files and libraries using the find_path and find_library CMake built-in commands and sets relevant variables using the find_package_handle_standard_args, as we did in Recipe 3, Detecting Python modules and packages.
- In FindZeroMQ.cmake, we first check whether the ZeroMQ_ROOT CMake variable was set by the user. This variable can be used to guide detection of the ZeroMQ library to a non-standard installation directory. The user might have set ZeroMQ_ROOT as an environment variable and we also check for that:
if(NOT ZeroMQ_ROOT)
set(ZeroMQ_ROOT "$ENV{ZeroMQ_ROOT}")
endif()
- We then search for the location of the zmq.h header file on the system. This is based on the _ZeroMQ_ROOT variable and uses the find_path CMake command:
if(NOT ZeroMQ_ROOT)
find_path(_ZeroMQ_ROOT NAMES include/zmq.h)
else()
set(_ZeroMQ_ROOT "${ZeroMQ_ROOT}")
endif()
find_path(ZeroMQ_INCLUDE_DIRS NAMES zmq.h HINTS ${_ZeroMQ_ROOT}/include)
- If the header file was successfully found, ZeroMQ_INCLUDE_DIRS is set to its location. We proceed to find the version of the ZeroMQ library available, using string manipulations and regular expressions:
set(_ZeroMQ_H ${ZeroMQ_INCLUDE_DIRS}/zmq.h)
function(_zmqver_EXTRACT _ZeroMQ_VER_COMPONENT _ZeroMQ_VER_OUTPUT)
set(CMAKE_MATCH_1 "0")
set(_ZeroMQ_expr "^[ \\t]*#define[ \\t]+${_ZeroMQ_VER_COMPONENT}[ \\t]+([0-9]+)$")
file(STRINGS "${_ZeroMQ_H}" _ZeroMQ_ver REGEX "${_ZeroMQ_expr}")
string(REGEX MATCH "${_ZeroMQ_expr}" ZeroMQ_ver "${_ZeroMQ_ver}")
set(${_ZeroMQ_VER_OUTPUT} "${CMAKE_MATCH_1}" PARENT_SCOPE)
endfunction()
_zmqver_EXTRACT("ZMQ_VERSION_MAJOR" ZeroMQ_VERSION_MAJOR)
_zmqver_EXTRACT("ZMQ_VERSION_MINOR" ZeroMQ_VERSION_MINOR)
_zmqver_EXTRACT("ZMQ_VERSION_PATCH" ZeroMQ_VERSION_PATCH)
- We then prepare the ZeroMQ_VERSION variable for the find_package_handle_standard_args command:
if(ZeroMQ_FIND_VERSION_COUNT GREATER 2)
set(ZeroMQ_VERSION "${ZeroMQ_VERSION_MAJOR}.${ZeroMQ_VERSION_MINOR}.${ZeroMQ_VERSION_PATCH}")
else()
set(ZeroMQ_VERSION "${ZeroMQ_VERSION_MAJOR}.${ZeroMQ_VERSION_MINOR}")
endif()
- We use the find_library command to search for the ZeroMQ library. Here, we need to make a distinction between Unix-based and Windows platforms, since the naming conventions for libraries are different:
if(NOT ${CMAKE_C_PLATFORM_ID} STREQUAL "Windows")
find_library(ZeroMQ_LIBRARIES
NAMES
zmq
HINTS
${_ZeroMQ_ROOT}/lib
${_ZeroMQ_ROOT}/lib/x86_64-linux-gnu
)
else()
find_library(ZeroMQ_LIBRARIES
NAMES
libzmq
"libzmq-mt-${ZeroMQ_VERSION_MAJOR}_${ZeroMQ_VERSION_MINOR}_${ZeroMQ_VERSION_PATCH}"
"libzmq-${CMAKE_VS_PLATFORM_TOOLSET}-mt-${ZeroMQ_VERSION_MAJOR}_${ZeroMQ_VERSION_MINOR}_${ZeroMQ_VERSION_PATCH}"
libzmq_d
"libzmq-mt-gd-${ZeroMQ_VERSION_MAJOR}_${ZeroMQ_VERSION_MINOR}_${ZeroMQ_VERSION_PATCH}"
"libzmq-${CMAKE_VS_PLATFORM_TOOLSET}-mt-gd-${ZeroMQ_VERSION_MAJOR}_${ZeroMQ_VERSION_MINOR}_${ZeroMQ_VERSION_PATCH}"
HINTS
${_ZeroMQ_ROOT}/lib
)
endif()
- Finally, we include the standard FindPackageHandleStandardArgs.cmake module and invoke the corresponding CMake command. If all required variables are found and the version matches, then the ZeroMQ_FOUND variable is set to TRUE:
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(ZeroMQ
FOUND_VAR
ZeroMQ_FOUND
REQUIRED_VARS
ZeroMQ_INCLUDE_DIRS
ZeroMQ_LIBRARIES
VERSION_VAR
ZeroMQ_VERSION
)
The FindZeroMQ.cmake module we just described has been adapted from https://github.com/zeromq/azmq/blob/master/config/FindZeroMQ.cmake.