Skip to content

Commit bae3375

Browse files
committed
Convert exemplar into an INTERFACE library
This commit eliminates the src/ directory, moving the contents of src/beman/exemplar/CMakeLists.txt into the top level CMakeLists.txt (except for the header FILE_SET, which now lives in include/beman/exemplar/CMakeLists.txt), removing identity.cpp, and changing beman.exemplar from STATIC/SHARED into INTERFACE. The cookiecutter template now allows the user to specify whether they want to stamp out an "interface" or "static" library, where the "static" option is similar to exemplar's previous status quo. To ensure that cookiecutter's "static" option remains valid, we add a new CI test that smoke tests that building, testing, and installing it completes without error.
1 parent bd9e4f4 commit bae3375

16 files changed

Lines changed: 152 additions & 68 deletions

File tree

.github/workflows/ci_tests.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ jobs:
4343
{ "stdlibs": ["libstdc++"],
4444
"tests": [
4545
"Debug.Default", "Release.Default", "Release.TSan",
46-
"Release.MaxSan", "Debug.Werror", "Debug.Dynamic",
46+
"Release.MaxSan", "Debug.Werror",
4747
"Debug.Coverage"
4848
]
4949
}
@@ -78,7 +78,7 @@ jobs:
7878
{ "stdlibs": ["libstdc++", "libc++"],
7979
"tests": [
8080
"Debug.Default", "Release.Default", "Release.TSan",
81-
"Release.MaxSan", "Debug.Werror", "Debug.Dynamic"
81+
"Release.MaxSan", "Debug.Werror"
8282
]
8383
}
8484
]
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2+
3+
name: Static Exemplar Test
4+
on:
5+
push:
6+
branches:
7+
- main
8+
pull_request:
9+
10+
jobs:
11+
static-exemplar-test:
12+
runs-on: ubuntu-latest
13+
container: ghcr.io/bemanproject/infra-containers-gcc:latest
14+
name: "Static exemplar smoke test"
15+
steps:
16+
- name: Checkout
17+
uses: actions/checkout@v4
18+
- name: Test static exemplar
19+
run: |
20+
cd cookiecutter
21+
source ./check_cookiecutter.sh
22+
cookiecutter_venv_path=$(mktemp --directory --dry-run)
23+
setup_venv "$cookiecutter_venv_path"
24+
stamp "$PWD" "./static_exemplar" "static"
25+
cd static_exemplar/exemplar
26+
cmake -B build -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=./infra/cmake/use-fetch-content.cmake -DCMAKE_CXX_STANDARD=20 -DCMAKE_INSTALL_PREFIX=$PWD/dist
27+
cmake --build build
28+
ctest --test-dir build
29+
cmake --install build

