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
19 changes: 19 additions & 0 deletions .github/workflows/verify-cpp-core-pin.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Verify cpp-core submodule pin

on:
push:
branches:
- main
pull_request:

jobs:
verify-cpp-core-pin:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive

- name: Verify cpp-core tag pin
run: make verify-submodule-pin
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "third_party/cpp-core"]
path = third_party/cpp-core
url = https://github.com/efvincent/cpp-core.git
24 changes: 21 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# aoc-cpp

Low-level Advent of Code workspace using C++23 modules and explicit systems-style design.
Low-level Advent of Code workspace using C++26 modules and explicit systems-style design.

This README is the documentation index and recommended reading path.

Expand Down Expand Up @@ -48,10 +48,26 @@ The rendered Doxygen site now uses a dedicated Markdown landing page so authored

### Requirements

- clang++ with C++23 modules support
- clang++ with C++26 modules support
- make
- doxygen (for API docs)

### Clone and submodule setup

The repository consumes core modules through a pinned git submodule.

```sh
git clone https://github.com/efvincent/aoc-cpp.git
cd aoc-cpp
git submodule update --init --recursive
```

To verify the pin contract locally:

```sh
make verify-submodule-pin
```

### Common commands

```sh
Expand All @@ -62,6 +78,7 @@ make instrument
make bear
make docs
make docs_pdf
make verify-submodule-pin
make clean
make clean_all

Expand Down Expand Up @@ -149,7 +166,8 @@ Example row with omitted part:

## Repository Layout

- src/: executable entry point and C++ module units
- src/: executable entry point and AoC-specific module units
- third_party/cpp-core/: pinned core module source submodule
- docs/: authored docs, Doxygen config, generated API docs
- data/: Advent of Code inputs
- build/: generated binaries, module caches, objects, and intermediate output
Expand Down
27 changes: 27 additions & 0 deletions ci/verify_cpp_core_submodule.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env sh
set -eu

submodule_path="${CPP_CORE_SUBMODULE_PATH:-third_party/cpp-core}"
tag_pattern="${CPP_CORE_TAG_PATTERN:-v[0-9]*.[0-9]*.[0-9]*}"

if ! git -C "$submodule_path" rev-parse --verify HEAD >/dev/null 2>&1; then
echo "cpp-core submodule is missing or not initialized: $submodule_path"
exit 1
fi

tag="$(git -C "$submodule_path" tag --points-at HEAD | head -n 1 || true)"

if [ -z "$tag" ]; then
echo "cpp-core submodule is not pinned to a release tag"
exit 1
fi

case "$tag" in
$tag_pattern)
echo "cpp-core pinned to release tag: $tag"
;;
*)
echo "cpp-core tag is not semver-shaped: $tag"
exit 1
;;
esac
30 changes: 30 additions & 0 deletions docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,36 @@ This document serves as the absolute reference for the architectural foundations

---

## Submodule Dependency Contract

- `cpp-core` is consumed via git submodule at `third_party/cpp-core`.
- Downstream pin policy: point only to released semver tags (`vMAJOR.MINOR.PATCH`).
- Reject untagged or floating submodule pointers in review/CI.

### Initial setup

```sh
git submodule update --init --recursive
```

### Standard upgrade workflow

```sh
git -C third_party/cpp-core fetch --tags origin
git -C third_party/cpp-core checkout vX.Y.Z
git add third_party/cpp-core
git commit -m "chore(submodule): bump cpp-core to vX.Y.Z"
```

After any bump, run full local integration checks (build modes and puzzle smoke runs) before opening a PR.

### Pin verification

- Local check: `make verify-submodule-pin`
- CI/script entrypoint: `ci/verify_cpp_core_submodule.sh`

---

## 1. Core Philosophy & Language Paradigm

### The "Orthodox C++" (C+) Paradigm
Expand Down
1 change: 1 addition & 0 deletions docs/Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -1010,6 +1010,7 @@ WARN_LOGFILE = docs/doxygen-warnings.log
# Note: If this tag is empty the current directory is searched.

INPUT = src \
third_party/cpp-core/src \
docs

# This tag can be used to specify the character encoding of the source files
Expand Down
35 changes: 22 additions & 13 deletions makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ MODE ?= debug

# Directory configuration
SRC_DIR := src
CORE_SRC_DIR := third_party/cpp-core/src
BUILD_DIR := build/$(MODE)
MOD_DIR := $(BUILD_DIR)/modules
OBJ_DIR := $(BUILD_DIR)/obj
Expand All @@ -32,7 +33,7 @@ CXX := clang++
OPENSSL_CFLAGS := $(shell pkg-config --cflags openssl 2>/dev/null)
OPENSSL_LIBS := $(shell pkg-config --libs openssl 2>/dev/null)

BASE_FLAGS := -std=c++23 -fno-exceptions -fno-rtti -Wall -Wextra -Wpedantic $(OPENSSL_CFLAGS)
BASE_FLAGS := -std=c++26 -fno-exceptions -fno-rtti -Wall -Wextra -Wpedantic -I./$(CORE_SRC_DIR) $(OPENSSL_CFLAGS)

ifeq ($(MODE), release)
# High optimization release
Expand All @@ -58,32 +59,37 @@ MJFLAGS = $(if $(GENERATE_COMPDB),-MJ $(COMPDB_DIR)/$(subst /,_,$(patsubst $(O
# Recursive source discovery for everything under src/
# =====================================================

CPPM_SRCS := $(shell find $(SRC_DIR) -type f -name '*.cppm' | sort)
AOC_CPPM_SRCS := $(shell find $(SRC_DIR) -type f -name '*.cppm' | sort)
CORE_CPPM_SRCS := $(shell find $(CORE_SRC_DIR) -type f -name '*.cppm' | sort)
CPP_SRCS := $(shell find $(SRC_DIR) -type f -name '*.cpp' | sort)

MODULE_SRCS := $(CPPM_SRCS)
MODULE_OBJS := $(patsubst $(SRC_DIR)/%.cppm,$(OBJ_DIR)/%.o,$(MODULE_SRCS))
CPP_OBJS := $(patsubst $(SRC_DIR)/%.cpp,$(OBJ_DIR)/%.o,$(CPP_SRCS))
MODULE_SRCS := $(AOC_CPPM_SRCS) $(CORE_CPPM_SRCS)

module_obj_from_src = $(OBJ_DIR)/$(patsubst %.cppm,%.o,$(1))
module_pcm_from_src = $(MOD_DIR)/$(patsubst %.cppm,%.pcm,$(1))

MODULE_OBJS := $(foreach src,$(MODULE_SRCS),$(call module_obj_from_src,$(src)))
CPP_OBJS := $(patsubst %.cpp,$(OBJ_DIR)/%.o,$(CPP_SRCS))

ALL_OBJS := $(MODULE_OBJS) $(CPP_OBJS)

# Point linker/consumers at every discovered prebuilt module.
LINK_MOD_FLAGS := $(foreach src,$(MODULE_SRCS),-fmodule-file=$(basename $(notdir $(src)))=$(MOD_DIR)/$(patsubst $(SRC_DIR)/%.cppm,%.pcm,$(src)))
LINK_MOD_FLAGS := $(foreach src,$(MODULE_SRCS),-fmodule-file=$(basename $(notdir $(src)))=$(call module_pcm_from_src,$(src)))

# Automatic module dependency extraction from `import <module>;` statements.
# Maps imported module names to local module object targets, so adding modules
# normally requires no makefile edits.
module_obj_from_name = $(patsubst $(SRC_DIR)/%.cppm,$(OBJ_DIR)/%.o,$(firstword $(filter %/$(1).cppm,$(MODULE_SRCS))))
imports_of_src = $(shell sed -n 's/^[[:space:]]*import[[:space:]]\([A-Za-z0-9_]*\)[[:space:]]*;.*/\1/p' $(1))
module_obj_from_name = $(call module_obj_from_src,$(firstword $(filter %/$(1).cppm,$(MODULE_SRCS))))
imports_of_src = $(shell sed -n 's/^[[:space:]]*\(export[[:space:]]\+\)\?import[[:space:]]\([A-Za-z0-9_.]*\)[[:space:]]*;.*/\2/p' $(1))
module_import_obj_deps = $(strip $(foreach m,$(call imports_of_src,$(1)),$(call module_obj_from_name,$(m))))

$(foreach src,$(MODULE_SRCS),$(eval $(patsubst $(SRC_DIR)/%.cppm,$(OBJ_DIR)/%.o,$(src)): $(call module_import_obj_deps,$(src))))
$(foreach src,$(MODULE_SRCS),$(eval $(call module_obj_from_src,$(src)): $(call module_import_obj_deps,$(src))))

#====================================
# Phase execution and meta rules
#====================================

.PHONY: all debug release lto instrument bench bench-debug bench-release bench-lto bench-instrument clean docs docs_pdf clean_all bear
.PHONY: all debug release lto instrument bench bench-debug bench-release bench-lto bench-instrument clean docs docs_pdf clean_all bear verify-submodule-pin

N ?= 1000
ARGS ?= 2015 2
Expand Down Expand Up @@ -117,6 +123,9 @@ bench-lto: lto
bench-instrument: instrument
@./bench_nanos.sh $(N) instrument $(ARGS)

verify-submodule-pin:
@sh ci/verify_cpp_core_submodule.sh

# The compilation database target: rebuilds with Clang -MJ fragments so
# module interface units are recorded correctly in compile_commands.json.
bear:
Expand All @@ -132,13 +141,13 @@ $(TARGET): $(ALL_OBJS)
@$(MKDIR) build
$(CXX) $(CXXFLAGS) $(ALL_OBJS) -o $(TARGET) $(OPENSSL_LIBS)

# rule A: Compile any module interface unit discovered under src/
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cppm
# rule A: Compile any module interface unit from AoC src or submodule core src.
$(OBJ_DIR)/%.o: %.cppm
@$(MKDIR) $(dir $(MOD_DIR)/$*.pcm) $(@D) $(if $(GENERATE_COMPDB),$(COMPDB_DIR))
$(CXX) $(CXXFLAGS) $(MOD_FLAGS) $(LINK_MOD_FLAGS) $(MJFLAGS) -fmodule-output=$(MOD_DIR)/$*.pcm -c $< -o $@

# rule B: Compile any translation unit discovered under src/
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp $(MODULE_OBJS)
$(OBJ_DIR)/%.o: %.cpp $(MODULE_OBJS)
@$(MKDIR) $(@D) $(if $(GENERATE_COMPDB),$(COMPDB_DIR))
$(CXX) $(CXXFLAGS) $(LINK_MOD_FLAGS) $(MJFLAGS) -c $< -o $@

Expand Down
Loading
Loading