Skip to content
Draft
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
4 changes: 2 additions & 2 deletions .github/workflows/ci_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
{ "stdlibs": ["libstdc++"],
"tests": [
"Debug.Default", "Release.Default", "Release.TSan",
"Release.MaxSan", "Debug.Werror", "Debug.Dynamic",
"Release.MaxSan", "Debug.Werror",
"Debug.Coverage"
]
}
Expand Down Expand Up @@ -78,7 +78,7 @@ jobs:
{ "stdlibs": ["libstdc++", "libc++"],
"tests": [
"Debug.Default", "Release.Default", "Release.TSan",
"Release.MaxSan", "Debug.Werror", "Debug.Dynamic"
"Release.MaxSan", "Debug.Werror"
]
}
]
Expand Down
19 changes: 17 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,24 @@ option(
${PROJECT_IS_TOP_LEVEL}
)

include(CTest)
add_library(beman.exemplar INTERFACE)
add_library(beman::exemplar ALIAS beman.exemplar)

target_sources(
beman.exemplar
PUBLIC
FILE_SET HEADERS
BASE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/include"
FILES
"${CMAKE_CURRENT_SOURCE_DIR}/include/beman/exemplar/identity.hpp"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's interesting how the header list moves to the top-level directory when it's a header-only library. This has two drawbacks:

  1. A header-only -> with-source-file transition is more dramatic.
  2. For a repository with multiple libraries, the top-level CMake file would grow quite large and we lose the "one CMakeLists.txt file per library" separation of concerns.

What are your thoughts on peeing the src/beman/exemplar directory and having it contain only a CMakeLists.txt that builds the target?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn't be necessary to have the list of files in the root, but I have found that creating the library and naming the header set at the root makes it more local.

https://github.com/steve-downey/optional/blob/main/CMakeLists.txt#L23-L28
and
https://github.com/steve-downey/optional/blob/main/include/beman/optional/CMakeLists.txt#L4-L15

)

set_target_properties(beman.exemplar PROPERTIES VERIFY_INTERFACE_HEADER_SETS ON)

add_subdirectory(src/beman/exemplar)
find_package(beman-install-library REQUIRED)
beman_install_library(beman.exemplar)

include(CTest)

if(BEMAN_EXEMPLAR_BUILD_TESTS)
add_subdirectory(tests/beman/exemplar)
Expand Down
18 changes: 7 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,6 @@ cmake -B build -S . -DCMAKE_CXX_STANDARD=20 -DBEMAN_EXEMPLAR_BUILD_TESTS=OFF

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


#### `BEMAN_EXEMPLAR_INSTALL_CONFIG_FILE_PACKAGE`

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

### Produce beman.exemplar static library
### Produce beman.exemplar interface library

You can include exemplar's headers locally
by producing a static `libbeman.exemplar.a` library.
You can produce exemplar's interface library locally by:

```bash
cmake --workflow --preset gcc-release
Expand All @@ -377,11 +375,9 @@ This will generate the following directory structure at `/opt/beman`.
│ └── exemplar
│ └── identity.hpp
└── lib
├── cmake
│   └── beman.exemplar
│   ├── beman.exemplar-config-version.cmake
│   ├── beman.exemplar-config.cmake
│   ├── beman.exemplar-targets-debug.cmake
│   └── beman.exemplar-targets.cmake
└── libbeman.exemplar.a
└── cmake
└── beman.exemplar
├── beman.exemplar-config-version.cmake
├── beman.exemplar-config.cmake
└── beman.exemplar-targets.cmake
```
3 changes: 2 additions & 1 deletion cookiecutter/check_cookiecutter.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ function check_consistency() {
paper="P0898R3" \
owner="bemanproject" \
description="A Beman Library Exemplar" \
godbolt_link="https://godbolt.org/z/4qEPK87va"
godbolt_link="https://godbolt.org/z/4qEPK87va" \
library_type="interface"
cp "$script_dir"/../.github/workflows/cookiecutter_test.yml "$out_dir_path"/exemplar/.github/workflows
local diff_path
diff_path=$(mktemp)
Expand Down
7 changes: 4 additions & 3 deletions cookiecutter/cookiecutter.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
"owner": "github-user-name",
"description": "Short project description.",
"godbolt_link": "https://www.example.com",
"library_type": ["interface", "static"],
"_copy_without_render": [
"infra",
".github/workflows"
]
"infra"
],
"_jinja2_env_vars": {"trim_blocks": true}
}
19 changes: 19 additions & 0 deletions cookiecutter/hooks/post_gen_project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

"""Post-generation hook to clean up template files based on library_type."""

import shutil
from pathlib import Path

# Get the library type from cookiecutter context
library_type = "{{ cookiecutter.library_type }}"

# If interface library, remove the src/ directory (not needed for header-only)
if library_type == "interface":
src_dir = Path("src")
if src_dir.exists():
shutil.rmtree(src_dir)
print("✓ Removed src/ directory (not needed for interface library)")

print("✓ Template generation complete")
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ jobs:
{ "stdlibs": ["libstdc++"],
"tests": [
"Debug.Default", "Release.Default", "Release.TSan",
"Release.MaxSan", "Debug.Werror", "Debug.Dynamic",
"Debug.Coverage"
"Release.MaxSan", "Debug.Werror",
"Debug.Coverage"{% if cookiecutter.library_type == "static" %}, "Debug.Dynamic"{% endif %}

]
}
]
Expand Down Expand Up @@ -78,7 +79,8 @@ jobs:
{ "stdlibs": ["libstdc++", "libc++"],
"tests": [
"Debug.Default", "Release.Default", "Release.TSan",
"Release.MaxSan", "Debug.Werror", "Debug.Dynamic"
"Release.MaxSan", "Debug.Werror"{% if cookiecutter.library_type == "static" %}, "Debug.Dynamic"{% endif %}

]
}
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ on:
schedule:
- cron: "0 16 * * 0"

