Skip to content

Commit d09520d

Browse files
committed
feat: Enhance NekoThreadPool with C++20 module support and improved configuration
- Updated project version to 1.0.0 in CMakeLists.txt. - Added option to enable C++20 module support. - Integrated NekoSchema as a dependency and modified fetching logic. - Implemented C++20 module interface in include/neko/thread/neko.thread.cppm. - Created threadPool.hpp header for traditional usage and module export. - Developed comprehensive tests for module functionality in tests/threadPool_module_test.cpp. - Refactored existing tests to use the new header structure. - Added installation rules for headers and targets in CMake configuration.
1 parent 9ba5a56 commit d09520d

File tree

7 files changed

+935
-52
lines changed

7 files changed

+935
-52
lines changed

CMakeLists.txt

Lines changed: 128 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
cmake_minimum_required(VERSION 3.14)
2-
project(NekoThreadPool VERSION 1.0 LANGUAGES CXX)
2+
project(NekoThreadPool VERSION 1.0.0 LANGUAGES CXX)
33

44
# ================
55
# === Config ====
66
# ================
77

88
option(NEKO_THREAD_POOL_BUILD_TESTS "Neko Thread Pool Build tests" ON)
99
option(NEKO_THREAD_POOL_AUTO_FETCH_DEPS "Neko Thread Pool Automatically fetch dependencies" ON)
10+
option(NEKO_THREAD_POOL_ENABLE_MODULE "Neko Thread Pool Enable C++20 module" OFF)
1011

11-
find_package(GTest CONFIG QUIET)
12+
find_package(NekoSchema QUIET)
13+
find_package(GTest QUIET)
1214

1315
# Print configuration summary
1416
message(STATUS "Start configuration Neko Thread Pool...")
@@ -18,22 +20,31 @@ message(STATUS " - CMake version: ${CMAKE_VERSION}")
1820
message(STATUS "")
1921
message(STATUS " - Neko Thread Pool Auto fetch deps: ${NEKO_THREAD_POOL_AUTO_FETCH_DEPS}")
2022
message(STATUS " - Neko Thread Pool Build tests: ${NEKO_THREAD_POOL_BUILD_TESTS}")
23+
message(STATUS " - Neko Thread Pool Enable module: ${NEKO_THREAD_POOL_ENABLE_MODULE}")
2124
message(STATUS "")
2225
message(STATUS "Dependency summary:")
26+
message(STATUS " - NekoSchema : ${NekoSchema_FOUND} version : ${NekoSchema_VERSION}")
2327
message(STATUS " - GTest : ${GTest_FOUND} version : ${GTest_VERSION}")
2428
message(STATUS "")
2529

2630
if(NEKO_THREAD_POOL_AUTO_FETCH_DEPS)
2731
include(FetchContent)
2832

29-
FetchContent_Declare(
30-
NekoSchema
31-
GIT_REPOSITORY https://github.com/moehoshio/NekoSchema.git
32-
GIT_TAG main
33-
)
34-
FetchContent_MakeAvailable(NekoSchema)
33+
if (NOT NekoSchema_FOUND)
34+
message(STATUS "NekoSchema not found; Neko Thread Pool Fetching NekoSchema...")
35+
36+
FetchContent_Declare(
37+
NekoSchema
38+
GIT_REPOSITORY https://github.com/moehoshio/NekoSchema.git
39+
GIT_TAG main
40+
)
41+
if (NEKO_THREAD_POOL_ENABLE_MODULE)
42+
set(NEKO_SCHEMA_ENABLE_MODULE ON CACHE BOOL "" FORCE)
43+
endif()
44+
FetchContent_MakeAvailable(NekoSchema)
45+
endif()
3546

36-
if(NOT GTEST_FOUND AND NEKO_THREAD_POOL_BUILD_TESTS)
47+
if(NOT GTest_FOUND AND NEKO_THREAD_POOL_BUILD_TESTS)
3748
message(STATUS "GTest not found; Neko Thread Pool Fetching GoogleTest...")
3849

