Skip to content

Commit 4ccd491

Browse files
authored
Support vendoring kassert as part of other libraries (#66)
* Allow specifying a custom prefix. * Formatting. * Reorganize vendoring variables. Users can tweak `KASSERT_CMAKE_NAMESPACE` (prefix to all targets), `KASSERT_CXX_NAMESPACE`, `KASSERT_INCLUDE_SUBDIR` (the subdir to place the headers into). The assertion macro prefix is derived from the C++ namespace. Users may also choose to set `KASSERT_VENDOR_ID`. If any of the other arguments is not given explicitly, it is derived passed on this variable. * Allow setting `KASSERT_PREFIX` explicitely. * Configure `kassertConfig.cmake` properly (also when vendoring). * Only set `KASSERT_VENDOR_ID` to default if not defined yet. * Make assertion level CMake properties work with vendoring. * Add tests. * Avoid installing test artifacts. * Fix: correct namespacing target export set. * Test if installation and using the installed library works. * Fix CMake formatting. * Build documentation correctly. * Fix some usages of the vendoring knobs in CMake where they were missed. * Make the tests work when vendoring. * Fix CMake formatting. * Documentation.
1 parent 27e05a6 commit 4ccd491

16 files changed

Lines changed: 419 additions & 233 deletions

CMakeLists.txt

Lines changed: 97 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -5,36 +5,71 @@ project(
55
LANGUAGES CXX
66
VERSION 0.2.2
77
)
8-
9-
# include guard to prevent duplicate targets when including this project as a subdirectory
10-
if (TARGET kassert::kassert)
11-
return()
12-
endif ()
13-
148
if (CMAKE_VERSION VERSION_LESS 3.21)
159
if (CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
1610
set(PROJECT_IS_TOP_LEVEL TRUE)
1711
else ()
1812
set(PROJECT_IS_TOP_LEVEL FALSE)
1913
endif ()
2014
endif ()
15+
16+
# This is the vendor ID, which is used to create the CMake namespace and the C++ namespace.
17+
if (NOT DEFINED KASSERT_VENDOR_ID)
18+
set(KASSERT_VENDOR_ID "kassert")
19+
endif ()
20+
21+
# Derive others if not already defined
22+
if (NOT DEFINED KASSERT_CMAKE_NAMESPACE)
23+
set(KASSERT_CMAKE_NAMESPACE "${KASSERT_VENDOR_ID}")
24+
endif ()
25+
26+
if (NOT DEFINED KASSERT_CXX_NAMESPACE)
27+
set(KASSERT_CXX_NAMESPACE "${KASSERT_VENDOR_ID}")
28+
endif ()
29+
30+
if (NOT DEFINED KASSERT_INCLUDE_SUBDIR)
31+
set(KASSERT_INCLUDE_SUBDIR "${KASSERT_VENDOR_ID}")
32+
endif ()
33+
34+
if (NOT DEFINED KASSERT_PREFIX)
35+
string(TOUPPER ${KASSERT_CXX_NAMESPACE} KASSERT_PREFIX)
36+
endif ()
37+
38+
# include guard to prevent duplicate targets when including this project as a subdirectory
39+
if (TARGET ${KASSERT_CMAKE_NAMESPACE}::kassert)
40+
return()
41+
endif ()
42+
2143
option(KASSERT_BUILD_TESTS "Build the tests." ${PROJECT_IS_TOP_LEVEL})
2244
option(KASSERT_BUILD_DOCS "Build the docs." ${PROJECT_IS_TOP_LEVEL})
2345
option(KASSERT_USE_BUNDLED_GTEST "Use bundled googletest (downloaded at configure time via FetchContent)." ON)
46+
option(KASSERT_INSTALL "Install the kassert library." ON)
2447

2548
if (KASSERT_BUILD_DOCS)
2649
add_subdirectory(docs)
2750
endif ()
2851

29-
add_library(kassert INTERFACE)
30-
target_include_directories(kassert INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
52+
add_library(${KASSERT_CMAKE_NAMESPACE}_kassert INTERFACE)
53+
set(kassert_sources kassert.hpp internal/logger.hpp internal/assertion_macros.hpp internal/expression_decomposition.hpp)
54+
set_target_properties(${KASSERT_CMAKE_NAMESPACE}_kassert PROPERTIES EXPORT_NAME kassert OUTPUT_NAME kassert)
55+
56+
# generate the header files from the .in files
57+
foreach (file ${kassert_sources})
58+
set(source_file include/kassert/${file}.in)
59+
set(target_file include/${KASSERT_INCLUDE_SUBDIR}/${file})
60+
configure_file(${source_file} ${target_file} @ONLY)
61+
endforeach ()
62+
63+
target_include_directories(
64+
${KASSERT_CMAKE_NAMESPACE}_kassert INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
65+
)
3166

3267
# set C++ standard to C++17
33-
target_compile_features(kassert INTERFACE cxx_std_17)
68+
target_compile_features(${KASSERT_CMAKE_NAMESPACE}_kassert INTERFACE cxx_std_17)
3469

35-
add_library(kassert_warnings INTERFACE)
70+
add_library(${KASSERT_CMAKE_NAMESPACE}_kassert_warnings INTERFACE)
3671
target_compile_options(
37-
kassert_warnings
72+
${KASSERT_CMAKE_NAMESPACE}_kassert_warnings
3873
INTERFACE "-Wall"
3974
"-Wextra"
4075
"-Wconversion"
@@ -49,14 +84,14 @@ target_compile_options(
4984

5085
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
5186
target_compile_options(
52-
kassert_warnings INTERFACE "-Wcast-align" "-Wnull-dereference" "-Wpedantic" "-Wextra-semi"
53-
"-Wno-gnu-zero-variadic-macro-arguments"
87+
${KASSERT_CMAKE_NAMESPACE}_kassert_warnings INTERFACE "-Wcast-align" "-Wnull-dereference" "-Wpedantic"
88+
"-Wextra-semi" "-Wno-gnu-zero-variadic-macro-arguments"
5489
)
5590
endif ()
5691

5792
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
5893
target_compile_options(
59-
kassert_warnings
94+
${KASSERT_CMAKE_NAMESPACE}_kassert_warnings
6095
INTERFACE "-Wcast-align"
6196
"-Wnull-dereference"
6297
"-Wpedantic"
@@ -71,16 +106,21 @@ endif ()
71106
# exception will be thrown upon failure, otherwise it behaves like regular KASSERT. You can either manually #define it,
72107
# or by setting the KASSERT_EXCEPTION_MODE target property to ON on the target which links to kassert.
73108
set(exception_mode_enabled "$<BOOL:$<TARGET_PROPERTY:KASSERT_EXCEPTION_MODE>>")
74-
target_compile_definitions(kassert INTERFACE "$<${exception_mode_enabled}:-DKASSERT_EXCEPTION_MODE>")
109+
target_compile_definitions(
110+
${KASSERT_CMAKE_NAMESPACE}_kassert INTERFACE "$<${exception_mode_enabled}:-D${KASSERT_PREFIX}_EXCEPTION_MODE>"
111+
)
75112

76113
# The assertion level controls which assertions are enabled during runtime. Assertion levels can be set explicitly using
77114
# the -DKASSERT_ASSERTION_LEVEL=... flag. You can also set the KASSERT_ASSERTION_LEVEL target property to the desired
78115
# level on the target which links to kassert. This will properly #define the assertion level for the target.
79-
set(assertion_level_set "$<BOOL:$<TARGET_PROPERTY:KASSERT_ASSERTION_LEVEL>>")
80-
set(assertion_level "$<TARGET_PROPERTY:KASSERT_ASSERTION_LEVEL>")
81-
target_compile_definitions(kassert INTERFACE "$<${assertion_level_set}:-DKASSERT_ASSERTION_LEVEL=${assertion_level}>")
116+
set(assertion_level_set "$<BOOL:$<TARGET_PROPERTY:${KASSERT_PREFIX}_ASSERTION_LEVEL>>")
117+
set(assertion_level "$<TARGET_PROPERTY:${KASSERT_PREFIX}_ASSERTION_LEVEL>")
118+
target_compile_definitions(
119+
${KASSERT_CMAKE_NAMESPACE}_kassert
120+
INTERFACE "$<${assertion_level_set}:-D${KASSERT_PREFIX}_ASSERTION_LEVEL=${assertion_level}>"
121+
)
82122

83-
add_library(kassert::kassert ALIAS kassert)
123+
add_library(${KASSERT_CMAKE_NAMESPACE}::kassert ALIAS ${KASSERT_CMAKE_NAMESPACE}_kassert)
84124

85125
# Tests are only built if KASSERT_BUILD_TESTS is set (OFF by default, ON if this is the top-level project)
86126
if (KASSERT_BUILD_TESTS)
@@ -89,35 +129,42 @@ if (KASSERT_BUILD_TESTS)
89129
add_subdirectory(tests)
90130
endif ()
91131

92-
include(CMakePackageConfigHelpers)
93-
write_basic_package_version_file(
94-
${CMAKE_CURRENT_BINARY_DIR}/kassertConfigVersion.cmake
95-
VERSION ${kassert_PROJECT_VERSION}
96-
COMPATIBILITY AnyNewerVersion ARCH_INDEPENDENT # requires CMake 3.14
97-
)
98-
configure_file(
99-
${CMAKE_CURRENT_SOURCE_DIR}/cmake/kassertConfig.cmake ${CMAKE_CURRENT_BINARY_DIR}/kassertConfig.cmake COPYONLY
100-
)
132+
if (KASSERT_INSTALL)
133+
include(CMakePackageConfigHelpers)
134+
write_basic_package_version_file(
135+
${CMAKE_CURRENT_BINARY_DIR}/${KASSERT_CMAKE_NAMESPACE}ConfigVersion.cmake
136+
VERSION ${kassert_PROJECT_VERSION}
137+
COMPATIBILITY AnyNewerVersion ARCH_INDEPENDENT # requires CMake 3.14
138+
)
139+
configure_file(
140+
${CMAKE_CURRENT_SOURCE_DIR}/cmake/Config.cmake.in
141+
${CMAKE_CURRENT_BINARY_DIR}/${KASSERT_CMAKE_NAMESPACE}Config.cmake @ONLY
142+
)
101143

102-
include(GNUInstallDirs)
103-
install(
104-
TARGETS kassert
105-
EXPORT kassertTargets
106-
INCLUDES
107-
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
108-
)
109-
install(
110-
DIRECTORY include/
111-
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
112-
FILES_MATCHING
113-
PATTERN "*.hpp"
114-
)
115-
install(
116-
EXPORT kassertTargets
117-
FILE kassertTargets.cmake
118-
NAMESPACE kassert::
119-
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/kassert
120-
)
121-
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/kassertConfigVersion.cmake ${CMAKE_CURRENT_BINARY_DIR}/kassertConfig.cmake
122-
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/kassert
123-
)
144+
include(GNUInstallDirs)
145+
install(
146+
TARGETS ${KASSERT_CMAKE_NAMESPACE}_kassert
147+
EXPORT ${KASSERT_CMAKE_NAMESPACE}Targets
148+
INCLUDES
149+
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
150+
)
151+
152+
foreach (file ${kassert_sources})
153+
get_filename_component(rel_dir ${file} DIRECTORY)
154+
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/${KASSERT_INCLUDE_SUBDIR}/${file}
155+
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${KASSERT_INCLUDE_SUBDIR}/${rel_dir}
156+
)
157+
endforeach ()
158+
159+
install(
160+
EXPORT ${KASSERT_CMAKE_NAMESPACE}Targets
161+
FILE ${KASSERT_CMAKE_NAMESPACE}Targets.cmake
162+
NAMESPACE ${KASSERT_CMAKE_NAMESPACE}::
163+
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${KASSERT_INCLUDE_SUBDIR}
164+
)
165+
166+
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${KASSERT_CMAKE_NAMESPACE}ConfigVersion.cmake
167+
${CMAKE_CURRENT_BINARY_DIR}/${KASSERT_CMAKE_NAMESPACE}Config.cmake
168+
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${KASSERT_INCLUDE_SUBDIR}
169+
)
170+
endif ()

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,29 @@ constexpr int heavy = KAMPING_ASSERTION_LEVEL_HEAVY;
8181
8282
- C++17-ready compiler (GCC, Clang, ICX)
8383
84+
## Vendoring Support
85+
86+
KAssert can be embedded in other libraries with custom namespaces and macro names to prevent naming conflicts.
87+
88+
**When to vendor:** Use vendoring when developing a library that uses KAssert internally to avoid conflicts with user code that might also use KAssert.
89+
90+
### Configuration Variables
91+
92+
- `KASSERT_VENDOR_ID` - Base identifier for deriving other variables
93+
- `KASSERT_CMAKE_NAMESPACE` - Prefix for all CMake targets
94+
- `KASSERT_CXX_NAMESPACE` - C++ namespace for the library
95+
- `KASSERT_INCLUDE_SUBDIR` - Subdirectory for header installation
96+
- `KASSERT_PREFIX` - The prefix for all macros
97+
98+
### Example
99+
100+
```cmake
101+
set(KASSERT_VENDOR_ID "myassert")
102+
add_subdirectory(vendor/kassert)
103+
```
104+
105+
This generates macros like `MYASSERT()` instead of `KASSERT()`.
106+
84107
## LICENSE
85108

86109
KAssert is released under the MIT License. See [LICENSE](LICENSE) for details.

cmake/Config.cmake.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include("${CMAKE_CURRENT_LIST_DIR}/@KASSERT_CMAKE_NAMESPACE@Targets.cmake")

cmake/kassertConfig.cmake

Lines changed: 0 additions & 1 deletion
This file was deleted.

docs/CMakeLists.txt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
include_guard(GLOBAL)
2+
13
# find Doxygen
24
find_package(Doxygen)
35

@@ -48,11 +50,13 @@ if (DOXYGEN_FOUND)
4850
set(DOXYGEN_TAB_SIZE 2)
4951
set(DOXYGEN_ENABLED_SECTIONS KAMPING_MAIN_PAGE)
5052
set(DOXYGEN_FILE_PATTERNS *.cpp *.hpp *.dox *.md)
53+
set(DOXYGEN_STRIP_FROM_PATH ${PROJECT_BINARY_DIR}/include/) # omit build directory from file list in Doxygen output
5154

5255
doxygen_add_docs(
53-
docs ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}/../include/
56+
${KASSERT_CMAKE_NAMESPACE}_docs ${CMAKE_CURRENT_LIST_DIR}
57+
${PROJECT_BINARY_DIR}/include/${KASSERT_INCLUDE_SUBDIR}
5458
COMMENT "Generating Documentation"
55-
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/..
59+
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/.. ALL
5660
)
5761
include(GNUInstallDirs)
5862
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html/ TYPE DOC)

docs/main.dox

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,29 @@ constexpr int heavy = KAMPING_ASSERTION_LEVEL_HEAVY;
8181

8282
- C++17-ready compiler (GCC, Clang, ICX)
8383
- Building this documentation requires `Doxygen 1.9.2` or newer
84+
85+
## Vendoring Support
86+
87+
KAssert can be embedded in other libraries with custom namespaces and macro names to prevent naming conflicts.
88+
89+
**When to vendor:** Use vendoring when developing a library that uses KAssert internally to avoid conflicts with user code that might also use KAssert.
90+
91+
### Configuration Variables
92+
93+
- `KASSERT_VENDOR_ID` - Base identifier for deriving other variables
94+
- `KASSERT_CMAKE_NAMESPACE` - Prefix for all CMake targets
95+
- `KASSERT_CXX_NAMESPACE` - C++ namespace for the library
96+
- `KASSERT_INCLUDE_SUBDIR` - Subdirectory for header installation
97+
- `KASSERT_PREFIX` - The prefix for all macros
98+
99+
### Example
100+
101+
```cmake
102+
set(KASSERT_VENDOR_ID "myassert")
103+
add_subdirectory(vendor/kassert)
104+
```
105+
106+
This generates macros like `MYASSERT()` instead of `KASSERT()`.
84107

85108
## LICENSE
86109

0 commit comments

Comments
 (0)