cxx-init 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cxx_init-0.1.0/LICENSE +21 -0
- cxx_init-0.1.0/PKG-INFO +105 -0
- cxx_init-0.1.0/README.md +94 -0
- cxx_init-0.1.0/pyproject.toml +20 -0
- cxx_init-0.1.0/pyproject.toml.orig +20 -0
- cxx_init-0.1.0/src/cxx_init/__init__.py +1 -0
- cxx_init-0.1.0/src/cxx_init/cli.py +147 -0
- cxx_init-0.1.0/src/cxx_init/fixtures/canonical-app/.clang-format +263 -0
- cxx_init-0.1.0/src/cxx_init/fixtures/canonical-app/.clang-tidy +10 -0
- cxx_init-0.1.0/src/cxx_init/fixtures/canonical-app/.clangd +2 -0
- cxx_init-0.1.0/src/cxx_init/fixtures/canonical-app/.cxx.toml +3 -0
- cxx_init-0.1.0/src/cxx_init/fixtures/canonical-app/.gitignore +5 -0
- cxx_init-0.1.0/src/cxx_init/fixtures/canonical-app/CMakeLists.txt +50 -0
- cxx_init-0.1.0/src/cxx_init/fixtures/canonical-app/CMakePresets.json +103 -0
- cxx_init-0.1.0/src/cxx_init/fixtures/canonical-app/src/main.cpp +6 -0
- cxx_init-0.1.0/src/cxx_init/fixtures/canonical-app/tests/smoke_test.cpp +6 -0
cxx_init-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 snkio027
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
cxx_init-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cxx-init
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A small modern C++ project initializer.
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Requires-Python: >=3.10
|
|
8
|
+
Project-URL: Repository, https://github.com/snkio027/cxx-init
|
|
9
|
+
Project-URL: Issues, https://github.com/snkio027/cxx-init/issues
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
12
|
+
# cxx-init
|
|
13
|
+
|
|
14
|
+
A small personal tool for creating clean, modern C++ projects without repeating the same setup work.
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
uv tool install cxx-init
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Alternatively, use pipx:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pipx install cxx-init
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Create a project
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
cxx init hello
|
|
32
|
+
cd hello
|
|
33
|
+
cmake --workflow --preset dev
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The generated project uses normal C++ tooling directly and does not depend on `cxx` after creation.
|
|
37
|
+
|
|
38
|
+
Upgrade or uninstall the tool with:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
uv tool upgrade cxx-init
|
|
42
|
+
uv tool uninstall cxx-init
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Requirements
|
|
46
|
+
|
|
47
|
+
`cxx` requires Python 3.10 or newer. Generated projects require CMake 3.25 or newer,
|
|
48
|
+
Ninja, and a C++23 compiler.
|
|
49
|
+
|
|
50
|
+
## Design priorities
|
|
51
|
+
|
|
52
|
+
1. Personal developer experience first.
|
|
53
|
+
2. Small, readable implementation.
|
|
54
|
+
3. Minimal generated files.
|
|
55
|
+
4. No hidden host mutation.
|
|
56
|
+
5. No build-system wrapper.
|
|
57
|
+
6. No network requirement during project creation.
|
|
58
|
+
7. Prefer boring, inspectable code over framework-heavy abstractions.
|
|
59
|
+
|
|
60
|
+
## Scope
|
|
61
|
+
|
|
62
|
+
The current product creates one canonical `app` project. Additional artifact types remain deferred
|
|
63
|
+
until real usage demonstrates a need for them:
|
|
64
|
+
|
|
65
|
+
```text
|
|
66
|
+
lib
|
|
67
|
+
header-only
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Initial generated projects use:
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
C++23
|
|
74
|
+
Modern target-centric CMake
|
|
75
|
+
CMake Presets / Workflow Presets
|
|
76
|
+
Ninja
|
|
77
|
+
clangd
|
|
78
|
+
clang-format
|
|
79
|
+
clang-tidy
|
|
80
|
+
CTest
|
|
81
|
+
ASan / UBSan where supported
|
|
82
|
+
compile_commands.json
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Dependency managers, C++26, Modules, ROS, CUDA, benchmarking and fuzzing are intentionally deferred.
|
|
86
|
+
|
|
87
|
+
## Repository documents
|
|
88
|
+
|
|
89
|
+
- `AGENTS.md` — rules for Codex and other coding agents.
|
|
90
|
+
- `docs/architecture.md` — architecture and boundaries.
|
|
91
|
+
- `docs/implementation-plan.md` — current implementation sequence.
|
|
92
|
+
|
|
93
|
+
## Development
|
|
94
|
+
|
|
95
|
+
Build the wheel and source distribution with:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
uv build
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Run the black-box test suite with:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
python3 -m unittest discover -s tests -v
|
|
105
|
+
```
|
cxx_init-0.1.0/README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# cxx-init
|
|
2
|
+
|
|
3
|
+
A small personal tool for creating clean, modern C++ projects without repeating the same setup work.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
uv tool install cxx-init
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Alternatively, use pipx:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pipx install cxx-init
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Create a project
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
cxx init hello
|
|
21
|
+
cd hello
|
|
22
|
+
cmake --workflow --preset dev
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The generated project uses normal C++ tooling directly and does not depend on `cxx` after creation.
|
|
26
|
+
|
|
27
|
+
Upgrade or uninstall the tool with:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
uv tool upgrade cxx-init
|
|
31
|
+
uv tool uninstall cxx-init
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Requirements
|
|
35
|
+
|
|
36
|
+
`cxx` requires Python 3.10 or newer. Generated projects require CMake 3.25 or newer,
|
|
37
|
+
Ninja, and a C++23 compiler.
|
|
38
|
+
|
|
39
|
+
## Design priorities
|
|
40
|
+
|
|
41
|
+
1. Personal developer experience first.
|
|
42
|
+
2. Small, readable implementation.
|
|
43
|
+
3. Minimal generated files.
|
|
44
|
+
4. No hidden host mutation.
|
|
45
|
+
5. No build-system wrapper.
|
|
46
|
+
6. No network requirement during project creation.
|
|
47
|
+
7. Prefer boring, inspectable code over framework-heavy abstractions.
|
|
48
|
+
|
|
49
|
+
## Scope
|
|
50
|
+
|
|
51
|
+
The current product creates one canonical `app` project. Additional artifact types remain deferred
|
|
52
|
+
until real usage demonstrates a need for them:
|
|
53
|
+
|
|
54
|
+
```text
|
|
55
|
+
lib
|
|
56
|
+
header-only
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Initial generated projects use:
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
C++23
|
|
63
|
+
Modern target-centric CMake
|
|
64
|
+
CMake Presets / Workflow Presets
|
|
65
|
+
Ninja
|
|
66
|
+
clangd
|
|
67
|
+
clang-format
|
|
68
|
+
clang-tidy
|
|
69
|
+
CTest
|
|
70
|
+
ASan / UBSan where supported
|
|
71
|
+
compile_commands.json
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Dependency managers, C++26, Modules, ROS, CUDA, benchmarking and fuzzing are intentionally deferred.
|
|
75
|
+
|
|
76
|
+
## Repository documents
|
|
77
|
+
|
|
78
|
+
- `AGENTS.md` — rules for Codex and other coding agents.
|
|
79
|
+
- `docs/architecture.md` — architecture and boundaries.
|
|
80
|
+
- `docs/implementation-plan.md` — current implementation sequence.
|
|
81
|
+
|
|
82
|
+
## Development
|
|
83
|
+
|
|
84
|
+
Build the wheel and source distribution with:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
uv build
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Run the black-box test suite with:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
python3 -m unittest discover -s tests -v
|
|
94
|
+
```
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["uv_build>=0.12.7,<0.13"]
|
|
3
|
+
build-backend = "uv_build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "cxx-init"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A small modern C++ project initializer."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
dependencies = []
|
|
14
|
+
|
|
15
|
+
[project.urls]
|
|
16
|
+
Repository = "https://github.com/snkio027/cxx-init"
|
|
17
|
+
Issues = "https://github.com/snkio027/cxx-init/issues"
|
|
18
|
+
|
|
19
|
+
[project.scripts]
|
|
20
|
+
cxx = "cxx_init.cli:main"
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["uv_build>=0.12.7,<0.13"]
|
|
3
|
+
build-backend = "uv_build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "cxx-init"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A small modern C++ project initializer."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
dependencies = []
|
|
14
|
+
|
|
15
|
+
[project.urls]
|
|
16
|
+
Repository = "https://github.com/snkio027/cxx-init"
|
|
17
|
+
Issues = "https://github.com/snkio027/cxx-init/issues"
|
|
18
|
+
|
|
19
|
+
[project.scripts]
|
|
20
|
+
cxx = "cxx_init.cli:main"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""A small modern C++ project initializer."""
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import re
|
|
3
|
+
import shutil
|
|
4
|
+
import subprocess
|
|
5
|
+
import sys
|
|
6
|
+
import tempfile
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
NAME_PATTERN = re.compile(r"[a-z][a-z0-9-]*\Z")
|
|
11
|
+
FIXTURE_NAME = "robot-runtime"
|
|
12
|
+
FIXTURE_IDENTIFIER = "robot_runtime"
|
|
13
|
+
LOCAL_FIXTURE_ENTRIES = ("build", "CMakeUserPresets.json", ".DS_Store", ".idea", ".vscode")
|
|
14
|
+
VERSION = "0.1.0"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class GenerationError(Exception):
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def parse_args(argv):
|
|
22
|
+
parser = argparse.ArgumentParser(
|
|
23
|
+
prog="cxx",
|
|
24
|
+
description="Create a clean, native C++ project.",
|
|
25
|
+
)
|
|
26
|
+
parser.add_argument("--version", action="version", version=f"%(prog)s {VERSION}")
|
|
27
|
+
commands = parser.add_subparsers(dest="command", required=True)
|
|
28
|
+
|
|
29
|
+
init_parser = commands.add_parser("init", help="create an executable project")
|
|
30
|
+
init_parser.add_argument("name", help="project name: [a-z][a-z0-9-]*")
|
|
31
|
+
init_parser.add_argument(
|
|
32
|
+
"--no-git",
|
|
33
|
+
action="store_true",
|
|
34
|
+
help="do not initialize a local Git repository",
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
return parser.parse_args(argv)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def validate_destination(name, destination):
|
|
41
|
+
if NAME_PATTERN.fullmatch(name) is None:
|
|
42
|
+
raise GenerationError(f"invalid project name {name!r}; expected [a-z][a-z0-9-]*")
|
|
43
|
+
|
|
44
|
+
if destination.is_symlink():
|
|
45
|
+
raise GenerationError(f"destination must not be a symbolic link: {destination}")
|
|
46
|
+
|
|
47
|
+
if not destination.exists():
|
|
48
|
+
return False
|
|
49
|
+
|
|
50
|
+
if not destination.is_dir():
|
|
51
|
+
raise GenerationError(f"destination already exists and is not a directory: {destination}")
|
|
52
|
+
|
|
53
|
+
if next(destination.iterdir(), None) is not None:
|
|
54
|
+
raise GenerationError(f"destination already exists and is not empty: {destination}")
|
|
55
|
+
|
|
56
|
+
return True
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def render_fixture(root, name, identifier):
|
|
60
|
+
replacements = (
|
|
61
|
+
(FIXTURE_NAME, name),
|
|
62
|
+
(FIXTURE_IDENTIFIER, identifier),
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
for generated_file in sorted(candidate for candidate in root.rglob("*") if candidate.is_file()):
|
|
66
|
+
try:
|
|
67
|
+
content = generated_file.read_text(encoding="utf-8")
|
|
68
|
+
except UnicodeDecodeError as error:
|
|
69
|
+
raise GenerationError(f"fixture contains a non-text file: {generated_file}") from error
|
|
70
|
+
|
|
71
|
+
for source, replacement in replacements:
|
|
72
|
+
content = content.replace(source, replacement)
|
|
73
|
+
|
|
74
|
+
generated_file.write_text(content, encoding="utf-8")
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def initialize_git(root):
|
|
78
|
+
try:
|
|
79
|
+
result = subprocess.run(
|
|
80
|
+
["git", "init", "--quiet"],
|
|
81
|
+
cwd=root,
|
|
82
|
+
check=False,
|
|
83
|
+
capture_output=True,
|
|
84
|
+
text=True,
|
|
85
|
+
)
|
|
86
|
+
except FileNotFoundError as error:
|
|
87
|
+
raise GenerationError("git is not available; rerun with --no-git") from error
|
|
88
|
+
|
|
89
|
+
if result.returncode != 0:
|
|
90
|
+
detail = result.stderr.strip() or "unknown error"
|
|
91
|
+
raise GenerationError(f"git init failed: {detail}")
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def create_app(name, use_git):
|
|
95
|
+
fixture = Path(__file__).resolve().parent / "fixtures" / "canonical-app"
|
|
96
|
+
if not fixture.is_dir():
|
|
97
|
+
raise GenerationError(f"bundled app fixture is missing: {fixture}")
|
|
98
|
+
|
|
99
|
+
destination = Path.cwd() / name
|
|
100
|
+
destination_was_empty = validate_destination(name, destination)
|
|
101
|
+
identifier = name.replace("-", "_")
|
|
102
|
+
|
|
103
|
+
staging = Path(tempfile.mkdtemp(prefix=f".{name}.cxx-", dir=destination.parent))
|
|
104
|
+
try:
|
|
105
|
+
shutil.copytree(
|
|
106
|
+
fixture,
|
|
107
|
+
staging,
|
|
108
|
+
dirs_exist_ok=True,
|
|
109
|
+
ignore=shutil.ignore_patterns(*LOCAL_FIXTURE_ENTRIES),
|
|
110
|
+
)
|
|
111
|
+
render_fixture(staging, name, identifier)
|
|
112
|
+
|
|
113
|
+
if use_git:
|
|
114
|
+
initialize_git(staging)
|
|
115
|
+
|
|
116
|
+
if destination_was_empty:
|
|
117
|
+
destination.rmdir()
|
|
118
|
+
|
|
119
|
+
staging.replace(destination)
|
|
120
|
+
except Exception:
|
|
121
|
+
shutil.rmtree(staging, ignore_errors=True)
|
|
122
|
+
if destination_was_empty and not destination.exists():
|
|
123
|
+
destination.mkdir()
|
|
124
|
+
raise
|
|
125
|
+
|
|
126
|
+
return destination
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def main(argv=None):
|
|
130
|
+
args = parse_args(argv)
|
|
131
|
+
|
|
132
|
+
try:
|
|
133
|
+
destination = create_app(args.name, use_git=not args.no_git)
|
|
134
|
+
except (GenerationError, OSError) as error:
|
|
135
|
+
print(f"cxx: error: {error}", file=sys.stderr)
|
|
136
|
+
return 1
|
|
137
|
+
|
|
138
|
+
print(f"Created C++ project: {destination.name}")
|
|
139
|
+
print()
|
|
140
|
+
print("Next:")
|
|
141
|
+
print(f" cd {args.name}")
|
|
142
|
+
print(" cmake --workflow --preset dev")
|
|
143
|
+
return 0
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
if __name__ == "__main__":
|
|
147
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
---
|
|
2
|
+
# =============================================================================
|
|
3
|
+
# Modern C++ Systems House Style
|
|
4
|
+
#
|
|
5
|
+
# Language baseline : C++23
|
|
6
|
+
# Formatter baseline: clang-format 23.1.x
|
|
7
|
+
# Style philosophy : Google-derived, compact, explicit, type-first,
|
|
8
|
+
# low-diff-noise, systems-oriented.
|
|
9
|
+
# =============================================================================
|
|
10
|
+
|
|
11
|
+
Language: Cpp
|
|
12
|
+
BasedOnStyle: Google
|
|
13
|
+
Standard: c++23
|
|
14
|
+
|
|
15
|
+
# -----------------------------------------------------------------------------
|
|
16
|
+
# Core layout
|
|
17
|
+
# -----------------------------------------------------------------------------
|
|
18
|
+
|
|
19
|
+
ColumnLimit: 100
|
|
20
|
+
|
|
21
|
+
IndentWidth: 4
|
|
22
|
+
ContinuationIndentWidth: 4
|
|
23
|
+
TabWidth: 4
|
|
24
|
+
UseTab: Never
|
|
25
|
+
|
|
26
|
+
# Keep multiline expressions visually anchored to their opening delimiter.
|
|
27
|
+
AlignAfterOpenBracket: true
|
|
28
|
+
|
|
29
|
+
# Avoid artificial visual tables that create noisy diffs when identifiers change.
|
|
30
|
+
AlignTrailingComments:
|
|
31
|
+
Kind: Never
|
|
32
|
+
OverEmptyLines: 0
|
|
33
|
+
|
|
34
|
+
SpacesBeforeTrailingComments: 2
|
|
35
|
+
|
|
36
|
+
# -----------------------------------------------------------------------------
|
|
37
|
+
# Type spelling: T*, T&, T&&
|
|
38
|
+
# -----------------------------------------------------------------------------
|
|
39
|
+
|
|
40
|
+
# Do not infer pointer style from legacy code in each individual file.
|
|
41
|
+
DerivePointerAlignment: false
|
|
42
|
+
|
|
43
|
+
# Type-first visual model:
|
|
44
|
+
#
|
|
45
|
+
# T* ptr;
|
|
46
|
+
# T& ref;
|
|
47
|
+
# T&& ref;
|
|
48
|
+
#
|
|
49
|
+
PointerAlignment: Left
|
|
50
|
+
ReferenceAlignment: Left
|
|
51
|
+
|
|
52
|
+
# House style uses west-const in authored code:
|
|
53
|
+
#
|
|
54
|
+
# const T*
|
|
55
|
+
# const T&
|
|
56
|
+
#
|
|
57
|
+
# Do NOT ask clang-format to rewrite qualifiers automatically: clang-format
|
|
58
|
+
# explicitly warns that qualifier reordering can make incorrect semantic guesses.
|
|
59
|
+
QualifierAlignment: Leave
|
|
60
|
+
SpaceAroundPointerQualifiers: Default
|
|
61
|
+
|
|
62
|
+
# -----------------------------------------------------------------------------
|
|
63
|
+
# Classes / records
|
|
64
|
+
# -----------------------------------------------------------------------------
|
|
65
|
+
|
|
66
|
+
# Prefer:
|
|
67
|
+
#
|
|
68
|
+
# class Foo {
|
|
69
|
+
# public:
|
|
70
|
+
# ...
|
|
71
|
+
#
|
|
72
|
+
# private:
|
|
73
|
+
# ...
|
|
74
|
+
# };
|
|
75
|
+
#
|
|
76
|
+
IndentAccessModifiers: false
|
|
77
|
+
AccessModifierOffset: -4
|
|
78
|
+
|
|
79
|
+
EmptyLineBeforeAccessModifier: LogicalBlock
|
|
80
|
+
EmptyLineAfterAccessModifier: Never
|
|
81
|
+
|
|
82
|
+
# Empty marker/tag records may remain compact:
|
|
83
|
+
#
|
|
84
|
+
# struct EmptyTag {};
|
|
85
|
+
#
|
|
86
|
+
# Non-empty records remain multiline.
|
|
87
|
+
AllowShortRecordOnASingleLine: Empty
|
|
88
|
+
|
|
89
|
+
# -----------------------------------------------------------------------------
|
|
90
|
+
# Control flow
|
|
91
|
+
# -----------------------------------------------------------------------------
|
|
92
|
+
|
|
93
|
+
BreakBeforeBraces: Attach
|
|
94
|
+
|
|
95
|
+
# Never collapse control-flow bodies onto one line.
|
|
96
|
+
AllowShortIfStatementsOnASingleLine: Never
|
|
97
|
+
AllowShortLoopsOnASingleLine: false
|
|
98
|
+
AllowShortBlocksOnASingleLine: Never
|
|
99
|
+
AllowShortCaseLabelsOnASingleLine: false
|
|
100
|
+
|
|
101
|
+
# Keep switch structure shallow and visually obvious.
|
|
102
|
+
IndentCaseLabels: false
|
|
103
|
+
|
|
104
|
+
# -----------------------------------------------------------------------------
|
|
105
|
+
# Functions / lambdas
|
|
106
|
+
# -----------------------------------------------------------------------------
|
|
107
|
+
|
|
108
|
+
# Empty functions may stay compact; real implementations get a normal body.
|
|
109
|
+
AllowShortFunctionsOnASingleLine: Empty
|
|
110
|
+
|
|
111
|
+
# Small inline callback lambdas are often clearer on one line:
|
|
112
|
+
#
|
|
113
|
+
# std::ranges::find_if(values, [](int value) { return value > 0; });
|
|
114
|
+
#
|
|
115
|
+
AllowShortLambdasOnASingleLine: Inline
|
|
116
|
+
|
|
117
|
+
# If a parameter/argument list fits within 100 columns, keep it on one line.
|
|
118
|
+
# Once it must wrap, prefer one logical item per continuation line instead of
|
|
119
|
+
# dense partial bin-packing.
|
|
120
|
+
PackParameters:
|
|
121
|
+
BinPack: OnePerLine
|
|
122
|
+
|
|
123
|
+
PackArguments:
|
|
124
|
+
BinPack: OnePerLine
|
|
125
|
+
|
|
126
|
+
AllowAllParametersOfDeclarationOnNextLine: false
|
|
127
|
+
AllowAllArgumentsOnNextLine: false
|
|
128
|
+
|
|
129
|
+
# Keep noexcept attached to the function signature.
|
|
130
|
+
AllowBreakBeforeNoexceptSpecifier: Never
|
|
131
|
+
|
|
132
|
+
# -----------------------------------------------------------------------------
|
|
133
|
+
# Constructors / inheritance
|
|
134
|
+
# -----------------------------------------------------------------------------
|
|
135
|
+
|
|
136
|
+
# Short:
|
|
137
|
+
#
|
|
138
|
+
# Point::Point(float x, float y) : x_(x), y_(y) {}
|
|
139
|
+
#
|
|
140
|
+
# Long:
|
|
141
|
+
#
|
|
142
|
+
# RobotFrame::RobotFrame(...)
|
|
143
|
+
# : samples_(...),
|
|
144
|
+
# timestamp_(...) {}
|
|
145
|
+
#
|
|
146
|
+
BreakConstructorInitializers: BeforeColon
|
|
147
|
+
PackConstructorInitializers: CurrentLine
|
|
148
|
+
|
|
149
|
+
# Long inheritance lists use the same visual grammar.
|
|
150
|
+
BreakInheritanceList: BeforeColon
|
|
151
|
+
|
|
152
|
+
# -----------------------------------------------------------------------------
|
|
153
|
+
# C++20 / C++23 Concepts
|
|
154
|
+
# -----------------------------------------------------------------------------
|
|
155
|
+
|
|
156
|
+
# Prefer:
|
|
157
|
+
#
|
|
158
|
+
# template <typename T>
|
|
159
|
+
# concept Sensor = ...;
|
|
160
|
+
#
|
|
161
|
+
BreakBeforeConceptDeclarations: Always
|
|
162
|
+
|
|
163
|
+
# Prefer:
|
|
164
|
+
#
|
|
165
|
+
# template <typename T>
|
|
166
|
+
# requires Sensor<T>
|
|
167
|
+
# void process(T value);
|
|
168
|
+
#
|
|
169
|
+
RequiresClausePosition: OwnLine
|
|
170
|
+
IndentRequiresClause: false
|
|
171
|
+
|
|
172
|
+
# Avoid excessive indentation inside requires expressions.
|
|
173
|
+
RequiresExpressionIndentation: OuterScope
|
|
174
|
+
|
|
175
|
+
# Keep normal compound requirements readable and compact:
|
|
176
|
+
#
|
|
177
|
+
# { value.read() } -> std::same_as<int>;
|
|
178
|
+
#
|
|
179
|
+
AllowShortCompoundRequirementOnASingleLine: true
|
|
180
|
+
|
|
181
|
+
SpaceAfterTemplateKeyword: true
|
|
182
|
+
|
|
183
|
+
# -----------------------------------------------------------------------------
|
|
184
|
+
# Enums / namespaces
|
|
185
|
+
# -----------------------------------------------------------------------------
|
|
186
|
+
|
|
187
|
+
AllowShortEnumsOnASingleLine: false
|
|
188
|
+
AllowShortNamespacesOnASingleLine: false
|
|
189
|
+
|
|
190
|
+
NamespaceIndentation: None
|
|
191
|
+
FixNamespaceComments: true
|
|
192
|
+
ShortNamespaceLines: 1
|
|
193
|
+
|
|
194
|
+
# -----------------------------------------------------------------------------
|
|
195
|
+
# Vertical rhythm
|
|
196
|
+
# -----------------------------------------------------------------------------
|
|
197
|
+
|
|
198
|
+
MaxEmptyLinesToKeep: 1
|
|
199
|
+
|
|
200
|
+
KeepEmptyLines:
|
|
201
|
+
AtStartOfBlock: false
|
|
202
|
+
AtStartOfFile: false
|
|
203
|
+
AtEndOfFile: false
|
|
204
|
+
|
|
205
|
+
# Give top-level definitions enough breathing room without allowing arbitrary
|
|
206
|
+
# vertical whitespace to accumulate.
|
|
207
|
+
SeparateDefinitionBlocks: Always
|
|
208
|
+
|
|
209
|
+
# -----------------------------------------------------------------------------
|
|
210
|
+
# String literals
|
|
211
|
+
# -----------------------------------------------------------------------------
|
|
212
|
+
|
|
213
|
+
# Do not manufacture adjacent string literals merely to satisfy ColumnLimit.
|
|
214
|
+
# Long human-facing strings should be intentionally structured by the author.
|
|
215
|
+
BreakStringLiterals: false
|
|
216
|
+
|
|
217
|
+
# -----------------------------------------------------------------------------
|
|
218
|
+
# Includes
|
|
219
|
+
# -----------------------------------------------------------------------------
|
|
220
|
+
|
|
221
|
+
# The main header corresponding to a .cpp automatically receives category 0.
|
|
222
|
+
#
|
|
223
|
+
# Example:
|
|
224
|
+
#
|
|
225
|
+
# robot_frame.cpp
|
|
226
|
+
# robot_frame.hpp <- category 0 automatically
|
|
227
|
+
#
|
|
228
|
+
MainIncludeChar: Quote
|
|
229
|
+
IncludeIsMainRegex: "(_test)?$"
|
|
230
|
+
|
|
231
|
+
# Merge existing include blocks, sort them, then rebuild semantic groups.
|
|
232
|
+
IncludeBlocks: Regroup
|
|
233
|
+
|
|
234
|
+
SortIncludes:
|
|
235
|
+
Enabled: true
|
|
236
|
+
IgnoreCase: false
|
|
237
|
+
IgnoreExtension: false
|
|
238
|
+
|
|
239
|
+
# clang-format uses the FIRST matching regex.
|
|
240
|
+
#
|
|
241
|
+
# Resulting order:
|
|
242
|
+
#
|
|
243
|
+
# 0. Current translation unit's main header
|
|
244
|
+
# 1. Standard library + OS/system headers
|
|
245
|
+
# 2. Known third-party libraries
|
|
246
|
+
# 3. Project-local headers
|
|
247
|
+
#
|
|
248
|
+
IncludeCategories:
|
|
249
|
+
# Known third-party roots must appear before the generic <...> matcher.
|
|
250
|
+
- Regex: '^["<](boost|fmt|spdlog|nlohmann|gtest|gmock|benchmark|Eigen|eigen3)/'
|
|
251
|
+
Priority: 2
|
|
252
|
+
CaseSensitive: true
|
|
253
|
+
|
|
254
|
+
# Standard C/C++ library and platform/system headers.
|
|
255
|
+
- Regex: "^<.*>$"
|
|
256
|
+
Priority: 1
|
|
257
|
+
CaseSensitive: true
|
|
258
|
+
|
|
259
|
+
# Project-local headers.
|
|
260
|
+
- Regex: '^".*"$'
|
|
261
|
+
Priority: 3
|
|
262
|
+
CaseSensitive: true
|
|
263
|
+
...
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.25)
|
|
2
|
+
|
|
3
|
+
project(robot_runtime LANGUAGES CXX)
|
|
4
|
+
|
|
5
|
+
option(ENABLE_SANITIZERS "Enable address and undefined behavior sanitizers" OFF)
|
|
6
|
+
|
|
7
|
+
include(CTest)
|
|
8
|
+
|
|
9
|
+
add_executable(robot_runtime src/main.cpp)
|
|
10
|
+
target_compile_features(robot_runtime PRIVATE cxx_std_23)
|
|
11
|
+
set_target_properties(robot_runtime PROPERTIES CXX_EXTENSIONS OFF)
|
|
12
|
+
|
|
13
|
+
if(MSVC)
|
|
14
|
+
target_compile_options(robot_runtime PRIVATE /W4 /permissive-)
|
|
15
|
+
elseif(CMAKE_CXX_COMPILER_ID MATCHES "^(AppleClang|Clang|GNU)$")
|
|
16
|
+
target_compile_options(robot_runtime PRIVATE -Wall -Wextra -Wpedantic)
|
|
17
|
+
endif()
|
|
18
|
+
|
|
19
|
+
if(ENABLE_SANITIZERS)
|
|
20
|
+
if(CMAKE_CXX_COMPILER_ID MATCHES "^(AppleClang|Clang|GNU)$")
|
|
21
|
+
target_compile_options(
|
|
22
|
+
robot_runtime PRIVATE -fsanitize=address,undefined -fno-omit-frame-pointer
|
|
23
|
+
)
|
|
24
|
+
target_link_options(robot_runtime PRIVATE -fsanitize=address,undefined)
|
|
25
|
+
else()
|
|
26
|
+
message(FATAL_ERROR "Sanitizers are only configured for Clang, AppleClang, and GCC")
|
|
27
|
+
endif()
|
|
28
|
+
endif()
|
|
29
|
+
|
|
30
|
+
if(BUILD_TESTING)
|
|
31
|
+
add_executable(robot_runtime_smoke_test tests/smoke_test.cpp)
|
|
32
|
+
target_compile_features(robot_runtime_smoke_test PRIVATE cxx_std_23)
|
|
33
|
+
set_target_properties(robot_runtime_smoke_test PROPERTIES CXX_EXTENSIONS OFF)
|
|
34
|
+
|
|
35
|
+
if(MSVC)
|
|
36
|
+
target_compile_options(robot_runtime_smoke_test PRIVATE /W4 /permissive-)
|
|
37
|
+
elseif(CMAKE_CXX_COMPILER_ID MATCHES "^(AppleClang|Clang|GNU)$")
|
|
38
|
+
target_compile_options(robot_runtime_smoke_test PRIVATE -Wall -Wextra -Wpedantic)
|
|
39
|
+
endif()
|
|
40
|
+
|
|
41
|
+
if(ENABLE_SANITIZERS)
|
|
42
|
+
target_compile_options(
|
|
43
|
+
robot_runtime_smoke_test
|
|
44
|
+
PRIVATE -fsanitize=address,undefined -fno-omit-frame-pointer
|
|
45
|
+
)
|
|
46
|
+
target_link_options(robot_runtime_smoke_test PRIVATE -fsanitize=address,undefined)
|
|
47
|
+
endif()
|
|
48
|
+
|
|
49
|
+
add_test(NAME robot_runtime.smoke COMMAND robot_runtime_smoke_test)
|
|
50
|
+
endif()
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 6,
|
|
3
|
+
"cmakeMinimumRequired": {
|
|
4
|
+
"major": 3,
|
|
5
|
+
"minor": 25,
|
|
6
|
+
"patch": 0
|
|
7
|
+
},
|
|
8
|
+
"configurePresets": [
|
|
9
|
+
{
|
|
10
|
+
"name": "dev",
|
|
11
|
+
"displayName": "Development",
|
|
12
|
+
"generator": "Ninja",
|
|
13
|
+
"binaryDir": "${sourceDir}/build/dev",
|
|
14
|
+
"cacheVariables": {
|
|
15
|
+
"BUILD_TESTING": true,
|
|
16
|
+
"CMAKE_BUILD_TYPE": "Debug",
|
|
17
|
+
"CMAKE_EXPORT_COMPILE_COMMANDS": true,
|
|
18
|
+
"CMAKE_OSX_SYSROOT": "macosx"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"name": "san",
|
|
23
|
+
"displayName": "Sanitizers",
|
|
24
|
+
"inherits": "dev",
|
|
25
|
+
"binaryDir": "${sourceDir}/build/san",
|
|
26
|
+
"cacheVariables": {
|
|
27
|
+
"ENABLE_SANITIZERS": true
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
"buildPresets": [
|
|
32
|
+
{
|
|
33
|
+
"name": "dev",
|
|
34
|
+
"configurePreset": "dev"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"name": "san",
|
|
38
|
+
"configurePreset": "san"
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
"testPresets": [
|
|
42
|
+
{
|
|
43
|
+
"name": "dev",
|
|
44
|
+
"configurePreset": "dev",
|
|
45
|
+
"output": {
|
|
46
|
+
"outputOnFailure": true
|
|
47
|
+
},
|
|
48
|
+
"execution": {
|
|
49
|
+
"noTestsAction": "error",
|
|
50
|
+
"stopOnFailure": true
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"name": "san",
|
|
55
|
+
"configurePreset": "san",
|
|
56
|
+
"output": {
|
|
57
|
+
"outputOnFailure": true
|
|
58
|
+
},
|
|
59
|
+
"execution": {
|
|
60
|
+
"noTestsAction": "error",
|
|
61
|
+
"stopOnFailure": true
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
],
|
|
65
|
+
"workflowPresets": [
|
|
66
|
+
{
|
|
67
|
+
"name": "dev",
|
|
68
|
+
"displayName": "Development workflow",
|
|
69
|
+
"steps": [
|
|
70
|
+
{
|
|
71
|
+
"type": "configure",
|
|
72
|
+
"name": "dev"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"type": "build",
|
|
76
|
+
"name": "dev"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"type": "test",
|
|
80
|
+
"name": "dev"
|
|
81
|
+
}
|
|
82
|
+
]
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"name": "san",
|
|
86
|
+
"displayName": "Sanitizer workflow",
|
|
87
|
+
"steps": [
|
|
88
|
+
{
|
|
89
|
+
"type": "configure",
|
|
90
|
+
"name": "san"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"type": "build",
|
|
94
|
+
"name": "san"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"type": "test",
|
|
98
|
+
"name": "san"
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
}
|