From 780f1a4c8b194f19d52417ea8a6a1ca34e829e06 Mon Sep 17 00:00:00 2001 From: Morris Hafner Date: Tue, 23 Apr 2019 00:50:00 +0100 Subject: [PATCH] Added CMake build system --- CMakeLists.txt | 36 +++++++ README.md | 68 +++++++++++- cmake/CMakeLists.txt | 0 cmake/FindCppcoroCoroutines.cmake | 36 +++++++ cmake/cppcoroConfig.cmake | 6 ++ lib/CMakeLists.txt | 168 ++++++++++++++++++++++++++++++ test/CMakeLists.txt | 49 +++++++++ 7 files changed, 361 insertions(+), 2 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 cmake/CMakeLists.txt create mode 100644 cmake/FindCppcoroCoroutines.cmake create mode 100644 cmake/cppcoroConfig.cmake create mode 100644 lib/CMakeLists.txt create mode 100644 test/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..7d6f0139 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 3.13) +project(cppcoro LANGUAGES CXX) + +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") +include(CTest) + +add_subdirectory(lib) +if(BUILD_TESTING) + add_subdirectory(test) +endif() + +export(EXPORT cppcoroTargets + FILE "${PROJECT_BINARY_DIR}/cppcoro/cppcoroTargets.cmake" + NAMESPACE cppcoro::) +configure_file(cmake/cppcoroConfig.cmake + "${PROJECT_BINARY_DIR}/cppcoro/cppcoroConfig.cmake" + COPYONLY) + +set(config_package_location lib/cmake/cppcoro) +install(DIRECTORY include + DESTINATION . + COMPONENT Devel) +install(FILES cmake/FindCppcoroCoroutines.cmake + DESTINATION ${config_package_location} + COMPONENT Devel) +install(EXPORT cppcoroTargets + FILE cppcoroTargets.cmake + NAMESPACE cppcoro:: + DESTINATION ${config_package_location}) +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/cppcoro/cppcoroConfig.cmake + DESTINATION ${config_package_location} + COMPONENT Devel) diff --git a/README.md b/README.md index 51adb4ec..7ae78b64 100644 --- a/README.md +++ b/README.md @@ -2859,7 +2859,7 @@ Given a type, `S`, that implements the `DelayedScheduler` and an instance, `s` o The cppcoro library supports building under Windows with Visual Studio 2017 and Linux with Clang 5.0+. -This library makes use of the [Cake build system](https://github.com/lewissbaker/cake) (no, not the [C# one](http://cakebuild.net/)). +This library makes use of either the [Cake build system](https://github.com/lewissbaker/cake) (no, not the [C# one](http://cakebuild.net/)) or CMake. The cake build system is checked out automatically as a git submodule so you don't need to download or install it separately. @@ -2867,10 +2867,12 @@ The cake build system is checked out automatically as a git submodule so you don This library currently requires Visual Studio 2017 or later and the Windows 10 SDK. -Support for Clang ([#3](https://github.com/lewissbaker/cppcoro/issues/3)) and Linux ([#15](https://github.com/lewissbaker/cppcoro/issues/15)) is planned. +Support for Linux ([#15](https://github.com/lewissbaker/cppcoro/issues/15)) is planned. ### Prerequisites +The CMakeLists requires version 3.13 or later. + The Cake build-system is implemented in Python and requires Python 2.7 to be installed. Ensure Python 2.7 interpreter is in your PATH and available as 'python'. @@ -2903,6 +2905,68 @@ c:\Code\cppcoro> git submodule update --init --recursive ### Building from the command-line +#### With CMake + +Cppcoro follows the usual CMake workflow with no custom options added. Notable [standard CMake options](https://cmake.org/cmake/help/latest/manual/cmake-variables.7.html): + +| Flag | Description | Default Value | +|----------------------|------------------------------|------------------------| +| BUILD_TESTING | Build the unit tests | ON | +| BUILD_SHARED_LIBS | Build as a shared library | OFF | +| CMAKE_BUILD_TYPE | Build as `Debug`/`Release` | | +| CMAKE_INSTALL_PREFIX | Where to install the library | `/usr/local` (on Unix) | + +CMake also respects the [conventional environment variables](https://cmake.org/cmake/help/latest/manual/cmake-env-variables.7.html): + +| Environment Variable | Description | +|----------------------|-------------------------------| +| CXX | Path to the C++ compiler | +| CXXFLAGS | C++ compiler flags to prepend | +| LDFLAGS | Linker flags to prepend | + +Example: + +```bash +cd +mkdir build +cd build +export CXX=clang++ +export CXXFLAGS="-stdlib=libc++ -march=native" +export LDFLAGS="-stdlib=libc++ -fuse-ld=lld -Wl,--gdb-index" +cmake .. [-GNinja] -DCMAKE_INSTALL_PREFIX=$HOME/.local -DBUILD_SHARED_LIBS=ON +ninja # or make -jN +ninja test # Run the tests +ninja install +``` + +The CMake build scripts will also install a `cppcoroConfig.cmake` file for consumers to use. +It will check at the consumer site that coroutines are indeed supported by the system and enable the appropriate compiler flag for Clang or MSVC, respectively. +Assuming cppcoro has been installed to `$HOME/.local` like in the example above it can be consumed like this: + +```cmake +find_package(cppcoro REQUIRED) +add_executable(app main.cpp) +target_link_libraries(app PRIVATE cppcoro::cppcoro) +``` + +```bash +$ cmake . -Dcppcoro_ROOT=$HOME/.local +# ... +-- Performing Test Coroutines_SUPPORTS_MS_FLAG +-- Performing Test Coroutines_SUPPORTS_MS_FLAG - Failed +-- Performing Test Coroutines_SUPPORTS_GNU_FLAG +-- Performing Test Coroutines_SUPPORTS_GNU_FLAG - Success +-- Looking for C++ include coroutine +-- Looking for C++ include coroutine - not found +-- Looking for C++ include experimental/coroutine +-- Looking for C++ include experimental/coroutine - found +-- Configuring done +-- Generating done +# ... +``` + +#### With Cake + To build from the command-line just run 'cake.bat' in the workspace root. eg. diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt new file mode 100644 index 00000000..e69de29b diff --git a/cmake/FindCppcoroCoroutines.cmake b/cmake/FindCppcoroCoroutines.cmake new file mode 100644 index 00000000..7f01ddb2 --- /dev/null +++ b/cmake/FindCppcoroCoroutines.cmake @@ -0,0 +1,36 @@ +include(CheckCXXCompilerFlag) +include(CheckIncludeFileCXX) +include(FindPackageHandleStandardArgs) + +check_cxx_compiler_flag(/await Coroutines_SUPPORTS_MS_FLAG) +check_cxx_compiler_flag(-fcoroutines-ts Coroutines_SUPPORTS_GNU_FLAG) +if(Coroutines_SUPPORTS_MS_FLAG OR Coroutines_SUPPORTS_GNU_FLAG) + set(Coroutines_COMPILER_SUPPORT ON) +endif() + +if(Coroutines_SUPPORTS_MS_FLAG) + check_include_file_cxx("coroutine" Coroutines_STANDARD_LIBRARY_SUPPORT "/await") + check_include_file_cxx("experimental/coroutine" Coroutines_EXPERIMENTAL_LIBRARY_SUPPORT "/await") +elseif(Coroutines_SUPPORTS_GNU_FLAG) + check_include_file_cxx("coroutine" Coroutines_STANDARD_LIBRARY_SUPPORT "-fcoroutines-ts") + check_include_file_cxx("experimental/coroutine" Coroutines_EXPERIMENTAL_LIBRARY_SUPPORT "-fcoroutines-ts") +endif() + +if(Coroutines_EXPERIMENTAL_LIBRARY_SUPPORT OR Coroutines_STANDARD_LIBRARY_SUPPORT) + set(Coroutines_LIBRARY_SUPPORT ON) +endif() + +find_package_handle_standard_args(CppcoroCoroutines + REQUIRED_VARS Coroutines_LIBRARY_SUPPORT Coroutines_COMPILER_SUPPORT + FAIL_MESSAGE "Verify that the compiler and the standard library both support the Coroutines TS") + +if(NOT CppcoroCoroutines_FOUND OR TARGET cppcoro::coroutines) + return() +endif() + +add_library(cppcoro::coroutines INTERFACE IMPORTED) +if(Coroutines_SUPPORTS_MS_FLAG) + target_compile_options(cppcoro::coroutines INTERFACE /await) +elseif(Coroutines_SUPPORTS_GNU_FLAG) + target_compile_options(cppcoro::coroutines INTERFACE -fcoroutines-ts) +endif() diff --git a/cmake/cppcoroConfig.cmake b/cmake/cppcoroConfig.cmake new file mode 100644 index 00000000..b2c01e83 --- /dev/null +++ b/cmake/cppcoroConfig.cmake @@ -0,0 +1,6 @@ +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) + +include(CMakeFindDependencyMacro) +find_dependency(CppcoroCoroutines QUIET REQUIRED) + +include("${CMAKE_CURRENT_LIST_DIR}/cppcoroTargets.cmake") diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100644 index 00000000..afde4e0a --- /dev/null +++ b/lib/CMakeLists.txt @@ -0,0 +1,168 @@ +set(includes + awaitable_traits.hpp + is_awaitable.hpp + async_auto_reset_event.hpp + async_manual_reset_event.hpp + async_generator.hpp + async_mutex.hpp + async_latch.hpp + async_scope.hpp + broken_promise.hpp + cancellation_registration.hpp + cancellation_source.hpp + cancellation_token.hpp + task.hpp + sequence_barrier.hpp + sequence_traits.hpp + single_producer_sequencer.hpp + multi_producer_sequencer.hpp + shared_task.hpp + shared_task.hpp + single_consumer_event.hpp + single_consumer_async_auto_reset_event.hpp + sync_wait.hpp + task.hpp + io_service.hpp + config.hpp + on_scope_exit.hpp + file_share_mode.hpp + file_open_mode.hpp + file_buffering_mode.hpp + file.hpp + fmap.hpp + when_all.hpp + when_all_ready.hpp + resume_on.hpp + schedule_on.hpp + generator.hpp + readable_file.hpp + recursive_generator.hpp + writable_file.hpp + read_only_file.hpp + write_only_file.hpp + read_write_file.hpp + file_read_operation.hpp + file_write_operation.hpp + static_thread_pool.hpp +) +list(TRANSFORM includes PREPEND "${PROJECT_SOURCE_DIR}/include/cppcoro/") + +set(netIncludes + ip_address.hpp + ip_endpoint.hpp + ipv4_address.hpp + ipv4_endpoint.hpp + ipv6_address.hpp + ipv6_endpoint.hpp + socket.hpp +) +list(TRANSFORM netIncludes PREPEND "${PROJECT_SOURCE_DIR}/include/cppcoro/net/") + +set(detailIncludes + void_value.hpp + when_all_ready_awaitable.hpp + when_all_counter.hpp + when_all_task.hpp + get_awaiter.hpp + is_awaiter.hpp + any.hpp + sync_wait_task.hpp + unwrap_reference.hpp + lightweight_manual_reset_event.hpp +) +list(TRANSFORM detailIncludes PREPEND "${PROJECT_SOURCE_DIR}/include/cppcoro/detail/") + +set(privateHeaders + cancellation_state.hpp + socket_helpers.hpp + auto_reset_event.hpp + spin_wait.hpp + spin_mutex.hpp +) + +set(sources + async_auto_reset_event.cpp + async_manual_reset_event.cpp + async_mutex.cpp + cancellation_state.cpp + cancellation_token.cpp + cancellation_source.cpp + cancellation_registration.cpp + lightweight_manual_reset_event.cpp + ip_address.cpp + ip_endpoint.cpp + ipv4_address.cpp + ipv4_endpoint.cpp + ipv6_address.cpp + ipv6_endpoint.cpp + static_thread_pool.cpp + auto_reset_event.cpp + spin_wait.cpp + spin_mutex.cpp +) + +if(WIN32) + set(win32DetailIncludes + win32.hpp + win32_overlapped_operation.hpp + ) + list(TRANSFORM win32DetailIncludes PREPEND "${PROJECT_SOURCE_DIR}/include/cppcoro/detail/") + list(APPEND detailIncludes ${win32DetailIncludes}) + + set(win32NetIncludes + socket.hpp + socket_accept_operation.hpp + socket_connect_operation.hpp + socket_disconnect_operation.hpp + socket_recv_operation.hpp + socket_recv_from_operation.hpp + socket_send_operation.hpp + socket_send_to_operation.hpp + ) + list(TRANSFORM win32NetIncludes PREPEND "${PROJECT_SOURCE_DIR}/include/cppcoro/net/") + list(APPEND netIncludes ${win32NetIncludes}) + + set(win32Sources + win32.cpp + io_service.cpp + file.cpp + readable_file.cpp + writable_file.cpp + read_only_file.cpp + write_only_file.cpp + read_write_file.cpp + file_read_operation.cpp + file_write_operation.cpp + socket_helpers.cpp + socket.cpp + socket_accept_operation.cpp + socket_connect_operation.cpp + socket_disconnect_operation.cpp + socket_send_operation.cpp + socket_send_to_operation.cpp + socket_recv_operation.cpp + socket_recv_from_operation.cpp + ) + list(APPEND sources ${win32Sources}) +endif() + +add_library(cppcoro + ${includes} + ${netIncludes} + ${detailIncludes} + ${privateHeaders} + ${sources} +) + +target_include_directories(cppcoro PUBLIC + $ + $) +target_compile_features(cppcoro PUBLIC cxx_std_20) + +find_package(CppcoroCoroutines REQUIRED) +target_link_libraries(cppcoro PUBLIC cppcoro::coroutines) + +install(TARGETS cppcoro EXPORT cppcoroTargets + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + RUNTIME DESTINATION bin) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 00000000..0a603000 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,49 @@ +add_library(doctest::doctest INTERFACE IMPORTED) +target_include_directories(doctest::doctest INTERFACE doctest) + +find_package(Threads REQUIRED) + +add_executable(run + counted.hpp + io_service_fixture.hpp + + main.cpp + counted.cpp + generator_tests.cpp + recursive_generator_tests.cpp + async_generator_tests.cpp + async_auto_reset_event_tests.cpp + async_manual_reset_event_tests.cpp + async_mutex_tests.cpp + async_latch_tests.cpp + cancellation_token_tests.cpp + task_tests.cpp + sequence_barrier_tests.cpp + shared_task_tests.cpp + sync_wait_tests.cpp + single_consumer_async_auto_reset_event_tests.cpp + single_producer_sequencer_tests.cpp + multi_producer_sequencer_tests.cpp + when_all_tests.cpp + when_all_ready_tests.cpp + ip_address_tests.cpp + ip_endpoint_tests.cpp + ipv4_address_tests.cpp + ipv4_endpoint_tests.cpp + ipv6_address_tests.cpp + ipv6_endpoint_tests.cpp + static_thread_pool_tests.cpp +) + +if(WIN32) + target_sources(run PRIVATE + scheduling_operator_tests.cpp + io_service_tests.cpp + file_tests.cpp + socket_tests.cpp + ) +endif() + +target_link_libraries(run PRIVATE cppcoro Threads::Threads) + +add_test(NAME test COMMAND run)