Skip to content

Commit 7d7ae0f

Browse files
committed
Unified filename handling
1 parent eb8e8d3 commit 7d7ae0f

File tree

2 files changed

+93
-44
lines changed

2 files changed

+93
-44
lines changed

README.md

Lines changed: 59 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ include(${cpp-library_SOURCE_DIR}/cpp-library.cmake)
3939
cpp_library_setup(
4040
DESCRIPTION "Your library description"
4141
NAMESPACE your_namespace
42-
HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/your_namespace/your_header.hpp
43-
# Optional: add SOURCES for non-header-only libraries
44-
SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/your_library.cpp
45-
EXAMPLES your_example your_example_fail
46-
TESTS your_tests
42+
HEADERS your_header.hpp
43+
# Add SOURCES for non-header-only libraries (omit for header-only)
44+
SOURCES your_library.cpp
45+
EXAMPLES your_example.cpp your_example_fail.cpp
46+
TESTS your_tests.cpp
4747
DOCS_EXCLUDE_SYMBOLS "your_namespace::implementation"
4848
)
4949
```
@@ -63,27 +63,68 @@ cpp_library_setup(
6363
# Required parameters
6464
DESCRIPTION description # e.g., "Type-safe operators for enums"
6565
NAMESPACE namespace # e.g., "stlab"
66-
HEADERS header_list # List of header files
66+
HEADERS header_list # List of header filenames (e.g., "your_header.hpp")
6767
68-
# Optional: source specification for non-header-only libraries
69-
SOURCES source_list # List of source files (auto-detected from src/ if not provided)
68+
# Source specification for non-header-only libraries
69+
SOURCES source_list # List of source filenames (e.g., "your_library.cpp", omit for header-only libraries)
7070
7171
# Optional features
72-
[EXAMPLES example_list] # Example executables to build
73-
[TESTS test_list] # Test executables to build
72+
[EXAMPLES example_list] # Example source files to build (e.g., "example.cpp example_fail.cpp")
73+
[TESTS test_list] # Test source files to build (e.g., "tests.cpp")
7474
[DOCS_EXCLUDE_SYMBOLS symbols] # Symbols to exclude from docs
7575
[REQUIRES_CPP_VERSION 17|20|23] # C++ version (default: 17)
7676
[FORCE_INIT] # Force regeneration of template files
7777
)
7878
```
7979

80-
**Note**: The project name is automatically taken from `PROJECT_NAME` (set by the `project()` command). You must call `project(your-library)` before `cpp_library_setup()`. Version is automatically detected from git tags.
80+
**Note**: The project name is automatically taken from `PROJECT_NAME` (set by the `project()`
81+
command). You must call `project(your-library)` before `cpp_library_setup()`. Version is
82+
automatically detected from git tags.
83+
84+
**NOTE**: Examples using doctest should have `test` in the name if you want them to be visible in
85+
the TestMate test explorer.
86+
87+
### Path Conventions
88+
89+
The template uses consistent path conventions for all file specifications:
90+
91+
- **HEADERS**: Filenames only, automatically placed in `include/<namespace>/` directory
92+
- Examples: `your_header.hpp`, `enum_ops.hpp` (automatically becomes `include/your_namespace/your_header.hpp`)
93+
- **SOURCES**: Filenames only, automatically placed in `src/` directory (omit for header-only libraries)
94+
- Examples: `your_library.cpp`, `implementation.cpp` (automatically becomes `src/your_library.cpp`)
95+
- **EXAMPLES**: Source files with `.cpp` extension, located in `examples/` directory
96+
- Examples: `example.cpp`, `example_fail.cpp`
97+
- **TESTS**: Source files with `.cpp` extension, located in `tests/` directory
98+
- Examples: `tests.cpp`, `unit_tests.cpp`
99+
100+
The template automatically generates the full paths based on these conventions. HEADERS are placed in `include/<namespace>/` and SOURCES are placed in `src/`.
101+
102+
### Library Types
103+
104+
**Header-only libraries**: Specify only `HEADERS`, omit `SOURCES`
105+
```cmake
106+
cpp_library_setup(
107+
DESCRIPTION "Header-only library"
108+
NAMESPACE my_lib
109+
HEADERS my_header.hpp
110+
# No SOURCES needed for header-only
111+
)
112+
```
113+
114+
**Non-header-only libraries**: Specify both `HEADERS` and `SOURCES`
115+
```cmake
116+
cpp_library_setup(
117+
DESCRIPTION "Library with implementation"
118+
NAMESPACE my_lib
119+
HEADERS my_header.hpp
120+
SOURCES my_library.cpp implementation.cpp
121+
)
122+
```
81123

