diff --git a/.gitignore b/.gitignore index 6fb4a73b..566f81e0 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,12 @@ /smoketest*.conf /smoketeststorage /storage +.idea +cmake_install.cmake +CMakeCache.txt +*.cbp +Makefile +*.pb.cc +*.pb.h +*_pb2.py +CMakeFiles \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..018c8d95 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,484 @@ +cmake_minimum_required (VERSION 2.8) +project (logcabin) +set (LOGCABIN_VERSION_MAJOR 1) +set (LOGCABIN_VERSION_MINOR 2) + +include_directories(BEFORE .) +include_directories(BEFORE ./include) +include_directories(BEFORE ./build) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-overflow -fPIC") + +# TODO: accept user input +set(CMAKE_PROTO_CXX_FLAGS " ") +set(CMAKE_GTEST_CXX_FLAGS " ") + +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -DDEBUG") +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2 -DNDEBUG") + +file(MAKE_DIRECTORY build) + +cmake_policy(SET CMP0015 NEW) +link_directories(build) + +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build) + +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + + ## clang will always use c++11 as std + set(CPP_STD c++11) + + set (FLAG_LIST + -Wno-c++98-compat-pedantic + -Wno-covered-switch-default + -Wno-deprecated + -Wno-disabled-macro-expansion + -Wno-documentation-unknown-command + -Wno-exit-time-destructors + -Wno-float-equal + -Wno-global-constructors + -Wno-gnu-zero-variadic-macro-arguments + -Wno-missing-noreturn + -Wno-missing-prototypes + -Wno-missing-variable-declarations + -Wno-packed + -Wno-padded + -Wno-reserved-id-macro + -Wno-shadow + -Wno-shift-sign-overflow + -Wno-switch-enum + -Wno-undef + -Wno-unknown-warning-option + -Wno-unused-macros + -Wno-unused-member-function + -Wno-unused-parameter + -Wno-used-but-marked-unused + -Wno-vla + -Wno-vla-extension + -Wno-weak-vtables + -Weverything + -Wno-unreachable-code ## clang 3.4 is knon to emit warnings without -Wno-unreachable-code, I will move this out when I have idea to get compiler version + ) + foreach(FLAG in ${FLAG_LIST}) + set(CMAKE_LOGCABIN_CXX_FLAGS "${LOGCABIN_CXX_FLAGS} ${FLAG}" ) + endforeach() +elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + + ## detect gcc version to decide wich c std should we use + execute_process( + COMMAND ${CMAKE_CXX_COMPILER} -v + OUTPUT_VARIABLE COMPILER_VERSION_OUTPUT + ERROR_VARIABLE COMPILER_VERSION_ERROR + ) + + string(REGEX MATCH "gcc version ([0-9]+)\\.([0-9]+)\\.([0-9]+)" + GCC_COMPILER_VERSION "${COMPILER_VERSION_ERROR} ${COMPILER_VERSION_OUTPUT}") + STRING(REPLACE "gcc version " "" GCC_VERSION_NUMBER ${GCC_COMPILER_VERSION}) + if(${GCC_VERSION_NUMBER} VERSION_LESS "4.7.0") + set(CPP_STD c++0x) + else() + set(CPP_STD c++11) + endif() + + ## gcc std setting end + + set(FLAG_LIST + -Wall + -Wextra + -Wcast-align + -Wcast-qual + -Wconversion + -Weffc++ + -Wformat=2 + -Wmissing-format-attribute + -Wno-non-template-friend + -Wno-unused-parameter + -Woverloaded-virtual + -Wwrite-strings + -DSWIG # For some unknown reason, this suppresses some definitions + # in headers generated by protobuf 2.6 (but not 2.5) that we + # don't use and that cause warnings with -Weffc++. + ) + foreach(FLAG ${FLAG_LIST}) + set(CMAKE_LOGCABIN_CXX_FLAGS "${LOGCABIN_CXX_FLAGS} ${FLAG}" ) + endforeach() +endif() + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=${CPP_STD}") + +## here starts the src list +# add core dir +set(CORE_SRC + Core/Buffer.cc + Core/Checksum.cc + Core/ConditionVariable.cc + Core/Config.cc + Core/Debug.cc + Core/ProtoBuf.cc + Core/Random.cc + Core/RollingStat.cc + Core/ThreadId.cc + Core/Time.cc + Core/StringUtil.cc + Core/Util.cc +) + +set(CORE_PROTO + Core/ProtoBufTest.proto + ) + +set(CORE_PROTO_SRC + build/Core/ProtoBufTest.pb.cc + ) + +# add client dir +set(CLIENT_SRC + Client/Backoff.cc + Client/Client.cc + Client/ClientImpl.cc + Client/LeaderRPC.cc + Client/MockClientImpl.cc + Client/SessionManager.cc + Client/Util.cc + ) + +set(PROTOCOL_PROTO + Protocol/Client.proto + Protocol/Raft.proto + Protocol/RaftLogMetadata.proto + Protocol/ServerStats.proto + Protocol/ServerControl.proto + ) + +set(PROTOCOL_SRC + build/Protocol/Client.pb.cc + build/Protocol/Raft.pb.cc + build/Protocol/RaftLogMetadata.pb.cc + build/Protocol/ServerStats.pb.cc + build/Protocol/ServerControl.pb.cc + ) + +set(SERVER_PROTO + Server/SnapshotStats.proto + Server/SnapshotMetadata.proto + Server/SnapshotStateMachine.proto + ) + +set(SERVER_PROTO_FOR_STORAGE_TOOL_SRC + build/Server/SnapshotMetadata.pb.cc + build/Server/SnapshotStateMachine.pb.cc + ) + +set(SERVER_PROTO_SRC + build/Server/SnapshotStats.pb.cc + ${SERVER_PROTO_FOR_STORAGE_TOOL_SRC} + ) + +set(STORAGE_PROTO + Storage/SegmentedLog.proto + Storage/SimpleFileLog.proto + ) + +set(STORAGE_PROTO_SRC + build/Storage/SegmentedLog.pb.cc + build/Storage/SimpleFileLog.pb.cc + ) + +set(TREE_PROTO + Tree/Snapshot.proto + ) +set(TREE_PROTO_SRC + build/Tree/Snapshot.pb.cc + ) + +set(RPC_SRC + RPC/Address.cc + RPC/ClientRPC.cc + RPC/ClientSession.cc + RPC/MessageSocket.cc + RPC/OpaqueClientRPC.cc + RPC/OpaqueServer.cc + RPC/OpaqueServerRPC.cc + RPC/Protocol.cc + RPC/Server.cc + RPC/ServerRPC.cc + RPC/ThreadDispatchService.cc + ) + +set(EVENT_SRC + Event/File.cc + Event/Loop.cc + Event/Signal.cc + Event/Timer.cc + ) + +set(SERVER_SRC + Server/ClientService.cc + Server/ControlService.cc + Server/Globals.cc + Server/RaftConsensus.cc + Server/RaftConsensusInvariants.cc + Server/RaftService.cc + Server/ServerStats.cc + Server/StateMachine.cc + ) + +set(STORAGE_SRC + Storage/FilesystemUtil.cc + Storage/Layout.cc + Storage/Log.cc + Storage/LogFactory.cc + Storage/MemoryLog.cc + Storage/SegmentedLog.cc + Storage/SimpleFileLog.cc + Storage/SnapshotFile.cc + ) + +set(TREE_SRC + Tree/ProtoBuf.cc + Tree/Tree.cc + ) + +#src list is end + +## search for test and mock files +file(GLOB TEST_FILES + ./Core/*Test.cc + ./Event/*Test.cc + ./RPC/*Test.cc + ./Protocol/*Test.cc + ./Tree/*Test.cc + ./Client/*Test.cc + ./Storage/*Test.cc + ./Server/*Test.cc + ) +file(GLOB MOCK_FILES + ./Core/*Mock.cc + ./Event/*Mock.cc + ./RPC/*Mock.cc + ./Protocol/*Mock.cc + ./Tree/*Mock.cc + ./Client/*Mock.cc + ./Storage/*Mock.cc + ./Server/*Mock.cc + ) + +## search for example files +file(GLOB EXAMPLE_FILES + ./Examples/*.cc + ) + +# protoc generator + +macro(c_proto_buff INPUT_LIST OUTPUT_LIST) + list(LENGTH ${INPUT_LIST} LIST_SIZE) + math(EXPR MAX_INDEX ${LIST_SIZE}-1) + + ## get the first output to make the output dir + list(GET ${OUTPUT_LIST} 0 CUR_OUTPUT) + + ## create dir prefix + string(REGEX MATCH build/.*/ OUTPUT_PATH ${CUR_OUTPUT}) + file(MAKE_DIRECTORY ${OUTPUT_PATH}) + + foreach(INDEX RANGE 0 ${MAX_INDEX}-1) + list(GET ${INPUT_LIST} ${INDEX} CUR_INPUT) + list(GET ${OUTPUT_LIST} ${INDEX} CUR_OUTPUT) + + + add_custom_command( + OUTPUT ${CUR_OUTPUT} + COMMAND protoc -I. --cpp_out=. --python_out=. ./build/${CUR_INPUT} + DEPENDS ${CUR_INPUT} ${OUTPUT_PATH} copy_proto_files_to_build + ) + endforeach() + +endmacro(c_proto_buff) + +add_custom_target(copy_proto_files_to_build + ## This command will only works on linux, cp on macos doesn't provide --parents option + COMMAND pwd && cp --parents ${CORE_PROTO} ${PROTOCOL_PROTO} ${TREE_PROTO} ${SERVER_PROTO} ${STORAGE_PROTO} ./build + DEPENDS ${CORE_PROTO} ${PROTOCOL_PROTO} ${TREE_PROTO} ${SERVER_PROTO} ${STORAGE_PROTO} + ) + +c_proto_buff(CORE_PROTO CORE_PROTO_SRC) +c_proto_buff(PROTOCOL_PROTO PROTOCOL_SRC) +c_proto_buff(TREE_PROTO TREE_PROTO_SRC) +c_proto_buff(SERVER_PROTO SERVER_PROTO_SRC) +c_proto_buff(STORAGE_PROTO STORAGE_PROTO_SRC) + +## append compiler flags (and generate a object) + +# logcabin srcs +set_property( + SOURCE + Storage/Tool.cc + Server/Main.cc + ${CORE_SRC} + ${CLIENT_SRC} + ${EVENT_SRC} + ${RPC_SRC} + ${SERVER_SRC} + ${STORAGE_SRC} + ${TREE_SRC} + ${EXAMPLE_FILES} + APPEND_STRING + PROPERTY + COMPILE_FLAGS + " ${CMAKE_LOGCABIN_CXX_FLAGS}" + ) + +# protobuf flags +set_property( + SOURCE + ${CORE_PROTO_SRC} + ${PROTOCOL_SRC} + ${TREE_PROTO_SRC} + ${SERVER_PROTO_SRC} + ${STORAGE_PROTO_SRC} + APPEND_STRING + PROPERTY + COMPILE_FLAGS + " ${CMAKE_PROTO_CXX_FLAGS}" + ) + +set_property( + SOURCE + gtest/src/gtest-all.cc + test/TestRunner.cc + ${TEST_FILES} + ${MOCK_FILES} + APPEND_STRING + PROPERTY + COMPILE_FLAGS + # -fno-access-control allows tests to access private members + " ${CMAKE_GTEST_CXX_FLAGS} ${CMAKE_LOGCABIN_CXX_FLAGS} -fno-access-control" + ) + +##executable daemon +add_executable(LogCabin + Server/Main.cc + ) + +add_executable(ServerControl + Client/ServerControl.cc + ) + +add_library(logcabin STATIC + ${CLIENT_SRC} + ${TREE_SRC} + ${TREE_PROTO_SRC} + ${PROTOCOL_SRC} + ${RPC_SRC} + ${EVENT_SRC} + ${CORE_SRC} + ${CORE_PROTO_SRC} + ) + +add_library(ServerSrcObject STATIC + ${SERVER_SRC} + ${SERVER_PROTO_SRC} + ${PROTOCOL_SRC} + ) +#add_dependencies(ServerSrcObject ${PROTOCOL_SRC}) + +add_library(StorageSrcObject STATIC + ${STORAGE_PROTO_SRC} + ${STORAGE_SRC} + ${PROTOCOL_SRC} + ) +#add_dependencies(StorageSrcObject ${PROTOCOL_SRC}) + +add_executable(StorageTool + Storage/Tool.cc + ) + +add_custom_target(check + COMMAND scripts/cpplint.py + ) +add_custom_target(lint + COMMAND scripts/cpplint.py + ) +add_custom_target(docs + COMMAND doxygen docs/Doxyfile + ) +add_custom_target(tags + COMMAND ctags -R --exclude=build --exclude=docs --exclude=CMakeFiles . + ) + +# check library exists +function(check_lib_exist LIB_NAME) + set(PATH_VAR_NAME "${LIB_NAME}_PATH") + find_library(${PATH_VAR_NAME} NAMES ${LIB_NAME}) + if("${${PATH_VAR_NAME}}" STREQUAL "${PATH_VAR_NAME}-NOTFOUND") + ## sending warrning allows user to compile the lib without unnecessary dependency + message(WARNING "can not find library ${LIB_NAME}") + endif() +endfunction(check_lib_exist) + +check_lib_exist(pthread) +check_lib_exist(protobuf) +check_lib_exist(rt) +check_lib_exist(cryptopp) + +# collect all libs when they all exist +SET(LIBRARIES pthread protobuf rt cryptopp) + +target_link_libraries(LogCabin ServerSrcObject StorageSrcObject logcabin ${LIBRARIES}) +target_link_libraries(StorageTool ServerSrcObject StorageSrcObject logcabin ${LIBRARIES}) +target_link_libraries(ServerControl logcabin ${LIBRARIES}) + +## The following codes will build the examples +add_executable(Benchmark + Examples/Benchmark.cc + ) +target_link_libraries(Benchmark logcabin ${LIBRARIES}) + +add_executable(FailoverTest + Examples/FailoverTest.cc + ) +target_link_libraries(FailoverTest logcabin ${LIBRARIES}) + +add_executable(HelloWorld + Examples/HelloWorld.cc + ) +target_link_libraries(HelloWorld logcabin ${LIBRARIES}) + +add_executable(Reconfigure + Examples/Reconfigure.cc + ) +target_link_libraries(Reconfigure logcabin ${LIBRARIES}) + +add_executable(ReconfigureTest + Examples/ReconfigureTest.cc + ) +target_link_libraries(ReconfigureTest logcabin ${LIBRARIES}) + +add_executable(SmokeTest + Examples/SmokeTest.cc + ) +target_link_libraries(SmokeTest logcabin ${LIBRARIES}) + +add_executable(TreeOps + Examples/TreeOps.cc + ) +target_link_libraries(TreeOps logcabin ${LIBRARIES}) + +include_directories(BEFORE ./gtest) +include_directories(BEFORE ./gtest/include) + +add_executable(TestRunner + test/TestRunner.cc + gtest/src/gtest-all.cc + ${TEST_FILES} + ${MOCK_FILES} + ) +add_custom_command( + OUTPUT gtest/src/gtest-all.cc + COMMAND git submodule update --init --recursive + ) + +target_link_libraries(TestRunner ServerSrcObject StorageSrcObject logcabin ${LIBRARIES}) + diff --git a/docs/Doxyfile b/docs/Doxyfile index a041cf1f..69bd4dd1 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -797,7 +797,8 @@ RECURSIVE = YES EXCLUDE = gtest/ \ build/ \ docs/ \ - test/ + test/ \ + CMakeFiles/ # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded diff --git a/scripts/cpplint.py b/scripts/cpplint.py index 0eda091e..48556b6a 100755 --- a/scripts/cpplint.py +++ b/scripts/cpplint.py @@ -3140,7 +3140,7 @@ def process(filename): def main(): if len(sys.argv) == 1: def list_all(result, dirname, filenames): - if re.search('\./(gtest|build)(/|$)', dirname): + if re.search('\./(gtest|build|CMakeFiles)(/|$)', dirname): return result += [dirname + '/' + filename for filename in filenames] files = []