-
Notifications
You must be signed in to change notification settings - Fork 12
/
CMakeLists.txt
349 lines (297 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
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
cmake_minimum_required(VERSION 3.16.3)
file(READ "VERSION" _VERSION)
string(STRIP ${_VERSION} VERSION)
project(slog VERSION ${VERSION})
set(CMAKE_CXX_STANDARD 17)
if (NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE RelWithDebInfo)
endif()
configure_file("version.h.in" "version.h")
message(STATUS "Version: ${CMAKE_PROJECT_VERSION}")
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
#========================================
# Options
#========================================
option(BUILD_SLOG_CLIENT "Build the client" ON)
option(BUILD_SLOG_TESTS "Build the tests" ON)
option(ENABLE_TXN_EVENT_RECORDING "Enable transaction events recording" ON)
option(FETCH_DEPENDENCIES "Automatically fetch the dependencies" OFF)
set(REMASTER_PROTOCOL "COUNTERLESS" CACHE STRING "Protocol for remastering (\"SIMPLE\", \"PER_KEY\", \"COUNTERLESS\", \"NONE\")")
set(LOCK_MANAGER "RMA" CACHE STRING "Lock manager (\"OLD\", \"DDR\", \"RMA\")")
message(STATUS "Options:")
message(STATUS " BUILD_SLOG_CLIENT = ${BUILD_SLOG_CLIENT}")
message(STATUS " ENABLE_TXN_EVENT_RECORDING = ${ENABLE_TXN_EVENT_RECORDING}")
message(STATUS " REMASTER_PROTOCOL = ${REMASTER_PROTOCOL}")
message(STATUS " LOCK_MANAGER = ${LOCK_MANAGER}")
#========================================
# Dependencies
#========================================
set(DEPENDENCIES_DIR "${CMAKE_SOURCE_DIR}/.deps")
if (EXISTS "${DEPENDENCIES_DIR}" AND IS_DIRECTORY "${DEPENDENCIES_DIR}" AND NOT ${FETCH_DEPENDENCIES})
message(STATUS "Using dependencies from ${DEPENDENCIES_DIR}")
list(APPEND CMAKE_PREFIX_PATH ${DEPENDENCIES_DIR})
# gflags does not include this in its target so need to add manually
link_directories("${DEPENDENCIES_DIR}/lib")
set(GFLAGS_USE_TARGET_NAMESPACE TRUE)
find_package(gflags REQUIRED)
find_package(glog REQUIRED)
find_package(cppzmq REQUIRED)
find_package(RapidJSON REQUIRED)
add_library(rapidjson INTERFACE)
target_include_directories(rapidjson INTERFACE "${RAPIDJSON_INCLUDE_DIRS}")
else()
message(STATUS "Fetching dependencies")
include(FetchContent)
FetchContent_Declare(libzmq
GIT_REPOSITORY https://github.com/zeromq/libzmq.git
GIT_TAG v4.3.3
)
FetchContent_GetProperties(libzmq)
if(NOT libzmq_POPULATED)
message("Populating: ZeroMQ")
FetchContent_Populate(libzmq)
set(ZMQ_BUILD_TESTS OFF CACHE INTERNAL "Build tests for ZeroMQ" FORCE)
add_subdirectory(${libzmq_SOURCE_DIR} ${libzmq_BINARY_DIR})
endif()
FetchContent_Declare(cppzmq
GIT_REPOSITORY https://github.com/zeromq/cppzmq.git
GIT_TAG v4.7.1
)
FetchContent_GetProperties(cppzmq)
if(NOT cppzmq_POPULATED)
message("Populating: cppzmq")
FetchContent_Populate(cppzmq)
set(CPPZMQ_BUILD_TESTS OFF CACHE INTERNAL "Build tests for cppzmq" FORCE)
add_subdirectory(${cppzmq_SOURCE_DIR} ${cppzmq_BINARY_DIR})
endif()
FetchContent_Declare(gflags
GIT_REPOSITORY https://github.com/gflags/gflags.git
GIT_TAG v2.2.2
)
FetchContent_GetProperties(gflags)
if(NOT gflags_POPULATED)
message("Populating: gflags")
FetchContent_Populate(gflags)
set(GFLAGS_BUILD_TESTING OFF CACHE INTERNAL "Build tests")
# Needed to work with glog
set(GFLAGS_NAMESPACE "google" CACHE INTERNAL "Set namespace for gflags")
add_subdirectory(${gflags_SOURCE_DIR} ${gflags_BINARY_DIR})
endif()
FetchContent_Declare(glog
GIT_REPOSITORY https://github.com/google/glog.git
GIT_TAG v0.4.0
)
FetchContent_GetProperties(glog)
if(NOT glog_POPULATED)
message("Populating: glog")
FetchContent_Populate(glog)
set(WITH_GFLAGS FALSE CACHE INTERNAL "Build glog with gflags")
set(BUILD_TESTING FALSE CACHE INTERNAL "Build tests")
add_subdirectory(${glog_SOURCE_DIR} ${glog_BINARY_DIR})
endif()
FetchContent_Declare(rapidjson
GIT_REPOSITORY https://github.com/Tencent/rapidjson
GIT_TAG v1.1.0
GIT_SHALLOW TRUE
)
FetchContent_GetProperties(rapidjson)
if (NOT rapidjson_POPULATED)
message("Populating: rapidjson")
FetchContent_Populate(rapidjson)
add_library(rapidjson INTERFACE)
target_include_directories(rapidjson INTERFACE "${rapidjson_SOURCE_DIR}/include")
endif()
FetchContent_Declare(protobuf
GIT_REPOSITORY https://github.com/protocolbuffers/protobuf.git
GIT_TAG v3.14.0
)
FetchContent_GetProperties(protobuf)
if (NOT protobuf_POPULATED)
message("Populating: protobuf")
FetchContent_Populate(protobuf)
set(protobuf_BUILD_TESTS OFF CACHE INTERNAL "Build protobuf tests" FORCE)
add_subdirectory(${protobuf_SOURCE_DIR}/cmake ${protobuf_BINARY_DIR})
endif()
endif()
#========================================
# Protobuf
#========================================
# Call this so that we can use protobuf_generate_cpp and protobuf_generate_python
# Other results are discarded
set(Protobuf_USE_STATIC_LIBS ON)
find_package(Protobuf QUIET)
# Generating code from protobuf files is done here instead of in a CMakeLists.txt
# in the 'proto' directory because, otherwise, we cannot do absolute import in the
# .proto files as well as in Python.
# Turn this off so that "protobuf_generate_cpp" won't append directory
# of each .proto file to the protobuf include path, which should contain only
# the project root directory. The reason is that protoc uses the longest path
# to match with the prefix of each file name, generating relative import instead
# of absolute import. For example, if the include path has:
# "slog/something/proto" and "slog/"
# The path "slog/something/proto/messageA.proto" will become "messageA.proto",
# because it is matched with "slog/something/proto". On the other hand, if only
# "slog/" is present, we get "something/proto/messageA.proto", which is absolute
# with respect to the project root "slog/"
set(PROTOBUF_GENERATE_CPP_APPEND_PATH OFF)
set(PROTO_PREFIX proto)
# Generate cpp code
protobuf_generate_cpp(PROTO_CPP_SRCS PROTO_CPP_HEADERS
${PROTO_PREFIX}/api.proto
${PROTO_PREFIX}/configuration.proto
${PROTO_PREFIX}/internal.proto
${PROTO_PREFIX}/offline_data.proto
${PROTO_PREFIX}/modules.proto
${PROTO_PREFIX}/transaction.proto)
add_library(proto ${PROTO_CPP_SRCS} ${PROTO_CPP_HEADERS})
target_include_directories(proto PUBLIC ${CMAKE_BINARY_DIR})
target_link_libraries(proto PUBLIC protobuf::libprotobuf)
# Generate python code
protobuf_generate_python(PROTO_PY_SRCS
${PROTO_PREFIX}/configuration.proto
${PROTO_PREFIX}/offline_data.proto
${PROTO_PREFIX}/modules.proto
${PROTO_PREFIX}/transaction.proto)
# Copy generated python code to the "tools" directory
set(PROTO_PY_DEST_DIR ${CMAKE_SOURCE_DIR}/tools)
set(PROTO_PY_DEST_SRCS "")
foreach(FULL_PATH ${PROTO_PY_SRCS})
# /base/path/relative/path/file_name.py => relative/path/file_name.py
file(
RELATIVE_PATH
RELATIVE_DIR_AND_FILE_NAME
${CMAKE_BINARY_DIR}
${FULL_PATH})
# relative/path/file_name.py => relative/path
get_filename_component(RELATIVE_DIR ${RELATIVE_DIR_AND_FILE_NAME} DIRECTORY)
set(PROTO_PY_DEST_SRC ${PROTO_PY_DEST_DIR}/${RELATIVE_DIR_AND_FILE_NAME})
add_custom_command(
OUTPUT ${PROTO_PY_DEST_SRC}
COMMAND mkdir -p ${PROTO_PY_DEST_DIR}/${RELATIVE_DIR} && cp ${FULL_PATH} ${PROTO_PY_DEST_SRC}
DEPENDS ${FULL_PATH}
)
list(APPEND PROTO_PY_DEST_SRCS ${PROTO_PY_DEST_SRC})
endforeach(FULL_PATH)
# Trigger the python code generation and copy commands
add_custom_target(proto_py ALL DEPENDS ${PROTO_PY_DEST_SRCS})
#========================================
# Build flags
#========================================
set(CMAKE_CXX_FLAGS "-Wall -Wextra")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
set(CMAKE_CXX_FLAGS_DEBUG "-g -fno-omit-frame-pointer")
set(CMAKE_CXX_FLAGS_ASAN "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address")
set(CMAKE_CXX_FLAGS_UBSAN "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=undefined")
set(CMAKE_CXX_FLAGS_TSAN "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=thread")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} ${CMAKE_CXX_FLAGS_DEBUG} -DNDEBUG")
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
#========================================
# Library
#========================================
set(SLOG_CORE_SRC_DIRS common connection data_structure execution module paxos storage workload)
add_library(slog-core STATIC "")
foreach (DIR ${SLOG_CORE_SRC_DIRS})
add_subdirectory(${DIR})
endforeach()
target_include_directories(slog-core PUBLIC ${CMAKE_SOURCE_DIR})
target_link_libraries(slog-core
PUBLIC
proto
glog::glog
cppzmq-static
rapidjson)
set(ENABLE_REMASTER TRUE)
string(TOUPPER ${REMASTER_PROTOCOL} REMASTER_PROTOCOL_)
string(TOUPPER ${LOCK_MANAGER} LOCK_MANAGER_)
if (REMASTER_PROTOCOL_ STREQUAL "SIMPLE")
if (NOT LOCK_MANAGER_ STREQUAL "OLD")
message(FATAL_ERROR "SIMPLE remaster protocol is only compatible with OLD lock manager")
endif()
target_compile_definitions(slog-core PUBLIC REMASTER_PROTOCOL_SIMPLE)
elseif (REMASTER_PROTOCOL_ STREQUAL "PER_KEY")
if (NOT LOCK_MANAGER_ STREQUAL "OLD")
message(FATAL_ERROR "PER_KEY remaster protocol is only compatible with OLD lock manager")
endif()
target_compile_definitions(slog-core PUBLIC REMASTER_PROTOCOL_PER_KEY)
elseif (REMASTER_PROTOCOL_ STREQUAL "COUNTERLESS")
if (LOCK_MANAGER_ STREQUAL "OLD")
message(FATAL_ERROR "COUNTERLESS remaster protocol is not compatible with OLD lock manager")
endif()
target_compile_definitions(slog-core PUBLIC REMASTER_PROTOCOL_COUNTERLESS)
elseif (REMASTER_PROTOCOL_ STREQUAL "NONE")
set(ENABLE_REMASTER FALSE)
else()
message(FATAL_ERROR "Invalid REMASTER_PROTOCOL. It must be one of: \"SIMPLE\", \"PER_KEY\", \"COUNTERLESS\", or \"NONE\"")
endif()
if (LOCK_MANAGER_ STREQUAL "OLD")
target_compile_definitions(slog-core PUBLIC LOCK_MANAGER_OLD)
elseif (LOCK_MANAGER_ STREQUAL "RMA")
target_compile_definitions(slog-core PUBLIC LOCK_MANAGER_RMA)
elseif (LOCK_MANAGER_ STREQUAL "DDR")
target_compile_definitions(slog-core PUBLIC LOCK_MANAGER_DDR)
else()
message(FATAL_ERROR "Invalid LOCK_MANAGER. It must be one of: \"OLD\", \"RMA\", or \"DDR\"")
endif()
if (ENABLE_REMASTER)
target_compile_definitions(slog-core PUBLIC ENABLE_REMASTER)
endif()
if (ENABLE_TXN_EVENT_RECORDING)
target_compile_definitions(slog-core PUBLIC ENABLE_TXN_EVENT_RECORDING)
endif()
#========================================
# Executables
#========================================
# Create an executable for each service
add_executable(slog service/slog.cpp service/service_utils.h)
target_link_libraries(slog PRIVATE slog-core gflags::gflags)
if (BUILD_SLOG_CLIENT)
add_executable(client service/client.cpp service/service_utils.h)
target_link_libraries(client
PRIVATE
slog-core
gflags::gflags
)
endif()
add_executable(benchmark service/benchmark.cpp service/service_utils.h)
target_link_libraries(benchmark
PRIVATE
slog-core
gflags::gflags
)
add_executable(scheduler_benchmark service/scheduler_benchmark.cpp)
target_link_libraries(scheduler_benchmark
PRIVATE
slog-core
gflags::gflags
)
#========================================
# Tests
#========================================
if (BUILD_SLOG_TESTS)
enable_testing()
add_subdirectory(test)
else()
message(STATUS "BUILD_SLOG_TESTS is off. No test will be built")
endif()
#========================================
# clang-format
#========================================
find_program(CLANG_FORMAT "clang-format")
if (CLANG_FORMAT)
set(ALL_SRC_FILES)
foreach (SRC_DIR ${SLOG_CORE_SRC_DIRS} service test)
file(GLOB_RECURSE SRC_FILES
${PROJECT_SOURCE_DIR}/${SRC_DIR}/*.cpp
${PROJECT_SOURCE_DIR}/${SRC_DIR}/*.h)
list(APPEND ALL_SRC_FILES ${SRC_FILES})
endforeach()
add_custom_target(
format
${CLANG_FORMAT}
-i
-style=file
${ALL_SRC_FILES}
)
else()
message(STATUS "Could not find clang-format")
endif()