82124
## Features
83125
### Non-Header-Only Library Support
84126

85-
- **Automatic detection of sources in `src/`**: If source files are present in `src/`, the template will build a regular (static) library instead of header-only INTERFACE target.
86-
Specify sources manually with the `SOURCES` argument, or let the template auto-detect files in `src/`.
127+
- **Non-header-only library support**: For libraries with source files, specify them explicitly with the `SOURCES` argument as filenames (e.g., `"your_library.cpp"`).
87128
Both header-only and compiled libraries are supported seamlessly.
88129

89130
### Automated Infrastructure
@@ -177,9 +218,9 @@ include(${cpp-library_SOURCE_DIR}/cpp-library.cmake)
177218
cpp_library_setup(
178219
DESCRIPTION "Type-safe operators for enums"
179220
NAMESPACE stlab
180-
HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/stlab/enum_ops.hpp
181-
EXAMPLES enum_ops_example enum_ops_example_fail
182-
TESTS enum_ops_tests
221+
HEADERS enum_ops.hpp
222+
EXAMPLES enum_ops_example_test.cpp enum_ops_example_fail.cpp
223+
TESTS enum_ops_tests.cpp
183224
DOCS_EXCLUDE_SYMBOLS "stlab::implementation"
184225
)
185226
```
@@ -202,9 +243,9 @@ cpp_library_setup(
202243

203244
3. **Add your headers** to `include/your_namespace/`
204245

205-
4. **Add examples** to `examples/` (use `_fail` suffix for compile-fail tests)
246+
4. **Add examples** to `examples/` (use `_fail` suffix for compile-fail tests, e.g., `example.cpp`, `example_fail.cpp`)
206247

207-
5. **Add tests** to `tests/` (use `_fail` suffix for compile-fail tests)
248+
5. **Add tests** to `tests/` (use `_fail` suffix for compile-fail tests, e.g., `tests.cpp`, `tests_fail.cpp`)
208249

209250
6. **Build and test**:
210251
```bash

cpp-library.cmake

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -50,46 +50,49 @@ function(_cpp_library_setup_executables)
5050

5151
# Add executables
5252
foreach(executable IN LISTS ARG_EXECUTABLES)
53-
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${source_dir}/${executable}.cpp")
53+
# Extract the base name without extension for target naming
54+
get_filename_component(executable_base "${executable}" NAME_WE)
55+
56+
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${source_dir}/${executable}")
5457

5558
# Check if this is a compile-fail test (has "_fail" in the name)
56-
string(FIND "${executable}" "_fail" fail_pos)
59+
string(FIND "${executable_base}" "_fail" fail_pos)
5760
if(fail_pos GREATER -1)
5861
# Negative compile test: this executable must fail to compile
59-
add_executable(${executable} EXCLUDE_FROM_ALL "${source_dir}/${executable}.cpp")
60-
target_link_libraries(${executable} PRIVATE ${ARG_NAMESPACE}::${CLEAN_NAME})
62+
add_executable(${executable_base} EXCLUDE_FROM_ALL "${source_dir}/${executable}")
63+
target_link_libraries(${executable_base} PRIVATE ${ARG_NAMESPACE}::${CLEAN_NAME})
6164
add_test(
62-
NAME compile_${executable}
63-
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target ${executable}
65+
NAME compile_${executable_base}
66+
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target ${executable_base}
6467
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
6568
)
66-
set_tests_properties(compile_${executable} PROPERTIES WILL_FAIL TRUE)
69+
set_tests_properties(compile_${executable_base} PROPERTIES WILL_FAIL TRUE)
6770
else()
6871
# Regular executable - conditionally build based on preset
69-
add_executable(${executable} "${source_dir}/${executable}.cpp")
70-
target_link_libraries(${executable} PRIVATE ${ARG_NAMESPACE}::${CLEAN_NAME} doctest::doctest)
72+
add_executable(${executable_base} "${source_dir}/${executable}")
73+
target_link_libraries(${executable_base} PRIVATE ${ARG_NAMESPACE}::${CLEAN_NAME} doctest::doctest)
7174

