/
CMakeLists.txt
316 lines (265 loc) · 11.8 KB
/
CMakeLists.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
# 3.11 is required for basic FetchContent support.
cmake_minimum_required(VERSION 3.11)
# The launchdarkly/api.h header contains the SDK's version.
# See .ldrelease/update-version.sh for how it is updated during the release process.
# It is used here in order to set the project's package version.
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/include/launchdarkly/api.h" FILE_API_H)
string(REGEX MATCH "LD_SDK_VERSION \"(.*)\"\n\n" _ ${FILE_API_H})
if(NOT DEFINED CMAKE_MATCH_1)
message(FATAL_ERROR "LaunchDarkly - Unable to determine SDK version from <launchdarkly/api.h>")
endif()
project(ldserverapi
VERSION ${CMAKE_MATCH_1}
DESCRIPTION "LaunchDarkly C Server SDK"
)
message(STATUS "LaunchDarkly C Server SDK ${PROJECT_VERSION}")
# Contains various Find files, code coverage, 3rd party library FetchContent scripts,
# and the project's Package Configuration script.
set(CMAKE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
# Download 3rd party libraries.
include(FetchContent)
include(${CMAKE_FILES}/uthash.cmake)
include(${CMAKE_FILES}/hexify.cmake)
include(${CMAKE_FILES}/semver.cmake)
include(${CMAKE_FILES}/sha1.cmake)
include(${CMAKE_FILES}/timestamp.cmake)
# Provide user configurable options.
include(CMakeDependentOption)
option(BUILD_TESTING "Enable C++ unit tests." ON)
option(BUILD_TEST_SERVICE "Build the contract test service. Requires C++" OFF)
option(REDIS_STORE "Build optional redis store support" OFF)
option(COVERAGE "Add support for generating coverage reports" OFF)
option(SKIP_DATABASE_TESTS "Do not test external store integrations" OFF)
option(SKIP_BASE_INSTALL "Do not install the base library on install" OFF)
# Add an option for enabling the "CMake Project Tests" (see tests/cmake_projects README).
# These tests require testing to be enabled (BUILD_TESTING), but aren't unit tests, so are disabled by default.
cmake_dependent_option(ENABLE_CMAKE_PROJECT_TESTS
"Test integration of SDK into other CMake projects" OFF
"BUILD_TESTING" OFF
)
# Emit variables for informational/debugging purposes.
message(STATUS "LaunchDarkly - BUILD_TESTING: ${BUILD_TESTING}")
message(STATUS "LaunchDarkly - BUILD_TEST_SERVICE: ${BUILD_TEST_SERVICE}")
message(STATUS "LaunchDarkly - BUILD_SHARED_LIBS: ${BUILD_SHARED_LIBS}")
message(STATUS "LaunchDarkly - REDIS_STORE: ${REDIS_STORE}")
message(STATUS "LaunchDarkly - COVERAGE: ${COVERAGE}")
message(STATUS "LaunchDarkly - SKIP_DATABASE_TESTS: ${SKIP_DATABASE_TESTS}")
message(STATUS "LaunchDarkly - SKIP_BASE_INSTALL: ${SKIP_BASE_INSTALL}")
message(STATUS "LaunchDarkly - ENABLE_CMAKE_PROJECT_TESTS: ${ENABLE_CMAKE_PROJECT_TESTS}")
# The SDK uses two system packages, CURL and PCRE.
# Use the CMAKE_FILES directory to find these packages first - necessary because FindPCRE is provided
# with the SDK (while FindCURL is provided by CMake itself.)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_FILES}")
find_package(CURL REQUIRED)
find_package(PCRE REQUIRED)
set(CMAKE_THREAD_PREFER_PTHREAD ON)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
# Build the unit test binary, and add all of the unit tests.
include(CTest)
if(BUILD_TESTING)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
configure_file(external/googletest/CMakeLists.txt.in
${CMAKE_BINARY_DIR}/googletest-download/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download )
execute_process(COMMAND ${CMAKE_COMMAND} --build .
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download )
add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src
${CMAKE_BINARY_DIR}/googletest-build EXCLUDE_FROM_ALL)
enable_testing()
# Adds unit tests, and if enabled, cmake project tests.
add_subdirectory(tests)
endif()
# Enable code coverage.
if (COVERAGE)
include(${CMAKE_FILES}/CodeCoverage.cmake)
append_coverage_compiler_flags()
setup_target_for_coverage_gcovr_html(NAME coverage)
endif()
set(LD_INCLUDE_PATHS
"src"
"src/store"
"c-sdk-common/include"
"c-sdk-common/src"
${CURL_INCLUDE_DIR}
${PCRE_INCLUDE_DIR}
)
file(GLOB SOURCES "src/*" "src/store/*" "src/integrations/*" "third-party/src/*" "c-sdk-common/src/*")
if(NOT DEFINED MSVC)
list(REMOVE_ITEM SOURCES
"${CMAKE_CURRENT_SOURCE_DIR}/third-party/src/strptime.c"
)
endif()
# Define the main ldserverapi target.
# The 3rd party libs are included as object archives, so that static library users can include one
# artifact, rather than the ldserverapi + these dependencies individually.
add_library(ldserverapi
$<TARGET_OBJECTS:hexify>
$<TARGET_OBJECTS:semver>
$<TARGET_OBJECTS:sha1>
$<TARGET_OBJECTS:timestamp>
${SOURCES})
if(REDIS_STORE)
add_subdirectory(stores/redis)
endif()
# Allow linking against the target ldserverapi::ldserverapi when using find_package, or when
# using add_subdirectory.
add_library(ldserverapi::ldserverapi ALIAS ldserverapi)
target_link_libraries(ldserverapi
PRIVATE
uthash
hexify
semver
sha1
timestamp
Threads::Threads
${CURL_LIBRARIES}
${PCRE_LIBRARIES}
)
if(NOT WIN32 AND NOT APPLE)
# Required for fmod function definition, which is implemented in libm (the c math library.)
# This is part of the c standard library on macOS, and apparently not required on Windows.
target_link_libraries(ldserverapi PRIVATE m)
endif()
target_include_directories(ldserverapi
PUBLIC
# During the build phase, the SDK requires headers from the shared c-sdk-common subtree and the
# normal include directory.
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/c-sdk-common/include>
# Installed headers should all be lumped into a single include directory.
$<INSTALL_INTERFACE:include>
PRIVATE
${LD_INCLUDE_PATHS}
)
# Setup compiler definitions.
target_compile_definitions(ldserverapi
PRIVATE -D LAUNCHDARKLY_CONCURRENCY_ABORT
-D LAUNCHDARKLY_USE_ASSERT
-D LAUNCHDARKLY_DEFENSIVE
)
if(MSVC)
target_compile_definitions(ldserverapi
PRIVATE -D CURL_STATICLIB
-D PCRE_STATIC
-D _CRT_SECURE_NO_WARNINGS
)
else()
target_compile_definitions(ldserverapi
PRIVATE -D __USE_XOPEN
-D _GNU_SOURCE
)
target_compile_options(ldserverapi
PRIVATE -fno-omit-frame-pointer
-pedantic
-Wall
-Wextra
-Werror
-Wstrict-prototypes
-Wmissing-prototypes
-Wmissing-declarations
-std=c89
)
endif(MSVC)
if(BUILD_SHARED_LIBS)
set_property(TARGET ldserverapi PROPERTY C_VISIBILITY_PRESET hidden)
endif(BUILD_SHARED_LIBS)
if(NOT SKIP_BASE_INSTALL)
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
# All of these variables are defined relative to the build tree.
# Generally, the scheme used here is that files created in the build tree will be copied over to the install tree.
# This makes it simpler to support the add_subdirectory/find_package workflows in a unified manner.
set(LDSERVERSDK_CMAKE_CONFIG_DIR "${CMAKE_CURRENT_BINARY_DIR}")
# Path of the (to be created) cmake version configuration.
set(LDSERVERSDK_CMAKE_VERSION_CONFIG_FILE "${LDSERVERSDK_CMAKE_CONFIG_DIR}/${PROJECT_NAME}ConfigVersion.cmake")
# Path of the (to be copied/renamed) cmake package configuration.
# This file already exists in the project's cmake directory, but is copied here so the install steps are uniform.
set(LDSERVERSDK_CMAKE_PROJECT_CONFIG_FILE "${LDSERVERSDK_CMAKE_CONFIG_DIR}/${PROJECT_NAME}Config.cmake")
# Path of the (to be created) cmake targets configuration.
set(LDSERVERSDK_CMAKE_PROJECT_TARGETS_FILE "${LDSERVERSDK_CMAKE_CONFIG_DIR}/${PROJECT_NAME}Targets.cmake")
# Arbitrary name of the targets file, which serves to contain the ldserverapi target.
# This file allows other projects to import the target for convenient usage.
set(LDSERVERSDK_EXPORT_NAME "${PROJECT_NAME}-targets")
# Generate a version config for the SDK.
write_basic_package_version_file(${LDSERVERSDK_CMAKE_VERSION_CONFIG_FILE}
VERSION ${PACKAGE_VERSION}
COMPATIBILITY SameMajorVersion
)
# Copy over the cmake project config to the build tree. If this scheme is later changed to generate the config
# using a template, rather than including the source directly in the repo as is currently the case,
# the installation won't need to change.
configure_file(${CMAKE_FILES}/${PROJECT_NAME}Config.cmake
${LDSERVERSDK_CMAKE_PROJECT_CONFIG_FILE}
COPYONLY
)
# Instead of directly installing the library to a destination, associate it to an "export".
# The name of the export is arbitrary; it just needs to be consistent.
install(
TARGETS ${PROJECT_NAME}
EXPORT ${LDSERVERSDK_EXPORT_NAME}
# This line is only required for cmake < 3.14 support.
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
# Take the export and generate a new CMake file containing the targets contained within.
# This lives in the build tree, and MUST NOT BE INSTALLED, since paths are relative to the build tree,
# not the install tree.
export(EXPORT ${LDSERVERSDK_EXPORT_NAME}
FILE ${LDSERVERSDK_CMAKE_PROJECT_TARGETS_FILE} # <-- build tree
NAMESPACE ldserverapi::
)
# Do the same as the above, but for the install tree. This file will take the name
# <export-name>.cmake. This results in two different export files - one for the build tree (above)
# and one for the install tree (below.)
install(EXPORT ${LDSERVERSDK_EXPORT_NAME}
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ldserverapi
NAMESPACE ldserverapi::
FILE ${PROJECT_NAME}Targets.cmake
)
# Install SDK include directory.
install(
DIRECTORY include/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
FILES_MATCHING PATTERN "*.h*"
)
# Install c-sdk-common include directory.
install(
DIRECTORY c-sdk-common/include/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
FILES_MATCHING PATTERN "*.h*"
)
# Install the custom FindPCRE module, the project config, and the version config, all to the
# install tree's cmake/ldserverapi directory.
install(
FILES
${CMAKE_FILES}/FindPCRE.cmake
${LDSERVERSDK_CMAKE_PROJECT_CONFIG_FILE}
${LDSERVERSDK_CMAKE_VERSION_CONFIG_FILE}
DESTINATION
${CMAKE_INSTALL_LIBDIR}/cmake/ldserverapi
)
endif()
# test targets ----------------------------------------------------------------
if(BUILD_TESTING)
file(GLOB TEST_UTILS_SRC "test-utils/src/*" "c-sdk-common/test-utils/src/*")
add_library(test-utils STATIC ${TEST_UTILS_SRC})
target_link_libraries(test-utils PRIVATE ldserverapi )
target_include_directories(test-utils
PUBLIC
"test-utils/include"
"c-sdk-common/test-utils/include"
$<TARGET_PROPERTY:ldserverapi,INCLUDE_DIRECTORIES> # Some of the internal headers of ldserverapi
# include 3rd party dependencies, which are not part of the public interface of the SDK. Therefore
# any test code that imports these internal headers, for testing purposes, will need access to those
# 3rd party includes. The INCLUDE_DIRECTORIES property of target ldserverapi includes both the public
# and private headers, so propagate them here.
)
target_compile_definitions(test-utils
PRIVATE -D LAUNCHDARKLY_USE_ASSERT
-D LAUNCHDARKLY_CONCURRENCY_ABORT
)
endif()
if (BUILD_TEST_SERVICE)
add_subdirectory(contract-tests)
endif()