diff --git a/CMake/BoostTest.cmake b/CMake/BoostTest.cmake new file mode 100644 index 0000000..fda8ffb --- /dev/null +++ b/CMake/BoostTest.cmake @@ -0,0 +1,70 @@ +function(boost_test_discover_tests TARGET) + cmake_parse_arguments( + BOOST_TEST + "" + "WORKING_DIRECTORY;DISCOVERY_TIMEOUT" + "EXTRA_ARGS" + ${ARGN} + ) + if (NOT BOOST_TEST_WORKING_DIRECTORY) + set(BOOST_TEST_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + endif() + if (NOT BOOST_TEST_DISCOVERY_TIMEOUT) + set(BOOST_TEST_DISCOVERY_TIMEOUT 10) + endif() + get_property( + has_counter + TARGET ${TARGET} + PROPERTY BOOST_TEST_DISCOVERED_TEST_COUNTER + SET + ) + if(has_counter) + get_property( + counter + TARGET ${TARGET} + PROPERTY BOOST_TEST_DISCOVERED_TEST_COUNTER + ) + math(EXPR counter "${counter} + 1") + else() + set(counter 1) + endif() + set_property( + TARGET ${TARGET} + PROPERTY BOOST_TEST_DISCOVERED_TEST_COUNTER + ${counter} + ) + + # Define rule to generate test list for aforementioned test executable + set(ctest_file_base "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_${counter}") + set(ctest_include_file "${ctest_file_base}_include.cmake") + set(ctest_tests_file "${ctest_file_base}_tests.cmake") + add_custom_command( + TARGET ${TARGET} POST_BUILD + COMMAND "${CMAKE_COMMAND}" + -D "TEST_TARGET=${TARGET}" + -D "TEST_EXECUTABLE=$" + -D "TEST_WORKING_DIR=${BOOST_TEST_WORKING_DIRECTORY}" + -D "TEST_DISCOVERY_TIMEOUT=${BOOST_TEST_DISCOVERY_TIMEOUT}" + -D "CTEST_FILE=${ctest_tests_file}" + -P "${_BOOST_TEST_DISCOVER_TEST_SCRIPTS}" + VERBATIM + ) + + file(WRITE "${ctest_include_file}" + "if(EXISTS \"${ctest_tests_file}\")\n" + " include(\"${ctest_tests_file}\")\n" + "else()\n" + " add_test(${TARGET}_NOT_BUILT ${TARGET}_NOT_BUILT)\n" + "endif()\n" + ) + + # Add discovered tests to directory TEST_INCLUDE_FILES + set_property(DIRECTORY + APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}" + ) + +endfunction() + +set(_BOOST_TEST_DISCOVER_TEST_SCRIPTS + ${CMAKE_CURRENT_LIST_DIR}/BoostTestDiscoverTests.cmake +) diff --git a/CMake/BoostTestDiscoverTests.cmake b/CMake/BoostTestDiscoverTests.cmake new file mode 100644 index 0000000..b5d74bf --- /dev/null +++ b/CMake/BoostTestDiscoverTests.cmake @@ -0,0 +1,56 @@ +set(script) + +function(add_command NAME) + set(_args "") + foreach (_arg ${ARGN}) + set(_args "${_args} ${_arg}") + endforeach() + set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE) +endfunction() + +# List all available tests from executable +execute_process( + COMMAND "${TEST_EXECUTABLE}" -- --list_tests + WORKING_DIRECTORY "${TEST_WORKING_DIR}" + TIMEOUT "${TEST_DISCOVERY_TIMEOUT}" + OUTPUT_VARIABLE _boost_test_output + RESULT_VARIABLE _boost_test_result +) + +if (NOT ${_boost_test_result} EQUAL 0) + message(FATAL_ERROR + "Error listing test content from executable ${TEST_EXECUTABLE}.\n" + "Result: ${_boost_test_result}\n" + "Output:\n" + " ${_boost_test_output}" + ) +endif() + +string(REPLACE "\n" ";" _boost_test_output "${_boost_test_output}") + +# Parse output +foreach(line ${_boost_test_output}) + set(test ${line}) + set(pretty_test ${test}) + string(REGEX REPLACE "^MANUAL_" "" pretty_test "${pretty_test}") + add_command(add_test + "\"${pretty_test}\"" + "${TEST_EXECUTABLE}" + "\"--run_test=${line}\"" + ) + if (line MATCHES "^MANUAL_") + add_command(set_tests_properties + "${pretty_test}" + PROPERTIES DISABLED TRUE + ) + endif() + add_command(set_tests_properties + "\"${pretty_test}\"" + PROPERTIES + WORKING_DIRECTORY "${TEST_WORKING_DIR}" + LABELS "${TEST_TARGET}" + ) +endforeach() + +# Write CTest script +file(WRITE "${CTEST_FILE}" "${script}") diff --git a/CMakeLists.txt b/CMakeLists.txt index 6a31b08..7d2b305 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,22 @@ set(DISRUPTOR_VERSION "${DISRUPTOR_VERSION_MAJOR}.${DISRUPTOR_VERSION_MINOR}.${D enable_testing() +option(DISRUPTOR_BUILD_TESTS "Enable the build of tests and samples." OFF) +option(DISRUPTOR_BUILD_STATIC "Enable the build of the disruptor static library." ON) +option(DISRUPTOR_BUILD_SHARED "Enable the build of the disruptor static library." OFF) +option(DISRUPTOR_CONAN "Try to use conan to fetch dependencies." ON) + +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/CMake) + +if (DISRUPTOR_CONAN) + if (EXISTS ${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) + include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) + conan_basic_setup(TARGETS) + set(WITH_CONAN "conan") + message(STATUS "Using conan for dependencies.") + endif() +endif() + # enable gcc specific stuff if(CMAKE_COMPILER_IS_GNUCXX) set(COMPILER_FLAGS "-std=c++14") @@ -46,8 +62,12 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMPILER_FLAGS} ${WARNING_FLAGS}") add_subdirectory(Disruptor) if(DISRUPTOR_BUILD_TESTS) - add_subdirectory(googletest-release-1.8.0) - include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR}) + message(STATUS + "Building tests and samples." + ) + if (NOT WITH_CONAN) + add_subdirectory(googletest-release-1.8.0) + endif() add_subdirectory(Disruptor.PerfTests) add_subdirectory(Disruptor.TestTools) diff --git a/Disruptor.PerfTests/CMakeLists.txt b/Disruptor.PerfTests/CMakeLists.txt index 45586eb..e2f985a 100644 --- a/Disruptor.PerfTests/CMakeLists.txt +++ b/Disruptor.PerfTests/CMakeLists.txt @@ -1,16 +1,6 @@ project(Disruptor.PerfTests) cmake_minimum_required(VERSION 2.6) - -find_package(Boost COMPONENTS system thread date_time) -if(Boost_FOUND) - include_directories(${Boost_INCLUDE_DIRS}) - link_directories(${Boost_LIBRARY_DIRS}) -endif() - -include_directories("..") - - set(DisruptorPerfTests_sources main.cpp @@ -52,9 +42,13 @@ set(DisruptorPerfTests_sources ValueMutationEventHandler.cpp ) -add_definitions(-DBOOST_TEST_DYN_LINK) - add_executable(Disruptor.PerfTests ${DisruptorPerfTests_sources}) -target_link_libraries(Disruptor.PerfTests DisruptorStatic Disruptor.TestTools ${Boost_LIBRARIES} pthread) + +target_link_libraries(Disruptor.PerfTests + PRIVATE + Disruptor + Disruptor.TestTools + pthread +) add_custom_target(performance_test ${CMAKE_CURRENT_BINARY_DIR}/Disruptor.PerfTests) diff --git a/Disruptor.TestTools/BoostTestOptions.h b/Disruptor.TestTools/BoostTestOptions.h new file mode 100644 index 0000000..d322cc7 --- /dev/null +++ b/Disruptor.TestTools/BoostTestOptions.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include + +namespace Disruptor +{ +namespace Tests +{ + + static const boost::unit_test::label Manual("MANUAL"); + + struct BoostTestsListerVisitor : boost::unit_test::test_tree_visitor + { + void visit(const boost::unit_test::test_case& test) + { + static const auto& master = boost::unit_test::framework::master_test_suite(); + static const auto& masterName = master.p_name.get(); + + auto fullName = test.full_name(); + auto pos = fullName.find(masterName); + if (pos != std::string::npos) + fullName.erase(pos, masterName.length()); + + if (test.has_label("MANUAL")) + std::cout << "MANUAL_"; + std::cout << fullName << std::endl; + } + }; + + inline void addAdditionalCommandLineOptions() + { + int argc = boost::unit_test::framework::master_test_suite().argc; + for (int i = 0; i < argc; i++) + { + std::string argument(boost::unit_test::framework::master_test_suite().argv[i]); + if (argument == "--list_tests") + { + BoostTestsListerVisitor visitor; + boost::unit_test::traverse_test_tree(boost::unit_test::framework::master_test_suite(), visitor); + exit(0); + } + } + } + +} +} diff --git a/Disruptor.TestTools/CMakeLists.txt b/Disruptor.TestTools/CMakeLists.txt index 6d8105d..9da2853 100644 --- a/Disruptor.TestTools/CMakeLists.txt +++ b/Disruptor.TestTools/CMakeLists.txt @@ -1,16 +1,6 @@ project(Disruptor.TestTools) cmake_minimum_required(VERSION 2.6) - -find_package(Boost COMPONENTS system) -if(Boost_FOUND) - include_directories(${Boost_INCLUDE_DIRS}) - link_directories(${Boost_LIBRARY_DIRS}) -endif() - -include_directories("..") - - set(DisruptorTestTools_sources CountdownEvent.cpp @@ -22,3 +12,8 @@ set(DisruptorTestTools_sources ) add_library(Disruptor.TestTools STATIC ${DisruptorTestTools_sources}) + +target_link_libraries(Disruptor.TestTools + PUBLIC + Disruptor +) diff --git a/Disruptor.Tests/CMakeLists.txt b/Disruptor.Tests/CMakeLists.txt index 5d3ec82..46f6eae 100644 --- a/Disruptor.Tests/CMakeLists.txt +++ b/Disruptor.Tests/CMakeLists.txt @@ -1,13 +1,16 @@ project(Disruptor.Tests) cmake_minimum_required(VERSION 2.6) -find_package(Boost COMPONENTS system chrono thread unit_test_framework) -if(Boost_FOUND) - include_directories(${Boost_INCLUDE_DIRS}) - link_directories(${Boost_LIBRARY_DIRS}) -endif() +include (BoostTest) -ADD_DEFINITIONS(-DBOOST_TEST_DYN_LINK) +if (WITH_CONAN) + set(GMock_LIBRARY CONAN_PKG::gtest) + set(Boost_Libraries CONAN_PKG::boost) +else() + set(GMock_LIBRARY gtest gmock) + find_package(Boost COMPONENTS unit_test_framework REQUIRED) + set(Boost_Libraries Boost::unit_test_framwork) +endif() set(DisruptorTests_sources @@ -57,10 +60,12 @@ set(DisruptorTests_sources YieldingWaitStrategyTests.cpp ) -include_directories("..") - add_executable(Disruptor.Tests ${DisruptorTests_sources}) -target_link_libraries(Disruptor.Tests DisruptorStatic Disruptor.TestTools ${Boost_LIBRARIES} gmock) - -add_test(cmake_Disruptor.Tests ${CMAKE_CURRENT_BINARY_DIR}/Disruptor.Tests --result_code=no --report_level=no) +boost_test_discover_tests(Disruptor.Tests) +target_link_libraries(Disruptor.Tests + PRIVATE + Disruptor.TestTools + ${GMock_LIBRARY} + ${Boost_LIBRARIES} +) diff --git a/Disruptor.Tests/main.cpp b/Disruptor.Tests/main.cpp index bacc16a..ba2c312 100644 --- a/Disruptor.Tests/main.cpp +++ b/Disruptor.Tests/main.cpp @@ -6,6 +6,8 @@ #include +#include "Disruptor.TestTools/BoostTestOptions.h" + #if _MSC_VER # pragma warning (disable: 4231) // nonstandard extension used : 'extern' before template explicit instantiation #endif @@ -21,6 +23,9 @@ struct GlobalFixture testing::GTEST_FLAG(throw_on_failure) = true; testing::InitGoogleMock(&boost::unit_test::framework::master_test_suite().argc, boost::unit_test::framework::master_test_suite().argv); + + Disruptor::Tests::addAdditionalCommandLineOptions(); + } ~GlobalFixture() @@ -29,4 +34,3 @@ struct GlobalFixture }; BOOST_GLOBAL_FIXTURE(GlobalFixture); - diff --git a/Disruptor/CMakeLists.txt b/Disruptor/CMakeLists.txt index 6f9bc4f..789da10 100644 --- a/Disruptor/CMakeLists.txt +++ b/Disruptor/CMakeLists.txt @@ -1,15 +1,13 @@ project(Disruptor) cmake_minimum_required(VERSION 2.6) -find_package(Boost COMPONENTS system thread chrono) -if(Boost_FOUND) - include_directories(${Boost_INCLUDE_DIRS}) - link_directories(${Boost_LIBRARY_DIRS}) +if (WITH_CONAN) + set(Boost_Libraries CONAN_PKG::boost) +else() + find_package(Boost COMPONENTS system thread chrono REQUIRED) + set(Boost_Libraries Boost::boost Boost::system Boost::thread Boost::chrono) endif() -include_directories("..") - - set(Disruptor_sources BasicExecutor.cpp @@ -114,18 +112,59 @@ set(Disruptor_headers YieldingWaitStrategy.h ) -add_library(DisruptorShared SHARED ${Disruptor_sources}) -target_link_libraries(DisruptorShared ${Boost_LIBRARIES}) -set_target_properties(DisruptorShared PROPERTIES OUTPUT_NAME Disruptor) -set_target_properties(DisruptorShared PROPERTIES VERSION ${DISRUPTOR_VERSION}) -set_target_properties(DisruptorShared PROPERTIES SOVERSION ${DISRUPTOR_VERSION_MAJOR}) +get_filename_component(PARENT_DIR ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY) + +function(configure_disruptor_target DISRUPTOR_TARGET) + target_include_directories(${DISRUPTOR_TARGET} + PUBLIC + $ + $ + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ) + target_link_libraries(${DISRUPTOR_TARGET} PUBLIC ${Boost_Libraries}) +endfunction() + + +set(DISRUPTOR_TARGETS) + +if (DISRUPTOR_BUILD_SHARED) + message(STATUS + "Building Disruptor as a shared library." + ) + add_library(DisruptorShared SHARED ${Disruptor_sources}) + configure_disruptor_target(DisruptorShared) + + set_target_properties(DisruptorShared PROPERTIES OUTPUT_NAME Disruptor) + set_target_properties(DisruptorShared PROPERTIES VERSION ${DISRUPTOR_VERSION}) + set_target_properties(DisruptorShared PROPERTIES SOVERSION ${DISRUPTOR_VERSION_MAJOR}) -add_library(DisruptorStatic STATIC ${Disruptor_sources}) -set_target_properties(DisruptorStatic PROPERTIES OUTPUT_NAME Disruptor) + list(APPEND DISRUPTOR_TARGETS DisruptorShared) +endif() + +if (DISRUPTOR_BUILD_STATIC) + message(STATUS + "Building Disruptor as a static library." + ) + add_library(DisruptorStatic STATIC ${Disruptor_sources}) + configure_disruptor_target(DisruptorStatic) + + set_target_properties(DisruptorStatic PROPERTIES OUTPUT_NAME Disruptor) + + list(APPEND DISRUPTOR_TARGETS DisruptorStatic) +endif() + +if (DISRUPTOR_BUILD_SHARED AND DISRUPTOR_BUILD_STATIC) + add_library(Disruptor ALIAS DisruptorStatic) +elseif(DISRUPTOR_BUILD_SHARED) + add_library(Disruptor ALIAS DisruptorShared) +else() + add_library(Disruptor ALIAS DisruptorStatic) +endif() install(FILES ${Disruptor_headers} DESTINATION include/Disruptor) -install(TARGETS DisruptorShared DisruptorStatic +install(TARGETS ${DISRUPTOR_TARGETS} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib ) diff --git a/README.md b/README.md index 195e523..08b78ff 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,22 @@ make If [Boost](http://www.boost.org/) has been installed into a custom location you will probably need to specify **BOOST_ROOT** variable. Please refer to the [Find boost](https://cmake.org/cmake/help/v3.0/module/FindBoost.html) documentation for details. +If you want to install [Boost](http://www.boost.org/) and other dependencies through conan, run `conan install` inside your `build` directory prior to running `cmake`: + +```sh +mkdir build && cd build +conan install .. +cmake .. -DCMAKE_BUILD_TYPE=release +make +``` + +By default, Disruptor's `CMakeLists.txt` will try to use files generated by conan for CMake. If it does not exist, it will fall back to your standard boost installation. To disable conan, use the **DISRUPTOR_CONAN** +flag: + +```sh +cmake .. -DCMAKE_BUILD_TYPE=release -DDISRUPTOR_CONAN=OFF +``` + Optionally you may want to compile and run the unit tests and benchmarks. The tests compilation is activated by means of **DISRUPTOR_BUILD_TESTS** flag: ```sh diff --git a/conanfile.txt b/conanfile.txt new file mode 100644 index 0000000..6c69213 --- /dev/null +++ b/conanfile.txt @@ -0,0 +1,9 @@ +[requires] +boost/1.72.0 +gtest/1.8.0@bincrafters/stable + +[generators] +cmake + +[options] +gtest:build_gmock=True