7275
# Only fully build (compile and link) in test preset
7376
# In clang-tidy preset, compile with clang-tidy but don't link
7477
if(CMAKE_CXX_CLANG_TIDY)
7578
# In clang-tidy mode, exclude from all builds but still compile
76-
set_target_properties(${executable} PROPERTIES EXCLUDE_FROM_ALL TRUE)
79+
set_target_properties(${executable_base} PROPERTIES EXCLUDE_FROM_ALL TRUE)
7780
# Don't add as a test in clang-tidy mode since we're not linking
7881
else()
7982
# In test mode, build normally and add as test
80-
add_test(NAME ${executable} COMMAND ${executable})
83+
add_test(NAME ${executable_base} COMMAND ${executable_base})
8184

8285
# Set test properties for better IDE integration (only for tests)
8386
if(ARG_TYPE STREQUAL "tests")
84-
set_tests_properties(${executable} PROPERTIES
87+
set_tests_properties(${executable_base} PROPERTIES
8588
LABELS "doctest"
8689
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
8790
)
8891
endif()
8992
endif()
9093
endif()
9194
else()
92-
message(WARNING "${ARG_TYPE} file ${source_dir}/${executable}.cpp not found")
95+
message(WARNING "${ARG_TYPE} file ${source_dir}/${executable} not found")
9396
endif()
9497
endforeach()
9598

@@ -107,22 +110,16 @@ function(cpp_library_setup)
107110
REQUIRES_CPP_VERSION # C++ version (default: 17)
108111
)
109112
set(multiValueArgs
110-
HEADERS # List of header files
111-
SOURCES # List of source files (optional, for non-header-only)
112-
EXAMPLES # Example executables to build
113-
TESTS # Test executables to build
113+
HEADERS # List of header filenames (e.g., "your_header.hpp")
114+
SOURCES # List of source filenames (e.g., "your_library.cpp")
115+
EXAMPLES # Example source files to build (e.g., "example.cpp example_fail.cpp")
116+
TESTS # Test source files to build (e.g., "tests.cpp")
114117
DOCS_EXCLUDE_SYMBOLS # Symbols to exclude from docs
115118
)
116119

117120
cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
118121

119-
# Detect sources in <root>/src if SOURCES not provided
120-
if(NOT ARG_SOURCES)
121-
file(GLOB_RECURSE DETECTED_SOURCES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "src/*.cpp" "src/*.c" "src/*.cc" "src/*.cxx")
122-
if(DETECTED_SOURCES)
123-
set(ARG_SOURCES ${DETECTED_SOURCES})
124-
endif()
125-
endif()
122+
126123

127124
# Validate required arguments
128125
if(NOT ARG_DESCRIPTION)
@@ -177,14 +174,25 @@ function(cpp_library_setup)
177174
set(PROJECT_VERSION_MINOR ${ARG_VERSION_MINOR} PARENT_SCOPE)
178175
set(PROJECT_VERSION_PATCH ${ARG_VERSION_PATCH} PARENT_SCOPE)
179176

177+
# Generate full paths for HEADERS and SOURCES based on conventions
178+
set(GENERATED_HEADERS "")
179+
foreach(header IN LISTS ARG_HEADERS)
180+
list(APPEND GENERATED_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/include/${ARG_NAMESPACE}/${header}")
181+
endforeach()
182+
183+
set(GENERATED_SOURCES "")
184+
foreach(source IN LISTS ARG_SOURCES)
185+
list(APPEND GENERATED_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/${source}")
186+
endforeach()
187+
180188
# Create the basic library target (always done)
181189
_cpp_library_setup_core(
182190
NAME "${ARG_NAME}"
183191
VERSION "${ARG_VERSION}"
184192
DESCRIPTION "${ARG_DESCRIPTION}"
185193
NAMESPACE "${ARG_NAMESPACE}"
186-
HEADERS "${ARG_HEADERS}"
187-
SOURCES "${ARG_SOURCES}"
194+
HEADERS "${GENERATED_HEADERS}"
195+
SOURCES "${GENERATED_SOURCES}"
188196
REQUIRES_CPP_VERSION "${ARG_REQUIRES_CPP_VERSION}"
189197
TOP_LEVEL "${PROJECT_IS_TOP_LEVEL}"
190198
)

0 commit comments

Comments
 (0)