Skip to content

CMake review #77

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jun 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
git \
graphviz \
lcov \
libclang-rt-18-dev \
lldb \
llvm \
nano \
Expand Down
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"HISTFILE",
"hwrap",
"lgcov",
"libclang",
"lldb",
"ltsan",
"lubsan",
Expand Down
9 changes: 3 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
cmake_minimum_required(VERSION 3.15)
project(cpp_channel)
set(PROJECT_VERSION 1.3.0)
project(cpp_channel VERSION 1.3.0)

set(CMAKE_CXX_STANDARD 11 CACHE STRING "C++ standard")
set(CMAKE_CXX_STANDARD_REQUIRED YES)
set(CXX_EXTENSIONS NO)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CXX_EXTENSIONS OFF)

list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
include(warnings)

include_directories(include)

add_library(msd_channel INTERFACE)
target_include_directories(msd_channel INTERFACE include)

Expand Down
3 changes: 2 additions & 1 deletion benchmarks/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
include(FetchContent)

if(NOT benchmark_POPULATED)
set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "" FORCE)
set(BENCHMARK_ENABLE_GTEST_TESTS OFF CACHE BOOL "" FORCE)
Expand All @@ -10,7 +11,7 @@ endif()
function(package_add_benchmark TESTNAME)
add_executable(${TESTNAME} ${ARGN})
set_target_warnings(${TESTNAME} PRIVATE)
target_link_libraries(${TESTNAME} benchmark)
target_link_libraries(${TESTNAME} msd_channel benchmark)
endfunction()

package_add_benchmark(channel_benchmark channel_benchmark.cpp)
5 changes: 3 additions & 2 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ function(add_example NAME)
add_executable(${NAME} ${ARGN})

set_target_warnings(${NAME} PRIVATE)
target_link_libraries(${NAME} msd_channel)

if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
target_compile_options(${NAME} PRIVATE -fsanitize=thread)
target_link_libraries(${NAME} -ltsan)
target_link_options(${NAME} PRIVATE -fsanitize=thread)
endif()

add_dependencies(examples ${NAME})
Expand Down
27 changes: 14 additions & 13 deletions examples/close.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include <future>
#include <iostream>
#include <mutex>
#include <string>
#include <thread>

