Skip to content

Commit aea7c41

Browse files
authored
Merge pull request #58 from cpp-best-practices/package_project
2 parents b5bc1e9 + 120dfa9 commit aea7c41

20 files changed

Lines changed: 668 additions & 77 deletions

.clang-tidy

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Checks: "*,
1313
-readability-avoid-const-params-in-decls,
1414
-cppcoreguidelines-non-private-member-variables-in-classes,
1515
-misc-non-private-member-variables-in-classes,
16+
-misc-definitions-in-headers,
1617
"
1718
WarningsAsErrors: ''
1819
HeaderFilterRegex: ''

.github/workflows/ci.yml

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
name: ci
2+
on:
3+
pull_request:
4+
push:
5+
branches:
6+
- main
7+
- master
8+
9+
jobs:
10+
Test:
11+
runs-on: ${{ matrix.os }}
12+
strategy:
13+
fail-fast: false
14+
matrix:
15+
os:
16+
- windows-2022
17+
- ubuntu-20.04
18+
- macos-11
19+
compiler:
20+
- llvm
21+
- gcc
22+
include:
23+
- os: "windows-2022"
24+
compiler: "msvc"
25+
exclude:
26+
- os: "windows-2022"
27+
compiler: "gcc"
28+
steps:
29+
- uses: actions/checkout@v2
30+
- name: Cache
31+
uses: actions/cache@v2
32+
with:
33+
path: |
34+
~/vcpkg
35+
./build/vcpkg_installed
36+
${{ env.HOME }}/.cache/vcpkg/archives
37+
${{ env.XDG_CACHE_HOME }}/vcpkg/archives
38+
${{ env.LOCALAPPDATA }}\vcpkg\archives
39+
${{ env.APPDATA }}\vcpkg\archives
40+
key: ${{ runner.os }}-${{ matrix.compiler }}-${{ env.BUILD_TYPE }}-${{ hashFiles('**/CMakeLists.txt') }}-${{ hashFiles('./vcpkg.json')}}
41+
restore-keys: |
42+
${{ runner.os }}-${{ env.BUILD_TYPE }}
43+
44+
- name: Setup Cpp
45+
uses: aminya/setup-cpp@v1
46+
with:
47+
compiler: ${{ matrix.compiler }}
48+
vcvarsall: ${{ contains(matrix.os, 'windows') }}
49+
cmake: true
50+
ninja: true
51+
vcpkg: true
52+
cppcheck: true
53+
clangtidy: true
54+
task: true
55+
doxygen: true
56+
57+
- name: Test
58+
run: |
59+
task test
60+
task test_release
61+
task test_install

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
test/build
2-
.cache
2+
.cache
3+
install/
4+
test_install/build/

README.md

Lines changed: 118 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -56,19 +56,97 @@ project_options(
5656
)
5757
```
5858

59-
```cmake
60-
# add your executables, libraries, etc. here:
59+
Then add the executables or libraries to the project:
60+
61+
An executable:
6162

63+
```cmake
6264
add_executable(myprogram main.cpp)
63-
target_compile_features(myprogram INTERFACE cxx_std_17)
6465
target_link_libraries(myprogram PRIVATE project_options project_warnings) # connect project_options to myprogram
6566
66-
# find and link dependencies (assuming you have enabled vcpkg or Conan):
67-
find_package(fmt REQUIRED)
67+
# Find dependencies:
68+
set(DEPENDENCIES_CONFIGURED fmt Eigen3)
69+
70+
foreach(DEPENDENCY ${DEPENDENCIES_CONFIGURED})
71+
find_package(${DEPENDENCY} CONFIG REQUIRED)
72+
endforeach()
73+
74+
# Link dependencies
6875
target_link_system_libraries(
6976
main
7077
PRIVATE
7178
fmt::fmt
79+
Eigen3::Eigen
80+
)
81+
82+
# Package the project
83+
package_project(TARGETS main)
84+
```
85+
86+
A header-only library:
87+
88+
```cmake
89+
add_library(my_header_only_lib INTERFACE)
90+
target_link_libraries(my_header_only_lib INTERFACE project_options project_warnings) # connect project_options to my_header_only_lib
91+
92+
# Includes
93+
set(INCLUDE_DIR "include")
94+
target_include_directories(my_header_only_lib INTERFACE "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${INCLUDE_DIR}>"
95+
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
96+
97+
# Find dependencies:
98+
set(DEPENDENCIES_CONFIGURED fmt Eigen3)
99+
100+
foreach(DEPENDENCY ${DEPENDENCIES_CONFIGURED})
101+
find_package(${DEPENDENCY} CONFIG REQUIRED)
102+
endforeach()
103+
104+
# Link dependencies:
105+
target_link_system_libraries(
106+
my_header_only_lib
107+
INTERFACE
108+
fmt::fmt
109+
Eigen3::Eigen
110+
)
111+
112+
# Package the project
113+
package_project(
114+
TARGETS my_header_only_lib
115+
PUBLIC_DEPENDENCIES_CONFIGURED ${DEPENDENCIES_CONFIGURED}
116+
PUBLIC_INCLUDES ${INCLUDE_DIR}
117+
)
118+
```
119+
120+
A library with separate header and source files
121+
122+
```cmake
123+
add_library(my_lib "./src/my_lib/lib.cpp")
124+
target_link_libraries(my_lib INTERFACE project_options project_warnings) # connect project_options to my_lib
125+
126+
# Includes
127+
set(INCLUDE_DIR "include")
128+
target_include_directories(my_lib INTERFACE "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${INCLUDE_DIR}>"
129+
"$<INSTALL_INTERFACE:./${CMAKE_INSTALL_INCLUDEDIR}>")
130+
131+
# Find dependencies:
132+
set(DEPENDENCIES_CONFIGURED fmt Eigen3)
133+
134+
foreach(DEPENDENCY ${DEPENDENCIES_CONFIGURED})
135+
find_package(${DEPENDENCY} CONFIG REQUIRED)
136+
endforeach()
137+
138+
# Link dependencies:
139+
target_link_system_libraries(
140+
my_lib
141+
PRIVATE
142+
fmt::fmt
143+
Eigen3::Eigen
144+
)
145+
146+
# Package the project
147+
package_project(
148+
TARGETS my_lib
149+
PUBLIC_INCLUDES ${INCLUDE_DIR}
72150
)
73151
```
74152

