Concurrency

This commit is contained in:
2026-07-28 22:17:49 -04:00
parent f235a0cf78
commit 969e36c5ff
29 changed files with 2966 additions and 111 deletions
+71
View File
@@ -0,0 +1,71 @@
# Advanced Makefile showcasing pattern rules, VPATH, conditionals,
# functions, automatic variables, and target-specific variables.
#
# Usage: antelope -gnu (builds "all")
# antelope -gnu DEBUG=1 (debug build)
# antelope -gnu check (run the test target)
# antelope -gnu clean (clean build artifacts)
# ---- Project Configuration ----
PROJECT = myapp
SRCDIR = src
BUILDDIR = build
VPATH = $(SRCDIR)
# ---- Conditional Configuration ----
ifeq ($(DEBUG),1)
CFLAGS = -g -O0 -DDEBUG
BUILDDIR = build/debug
else
CFLAGS = -O2 -DNDEBUG
BUILDDIR = build/release
endif
# ---- Auto-discovered sources ----
SRCS := $(notdir $(wildcard $(SRCDIR)/*.c))
OBJS := $(patsubst %.c,$(BUILDDIR)/%.o,$(SRCS))
# ---- Targets ----
.PHONY: all clean check
all: $(BUILDDIR)/$(PROJECT)
# Output directory creation (order-only prerequisite — timestamp doesn't
# trigger rebuild, but the directory must exist before the recipe runs).
$(BUILDDIR)/$(PROJECT): $(OBJS) | $(BUILDDIR)
$(CC) $(CFLAGS) -o $@ $^
# Pattern rule: build .o from .c, placing output in BUILDDIR
$(BUILDDIR)/%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
# Create the output directory
$(BUILDDIR):
mkdir -p $@
# ---- Per-target variables (release target gets extra optimization) ----
$(BUILDDIR)/release/$(PROJECT): CFLAGS += -flto
# ---- Utility targets ----
check: $(BUILDDIR)/$(PROJECT)
@echo "Running tests..."
./$(BUILDDIR)/$(PROJECT) --test
@echo "All tests passed."
clean:
rm -rf $(BUILDDIR)
# ---- Informational ----
info:
$(info Project: $(PROJECT))
$(info Sources: $(SRCS))
$(info Objects: $(OBJS))
$(info CFLAGS: $(CFLAGS))
$(info Build dir: $(BUILDDIR))
+15
View File
@@ -0,0 +1,15 @@
# Basic GNU Make build — uses implicit rules
#
# Usage: antelope -gnu (builds "all" using implicit rules)
# antelope -gnu clean (cleans build artifacts)
#
# In GNU mode, the %.o: %.c implicit rule handles hello.c → hello.o for free.
all: hello
hello: hello.o
.PHONY: clean
clean:
rm -f hello hello.o
+20
View File
@@ -0,0 +1,20 @@
# Basic Antelope build — native mode (explicit, no magic)
#
# Usage: antelope (builds "all")
# antelope clean (cleans build artifacts)
CC = gcc
CFLAGS = -Wall -O2
all: hello
hello: hello.o
$(CC) $(CFLAGS) -o hello hello.o
hello.o: hello.c
$(CC) $(CFLAGS) -c hello.c
.PHONY: clean
clean:
rm -f hello hello.o
+7
View File
@@ -0,0 +1,7 @@
#include <stdio.h>
int main(void)
{
printf("Hello from Antelope!\n");
return 0;
}
+17
View File
@@ -0,0 +1,17 @@
# Parallel build example — multiple independent sub-projects
#
# Usage: antelope -gnu -j4 (build all modules in parallel with 4 jobs)
# antelope -gnu -j0 (build with unlimited parallelism)
# antelope -gnu clean (clean all modules)
SUBDIRS = module_a module_b module_c
.PHONY: all clean $(SUBDIRS)
all clean: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $@ $(MAKECMDGOALS)
# .WAIT ensures module_c starts only after module_a and module_b finish.
module_c: module_a module_b .WAIT
+91
View File
@@ -0,0 +1,91 @@
# .WAIT and .JOBS examples — GNU Make mode (-gnu)
#
# Usage:
# antelope -gnu -j4 Build all targets with 4 parallel jobs
# antelope -gnu clean Clean build artifacts
#
# .WAIT splits prerequisites into sequential groups:
# target: group1 .WAIT group2
# → group1 completes first, then group2 starts
#
# .JOBS limits concurrency for named targets (GNU Make 4.4+):
# .JOBS: 2 heavy_a heavy_b
# → at most 2 of {heavy_a, heavy_b} run concurrently
# ── Example 1: .WAIT ordering barrier ──────────────────────────────
#
# In a multi-stage build, .WAIT ensures earlier stages complete
# before later stages begin. Targets on the same side of .WAIT
# can run in parallel.
all: stage1 stage2 stage3
# Stage 1: independent tasks — all run in parallel
stage1: task_a task_b
@echo "[stage1] all prerequisite tasks complete"
task_a:
@echo "[task_a] running..."
@sleep 0.2
@echo "[task_a] done"
task_b:
@echo "[task_b] running..."
@sleep 0.2
@echo "[task_b] done"
# Stage 2: must wait for stage1, then runs two tasks in parallel
stage2: stage1 .WAIT task_c task_d
@echo "[stage2] all prerequisite tasks complete"
task_c:
@echo "[task_c] running..."
@sleep 0.3
@echo "[task_c] done"
task_d:
@echo "[task_d] running..."
@sleep 0.3
@echo "[task_d] done"
# Stage 3: must wait for stage2
stage3: stage2 .WAIT
@echo "[stage3] final stage complete"
# ── Example 2: .JOBS resource throttle ─────────────────────────────
#
# When some targets are resource-heavy (CPU, memory, I/O), .JOBS
# caps their concurrency while allowing lighter targets to use
# the full global -j limit.
.JOBS: 2 big_compile_a big_compile_b big_compile_c
all_heavy: big_compile_a big_compile_b big_compile_c small_task
@echo "All done"
big_compile_a:
@echo "[big_compile_a] compiling..."
@sleep 0.4
@echo "[big_compile_a] done"
big_compile_b:
@echo "[big_compile_b] compiling..."
@sleep 0.4
@echo "[big_compile_b] done"
big_compile_c:
@echo "[big_compile_c] compiling..."
@sleep 0.4
@echo "[big_compile_c] done"
small_task:
@echo "[small_task] done instantly"
# ── Housekeeping ────────────────────────────────────────────────────
.PHONY: all stage1 stage2 stage3 task_a task_b task_c task_d
.PHONY: all_heavy big_compile_a big_compile_b big_compile_c small_task
.PHONY: clean
clean:
@echo "Cleaning..."
+88
View File
@@ -0,0 +1,88 @@
# .WAIT and .JOBS examples — native mode
#
# Usage:
# antelope Build all targets
# antelope -j4 Build with 4 parallel jobs
# antelope clean Clean build artifacts
#
# .WAIT splits prerequisites into sequential groups:
# target: group1 .WAIT group2
# → group1 completes first, then group2 starts
#
# .JOBS limits concurrency for named targets:
# .JOBS: N target1 target2 ...
# → target1 and target2 run at most N jobs concurrently
# ── Example 1: .WAIT barrier ───────────────────────────────────────
#
# pipeline: fetch .WAIT build .WAIT test
# → fetch runs, then build after fetch, then test after build
# Within each group, targets can run in parallel.
pipeline: fetch build test
@echo "Pipeline complete"
fetch:
@echo "Fetching dependencies..."
@sleep 0.2
@echo "Fetch done"
build: compile_a compile_b
@echo "Build complete"
compile_a:
@echo "Compiling module A..."
@sleep 0.3
@echo "Module A done"
compile_b:
@echo "Compiling module B..."
@sleep 0.3
@echo "Module B done"
# .WAIT ensures test runs only after build completes
test: build .WAIT
@echo "Running tests..."
@sleep 0.1
@echo "All tests passed"
# ── Example 2: .JOBS throttle ──────────────────────────────────────
#
# .JOBS: 2 heavy_a heavy_b heavy_c
# → Only 2 of {heavy_a, heavy_b, heavy_c} run concurrently
# Light targets (light_x, light_y) use the global -j limit.
.JOBS: 2 heavy_a heavy_b heavy_c
heavy_jobs: heavy_a heavy_b heavy_c light_x light_y
@echo "All heavy and light jobs done"
heavy_a:
@echo "[heavy_a] starting..."
@sleep 0.5
@echo "[heavy_a] done"
heavy_b:
@echo "[heavy_b] starting..."
@sleep 0.5
@echo "[heavy_b] done"
heavy_c:
@echo "[heavy_c] starting..."
@sleep 0.5
@echo "[heavy_c] done"
light_x:
@echo "[light_x] done instantly"
light_y:
@echo "[light_y] done instantly"
# ── Housekeeping ────────────────────────────────────────────────────
.PHONY: pipeline fetch build compile_a compile_b test
.PHONY: heavy_jobs heavy_a heavy_b heavy_c light_x light_y
.PHONY: clean
clean:
@echo "Cleaning..."