{% raw -%}
jobs:
auto-update-pre-commit:
uses: bemanproject/infra-workflows/.github/workflows/[email protected]
secrets:
APP_ID: ${{ secrets.AUTO_PR_BOT_APP_ID }}
PRIVATE_KEY: ${{ secrets.AUTO_PR_BOT_PRIVATE_KEY }}
{%- endraw %}

21 changes: 20 additions & 1 deletion cookiecutter/{{cookiecutter.project_name}}/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,28 @@ option(
${PROJECT_IS_TOP_LEVEL}
)

include(CTest)
{% if cookiecutter.library_type == "interface" %}
add_library(beman.{{cookiecutter.project_name}} INTERFACE)
add_library(beman::{{cookiecutter.project_name}} ALIAS beman.{{cookiecutter.project_name}})

target_sources(
beman.{{cookiecutter.project_name}}
PUBLIC
FILE_SET HEADERS
BASE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/include"
FILES
"${CMAKE_CURRENT_SOURCE_DIR}/include/beman/{{cookiecutter.project_name}}/identity.hpp"
)

set_target_properties(beman.{{cookiecutter.project_name}} PROPERTIES VERIFY_INTERFACE_HEADER_SETS ON)

find_package(beman-install-library REQUIRED)
beman_install_library(beman.{{cookiecutter.project_name}})
{% else %}
add_subdirectory(src/beman/{{cookiecutter.project_name}})
{% endif %}

include(CTest)

if(BEMAN_{{cookiecutter.project_name.upper()}}_BUILD_TESTS)
add_subdirectory(tests/beman/{{cookiecutter.project_name}})
Expand Down
37 changes: 28 additions & 9 deletions cookiecutter/{{cookiecutter.project_name}}/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,6 @@ cmake -B build -S . -DCMAKE_CXX_STANDARD=20 -DBEMAN_{{cookiecutter.project_name.

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


#### `BEMAN_{{cookiecutter.project_name.upper()}}_INSTALL_CONFIG_FILE_PACKAGE`

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

### Produce beman.{{cookiecutter.project_name}} static library
### Produce beman.{{cookiecutter.project_name}} {{ cookiecutter.library_type }} library

You can include {{cookiecutter.project_name}}'s headers locally
by producing a static `libbeman.{{cookiecutter.project_name}}.a` library.
{% if cookiecutter.library_type == "interface" %}
You can produce {{cookiecutter.project_name}}'s interface library locally by:
{% else %}
You can produce {{cookiecutter.project_name}}'s static library `libbeman.{{cookiecutter.project_name}}.a` by:
{% endif %}

```bash
cmake --workflow --preset gcc-release
Expand All @@ -370,6 +372,22 @@ cmake --install build/gcc-release --prefix /opt/beman

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

{% if cookiecutter.library_type == "interface" %}
```txt
/opt/beman
├── include
│ └── beman
│ └── {{cookiecutter.project_name}}
│ └── identity.hpp
└── lib
└── cmake
└── beman.{{cookiecutter.project_name}}
├── beman.{{cookiecutter.project_name}}-config-version.cmake
├── beman.{{cookiecutter.project_name}}-config.cmake
└── beman.{{cookiecutter.project_name}}-targets.cmake

```
{% else %}
```txt
/opt/beman
├── include
Expand All @@ -378,10 +396,11 @@ This will generate the following directory structure at `/opt/beman`.
│ └── identity.hpp
└── lib
├── cmake
   └── beman.{{cookiecutter.project_name}}
   ├── beman.{{cookiecutter.project_name}}-config-version.cmake
   ├── beman.{{cookiecutter.project_name}}-config.cmake
   ├── beman.{{cookiecutter.project_name}}-targets-debug.cmake
   └── beman.{{cookiecutter.project_name}}-targets.cmake
└── beman.{{cookiecutter.project_name}}
├── beman.{{cookiecutter.project_name}}-config-version.cmake
├── beman.{{cookiecutter.project_name}}-config.cmake
├── beman.{{cookiecutter.project_name}}-targets-debug.cmake
└── beman.{{cookiecutter.project_name}}-targets.cmake
└── libbeman.{{cookiecutter.project_name}}.a
```
{% endif %}
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
add_library(beman.{{cookiecutter.project_name}})
add_library(beman::{{cookiecutter.project_name}} ALIAS beman.{{cookiecutter.project_name}})

target_sources(beman.{{cookiecutter.project_name}} PRIVATE identity.cpp)

target_sources(
beman.{{cookiecutter.project_name}}
PUBLIC
FILE_SET HEADERS
BASE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/../../../include"
FILES
"${CMAKE_CURRENT_SOURCE_DIR}/../../../include/beman/{{cookiecutter.project_name}}/identity.hpp"
PRIVATE
identity.cpp
)

set_target_properties(beman.{{cookiecutter.project_name}} PROPERTIES VERIFY_INTERFACE_HEADER_SETS ON)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <beman/{{cookiecutter.project_name}}/identity.hpp>

// Implementation file for static library build.
// For a simple identity function, there's nothing to implement here,
// but this file exists to demonstrate the static library structure.
20 changes: 0 additions & 20 deletions src/beman/exemplar/CMakeLists.txt

This file was deleted.

3 changes: 0 additions & 3 deletions src/beman/exemplar/identity.cpp

This file was deleted.

Loading