Skip to content
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
29 changes: 20 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ cpp_library_setup(
DESCRIPTION "${PROJECT_DESCRIPTION}"
NAMESPACE your_namespace
HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/your_namespace/your_header.hpp
# Optional: add SOURCES for non-header-only libraries
SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/your_library.cpp
EXAMPLES your_example your_example_fail
TESTS your_tests
DOCS_EXCLUDE_SYMBOLS "your_namespace::implementation"
Expand Down Expand Up @@ -66,14 +68,17 @@ cpp_library_setup(
# Header specification (one required)
HEADERS header_list # List of header files
HEADER_DIR directory # Directory to install recursively


# Optional: source specification for non-header-only libraries
SOURCES source_list # List of source files (e.g., src/*.cpp)

# Optional features
[EXAMPLES example_list] # Example executables to build
[TESTS test_list] # Test executables to build
[TESTS test_list] # Test executables to build
[DOCS_EXCLUDE_SYMBOLS symbols] # Symbols to exclude from docs
[REQUIRES_CPP_VERSION 17|20|23] # C++ version (default: 17)
[ADDITIONAL_DEPS dep_list] # Extra CPM dependencies

# Optional flags
[CUSTOM_INSTALL] # Skip default installation
[NO_PRESETS] # Skip CMakePresets.json generation
Expand All @@ -83,6 +88,11 @@ cpp_library_setup(
```

## Features
### Non-Header-Only Library Support

- **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.
Specify sources manually with the `SOURCES` argument, or let the template auto-detect files in `src/`.
Both header-only and compiled libraries are supported seamlessly.

### Automated Infrastructure

Expand Down Expand Up @@ -186,8 +196,8 @@ cpp_library_setup(
# Clone or create your project
mkdir my-library && cd my-library

# Create basic structure
mkdir -p include/your_namespace examples tests cmake
# Create basic structure
mkdir -p include/your_namespace src examples tests cmake

# Add CPM.cmake
curl -L https://github.com/cpm-cmake/CPM.cmake/releases/latest/download/get_cpm.cmake -o cmake/CPM.cmake
Expand All @@ -212,10 +222,11 @@ cpp_library_setup(

The template automatically generates:

- **CMakePresets.json**: Build configurations for different purposes
- **.github/workflows/ci.yml**: Multi-platform CI/CD pipeline
- **.gitignore**: Standard ignores for C++ projects
- **Package config files**: For proper CMake integration
- **CMakePresets.json**: Build configurations for different purposes
- **.github/workflows/ci.yml**: Multi-platform CI/CD pipeline
- **.gitignore**: Standard ignores for C++ projects
- **src/**: Source directory for non-header-only libraries (auto-detected)
- **Package config files**: For proper CMake integration

## License

Expand Down
91 changes: 70 additions & 21 deletions cmake/cpp-library-setup.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,48 @@ function(_cpp_library_setup_core)
)
set(multiValueArgs
HEADERS
SOURCES
)

cmake_parse_arguments(ARG "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

# Extract the library name without namespace prefix for target naming
string(REPLACE "${ARG_NAMESPACE}-" "" CLEAN_NAME "${ARG_NAME}")

# Create the INTERFACE library target
add_library(${ARG_NAME} INTERFACE)
add_library(${ARG_NAMESPACE}::${CLEAN_NAME} ALIAS ${ARG_NAME})

# Set include directories
target_include_directories(${ARG_NAME} INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)

# Set C++ standard requirement
target_compile_features(${ARG_NAME} INTERFACE cxx_std_${ARG_REQUIRES_CPP_VERSION})

# Set up installation if headers are specified
if(ARG_HEADERS)
# Use FILE_SET for modern CMake header installation
target_sources(${ARG_NAME} INTERFACE
FILE_SET headers
TYPE HEADERS
BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include
FILES ${ARG_HEADERS}
if(ARG_SOURCES)
# Create a regular library if sources are present
add_library(${ARG_NAME} STATIC ${ARG_SOURCES})
add_library(${ARG_NAMESPACE}::${CLEAN_NAME} ALIAS ${ARG_NAME})
target_include_directories(${ARG_NAME} PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
target_compile_features(${ARG_NAME} PUBLIC cxx_std_${ARG_REQUIRES_CPP_VERSION})
if(ARG_HEADERS)
target_sources(${ARG_NAME} PUBLIC
FILE_SET headers
TYPE HEADERS
BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include
FILES ${ARG_HEADERS}
)
endif()
else()
# Header-only INTERFACE target
add_library(${ARG_NAME} INTERFACE)
add_library(${ARG_NAMESPACE}::${CLEAN_NAME} ALIAS ${ARG_NAME})
target_include_directories(${ARG_NAME} INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
target_compile_features(${ARG_NAME} INTERFACE cxx_std_${ARG_REQUIRES_CPP_VERSION})
if(ARG_HEADERS)
target_sources(${ARG_NAME} INTERFACE
FILE_SET headers
TYPE HEADERS
BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include
FILES ${ARG_HEADERS}
)
endif()
endif()

# Only set up full installation when building as top-level project
Expand Down Expand Up @@ -93,3 +106,39 @@ function(_cpp_library_setup_core)
endif()

endfunction()

# Function to copy static template files
function(_cpp_library_copy_templates)
set(options FORCE_INIT)
cmake_parse_arguments(ARG "${options}" "" "" ${ARGN})

# List of static template files to copy
set(TEMPLATE_FILES
".clang-format"
".gitignore"
".gitattributes"
".vscode/extensions.json"
"docs/index.html"
)

foreach(template_file IN LISTS TEMPLATE_FILES)
set(source_file "${CPP_LIBRARY_ROOT}/templates/${template_file}")
set(dest_file "${CMAKE_CURRENT_SOURCE_DIR}/${template_file}")

# Check if template file exists
if(EXISTS "${source_file}")
# Copy if file doesn't exist or FORCE_INIT is enabled
if(NOT EXISTS "${dest_file}" OR ARG_FORCE_INIT)
# Create directory if needed
get_filename_component(dest_dir "${dest_file}" DIRECTORY)
file(MAKE_DIRECTORY "${dest_dir}")

# Copy the file
file(COPY "${source_file}" DESTINATION "${dest_dir}")
message(STATUS "Copied template file: ${template_file}")
endif()
else()
message(WARNING "Template file not found: ${source_file}")
endif()
endforeach()
endfunction()
21 changes: 17 additions & 4 deletions cpp-library.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,22 @@ function(cpp_library_setup)
)
set(multiValueArgs
HEADERS # List of header files
EXAMPLES # Example executables to build
TESTS # Test executables to build
DOCS_EXCLUDE_SYMBOLS # Symbols to exclude from docs
ADDITIONAL_DEPS # Extra CPM dependencies
SOURCES # List of source files (optional, for non-header-only)
EXAMPLES # Example executables to build
TESTS # Test executables to build
DOCS_EXCLUDE_SYMBOLS # Symbols to exclude from docs
ADDITIONAL_DEPS # Extra CPM dependencies
)

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

# Detect sources in <root>/src if SOURCES not provided
if(NOT ARG_SOURCES)
file(GLOB_RECURSE DETECTED_SOURCES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "src/*.cpp" "src/*.c" "src/*.cc" "src/*.cxx")
if(DETECTED_SOURCES)
set(ARG_SOURCES ${DETECTED_SOURCES})
endif()
endif()

# Validate required arguments
if(NOT ARG_NAME)
Expand Down Expand Up @@ -79,6 +88,7 @@ function(cpp_library_setup)
DESCRIPTION "${ARG_DESCRIPTION}"
NAMESPACE "${ARG_NAMESPACE}"
HEADERS "${ARG_HEADERS}"
SOURCES "${ARG_SOURCES}"
HEADER_DIR "${ARG_HEADER_DIR}"
REQUIRES_CPP_VERSION "${ARG_REQUIRES_CPP_VERSION}"
TOP_LEVEL "${PROJECT_IS_TOP_LEVEL}"
Expand All @@ -103,6 +113,9 @@ function(cpp_library_setup)
if(NOT ARG_NO_PRESETS)
_cpp_library_generate_presets(FORCE_INIT ${ARG_FORCE_INIT})
endif()

# Copy static template files (like .clang-format, .gitignore, etc.)
_cpp_library_copy_templates(FORCE_INIT ${ARG_FORCE_INIT})

# Setup testing (if tests are specified)
if(BUILD_TESTING AND ARG_TESTS)
Expand Down
119 changes: 119 additions & 0 deletions templates/.clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Format style options described here:
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html

# Many of the alignment and single line changes were made to facilitate setting
# breakpoints on specific expressions.

---
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: false
# AlwaysBreakAfterDefinitionReturnType: TopLevel
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
BinPackArguments: true
BinPackParameters: false
# BraceWrapping:
# AfterClass: true
# AfterControlStatement: false
# AfterEnum: false
# AfterFunction: false
# AfterNamespace: false
# AfterObjCDeclaration: false
# AfterStruct: false
# AfterUnion: false
# AfterExternBlock: false
# BeforeCatch: false
# BeforeElse: false
# IndentBraces: false
# SplitEmptyFunction: true
# SplitEmptyRecord: true
# SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: false
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: AfterColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: false
ColumnLimit: 100
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '$'
IndentCaseLabels: true
IndentPPDirectives: None # Other option is AfterHash, which indents top level includes as well
IndentWidth: 4
IndentWrappedFunctionNames: true
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 4
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 1000
PointerAlignment: Left
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp17
TabWidth: 4
UseTab: Never
---
Language: Cpp
---
Language: ObjC
PointerAlignment: Right
...
2 changes: 2 additions & 0 deletions templates/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto
3 changes: 1 addition & 2 deletions templates/.gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/.cpm-cache
/.cpp-library-cache
/.cache
/build
include/.DS_Store
.DS_Store
compile_commands.json
8 changes: 8 additions & 0 deletions templates/.vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"recommendations": [
"matepek.vscode-catch2-test-adapter",
"llvm-vs-code-extensions.vscode-clangd",
"ms-vscode.live-server",
"xaver.clang-format"
]
}
14 changes: 14 additions & 0 deletions templates/docs/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<!-- Open or preview this file after building the docs to view the documentation. -->

<head>
<meta http-equiv="refresh" content="0; URL=../build/docs/html/index.html">
<title>Redirecting to Documentation</title>
</head>

<body>
<p>If you are not redirected automatically, <a href="../build/docs/html/index.html">click here</a>.</p>
</body>

</html>