-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
450 lines (369 loc) · 16.8 KB
/
Makefile
File metadata and controls
450 lines (369 loc) · 16.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
# ProjectKeystone Makefile
# Simple build system with debug, release, and asan modes
# Artifacts stored in build/debug, build/release, build/debug.asan, build/release.asan
#
# Usage:
# make # Build debug mode (build/debug)
# make release # Build release mode (build/release)
# make debug.asan # Build debug with ASan (build/debug.asan)
# make release.asan # Build release with ASan (build/release.asan)
# make test # Run tests (uses debug build)
# make test.asan # Run tests with ASan (uses debug.asan build)
# ============================================================================
# Configuration Variables
# ============================================================================
# Number of processors for parallel builds
NPROC ?= $(shell nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)
# Container runtime (Podman) — pass NATIVE=1 to bypass container on CI/host
ifeq ($(NATIVE),1)
CONTAINER_CHECK :=
CONTAINER_PREFIX :=
else
CONTAINER_CHECK := podman compose up -d dev >/dev/null 2>&1 || true;
CONTAINER_PREFIX := podman compose exec -T dev
endif
# Compiler flags
BUILD_FLAGS_debug := -O0 -g -D_DEBUG
BUILD_FLAGS_release := -O3 -DNDEBUG
BUILD_FLAGS_asan := -fsanitize=address -fno-omit-frame-pointer
BUILD_FLAGS_ubsan := -fsanitize=undefined -fno-omit-frame-pointer
BUILD_FLAGS_lsan := -fsanitize=leak -fno-omit-frame-pointer
BUILD_FLAGS_tsan := -fsanitize=thread -fno-omit-frame-pointer
BUILD_FLAGS_msan := -fsanitize=memory -fno-omit-frame-pointer
BUILD_DIR ?= build
EMPTY :=
SPACE := $(EMPTY) $(EMPTY)
BUILD_SUBDIR ?= x86
BUILD_SUBDIR := $(subst $(SPACE),.,$(strip $(sort $(subst .,$(SPACE),$(BUILD_SUBDIR)))))
CMAKE_BUILD_TYPE ?= Debug
# TSan slows thread ops 5-20x; give it more time per test
CTEST_TIMEOUT ?= 120
# Conan dependency management
CONAN_OUTPUT_DIR ?= build/conan-deps
CONAN_TOOLCHAIN := $(wildcard $(CONAN_OUTPUT_DIR)/conan_toolchain.cmake)
CMAKE_EXTRA_FLAGS ?=
ifneq ($(CONAN_TOOLCHAIN),)
CMAKE_EXTRA_FLAGS += -DCMAKE_TOOLCHAIN_FILE=$(CONAN_TOOLCHAIN)
endif
# ============================================================================
# Dependency Management (Conan)
# ============================================================================
.PHONY: deps
deps:
@echo "Installing Conan dependencies (Debug + Release)..."
conan install . --output-folder=$(CONAN_OUTPUT_DIR) --build=missing -s build_type=Debug -s compiler.cppstd=20
conan install . --output-folder=$(CONAN_OUTPUT_DIR) --build=missing -s build_type=Release -s compiler.cppstd=20
# ============================================================================
# Default target
# ============================================================================
.PHONY: default
default: compile
# Directory creation rule - only runs if directory doesn't exist
.PHONY: $(BUILD_DIR)
$(BUILD_DIR)/$(BUILD_SUBDIR):
@echo "Creating build directory: $@"
@mkdir -p $(BUILD_DIR)/$(BUILD_SUBDIR)
# Generic build rule for any mode
compile: $(BUILD_DIR)/$(BUILD_SUBDIR)
@echo "Building $* mode..."
$(CONTAINER_CHECK)
$(CONTAINER_PREFIX) bash -c "cmake -S . -B $(BUILD_DIR)/$(BUILD_SUBDIR) -G Ninja -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) -DCMAKE_CXX_FLAGS=\"$(BUILD_FLAGS)\" $(CMAKE_EXTRA_FLAGS)"
$(CONTAINER_PREFIX) bash -c "cmake --build $(BUILD_DIR)/$(BUILD_SUBDIR) -j$(NPROC)"
# ============================================================================
# Test Recipes
# ============================================================================
.PHONY: test test.unit test.basic test.module test.component test.async test.distributed test.concurrency test.simulation test.grpc test.profiling
# Test executables
TEST_BASIC := basic_delegation_tests
TEST_MODULE := module_coordination_tests
TEST_COMPONENT := component_coordination_tests
TEST_ASYNC := async_delegation_tests
TEST_DISTRIBUTED := distributed_hierarchy_tests
TEST_UNIT := unit_tests
TEST_CONCURRENCY := concurrency_unit_tests
TEST_SIMULATION := simulation_unit_tests
TEST_GRPC := distributed_grpc_tests
TEST_PROFILING := profiling_tests
# Run all tests with ctest
test: compile
@echo "Running all tests..."
$(CONTAINER_CHECK)
$(CONTAINER_PREFIX) bash -c "cd $(BUILD_DIR)/$(BUILD_SUBDIR) && ctest --output-on-failure -j$(NPROC) --timeout $(CTEST_TIMEOUT)"
# Individual test suites (run specific executable)
test.unit: compile
@echo "Running unit tests..."
$(CONTAINER_CHECK)
$(CONTAINER_PREFIX) ./$(BUILD_DIR)/$(BUILD_SUBDIR)/$(TEST_UNIT)
test.basic: compile
@echo "Running basic delegation tests..."
$(CONTAINER_CHECK)
$(CONTAINER_PREFIX) ./$(BUILD_DIR)/$(BUILD_SUBDIR)/$(TEST_BASIC)
test.module: compile
@echo "Running module coordination tests..."
$(CONTAINER_CHECK)
$(CONTAINER_PREFIX) ./$(BUILD_DIR)/$(BUILD_SUBDIR)/$(TEST_MODULE)
test.component: compile
@echo "Running component coordination tests..."
$(CONTAINER_CHECK)
$(CONTAINER_PREFIX) ./$(BUILD_DIR)/$(BUILD_SUBDIR)/$(TEST_COMPONENT)
test.async: compile
@echo "Running async delegation tests..."
$(CONTAINER_CHECK)
$(CONTAINER_PREFIX) ./$(BUILD_DIR)/$(BUILD_SUBDIR)/$(TEST_ASYNC)
test.distributed: compile
@echo "Running distributed hierarchy tests..."
$(CONTAINER_CHECK)
$(CONTAINER_PREFIX) ./$(BUILD_DIR)/$(BUILD_SUBDIR)/$(TEST_DISTRIBUTED)
test.concurrency: compile
@echo "Running concurrency unit tests..."
$(CONTAINER_CHECK)
$(CONTAINER_PREFIX) ./$(BUILD_DIR)/$(BUILD_SUBDIR)/$(TEST_CONCURRENCY)
test.simulation: compile
@echo "Running simulation unit tests..."
$(CONTAINER_CHECK)
$(CONTAINER_PREFIX) ./$(BUILD_DIR)/$(BUILD_SUBDIR)/$(TEST_SIMULATION)
test.grpc: compile.grpc
@echo "Running gRPC distributed tests..."
$(CONTAINER_CHECK)
$(CONTAINER_PREFIX) ./$(BUILD_DIR)/$(BUILD_SUBDIR)/$(TEST_GRPC)
test.profiling: compile.profile
@echo "Running profiling tests..."
$(CONTAINER_CHECK)
$(CONTAINER_PREFIX) ./$(BUILD_DIR)/$(BUILD_SUBDIR)/$(TEST_PROFILING)
# ============================================================================
# Benchmark Recipes
# ============================================================================
.PHONY: benchmark benchmark.message-pool benchmark.distributed benchmark.strings
# Run all benchmarks
benchmark: compile.release
@echo "Running benchmarks..."
$(CONTAINER_CHECK)
$(CONTAINER_PREFIX) ./scripts/run_benchmarks.sh
# Individual benchmark targets
benchmark.message-pool: compile.release
@echo "Running message pool benchmarks..."
$(CONTAINER_CHECK)
$(CONTAINER_PREFIX) ./$(BUILD_DIR)/$(BUILD_SUBDIR)/message_pool_benchmarks
benchmark.distributed: compile.release
@echo "Running distributed benchmarks..."
$(CONTAINER_CHECK)
$(CONTAINER_PREFIX) ./$(BUILD_DIR)/$(BUILD_SUBDIR)/distributed_benchmarks
benchmark.strings: compile.release
@echo "Running string allocation benchmarks..."
$(CONTAINER_CHECK)
$(CONTAINER_PREFIX) ./$(BUILD_DIR)/$(BUILD_SUBDIR)/string_allocation_benchmarks
# ============================================================================
# Load Testing
# ============================================================================
.PHONY: load-test load-test.quick
# Run all load test scenarios
load-test: compile.release
@echo "Running load tests (full duration)..."
$(CONTAINER_CHECK)
$(CONTAINER_PREFIX) ./tests/load/run_all_scenarios.sh
# Run load tests in quick mode (for CI)
load-test.quick: compile.release
@echo "Running load tests (quick mode)..."
$(CONTAINER_CHECK)
$(CONTAINER_PREFIX) ./tests/load/run_all_scenarios.sh --quick
# ============================================================================
# Coverage
# ============================================================================
.PHONY: coverage
coverage: compile.coverage
@echo "Generating coverage report..."
$(CONTAINER_CHECK)
$(CONTAINER_PREFIX) ./scripts/generate_coverage.sh
# ============================================================================
# CI/CD Helper Recipes
# ============================================================================
.PHONY: ci ci.quick pre-commit
# Full CI pipeline
ci: compile.debug.asan test.debug.asan lint format.check
@echo "✓ CI pipeline complete"
# Quick CI (for pull requests)
ci.quick: compile.debug.asan test.basic test.module test.component format.check
@echo "✓ Quick CI complete"
# Pre-commit checks
pre-commit: format.check lint.clang-tidy test.basic
@echo "✓ Pre-commit checks passed"
# ============================================================================
# Linting & Static Analysis
# ============================================================================
.PHONY: lint lint-clang-tidy lint-cppcheck
lint:
@echo "Running static analysis..."
$(CONTAINER_CHECK)
$(CONTAINER_PREFIX) ./scripts/run_static_analysis.sh $(LINT_FLAGS);
%.clang-tidy:
@echo "Running clang-tidy..."
@$(MAKE) $* LINT_FLAGS=--clang-tidy-only
%.cppcheck:
@echo "Running cppcheck..."
$(CONTAINER_CHECK)
@$(MAKE) $* LINT_FLAGS=--cppcheck-only
# ============================================================================
# Code Formatting
# ============================================================================
.PHONY: format format.check
format:
@echo "Formatting C++ code with clang-format..."
$(CONTAINER_CHECK)
$(CONTAINER_PREFIX) bash -c \
"find src include tests benchmarks -type f \( -name '*.cpp' -o -name '*.hpp' \) \
-not -path '*/build/*' -not -path '*/_deps/*' \
| xargs clang-format -i --Werror";
@echo "✓ Formatting complete"
format.check:
@echo "Checking C++ formatting..."
$(CONTAINER_CHECK)
$(CONTAINER_PREFIX) bash -c \
"find src include tests benchmarks -type f \( -name '*.cpp' -o -name '*.hpp' \) \
-not -path '*/build/*' -not -path '*/_deps/*' \
| xargs clang-format --dry-run --Werror"
@echo "✓ Formatting check passed"
# ============================================================================
# Clean Recipes
# ============================================================================
.PHONY: clean clean-all clean-everything
# Clean specific build directory
clean:
@echo "Cleaning directory $(BUILD_DIR)..."
rm -rf $(BUILD_DIR)/$(BUILD_SUBDIR)
# ============================================================================
# Container Management (Podman)
# ============================================================================
.PHONY: container.build container.up container.clean container.down container.shell
container.build:
@echo "Building container image: dev..."
podman compose build dev
container.build.%:
@echo "Building container image: $*..."
podman compose build $*
container.up:
@echo "Starting dev container..."
podman compose up -d dev
sleep 2
container.clean:
@echo "Cleaning container resources..."
podman compose down -v
podman rmi -f projectkeystone-dev:latest projectkeystone:latest || true
container.down:
@echo "Stopping containers..."
podman compose down
container.shell: container.up
$(CONTAINER_PREFIX) /bin/bash
# ============================================================================
# Build Variants
# ============================================================================
# Sanitizer pattern rules - append sanitizer flags to existing targets
%.asan:
@$(MAKE) $* BUILD_FLAGS="$(BUILD_FLAGS) $(BUILD_FLAGS_asan)" BUILD_SUBDIR="$(BUILD_SUBDIR)$(suffix $@)" CMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE)
%.ubsan:
@$(MAKE) $* BUILD_FLAGS="$(BUILD_FLAGS) $(BUILD_FLAGS_ubsan)" BUILD_SUBDIR="$(BUILD_SUBDIR)$(suffix $@)" CMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE)
%.lsan:
@$(MAKE) $* BUILD_FLAGS="$(BUILD_FLAGS) $(BUILD_FLAGS_lsan)" BUILD_SUBDIR="$(BUILD_SUBDIR)$(suffix $@)" CMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE)
%.tsan:
@$(MAKE) $* BUILD_FLAGS="$(BUILD_FLAGS) $(BUILD_FLAGS_tsan)" BUILD_SUBDIR="$(BUILD_SUBDIR)$(suffix $@)" CMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) CTEST_TIMEOUT=600
%.msan:
@$(MAKE) $* BUILD_FLAGS="$(BUILD_FLAGS) $(BUILD_FLAGS_msan)" BUILD_SUBDIR="$(BUILD_SUBDIR)$(suffix $@)" CMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE)
# Feature flag patterns
%.grpc:
@$(MAKE) $* BUILD_FLAGS="$(BUILD_FLAGS) -DENABLE_GRPC=ON" BUILD_SUBDIR="$(BUILD_SUBDIR)$(suffix $@)" CMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE)
%.coverage:
@$(MAKE) $* BUILD_FLAGS="$(BUILD_FLAGS) -DENABLE_COVERAGE=ON" BUILD_SUBDIR="$(BUILD_SUBDIR)$(suffix $@)" CMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE)
%.profile:
@$(MAKE) $* BUILD_FLAGS="$(BUILD_FLAGS) -DENABLE_PROFILING=ON" BUILD_SUBDIR="$(BUILD_SUBDIR)$(suffix $@)" CMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE)
%.fuzz:
@$(MAKE) $* BUILD_FLAGS="$(BUILD_FLAGS) -DENABLE_FUZZING=ON" BUILD_SUBDIR="$(BUILD_SUBDIR)$(suffix $@)" CMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE)
%.debug:
@$(MAKE) $* BUILD_FLAGS="$(BUILD_FLAGS) $(BUILD_FLAGS_debug)" BUILD_SUBDIR="$(BUILD_SUBDIR)$(suffix $@)" CMAKE_BUILD_TYPE=Debug
%.release:
@$(MAKE) $* BUILD_FLAGS="$(BUILD_FLAGS) $(BUILD_FLAGS_release)" BUILD_SUBDIR="$(BUILD_SUBDIR)$(suffix $@)" CMAKE_BUILD_TYPE=Release
# Pattern rule for native variants — matches any target with .native suffix.
# Bypasses the container and runs the underlying target directly on the host.
%.native:
@$(MAKE) $* NATIVE=1
# ============================================================================
# Help & Info
# ============================================================================
.PHONY: help
help:
@echo "ProjectKeystone Makefile"
@echo "Unified build system with debug, release, sanitizer modes, and testing"
@echo ""
@echo "Usage: make <target>[.modifier]"
@echo ""
@echo "Build Commands:"
@echo " make Build debug mode (build/x86.debug)"
@echo " make compile.release Build release mode (build/x86.release)"
@echo " make compile.debug.asan Build debug with ASan (build/x86.debug.asan)"
@echo ""
@echo "Sanitizer Modifiers (append to any build/test target):"
@echo " .asan AddressSanitizer + UBSan"
@echo " .ubsan UndefinedBehaviorSanitizer"
@echo " .tsan ThreadSanitizer"
@echo " .lsan LeakSanitizer"
@echo " .msan MemorySanitizer"
@echo ""
@echo "Feature Modifiers:"
@echo " .grpc Enable gRPC support"
@echo " .coverage Enable coverage instrumentation"
@echo " .profile Enable profiling"
@echo " .fuzz Enable fuzzing"
@echo ""
@echo "Test Commands:"
@echo " make test Run all tests (ctest)"
@echo " make test.debug.asan Run all tests with ASan"
@echo " make test.debug.tsan Run all tests with TSan"
@echo " make test.unit Run unit tests"
@echo " make test.basic Run basic delegation tests"
@echo " make test.module Run module coordination tests"
@echo " make test.component Run component coordination tests"
@echo " make test.async Run async delegation tests"
@echo " make test.distributed Run distributed hierarchy tests"
@echo " make test.concurrency Run concurrency unit tests"
@echo " make test.simulation Run simulation unit tests"
@echo " make test.grpc Run gRPC tests (requires .grpc build)"
@echo " make test.profiling Run profiling tests"
@echo ""
@echo "Benchmarks & Load Testing:"
@echo " make benchmark Run all benchmarks (release build)"
@echo " make benchmark.message-pool Run message pool benchmarks"
@echo " make benchmark.distributed Run distributed benchmarks"
@echo " make benchmark.strings Run string allocation benchmarks"
@echo " make load-test Run all load tests (full)"
@echo " make load-test.quick Run load tests (quick, for CI)"
@echo ""
@echo "Coverage:"
@echo " make coverage Generate coverage report"
@echo ""
@echo "Lint & Format:"
@echo " make lint Run all linters"
@echo " make lint.clang-tidy Run clang-tidy only"
@echo " make lint.cppcheck Run cppcheck only"
@echo " make format Format all C++ files"
@echo " make format.check Check formatting (CI)"
@echo ""
@echo "CI/CD:"
@echo " make ci Full CI pipeline (build, test, lint, format)"
@echo " make ci.quick Quick CI for PRs"
@echo " make pre-commit Pre-commit checks"
@echo ""
@echo "Container (Podman):"
@echo " make container.build Build container image"
@echo " make container.up Start dev container"
@echo " make container.down Stop containers"
@echo " make container.shell Enter dev container"
@echo ""
@echo "Clean:"
@echo " make clean Clean current build directory"
@echo " make clean.debug Clean debug build"
@echo " make clean.release.tsan Clean release TSan build"
@echo ""
@echo "Examples:"
@echo " make compile.debug.asan # Build debug with ASan (in container)"
@echo " make test.debug.asan # Run tests with ASan (in container)"
@echo " make compile.debug.asan.native # Build debug with ASan on host (no container)"
@echo " make test.debug.tsan.native # Run TSan tests on host (no container)"
@echo " make benchmark.native # Run benchmarks on host (no container)"