@@ -83,7 +161,7 @@ It accepts the following named flags:
83161
- `ENABLE_IPO`: Enable Interprocedural Optimization (Link Time Optimization, LTO) in the release build
84162
- `ENABLE_COVERAGE`: Enable coverage reporting for gcc/clang
85163
- `ENABLE_DOXYGEN`: Enable Doxygen doc builds of source
86-
- `WARNINGS_AS_ERRORS`: Treat compiler and static code analyzer warnings as errors. This also effects cmake warnings related to those.
164+
- `WARNINGS_AS_ERRORS`: Treat compiler and static code analyzer warnings as errors. This also affects CMake warnings related to those.
87165
- `ENABLE_SANITIZER_ADDRESS`: Enable address sanitizer
88166
- `ENABLE_SANITIZER_LEAK`: Enable leak sanitizer
89167
- `ENABLE_SANITIZER_UNDEFINED_BEHAVIOR`: Enable undefined behavior sanitizer
@@ -103,7 +181,7 @@ It gets the following named parameters that can have different values in front o
103181
- `CLANG_WARNINGS`: Override the defaults for the CLANG warnings
104182
- `GCC_WARNINGS`: Override the defaults for the GCC warnings
105183
- `CUDA_WARNINGS`: Override the defaults for the CUDA warnings
106-
- `CPPCHECK_WARNINGS`: Override the defaults for the options passed to CPPCHECK
184+
- `CPPCHECK_WARNINGS`: Override the defaults for the options passed to cppcheck
107185
- `CONAN_OPTIONS`: Extra Conan options
108186

109187
## `run_vcpkg` function
@@ -124,7 +202,7 @@ Named String:
124202
A function that accepts the same arguments as `target_link_libraries`. It has the following features:
125203

126204
- The include directories of the library are included as `SYSTEM` to suppress their warnings. This helps in enabling `WARNINGS_AS_ERRORS` for your own source code.
127-
- For installation of the package, the includes are considered to be at `${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}`.
205+
- For installation of the package, the includes are considered to be at `${CMAKE_INSTALL_INCLUDEDIR}`.
128206

129207
## `target_include_system_directories` function
130208