3950
FetchContent_Declare(
@@ -65,6 +76,52 @@ target_include_directories(NekoThreadPool INTERFACE
6576
target_link_libraries(NekoThreadPool INTERFACE NekoSchema)
6677
target_compile_features(NekoThreadPool INTERFACE cxx_std_20)
6778

79+
# ================
80+
# = C++20 Module =
81+
# ================
82+
83+
if(NEKO_THREAD_POOL_ENABLE_MODULE)
84+
message(STATUS "NekoThreadPool C++20 module enabled (NEKO_THREAD_POOL_ENABLE_MODULE=ON)")
85+
86+
# Check CMake version for module support
87+
if(CMAKE_VERSION VERSION_LESS 3.28)
88+
message(WARNING "CMake 3.28+ is recommended for full C++20 module support")
89+
endif()
90+
91+
# Create module library
92+
add_library(NekoThreadPool_module)
93+
add_library(Neko::ThreadPool::Module ALIAS NekoThreadPool_module)
94+
95+
target_sources(NekoThreadPool_module
96+
PUBLIC
97+
FILE_SET CXX_MODULES FILES
98+
${CMAKE_CURRENT_SOURCE_DIR}/include/neko/thread/neko.thread.cppm
99+
)
100+
101+
target_compile_features(NekoThreadPool_module PUBLIC cxx_std_20)
102+
103+
# Link dependencies (needed for module compilation)
104+
target_link_libraries(NekoThreadPool_module PUBLIC NekoSchema_module)
105+
106+
# Compiler-specific module flags
107+
if(MSVC)
108+
target_compile_options(NekoThreadPool_module PUBLIC /experimental:module)
109+
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
110+
target_compile_options(NekoThreadPool_module PUBLIC -fmodules-ts)
111+
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
112+
target_compile_options(NekoThreadPool_module PUBLIC -fmodules)
113+
endif()
114+
115+
# Module still needs access to the include directory for the headers
116+
target_include_directories(NekoThreadPool_module PUBLIC
117+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
118+
$<INSTALL_INTERFACE:include>
119+
)
120+
121+
else()
122+
message(STATUS "NekoThreadPool C++20 module disabled (NEKO_THREAD_POOL_ENABLE_MODULE=OFF)")
123+
endif()
124+
68125
# ================
69126
# ==== Tests =====
70127
# ================
@@ -85,9 +142,71 @@ if(NEKO_THREAD_POOL_BUILD_TESTS)
85142

86143
include(GoogleTest)
87144
gtest_discover_tests(threadPool_test)
145+
146+
# Module-based tests (if module is enabled)
147+
if(NEKO_THREAD_POOL_ENABLE_MODULE)
148+
message(STATUS "Neko Thread Pool module tests enabled")
149+
add_executable(threadPool_module_test tests/threadPool_module_test.cpp)
150+
target_link_libraries(threadPool_module_test PRIVATE NekoSchema_module NekoThreadPool_module GTest::gtest GTest::gtest_main)
151+
target_compile_features(threadPool_module_test PRIVATE cxx_std_20)
152+
gtest_discover_tests(threadPool_module_test)
153+
endif()
88154

89155
else()
90156
message(STATUS "NekoThreadPool tests disabled (NEKO_THREAD_POOL_BUILD_TESTS=OFF)")
91157
endif()
92158

159+
160+
# ================
161+
# == Install =====
162+
# ================
163+
164+
include(GNUInstallDirs)
165+
include(CMakePackageConfigHelpers)
166+
167+
# Install headers
168+
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/
169+
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
170+
FILES_MATCHING
171+
PATTERN "*.hpp"
172+
PATTERN "*.cppm"
173+
)
174+
175+
# Install targets
176+
install(TARGETS NekoThreadPool
177+
EXPORT NekoThreadPoolTargets
178+
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
179+
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
180+
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
181+
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
182+
FILE_SET CXX_MODULES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
183+
)
184+
185+
# Install export targets
186+
install(EXPORT NekoThreadPoolTargets
187+
FILE NekoThreadPoolTargets.cmake
188+
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/NekoThreadPool
189+
)
190+
191+
# Create and install Config file
192+
configure_package_config_file(
193+
${CMAKE_CURRENT_SOURCE_DIR}/cmake/NekoThreadPoolConfig.cmake.in
194+
${CMAKE_CURRENT_BINARY_DIR}/NekoThreadPoolConfig.cmake
195+
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/NekoThreadPool
196+
)
197+
198+
# Create and install Version file
199+
write_basic_package_version_file(
200+
${CMAKE_CURRENT_BINARY_DIR}/NekoThreadPoolConfigVersion.cmake
201+
VERSION ${PROJECT_VERSION}
202+
COMPATIBILITY SameMajorVersion
203+
ARCH_INDEPENDENT
204+
)
205+
206+
install(FILES
207+
${CMAKE_CURRENT_BINARY_DIR}/NekoThreadPoolConfig.cmake
208+
${CMAKE_CURRENT_BINARY_DIR}/NekoThreadPoolConfigVersion.cmake
209+
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/NekoThreadPool
210+
)
211+
93212
message(STATUS "Neko Thread Pool End of configuration")
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
@PACKAGE_INIT@
2+
3+
# Include the targets file
4+
include("${CMAKE_CURRENT_LIST_DIR}/NekoThreadPoolTargets.cmake")
5+
6+
# Create the Neko::Schema alias if it doesn't exist
7+
# (it exists in build tree but not after installation)
8+
if(TARGET NekoThreadPool AND NOT TARGET Neko::ThreadPool)
9+
add_library(Neko::ThreadPool ALIAS NekoThreadPool)
10+
endif()
11+
12+
check_required_components(NekoThreadPool)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* @file neko.thread.cppm
3+
* @brief C++20 module interface for NekoThread
4+
* @details This module exports all NekoThread functionality by wrapping the header files.
5+
* The original headers are still available for traditional include-based usage.
6+
*/
7+
8+
module;
9+
10+
#if !defined(__cpp_lib_modules) || (__cpp_lib_modules < 202207L)
11+
// Global module fragment - include headers that should not be exported
12+
#include <algorithm>
13+
#include <functional>
14+
#include <memory>
15+
#include <optional>
16+
17+
#include <atomic>
18+
#include <condition_variable>
19+
#include <mutex>
20+
#include <shared_mutex>
21+
22+
#include <thread>
23+
24+
#include <future>
25+
#include <queue>
26+
#include <unordered_set>
27+
#include <vector>
28+
#include <string>
29+
#endif
30+
31+
export module neko.thread;
32+
33+
import neko.schema;
34+
35+
#define NEKO_THREAD_POOL_ENABLE_MODULE true
36+
37+
export {
38+
#include "threadPool.hpp"
39+
}
Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88
#pragma once
99

10+
#if !defined(NEKO_THREAD_POOL_ENABLE_MODULE)
1011
#include <neko/schema/exception.hpp>
1112
#include <neko/schema/types.hpp>
1213

@@ -24,14 +25,16 @@
2425

2526
#include <future>
2627
#include <queue>
28+
#include <string>
2729
#include <unordered_set>
2830
#include <vector>
31+
#endif
2932

3033
/**
3134
* @brief Thread pool
32-
* @namespace neko::core::thread
35+
* @namespace neko::thread
3336
*/
34-
namespace neko::core::thread {
37+
namespace neko::thread {
3538

3639
using TaskId = neko::uint64;
3740

@@ -195,8 +198,8 @@ namespace neko::core::thread {
195198
if (self->hasPersonalTasks()) {
196199
return true;
197200
}
198-
return pool->stopping.load(std::memory_order_acquire) ||
199-
self->isStopping() ||
201+
return pool->stopping.load(std::memory_order_acquire) ||
202+
self->isStopping() ||
200203
!pool->globalTaskQueue.empty();
201204
});
202205

@@ -372,18 +375,18 @@ namespace neko::core::thread {
372375

373376
TaskId taskId = nextTaskId.fetch_add(1, std::memory_order_acq_rel);
374377
Task personalTask{[task]() { (*task)(); }, neko::Priority::Normal, taskId};
375-
378+
376379
// Post task and ensure visibility before notification
377380
self->postTask(std::move(personalTask));
378-
381+
379382
// Acquire the lock before notifying to ensure the task is visible
380-
// This prevents the race where a worker checks hasPersonalTasks()
383+
// This prevents the race where a worker checks hasPersonalTasks()
381384
// after we post but before we notify
382385
{
383386
std::unique_lock<std::shared_mutex> lk(globalTaskQueueMutex);
384387
// The lock ensures memory synchronization
385388
}
386-
389+
387390
globalTaskQueueCondVar.notify_all();
388391
return task->get_future();
389392
}
@@ -477,7 +480,7 @@ namespace neko::core::thread {
477480

478481
{
479482
std::unique_lock<std::shared_mutex> lock(workerMutex);
480-
483+
481484
if (newThreadCount == workers.size()) {
482485
return;
483486
}
@@ -504,7 +507,6 @@ namespace neko::core::thread {
504507
w->cleanup();
505508
}
506509
}
507-
508510
}
509511

510512
/**
@@ -588,4 +590,4 @@ namespace neko::core::thread {
588590
}
589591
};
590592

591-
} // namespace neko::core::thread
593+
} // namespace neko::thread

0 commit comments

Comments
 (0)