int main()
Expand All @@ -12,38 +14,37 @@ int main()
const auto input = [](msd::channel<int>& chan, int time_ms) {
static int inc = 0;

while (true) {
if (chan.closed()) {
break;
}

while (!chan.closed()) {
chan << ++inc;
std::cout << "in: " << inc << "\n";

std::this_thread::sleep_for(std::chrono::milliseconds{time_ms});
}

std::cout << "exit input\n";
};
const auto input_future = std::async(input, std::ref(channel), 10);

// Close the channel after some time
const auto timeout = [](msd::channel<int>& chan, int time_ms) {
std::this_thread::sleep_for(std::chrono::milliseconds{time_ms});

chan.close();
std::cout << "exit timeout\n";
};
auto timeout_future = std::async(timeout, std::ref(channel), 100);

// Display all the data from the channel
// When the channel is closed and empty, the iteration will end
const auto write = [](msd::channel<int>& chan, int time_ms) {
std::mutex cout_mutex;

const auto write = [&cout_mutex](msd::channel<int>& chan, int time_ms) {
for (auto out : chan) {
std::cout << "out: " << out << "\n";
std::string msg{"out: " + std::to_string(out) + "\n"};

{
std::lock_guard<std::mutex> lock(cout_mutex);
std::cout << msg;
}

std::this_thread::sleep_for(std::chrono::milliseconds{time_ms});
}

std::cout << "exit write\n";
};
const auto write_future1 = std::async(write, std::ref(channel), 1);
const auto write_future2 = std::async(write, std::ref(channel), 100);
Expand Down
5 changes: 3 additions & 2 deletions examples/cmake-project/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ project(cmake_project)
set(PROJECT_VERSION 0.1.0)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
set(CXX_EXTENSIONS NO)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CXX_EXTENSIONS OFF)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -Werror --coverage")

add_executable(cmake_project src/main.cpp)

include(FetchContent)

if(NOT channel_POPULATED)
FetchContent_Declare(channel URL https://github.com/andreiavrammsd/cpp-channel/archive/v1.3.0.zip
DOWNLOAD_EXTRACT_TIMESTAMP TRUE)
Expand Down
20 changes: 16 additions & 4 deletions examples/merge_channels.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <chrono>
#include <future>
#include <iostream>
#include <mutex>
#include <sstream>
#include <thread>

Expand All @@ -12,25 +13,36 @@ int main()
msd::channel<int> input_chan{30};
msd::channel<int> output_chan{10};

std::mutex cout_mutex;

// Send to channel
const auto writer = [&input_chan](int begin, int end) {
const auto writer = [&input_chan, &cout_mutex](int begin, int end) {
for (int i = begin; i <= end; ++i) {
input_chan.write(i);

std::stringstream msg;
msg << "Sent " << i << " from " << std::this_thread::get_id() << "\n";
std::cout << msg.str();

{
std::lock_guard<std::mutex> lock(cout_mutex);
std::cout << msg.str();
}

std::this_thread::sleep_for(std::chrono::milliseconds(10)); // simulate work
}
input_chan.close();
};

const auto reader = [&output_chan]() {
// Read
const auto reader = [&output_chan, &cout_mutex]() {
for (const auto out : output_chan) { // blocking until channel is drained (closed and empty)
std::stringstream msg;
msg << "Received " << out << " on " << std::this_thread::get_id() << "\n";
std::cout << msg.str();

{
std::lock_guard<std::mutex> lock(cout_mutex);
std::cout << msg.str();
}

std::this_thread::sleep_for(std::chrono::milliseconds(200)); // simulate work
}
Expand Down
20 changes: 16 additions & 4 deletions examples/multithreading_static_channel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,44 @@
#include <chrono>
#include <future>
#include <iostream>
#include <mutex>
#include <sstream>
#include <thread>

int main()
{
msd::static_channel<int, 50> chan{}; // always buffered

std::mutex cout_mutex;

// Send to channel
const auto writer = [&chan](int begin, int end) {
const auto writer = [&chan, &cout_mutex](int begin, int end) {
for (int i = begin; i <= end; ++i) {
chan.write(i);

std::stringstream msg;
msg << "Sent " << i << " from " << std::this_thread::get_id() << "\n";
std::cout << msg.str();

{
std::lock_guard<std::mutex> lock(cout_mutex);
std::cout << msg.str();
}

std::this_thread::sleep_for(std::chrono::milliseconds(10)); // simulate work
}
chan.close();
};

const auto reader = [&chan]() {
// Read
const auto reader = [&chan, &cout_mutex]() {
for (const auto out : chan) { // blocking until channel is drained (closed and empty)
std::stringstream msg;
msg << "Received " << out << " on " << std::this_thread::get_id() << "\n";
std::cout << msg.str();

{
std::lock_guard<std::mutex> lock(cout_mutex);
std::cout << msg.str();
}

std::this_thread::sleep_for(std::chrono::milliseconds(200)); // simulate work
}
Expand Down
19 changes: 6 additions & 13 deletions examples/streaming.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,9 @@ int main()
const auto input = [](messages& chan, std::size_t thread, std::chrono::milliseconds pause) {
thread_local static std::size_t inc = 0U;

while (true) {
if (chan.closed()) {
return;
}

while (!chan.closed()) {
++inc;
chan << std::string{std::to_string(inc) + " from: " + std::to_string(thread)};
chan << std::string{"Streaming " + std::to_string(inc) + " from thread " + std::to_string(thread)};

std::this_thread::sleep_for(pause);
}
Expand All @@ -35,20 +31,17 @@ int main()
in_futures.push_back(std::async(input, std::ref(channel), i, std::chrono::milliseconds{500}));
}

// Stream incoming data to a destination
const auto out = [](messages& chan, std::ostream& stream, const std::string& separator) {
std::move(chan.begin(), chan.end(), std::ostream_iterator<std::string>(stream, separator.c_str()));
};
const auto out_future = std::async(out, std::ref(channel), std::ref(std::cout), "\n");

// Close the channel after some time
const auto timeout = [](messages& chan, std::chrono::milliseconds after) {
std::this_thread::sleep_for(after);
chan.close();
};
const auto timeout_future = std::async(timeout, std::ref(channel), std::chrono::milliseconds{3000U});

out_future.wait();
// Stream incoming data to a destination
std::move(channel.begin(), channel.end(), std::ostream_iterator<std::string>(std::cout, "\n"));

// Wait for other threads
for (auto& future : in_futures) {
future.wait();
}
Expand Down
22 changes: 9 additions & 13 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0")
cmake_policy(SET CMP0135 NEW)
endif()

# Testing framework
if(MSVC)
option(gtest_force_shared_crt "Use shared (DLL) run-time lib even when Google Test is built as static lib." ON)
endif()

include(FetchContent)

if(NOT googletest_POPULATED)
set(INSTALL_GTEST OFF CACHE BOOL "" FORCE)
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
Expand All @@ -22,7 +19,7 @@ function(package_add_test TESTNAME)
add_executable(${TESTNAME} ${ARGN})

set_target_warnings(${TESTNAME} PRIVATE)
target_link_libraries(${TESTNAME} gtest gtest_main)
target_link_libraries(${TESTNAME} msd_channel gtest gtest_main)

if(CPP_CHANNEL_COVERAGE)
target_compile_options(${TESTNAME} PRIVATE --coverage)
Expand All @@ -35,14 +32,18 @@ function(package_add_test TESTNAME)
endif()
endif()

set(CPP_CHANNEL_SANITIZER_FLAGS "")
if(CPP_CHANNEL_SANITIZERS)
target_compile_options(${TESTNAME} PRIVATE -fsanitize=undefined)
target_link_libraries(${TESTNAME} -lubsan)
set(SANITIZERS -fsanitize=address -fno-sanitize-recover=address -fsanitize=undefined
-fno-sanitize-recover=undefined)

target_compile_options(${TESTNAME} PRIVATE ${SANITIZERS})
target_link_options(${TESTNAME} PRIVATE ${SANITIZERS})
endif()

if(CPP_CHANNEL_SANITIZE_THREADS)
target_compile_options(${TESTNAME} PRIVATE -fsanitize=thread)
target_link_libraries(${TESTNAME} -fsanitize=thread)
target_link_options(${TESTNAME} PRIVATE -fsanitize=thread)
endif()

add_test(NAME ${TESTNAME} COMMAND ${TESTNAME})
Expand All @@ -57,8 +58,3 @@ add_custom_target(channel_tests)
package_add_test(channel_test channel_test.cpp)
package_add_test(blocking_iterator_test blocking_iterator_test.cpp)
package_add_test(storage_test storage_test.cpp)

if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
# Disable warnings about C++17 extensions
target_compile_options(channel_test PRIVATE -Wno-c++17-extensions)
endif()