@@ -141,6 +219,37 @@ target_link_libraries(main_cuda PRIVATE project_options project_warnings)
141219
target_link_cuda(main_cuda)
142220
```
143221

222+
## `package_project` function
223+
224+
A function that packages the project for external usage (e.g. from vcpkg, Conan, etc).
225+
226+
The following arguments specify the package:
227+
228+
- `TARGETS`: the targets you want to package. It is recursively found for the current folder if not specified
229+
230+
- `PUBLIC_INCLUDES`: a list of public/interface include directories or files.
231+
_the given include directories are directly installed to the install destination. To have an `include` folder in the install destination with the content of your include directory, name your directory `include`._
232+
233+
- `PUBLIC_DEPENDENCIES_CONFIGURED`: the names of the INTERFACE/PUBLIC dependencies that are found using `CONFIG`.
234+
235+
- `PUBLIC_DEPENDENCIES`: the INTERFACE/PUBLIC dependencies that are found by any means using `find_dependency`. The arguments must be specified within quotes (e.g. `"<dependency> 1.0.0 EXACT"` or `"<dependency> CONFIG"`).
236+
237+
- `PRIVATE_DEPENDENCIES_CONFIGURED`: the names of the PRIVATE dependencies found using `CONFIG`. Only included when `BUILD_SHARED_LIBS` is `OFF`.
238+
239+
- `PRIVATE_DEPENDENCIES`: the PRIVATE dependencies found by any means using `find_dependency`. Only included when `BUILD_SHARED_LIBS` is `OFF`
240+
241+
Other arguments that are automatically found and manually specifying them is not recommended:
242+
243+
- `NAME`: the name of the package. Defaults to `${PROJECT_NAME}`.
244+
245+
- `VERSION`: the version of the package. Defaults to `${PROJECT_VERSION}`.
246+
247+
- `COMPATIBILITY`: the compatibility version of the package. Defaults to `SameMajorVersion`.
248+
249+
- `CONFIG_EXPORT_DESTINATION`: the destination for exporting the configuration files. Defaults to `${CMAKE_BINARY_DIR}`
250+
251+
- `CONFIG_INSTALL_DESTINATION`: the destination for installation of the configuration files. Defaults to `${CMAKE_INSTALL_DATADIR}/${NAME}`
252+
144253
## Changing the project_options dynamically
145254

146255
During the test and development, it can be useful to change options on the fly. For example, to enable sanitizers when running tests. You can include `DynamicOptions.cmake`, which imports the `dynamic_project_options` function.
@@ -203,20 +312,6 @@ dynamic_project_options(
203312
)
204313
```
205314

206-
```cmake
207-
# add your executables, libraries, etc. here:
208-
209-
add_executable(myprogram main.cpp)
210-
target_compile_features(myprogram INTERFACE cxx_std_17)
211-
target_link_libraries(myprogram PRIVATE project_options project_warnings) # connect project_options to myprogram
212-
213-
# find and link dependencies (assuming you have enabled vcpkg or Conan):
214-
find_package(fmt REQUIRED)
215-
target_link_system_libraries(
216-
main
217-
PRIVATE
218-
fmt::fmt
219-
)
220-
```
315+
Add your executables, etc., as described above.
221316

222317
</details>

Taskfile.yml

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,31 @@ tasks:
77
- cmake --build ./test/build --config Debug
88
- cd ./test/build && ctest -C Debug --verbose
99

10+
test_release:
11+
- cmake ./test -B ./test/build -DCMAKE_BUILD_TYPE:STRING=Release -G "Ninja Multi-Config"
12+
- cmake --build ./test/build --config Release
13+
- cd ./test/build && ctest -C Release --verbose
14+
15+
test_install:
16+
cmds:
17+
- task: test_release
18+
- cmake --install ./test/build --config Release --prefix ./install
19+
- cmake ./test_install -B ./test_install/build -DCMAKE_BUILD_TYPE:STRING=Release -G "Ninja Multi-Config" -DCMAKE_PREFIX_PATH:STRING={{.CWD}}/install;
20+
- cmake --build ./test_install/build --config Release
21+
- cd ./test_install/build && ctest -C Release --verbose
22+
vars:
23+
CWD:
24+
sh: git rev-parse --show-toplevel
25+
1026
format:
11-
- clang-format -i ./test/*.cpp
12-
- cmake-format --in-place ./Index.cmake ./src/*.cmake
27+
- clang-format -i ./test/src/*/*.cpp ./test/include/*/*.hpp ./test_install/*.cpp
28+
- cmake-format --in-place ./Index.cmake ./src/*.cmake ./test/CMakeLists.txt ./test_install/CMakeLists.txt
1329

1430
lint: cmake-lint ./Index.cmake ./src/*.cmake
1531

16-
clean: 'cd test && {{if eq OS "windows"}} cmd /c "if exist build ( rmdir /s/q build )" {{else}} rm -rf build {{end}}'
32+
clean: |
33+
{{if eq OS "windows"}}
34+
powershell -c 'function rmrf($path) { if (test-path $path) { rm -r -force $path }}; rmrf ./test/build; rmrf ./test_install/build/; rmrf ./install'
35+
{{else}}
36+
rm -rf ./test/build ./test_install/build/ ./install
37+
{{end}}

src/Index.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ include("${ProjectOptions_SRC_DIR}/SystemLink.cmake")
1212

1313
include("${ProjectOptions_SRC_DIR}/Cuda.cmake")
1414

15+
include("${ProjectOptions_SRC_DIR}/PackageProject.cmake")
16+
1517
#
1618
# Params:
1719
# - WARNINGS_AS_ERRORS: Treat compiler warnings as errors

0 commit comments

Comments
 (0)