CMakeLists.txt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,17 @@ option(
2727
# for find of beman-install-library
2828
include(infra/cmake/beman-install-library-config.cmake)
2929

30-
add_subdirectory(src/beman/exemplar)
30+
add_library(beman.exemplar INTERFACE)
31+
add_library(beman::exemplar ALIAS beman.exemplar)
32+
33+
target_sources(
34+
beman.exemplar
35+
PUBLIC FILE_SET HEADERS BASE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/include"
36+
)
37+
38+
set_target_properties(beman.exemplar PROPERTIES VERIFY_INTERFACE_HEADER_SETS ON)
39+
40+
add_subdirectory(include/beman/exemplar)
3141

3242
beman_install_library(beman.exemplar)
3343

README.md

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,6 @@ cmake -B build -S . -DCMAKE_CXX_STANDARD=20 -DBEMAN_EXEMPLAR_BUILD_TESTS=OFF
312312

313313
Enable building examples. Default: ON. Values: { ON, OFF }.
314314

315-
316315
#### `BEMAN_EXEMPLAR_INSTALL_CONFIG_FILE_PACKAGE`
317316

318317
Enable installing the CMake config file package. Default: ON.
@@ -358,10 +357,9 @@ any libraries or executables that include `beman.exemplar` headers.
358357
target_link_libraries(yourlib PUBLIC beman::exemplar)
359358
```
360359

361-
### Produce beman.exemplar static library
360+
### Produce beman.exemplar interface library
362361

363-
You can include exemplar's headers locally
364-
by producing a static `libbeman.exemplar.a` library.
362+
You can produce exemplar's interface library locally by:
365363

366364
```bash
367365
cmake --workflow --preset gcc-release
@@ -377,11 +375,9 @@ This will generate the following directory structure at `/opt/beman`.
377375
│ └── exemplar
378376
│ └── identity.hpp
379377
└── lib
380-
├── cmake
381-
│   └── beman.exemplar
382-
│   ├── beman.exemplar-config-version.cmake
383-
│   ├── beman.exemplar-config.cmake
384-
│   ├── beman.exemplar-targets-debug.cmake
385-
│   └── beman.exemplar-targets.cmake
386-
└── libbeman.exemplar.a
378+
└── cmake
379+
└── beman.exemplar
380+
├── beman.exemplar-config-version.cmake
381+
├── beman.exemplar-config.cmake
382+
└── beman.exemplar-targets.cmake
387383
```

cookiecutter/check_cookiecutter.sh

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,31 @@ set -euo pipefail
44

55
declare script_dir=$(realpath $(dirname "$BASH_SOURCE"))
66

7-
function check_consistency() {
8-
local out_dir_path
9-
out_dir_path=$(mktemp --directory --dry-run)
10-
cd /tmp
7+
function stamp() {
8+
local cookiecutter_dir="$1" ; shift
9+
local output_dir="$1" ; shift
10+
local library_type="$1" ; shift
1111
python3 \
1212
-m cookiecutter \
1313
--no-input \
14-
--output-dir "$out_dir_path" \
15-
"$script_dir" \
14+
--output-dir "$output_dir" \
15+
"$cookiecutter_dir" \
1616
project_name="exemplar" \
1717
cpp_build_version="17" \
1818
paper="P0898R3" \
1919
owner="bemanproject" \
2020
description="A Beman Library Exemplar" \
21-
godbolt_link="https://godbolt.org/z/4qEPK87va"
21+
godbolt_link="https://godbolt.org/z/4qEPK87va" \
22+
library_type="$library_type"
23+
}
24+
25+
function check_consistency() {
26+
local out_dir_path
27+
out_dir_path=$(mktemp --directory --dry-run)
28+
cd /tmp
29+
stamp "$script_dir" "$out_dir_path" "interface"
2230
cp "$script_dir"/../.github/workflows/cookiecutter_test.yml "$out_dir_path"/exemplar/.github/workflows
31+
cp "$script_dir"/../.github/workflows/static_exemplar_test.yml "$out_dir_path"/exemplar/.github/workflows
2332
local diff_path
2433
diff_path=$(mktemp)
2534
diff -r "$script_dir/.." "$out_dir_path/exemplar" \
@@ -65,12 +74,17 @@ function check_templating() {
6574
rm "$grep_path"
6675
}
6776

68-
function main() {
69-
local cookiecutter_venv_path
70-
cookiecutter_venv_path=$(mktemp --directory --dry-run)
77+
function setup_venv() {
78+
local path="$1" ; shift
7179
python3 -m venv "$cookiecutter_venv_path"
7280
source "$cookiecutter_venv_path/bin/activate"
7381
python3 -m pip install cookiecutter >& /dev/null
82+
}
83+
84+
function main() {
85+
local cookiecutter_venv_path
86+
cookiecutter_venv_path=$(mktemp --directory --dry-run)
87+
setup_venv "$cookiecutter_venv_path"
7488
check_consistency
7589
check_templating
7690
rm -rf "$cookiecutter_venv_path"

cookiecutter/cookiecutter.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"owner": "github-user-name",
66
"description": "Short project description.",
77
"godbolt_link": "https://www.example.com",
8+
"library_type": ["interface", "static"],
89
"_copy_without_render": [
910
"infra"
1011
],
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/usr/bin/env python3
2+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
"""Post-generation hook to clean up template files based on library_type."""
5+
6+
import shutil
7+
from pathlib import Path
8+
import os
9+
10+
# Get the library type from cookiecutter context
11+
library_type = "{{ cookiecutter.library_type }}"
12+
13+
# If interface library, remove the src/ directory (not needed for header-only)
14+
if library_type == "interface":
15+
src_dir = Path("src")
16+
if src_dir.exists():
17+
shutil.rmtree(src_dir)

cookiecutter/{{cookiecutter.project_name}}/.github/workflows/ci_tests.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,9 @@ jobs:
4343
{ "stdlibs": ["libstdc++"],
4444
"tests": [
4545
"Debug.Default", "Release.Default", "Release.TSan",
46-
"Release.MaxSan", "Debug.Werror", "Debug.Dynamic",
47-
"Debug.Coverage"
46+
"Release.MaxSan", "Debug.Werror",
47+
"Debug.Coverage"{% if cookiecutter.library_type == "static" %}, "Debug.Dynamic"{% endif %}
48+
4849
]
4950
}
5051
]
@@ -78,7 +79,8 @@ jobs:
7879
{ "stdlibs": ["libstdc++", "libc++"],
7980
"tests": [
8081
"Debug.Default", "Release.Default", "Release.TSan",
81-
"Release.MaxSan", "Debug.Werror", "Debug.Dynamic"
82+
"Release.MaxSan", "Debug.Werror"{% if cookiecutter.library_type == "static" %}, "Debug.Dynamic"{% endif %}
83+
8284
]
8385
}
8486
]

cookiecutter/{{cookiecutter.project_name}}/CMakeLists.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,24 @@ option(
2727
# for find of beman-install-library
2828
include(infra/cmake/beman-install-library-config.cmake)
2929

30+
{% if cookiecutter.library_type == "interface" %}
31+
add_library(beman.{{cookiecutter.project_name}} INTERFACE)
32+
{% else %}
33+
add_library(beman.{{cookiecutter.project_name}})
34+
{% endif %}
35+
add_library(beman::{{cookiecutter.project_name}} ALIAS beman.{{cookiecutter.project_name}})
36+
37+
target_sources(
38+
beman.{{cookiecutter.project_name}}
39+
PUBLIC FILE_SET HEADERS BASE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/include"
40+
)
41+
42+
set_target_properties(beman.{{cookiecutter.project_name}} PROPERTIES VERIFY_INTERFACE_HEADER_SETS ON)
43+
44+
add_subdirectory(include/beman/{{cookiecutter.project_name}})
45+
{% if cookiecutter.library_type == "static" %}
3046
add_subdirectory(src/beman/{{cookiecutter.project_name}})
47+
{% endif %}
3148

3249
beman_install_library(beman.{{cookiecutter.project_name}})
3350

cookiecutter/{{cookiecutter.project_name}}/README.md

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,6 @@ cmake -B build -S . -DCMAKE_CXX_STANDARD=20 -DBEMAN_{{cookiecutter.project_name.
312312

313313
Enable building examples. Default: ON. Values: { ON, OFF }.
314314

315-
316315
#### `BEMAN_{{cookiecutter.project_name.upper()}}_INSTALL_CONFIG_FILE_PACKAGE`
317316

318317
Enable installing the CMake config file package. Default: ON.
@@ -358,10 +357,13 @@ any libraries or executables that include `beman.{{cookiecutter.project_name}}`
358357
target_link_libraries(yourlib PUBLIC beman::{{cookiecutter.project_name}})
359358
```
360359

361-
### Produce beman.{{cookiecutter.project_name}} static library
360+
### Produce beman.{{cookiecutter.project_name}} {{ cookiecutter.library_type }} library
362361

363-
You can include {{cookiecutter.project_name}}'s headers locally
364-
by producing a static `libbeman.{{cookiecutter.project_name}}.a` library.
362+
{% if cookiecutter.library_type == "interface" %}
363+
You can produce {{cookiecutter.project_name}}'s interface library locally by:
364+
{% else %}
365+
You can produce {{cookiecutter.project_name}}'s static library `libbeman.{{cookiecutter.project_name}}.a` by:
366+
{% endif %}
365367

366368
```bash
367369
cmake --workflow --preset gcc-release
@@ -370,6 +372,21 @@ cmake --install build/gcc-release --prefix /opt/beman
370372

371373
This will generate the following directory structure at `/opt/beman`.
372374

375+
{% if cookiecutter.library_type == "interface" %}
376+
```txt
377+
/opt/beman
378+
├── include
379+
│ └── beman
380+
│ └── {{cookiecutter.project_name}}
381+
│ └── identity.hpp
382+
└── lib
383+
└── cmake
384+
└── beman.{{cookiecutter.project_name}}
385+
├── beman.{{cookiecutter.project_name}}-config-version.cmake
386+
├── beman.{{cookiecutter.project_name}}-config.cmake
387+
└── beman.{{cookiecutter.project_name}}-targets.cmake
388+
```
389+
{% else %}
373390
```txt
374391
/opt/beman
375392
├── include
@@ -378,10 +395,11 @@ This will generate the following directory structure at `/opt/beman`.
378395
│ └── identity.hpp
379396
└── lib
380397
├── cmake
381-
   └── beman.{{cookiecutter.project_name}}
382-
   ├── beman.{{cookiecutter.project_name}}-config-version.cmake
383-
   ├── beman.{{cookiecutter.project_name}}-config.cmake
384-
   ├── beman.{{cookiecutter.project_name}}-targets-debug.cmake
385-
   └── beman.{{cookiecutter.project_name}}-targets.cmake
398+
└── beman.{{cookiecutter.project_name}}
399+
├── beman.{{cookiecutter.project_name}}-config-version.cmake
400+
├── beman.{{cookiecutter.project_name}}-config.cmake
401+
├── beman.{{cookiecutter.project_name}}-targets-debug.cmake
402+
└── beman.{{cookiecutter.project_name}}-targets.cmake
386403
└── libbeman.{{cookiecutter.project_name}}.a
387404
```
405+
{% endif %}

0 commit comments

Comments
 (0)