# Lime parser generator -- hand-written GNU Makefile alternative. # # This file is the meson-free build path. It builds: # # bin/lime -- parser generator (single-file build by # default; pass LEX=1 to bundle the .lex # compiler into the same binary) # lib/liblime_parser.a -- runtime library (snapshot, parse_engine, # extension framework, conflict detection, # disambiguation, JIT stubs) # build/test/* -- the runtime-parse, destructor and # claims-proof tests # # Targets # make -- build lime + the library + tests # make test -- run the tests # make clean -- remove build artifacts # make format -- run clang-format across formatted files # make install -- install lime, liblime_parser.a, and the headers # under $(PREFIX) (default /usr/local) # # Configuration knobs # CC -- C compiler, default cc # CFLAGS -- extra C flags appended to the default set # LDFLAGS -- extra link flags # LEX=1 -- include the .lex compiler in the lime binary # JIT=0 -- disable LLVM JIT and build with stubs (default # auto-detects llvm-config) # PREFIX -- install prefix, default /usr/local # # This Makefile coexists with meson.build / ninja; pick whichever # build system you prefer. meson is recommended for development # (faster incremental builds, sanitizer presets, test isolation). # ------------------------------------------------------------------- # Configuration # ------------------------------------------------------------------- CC ?= cc AR ?= ar PREFIX ?= /usr/local # Pull in user CFLAGS at the end so they win. CSTD := -std=c11 -D_GNU_SOURCE CWARN := -Wall -Wextra -Wno-unused-parameter -Wno-comment COPT := -O2 -g CINCS := -Iinclude -Isrc -Isrc/lex CFLAGS_ALL := $(CSTD) $(CWARN) $(COPT) $(CINCS) $(CFLAGS) LDFLAGS_ALL := -lpthread $(LDFLAGS) # JIT: try llvm-config unless explicitly disabled. JIT ?= auto ifeq ($(JIT),0) CFLAGS_JIT := -DLIME_NO_JIT LDFLAGS_JIT := else ifeq ($(shell command -v llvm-config 2>/dev/null),) # No llvm-config -- silently fall back to stubs. CFLAGS_JIT := -DLIME_NO_JIT LDFLAGS_JIT := else CFLAGS_JIT := $(shell llvm-config --cflags) LDFLAGS_JIT := $(shell llvm-config --ldflags --libs core executionengine \ mcjit native analysis passes orcjit) endif endif # ------------------------------------------------------------------- # Layout # ------------------------------------------------------------------- BUILD := build BIN := bin LIB := lib LIME_BIN := $(BIN)/lime LIME_LIB := $(LIB)/liblime_parser.a # Library translation units. LIB_SRC := \ src/version.c \ src/snapshot.c \ src/snapshot_build.c \ src/snapshot_create.c \ src/snapshot_modify.c \ src/token_table.c \ src/tokenize.c \ src/tokenize_simd.c \ src/parse_context.c \ src/parse_engine.c \ src/extension.c \ src/conflict.c \ src/conflict_detector.c \ src/disambiguation.c \ src/strategy_priority.c \ src/strategy_fork_resolve.c \ src/mod_serialize.c \ src/dependency_resolver.c \ src/parser_manager.c \ src/parser_plugin.c \ src/parser_operations.c \ src/merkle_tree.c \ src/parser_composition.c \ src/parser_fork.c \ src/utf8.c \ src/lime_ast.c \ src/glr.c \ src/execution_policy.c \ src/extension_registry.c \ src/grammar_context.c \ src/context_switch.c \ src/lime_error.c \ src/jit_context.c \ src/jit_codegen.c \ src/jit_policy.c \ src/jit_tokenizer.c \ LIB_OBJ := $(LIB_SRC:%.c=$(BUILD)/%.o) LEX_SRC := $(wildcard src/lex/*.c) LEX_OBJ := $(LEX_SRC:%.c=$(BUILD)/%.o) # Tests TEST_LIST := \ test_claims_proof \ test_runtime_parse \ test_destructor \ test_extension_e2e \ TEST_BINS := $(addprefix $(BUILD)/test/,$(TEST_LIST)) # ------------------------------------------------------------------- # Default goal # ------------------------------------------------------------------- .PHONY: all all: $(LIME_BIN) $(LIME_LIB) $(TEST_BINS) # ------------------------------------------------------------------- # lime generator # ------------------------------------------------------------------- LIME_CFLAGS := $(CSTD) $(CWARN) $(COPT) $(CINCS) $(CFLAGS) ifeq ($(LEX),1) LIME_OBJ := $(BUILD)/lime.o $(LEX_OBJ) LIME_CFLAGS += -DLIME_HAS_LEX_COMPILER else LIME_OBJ := $(BUILD)/lime.o endif $(LIME_BIN): $(LIME_OBJ) | $(BIN) $(CC) -o $@ $^ $(LDFLAGS) $(BUILD)/lime.o: lime.c | $(BUILD) $(CC) $(LIME_CFLAGS) -c $< -o $@ $(BUILD)/src/lex/%.o: src/lex/%.c | $(BUILD)/src/lex $(CC) $(LIME_CFLAGS) -c $< -o $@ # ------------------------------------------------------------------- # Runtime library # ------------------------------------------------------------------- $(LIME_LIB): $(LIB_OBJ) | $(LIB) $(AR) rcs $@ $^ $(BUILD)/src/%.o: src/%.c | $(BUILD)/src $(CC) $(CFLAGS_ALL) $(CFLAGS_JIT) -c $< -o $@ # ------------------------------------------------------------------- # Tests # ------------------------------------------------------------------- # # Each test that needs a generated parser depends on the .y file # being run through lime first. The arithmetic grammar is shared # by test_runtime_parse and test_extension_e2e; %_grammar.c/h are # emitted into $(BUILD)/test/. # ------------------------------------------------------------------- $(BUILD)/test/test_claims_proof: tests/test_claims_proof.c $(LIME_LIB) | $(BUILD)/test $(CC) $(CFLAGS_ALL) $(CFLAGS_JIT) -o $@ $< $(LIME_LIB) \ $(LDFLAGS_ALL) $(LDFLAGS_JIT) $(BUILD)/test/bench_arith_grammar.c \ $(BUILD)/test/bench_arith_grammar.h \ $(BUILD)/test/bench_arith_grammar_snapshot.c: bench/bench_arith_grammar.y $(LIME_BIN) | $(BUILD)/test $(LIME_BIN) -T./limpar.c -n -d$(BUILD)/test $< $(BUILD)/test/test_runtime_parse: tests/test_runtime_parse.c \ $(BUILD)/test/bench_arith_grammar.c \ $(BUILD)/test/bench_arith_grammar_snapshot.c \ $(LIME_LIB) | $(BUILD)/test $(CC) $(CFLAGS_ALL) $(CFLAGS_JIT) -I$(BUILD)/test -o $@ \ tests/test_runtime_parse.c \ $(BUILD)/test/bench_arith_grammar.c \ $(BUILD)/test/bench_arith_grammar_snapshot.c \ $(LIME_LIB) $(LDFLAGS_ALL) $(LDFLAGS_JIT) $(BUILD)/test/test_extension_e2e: tests/test_extension_e2e.c \ $(BUILD)/test/bench_arith_grammar.c \ $(BUILD)/test/bench_arith_grammar_snapshot.c \ $(LIME_LIB) | $(BUILD)/test $(CC) $(CFLAGS_ALL) $(CFLAGS_JIT) -I$(BUILD)/test -o $@ \ tests/test_extension_e2e.c \ $(BUILD)/test/bench_arith_grammar.c \ $(BUILD)/test/bench_arith_grammar_snapshot.c \ $(LIME_LIB) $(LDFLAGS_ALL) $(LDFLAGS_JIT) $(BUILD)/test/test_destructor_grammar.c \ $(BUILD)/test/test_destructor_grammar.h: tests/test_destructor_grammar.y $(LIME_BIN) | $(BUILD)/test $(LIME_BIN) -T./limpar.c -d$(BUILD)/test $< $(BUILD)/test/test_destructor: tests/test_destructor.c \ $(BUILD)/test/test_destructor_grammar.c \ $(LIME_LIB) | $(BUILD)/test $(CC) $(CFLAGS_ALL) $(CFLAGS_JIT) -I$(BUILD)/test -Itests -o $@ \ tests/test_destructor.c \ $(BUILD)/test/test_destructor_grammar.c \ $(LIME_LIB) $(LDFLAGS_ALL) $(LDFLAGS_JIT) # ------------------------------------------------------------------- # Phony targets # ------------------------------------------------------------------- .PHONY: test format install clean help test: $(TEST_BINS) @set -e; for t in $(TEST_BINS); do echo "=== $$t ==="; $$t || exit 1; done format: @command -v clang-format >/dev/null || { \ echo "clang-format not in PATH; skipping" >&2; exit 0; } clang-format -i \ src/*.c src/*.h src/lex/*.c src/lex/*.h \ include/*.h \ tests/test_claims_proof.c tests/test_runtime_parse.c \ tests/test_destructor.c tests/test_extension_e2e.c \ bench/bench_jit_real_parser.c install: $(LIME_BIN) $(LIME_LIB) install -d $(DESTDIR)$(PREFIX)/bin install -d $(DESTDIR)$(PREFIX)/lib install -d $(DESTDIR)$(PREFIX)/include/lime install -m 0755 $(LIME_BIN) $(DESTDIR)$(PREFIX)/bin/ install -m 0644 $(LIME_LIB) $(DESTDIR)$(PREFIX)/lib/ install -m 0644 include/*.h $(DESTDIR)$(PREFIX)/include/lime/ install -m 0644 src/snapshot.h src/snapshot_modify.h src/extension.h \ $(DESTDIR)$(PREFIX)/include/lime/ install -m 0644 limpar.c $(DESTDIR)$(PREFIX)/share/lime/limpar.c clean: rm -rf $(BUILD) $(BIN) $(LIB) help: @echo "Targets:" @echo " all -- lime + library + tests" @echo " test -- run the test programs (after building)" @echo " format -- run clang-format" @echo " install -- install to PREFIX (default /usr/local)" @echo " dist -- create lime-parser-VERSION.tar.gz release tarball" @echo " clean -- remove build artifacts" @echo "Knobs: CC, CFLAGS, LDFLAGS, LEX=1, JIT=0, PREFIX" # ------------------------------------------------------------------- # Distribution tarball # ------------------------------------------------------------------- # # `make dist` produces a reproducible release tarball: # # lime-parser-X.Y.Z.tar.gz # # under ./build-dist/, containing every file tracked by git at HEAD # (no untracked / build artifacts). The version comes from # meson.build (single source of truth). Equivalent to # `meson dist -C builddir --no-tests` but doesn't require a # configured meson build directory. VERSION ?= $(shell awk -F"[ ,'\":]+" '/^[[:space:]]*version[[:space:]]*:/ { print $$3; exit }' meson.build) DIST_NAME = lime-parser-$(VERSION) DIST_DIR = build-dist .PHONY: dist dist: @echo "Creating release tarball $(DIST_NAME).tar.gz" @mkdir -p $(DIST_DIR) @git archive --format=tar.gz --prefix=$(DIST_NAME)/ \ -o $(DIST_DIR)/$(DIST_NAME).tar.gz HEAD @echo "Wrote $(DIST_DIR)/$(DIST_NAME).tar.gz" @echo " size: $$(du -h $(DIST_DIR)/$(DIST_NAME).tar.gz | cut -f1)" @echo " sha256: $$(shasum -a 256 $(DIST_DIR)/$(DIST_NAME).tar.gz | cut -d' ' -f1)" # ------------------------------------------------------------------- # Directory creation # ------------------------------------------------------------------- $(BUILD) $(BUILD)/src $(BUILD)/src/lex $(BUILD)/test $(BIN) $(LIB): mkdir -p $@ # ------------------------------------------------------------------- # Compatibility wrappers for the previous Makefile that just wrapped meson. # ------------------------------------------------------------------- BUILDDIR ?= builddir .PHONY: meson-setup meson-build meson-test meson-clean meson-reconfigure meson-setup: meson setup $(BUILDDIR) meson-build: meson-setup ninja -C $(BUILDDIR) meson-test: meson-build meson test -C $(BUILDDIR) --print-errorlogs meson-clean: rm -rf $(BUILDDIR) meson-reconfigure: meson setup --reconfigure $(BUILDDIR)