From 6abe93fcc9e3a7d825d682cc9e3c38c5058e4bfc Mon Sep 17 00:00:00 2001 From: friendlyanon Date: Wed, 29 Nov 2023 00:48:21 +0100 Subject: [PATCH] Add CMake build and client support --- .gitignore | 4 ++ CMakeLists.txt | 47 +++++++++++++++++++++++ cmake/dev-mode.cmake | 4 ++ cmake/install-config.cmake | 4 ++ cmake/install-rules.cmake | 66 ++++++++++++++++++++++++++++++++ cmake/project-is-top-level.cmake | 6 +++ cmake/variables.cmake | 28 ++++++++++++++ example/CMakeLists.txt | 34 ++++++++++++++++ test/unit/CMakeLists.txt | 29 ++++++++++++++ test/unit/src/run_tests.cpp | 23 ++++++++--- vcpkg.json | 23 +++++++++++ 11 files changed, 263 insertions(+), 5 deletions(-) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 cmake/dev-mode.cmake create mode 100644 cmake/install-config.cmake create mode 100644 cmake/install-rules.cmake create mode 100644 cmake/project-is-top-level.cmake create mode 100644 cmake/variables.cmake create mode 100644 example/CMakeLists.txt create mode 100644 test/unit/CMakeLists.txt create mode 100644 vcpkg.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5aabcc6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.cache/ +build/ +prefix/ +CMakeUserPresets.json diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..d2a6bfb --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,47 @@ +cmake_minimum_required(VERSION 3.15) + +project(async-mqtt5 VERSION 0.0.1 LANGUAGES NONE) + +include(cmake/project-is-top-level.cmake) +include(cmake/variables.cmake) + +add_library(async_mqtt5 INTERFACE) +add_library(Async::MQTT5 ALIAS async_mqtt5) + +set_property( + TARGET async_mqtt5 PROPERTY + EXPORT_NAME MQTT5 +) + +target_include_directories( + async_mqtt5 ${warning_guard} + INTERFACE + "$" +) + +target_compile_features(async_mqtt5 INTERFACE cxx_std_20) + +find_package(Boost 1.82 REQUIRED) +target_link_libraries(async_mqtt5 INTERFACE Boost::headers) + +if(NOT CMAKE_SKIP_INSTALL_RULES) + include(cmake/install-rules.cmake) +endif() + +if(PROJECT_IS_TOP_LEVEL) + option(BUILD_EXAMPLES "Build examples tree." "${async-mqtt5_DEVELOPER_MODE}") + if(BUILD_EXAMPLES) + add_subdirectory(example) + endif() +endif() + +if(NOT async-mqtt5_DEVELOPER_MODE) + return() +elseif(NOT PROJECT_IS_TOP_LEVEL) + message( + AUTHOR_WARNING + "Developer mode is intended for developers of async-mqtt5" + ) +endif() + +include(cmake/dev-mode.cmake) diff --git a/cmake/dev-mode.cmake b/cmake/dev-mode.cmake new file mode 100644 index 0000000..a6e82a3 --- /dev/null +++ b/cmake/dev-mode.cmake @@ -0,0 +1,4 @@ +include(CTest) +if(BUILD_TESTING) + add_subdirectory(test/unit) +endif() diff --git a/cmake/install-config.cmake b/cmake/install-config.cmake new file mode 100644 index 0000000..cb60343 --- /dev/null +++ b/cmake/install-config.cmake @@ -0,0 +1,4 @@ +include(CMakeFindDependencyMacro) +find_dependency(Boost 1.82) + +include("${CMAKE_CURRENT_LIST_DIR}/async-mqtt5Targets.cmake") diff --git a/cmake/install-rules.cmake b/cmake/install-rules.cmake new file mode 100644 index 0000000..8f62a8f --- /dev/null +++ b/cmake/install-rules.cmake @@ -0,0 +1,66 @@ +if(PROJECT_IS_TOP_LEVEL) + set( + CMAKE_INSTALL_INCLUDEDIR "include/async-mqtt5-${PROJECT_VERSION}" + CACHE STRING "" + ) + set_property(CACHE CMAKE_INSTALL_INCLUDEDIR PROPERTY TYPE PATH) +endif() + +# Project is configured with no languages, so tell GNUInstallDirs the lib dir +set(CMAKE_INSTALL_LIBDIR lib CACHE PATH "") + +include(CMakePackageConfigHelpers) +include(GNUInstallDirs) + +# find_package() call for consumers to find this project +set(package async-mqtt5) + +install( + DIRECTORY include/ + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" + COMPONENT async-mqtt5_Development +) + +install( + TARGETS async_mqtt5 + EXPORT async-mqtt5Targets + INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" +) + +write_basic_package_version_file( + "${package}ConfigVersion.cmake" + COMPATIBILITY SameMajorVersion + ARCH_INDEPENDENT +) + +# Allow package maintainers to freely override the path for the configs +set( + async-mqtt5_INSTALL_CMAKEDIR "${CMAKE_INSTALL_DATADIR}/${package}" + CACHE STRING "CMake package config location relative to the install prefix" +) +set_property(CACHE async-mqtt5_INSTALL_CMAKEDIR PROPERTY TYPE PATH) +mark_as_advanced(async-mqtt5_INSTALL_CMAKEDIR) + +install( + FILES cmake/install-config.cmake + DESTINATION "${async-mqtt5_INSTALL_CMAKEDIR}" + RENAME "${package}Config.cmake" + COMPONENT async-mqtt5_Development +) + +install( + FILES "${PROJECT_BINARY_DIR}/${package}ConfigVersion.cmake" + DESTINATION "${async-mqtt5_INSTALL_CMAKEDIR}" + COMPONENT async-mqtt5_Development +) + +install( + EXPORT async-mqtt5Targets + NAMESPACE Async:: + DESTINATION "${async-mqtt5_INSTALL_CMAKEDIR}" + COMPONENT async-mqtt5_Development +) + +if(PROJECT_IS_TOP_LEVEL) + include(CPack) +endif() diff --git a/cmake/project-is-top-level.cmake b/cmake/project-is-top-level.cmake new file mode 100644 index 0000000..3435fc0 --- /dev/null +++ b/cmake/project-is-top-level.cmake @@ -0,0 +1,6 @@ +# This variable is set by project() in CMake 3.21+ +string( + COMPARE EQUAL + "${CMAKE_SOURCE_DIR}" "${PROJECT_SOURCE_DIR}" + PROJECT_IS_TOP_LEVEL +) diff --git a/cmake/variables.cmake b/cmake/variables.cmake new file mode 100644 index 0000000..016f258 --- /dev/null +++ b/cmake/variables.cmake @@ -0,0 +1,28 @@ +# ---- Developer mode ---- + +# Developer mode enables targets and code paths in the CMake scripts that are +# only relevant for the developer(s) of async-mqtt5 +# Targets necessary to build the project must be provided unconditionally, so +# consumers can trivially build and package the project +if(PROJECT_IS_TOP_LEVEL) + option(async-mqtt5_DEVELOPER_MODE "Enable developer mode" OFF) +endif() + +# ---- Warning guard ---- + +# target_include_directories with the SYSTEM modifier will request the compiler +# to omit warnings from the provided paths, if the compiler supports that +# This is to provide a user experience similar to find_package when +# add_subdirectory or FetchContent is used to consume this project +set(warning_guard "") +if(NOT PROJECT_IS_TOP_LEVEL) + option( + async-mqtt5_INCLUDES_WITH_SYSTEM + "Use SYSTEM modifier for async-mqtt5's includes, disabling warnings" + ON + ) + mark_as_advanced(async-mqtt5_INCLUDES_WITH_SYSTEM) + if(async-mqtt5_INCLUDES_WITH_SYSTEM) + set(warning_guard SYSTEM) + endif() +endif() diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt new file mode 100644 index 0000000..141fa4a --- /dev/null +++ b/example/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 3.15) + +project(async-mqtt5-examples CXX) + +include(../cmake/project-is-top-level.cmake) + +if(PROJECT_IS_TOP_LEVEL) + find_package(async_mqtt5 REQUIRED) +endif() + +function(add_example name) + add_executable("${name}" ${ARGN}) + target_compile_features("${name}" PRIVATE cxx_std_20) + target_link_libraries("${name}" PRIVATE Async::MQTT5) +endfunction() + +foreach(f callbacks cpp20_coroutines futures publisher receiver) + add_example("${f}" "${f}.cpp") +endforeach() + +#[[ +add_example( + misc + src/run_examples.cpp + network_connection.cpp + openssl-tls.cpp + tcp.cpp + websocket-tcp.cpp + websocket-tls.cpp +) + +find_package(OpenSSL REQUIRED) +target_link_libraries(misc PRIVATE OpenSSL::SSL) +]] diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt new file mode 100644 index 0000000..8358750 --- /dev/null +++ b/test/unit/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.15) + +project(async-mqtt5-tests CXX) + +include(../../cmake/project-is-top-level.cmake) + +if(PROJECT_IS_TOP_LEVEL) + find_package(async_mqtt5 REQUIRED) + enable_testing() +endif() + +add_executable( + mqtt-test + src/run_tests.cpp + test/cancellation.cpp + test/client_broker.cpp + test/coroutine.cpp + test/publish_send_op.cpp + test/serialization.cpp + test/session.cpp +) + +target_include_directories(mqtt-test PRIVATE include) +target_compile_features(mqtt-test PRIVATE cxx_std_20) + +find_package(Boost 1.82 REQUIRED unit_test_framework) +target_link_libraries(mqtt-test PRIVATE Async::MQTT5 Boost::unit_test_framework) + +add_test(NAME mqtt-test COMMAND mqtt-test) diff --git a/test/unit/src/run_tests.cpp b/test/unit/src/run_tests.cpp index 89e56b6..a55f782 100644 --- a/test/unit/src/run_tests.cpp +++ b/test/unit/src/run_tests.cpp @@ -1,17 +1,30 @@ -#include +#include #include -boost::unit_test::test_suite* init_tests( - int /*argc*/, char* /*argv*/[] -) { +namespace { + +void setup_mqtt() { async_mqtt5::test::logging_enabled() = true; - return nullptr; +} + +} + +#ifdef BOOST_TEST_DYN_LINK +static bool init_tests() { + setup_mqtt(); + return true; } int main(int argc, char* argv[]) { return boost::unit_test::unit_test_main(&init_tests, argc, argv); } +#else +boost::unit_test::test_suite* init_unit_test_suite(int, char** const) { + setup_mqtt(); + return nullptr; +} +#endif /* * usage: ./mqtt-test [boost test --arg=val]* diff --git a/vcpkg.json b/vcpkg.json new file mode 100644 index 0000000..0ca89b7 --- /dev/null +++ b/vcpkg.json @@ -0,0 +1,23 @@ +{ + "name": "async-mqtt5", + "version-semver": "0.0.1", + "dependencies": [ + "boost-asio", + "boost-beast", + "boost-spirit" + ], + "default-features": [], + "features": { + "test": { + "description": "Dependencies for testing and examples", + "dependencies": [ + "boost-test", + { + "name": "boost-asio", + "default-features": false, + "features": ["ssl"] + } + ] + } + } +}