# Build and test the calog broker core and engine adapters. # # Layout: # src/ project source; one subdir per script language # (src/lua, src/mybasic, src/squirrel); core + actor live in src/ # tests/ test programs # vendor/ third-party engine sources, built from source (lua, mybasic, # squirrel-src) -- no system engine packages, so the build is # reproducible # obj/ all object files (ours and the vendored engines) # bin/ all binaries # # Core is strict (-Wconversion/-Wsign-conversion) + ASan/UBSan; adapters drop the # two conversion warnings (engine headers use wide macros). Vendored engines build # relaxed and un-sanitized but link into the sanitized binaries so cross-boundary # heap misuse is still caught. -MMD/-MP generate header dependencies automatically. CC = gcc CXX = g++ STRICT = -Wall -Wextra -Werror -Wconversion -Wsign-conversion WARN = -Wall -Wextra -Werror SAN = -fsanitize=address,undefined DEP = -MMD -MP COREFLAGS = -std=c11 $(STRICT) $(DEP) -g -O1 $(SAN) ADPFLAGS = -std=c11 $(WARN) $(DEP) -g -O1 $(SAN) LDFLAGS = $(SAN) # Our headers: src/ plus the per-language subdirs. VPATH lets the object rules find # a source by name without spelling out its directory. INC = -Isrc -Isrc/lua -Isrc/mybasic -Isrc/squirrel -Isrc/js -Isrc/berry -Isrc/s7 -Isrc/wren -Ilibs VPATH = src:src/lua:src/mybasic:src/squirrel:src/js:src/berry:src/s7:src/wren:libs:tests CORE = obj/value.o obj/broker.o # --- vendored my-basic (C) --- MBDIR = vendor/mybasic MBINC = -I$(MBDIR) MBFLAGS = -std=gnu11 -w -g -O1 -DMB_DOUBLE_FLOAT # --- vendored Lua 5.4.6 (C) --- # The platform define is chosen from uname, the way upstream Lua's own Makefile # does, so the build is correct on Linux / macOS / other POSIX without hand-editing. # LUA_USE_LINUX and _MACOSX enable dlopen-based package loading (loadlib.c); on # Linux that needs -ldl. The standalone interpreter (lua.c, the only file that uses # readline) is not built, so there is no readline dependency. The library is every # src/*.c except the two standalone mains (lua.c, luac.c). LUADIR = vendor/lua LUAINC = -I$(LUADIR)/src # Check $(OS) first -- Windows sets OS=Windows_NT in the environment (make inherits # it) and has no `uname`, so probing uname there yields an empty string that would # wrongly select POSIX. Only fall back to `uname` on Unix. (The rest of the project # is Unix-only anyway -- pthreads, sanitizers, setarch -- so the Windows branch just # keeps the Lua define correct, it does not by itself make a Windows build work.) ifeq ($(OS),Windows_NT) LUAPLAT = LUAPLATLIBS = else UNAMES := $(shell uname -s) ifeq ($(UNAMES),Linux) LUAPLAT = -DLUA_USE_LINUX LUAPLATLIBS = -ldl else ifeq ($(UNAMES),Darwin) LUAPLAT = -DLUA_USE_MACOSX LUAPLATLIBS = else LUAPLAT = -DLUA_USE_POSIX LUAPLATLIBS = endif endif LUAFLAGS = -std=c99 -w -g -O2 $(LUAPLAT) LUASRC = $(filter-out $(LUADIR)/src/lua.c $(LUADIR)/src/luac.c, $(wildcard $(LUADIR)/src/*.c)) LUAOBJ = $(patsubst $(LUADIR)/src/%.c,obj/%.o,$(LUASRC)) LUALIBS = $(LUAPLATLIBS) -lm # --- vendored Squirrel 3.2 (C++) --- # -D_SQ64 -DSQUSEDOUBLE so SQInteger/SQFloat are 64-bit int / double; the adapter # MUST share those defines so the ABI (object layout) matches the VM. SQDIR = vendor/squirrel-src SQDEF = -D_SQ64 -DSQUSEDOUBLE SQINC = -I$(SQDIR)/include SQXXFLAGS = -std=c++11 -w -g -O1 $(SQDEF) $(SQINC) -I$(SQDIR)/squirrel SQSRC = $(wildcard $(SQDIR)/squirrel/*.cpp) SQOBJ = $(patsubst $(SQDIR)/squirrel/%.cpp,obj/%.o,$(SQSRC)) # --- vendored QuickJS-ng (C, JavaScript, ES2023+). The core library is these four # .c files (cutils is header-only now). Needs -D_GNU_SOURCE: cutils.h uses # clock_gettime(CLOCK_MONOTONIC). --- QJSDIR = vendor/quickjs QJSINC = -I$(QJSDIR) QJSFLAGS = -std=c11 -w -g -O1 -D_GNU_SOURCE QJSOBJ = obj/quickjs.o obj/libregexp.o obj/libunicode.o obj/dtoa.o # --- vendored Berry (C). The library is every src/*.c; its build needs the coc- # generated headers under generate/ (regenerate with tools/coc from upstream) and # berry_conf.h. BE_INTGER_TYPE=2 in berry_conf.h gives 64-bit ints. --- # The library is every src/*.c plus the OS port (default/be_port.c) and the built-in # module/class tables (default/be_modtab.c); the standalone REPL (default/berry.c) is # omitted. src/ and default/ file names do not collide, so objects use $(notdir ...). BERRYDIR = vendor/berry BERRYINC = -I$(BERRYDIR)/src -I$(BERRYDIR) BERRYFLAGS = -std=c99 -w -g -O1 BERRYSRC = $(wildcard $(BERRYDIR)/src/*.c) $(BERRYDIR)/default/be_port.c $(BERRYDIR)/default/be_modtab.c BERRYOBJ = $(foreach f,$(BERRYSRC),obj/$(notdir $(f:.c=)).o) # --- vendored s7 Scheme (C, single file). Needs -D_GNU_SOURCE (struct timezone) and, # at link, -ldl (its optional C loader uses dlopen) + -lm. mus-config.h is our minimal # feature config; s7 int is 64-bit and strings are binary-safe. --- S7DIR = vendor/s7 S7INC = -I$(S7DIR) S7FLAGS = -std=c99 -w -g -O1 -D_GNU_SOURCE S7OBJ = obj/s7.o S7LIBS = -ldl -lm # --- vendored Wren (C, amalgamated single file wren.c + wren.h; regenerate via # util/generate_amalgamation.py from upstream). Links -lm. --- WRENDIR = vendor/wren WRENINC = -I$(WRENDIR) WRENFLAGS = -std=c99 -w -g -O1 WRENOBJ = obj/wren.o WRENLIBS = -lm # --- vendored SQLite (C amalgamation, single file). THREADSAFE=1 (serialized) because # the DB natives run inline on many context threads. Links -lm -lpthread. --- SQLITEDIR = vendor/sqlite SQLITEINC = -I$(SQLITEDIR) SQLITEFLAGS = -std=c11 -w -g -O2 -DSQLITE_THREADSAFE=1 -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_OMIT_LOAD_EXTENSION SQLITEOBJ = obj/sqlite3.o SQLITELIBS = -lm -lpthread # --- vendored ENet (reliable UDP; all sources except win32.c) for calogNet's ENet backend. ENETDIR = vendor/enet ENETINC = -I$(ENETDIR)/include ENETFLAGS = -std=c11 -w -g -O2 -D_GNU_SOURCE -DHAS_FCNTL=1 -DHAS_POLL=1 -DHAS_GETADDRINFO=1 -DHAS_GETNAMEINFO=1 -DHAS_GETHOSTBYNAME_R=1 -DHAS_GETHOSTBYADDR_R=1 -DHAS_INET_PTON=1 -DHAS_INET_NTOP=1 -DHAS_MSGHDR_FLAGS=1 -DHAS_SOCKLEN_T=1 ENETNAMES = callbacks compress host list packet peer protocol unix ENETOBJ = $(foreach n,$(ENETNAMES),obj/enet_$(n).o) BINS = bin/testBroker bin/testLua bin/testMyBasic bin/testPolyglot bin/testActor \ bin/testEngineLua bin/testEngineMyBasic bin/testSquirrel bin/testEngineSquirrel bin/testJs bin/testEngineJs \ bin/testEngineBerry bin/testEngineS7 bin/testEngineWren bin/testLoad bin/testDb bin/testNet bin/testTask bin/testExport bin/testJson bin/testTime bin/testFs bin/testCrypto bin/testKv bin/testTimer bin/testPubsub bin/testHttp bin/embed all: $(BINS) # ---- object rules, grouped by flag set (sources resolved via VPATH) ---- # strict C, no threads STRICTOBJ = obj/broker.o obj/value.o obj/luaEngine.o obj/squirrelEngine.o obj/jsEngine.o obj/berryEngine.o obj/s7Engine.o obj/wrenEngine.o obj/testBroker.o $(STRICTOBJ): obj/%.o: %.c | obj $(CC) $(COREFLAGS) $(INC) -c -o $@ $< # strict C, threaded THREADOBJ = obj/context.o obj/mybasicEngine.o obj/testActor.o obj/testEngineLua.o obj/testEngineSquirrel.o obj/testEngineJs.o obj/testEngineMyBasic.o obj/testEngineBerry.o obj/testEngineS7.o obj/testEngineWren.o obj/calogHandle.o obj/testDb.o obj/testNet.o obj/testTask.o obj/calogExport.o obj/testExport.o obj/calogJson.o obj/testJson.o obj/calogFs.o obj/testFs.o obj/calogTime.o obj/testTime.o obj/calogKv.o obj/testKv.o obj/testCrypto.o obj/calogTimer.o obj/testTimer.o obj/calogPubsub.o obj/testPubsub.o obj/testHttp.o $(THREADOBJ): obj/%.o: %.c | obj $(CC) $(COREFLAGS) $(INC) -pthread -c -o $@ $< # calogCrypto and calogHttp need the vendored OpenSSL headers, which are outside $(INC). OSSLINC = -Ivendor/openssl/include obj/calogCrypto.o obj/calogHttp.o: obj/%.o: %.c | obj $(CC) $(COREFLAGS) $(INC) $(OSSLINC) -pthread -c -o $@ $< # relaxed C + Lua headers LUAADP = obj/luaAdapter.o obj/testLua.o $(LUAADP): obj/%.o: %.c | obj $(CC) $(ADPFLAGS) $(INC) $(LUAINC) -c -o $@ $< # relaxed C + my-basic headers MBADP = obj/mybasicAdapter.o obj/testMyBasic.o $(MBADP): obj/%.o: %.c | obj $(CC) $(ADPFLAGS) $(INC) $(MBINC) -DMB_DOUBLE_FLOAT -c -o $@ $< # relaxed C + Squirrel headers SQADP = obj/squirrelAdapter.o obj/testSquirrel.o $(SQADP): obj/%.o: %.c | obj $(CC) $(ADPFLAGS) $(INC) $(SQDEF) $(SQINC) -c -o $@ $< # relaxed C + QuickJS headers JSADP = obj/jsAdapter.o obj/testJs.o $(JSADP): obj/%.o: %.c | obj $(CC) $(ADPFLAGS) $(INC) $(QJSINC) -c -o $@ $< # relaxed C + Berry headers BERRYADP = obj/berryAdapter.o $(BERRYADP): obj/%.o: %.c | obj $(CC) $(ADPFLAGS) $(INC) $(BERRYINC) -c -o $@ $< # relaxed C + s7 headers S7ADP = obj/s7Adapter.o $(S7ADP): obj/%.o: %.c | obj $(CC) $(ADPFLAGS) $(INC) $(S7INC) -c -o $@ $< # relaxed C + Wren headers WRENADP = obj/wrenAdapter.o $(WRENADP): obj/%.o: %.c | obj $(CC) $(ADPFLAGS) $(INC) $(WRENINC) -c -o $@ $< # DB library adapter: relaxed C + SQLite headers, sqlite backend compiled in DBADP = obj/calogDb.o $(DBADP): obj/%.o: %.c | obj $(CC) $(ADPFLAGS) $(INC) $(SQLITEINC) -DCALOG_WITH_SQLITE -c -o $@ $< # network library: strict C + ENet headers, ENet backend compiled in (self-contained, so # always enabled -- unlike the DB clients, ENet needs no server) NETADP = obj/calogNet.o $(NETADP): obj/%.o: %.c | obj $(CC) $(COREFLAGS) $(INC) $(ENETINC) -DCALOG_WITH_ENET -pthread -c -o $@ $< # task library: strict C with every engine name compiled in (it references each engine # vtable under its CALOG_WITH_* guard), so a task-using binary links all engine archives. ENGINEDEFS = -DCALOG_WITH_LUA -DCALOG_WITH_JS -DCALOG_WITH_SQUIRREL -DCALOG_WITH_MYBASIC -DCALOG_WITH_BERRY -DCALOG_WITH_S7 -DCALOG_WITH_WREN TASKADP = obj/calogTask.o $(TASKADP): obj/%.o: %.c | obj $(CC) $(COREFLAGS) $(INC) $(ENGINEDEFS) -pthread -c -o $@ $< # polyglot test pulls in both Lua and my-basic obj/testPolyglot.o: testPolyglot.c | obj $(CC) $(ADPFLAGS) $(INC) $(LUAINC) $(MBINC) -DMB_DOUBLE_FLOAT -c -o $@ $< # ---- vendored engine objects (also land in obj/) ---- obj/myBasic.o: $(MBDIR)/myBasic.c | obj $(CC) $(MBFLAGS) -c -o $@ $< obj/%.o: $(LUADIR)/src/%.c | obj $(CC) $(LUAFLAGS) -c -o $@ $< obj/%.o: $(SQDIR)/squirrel/%.cpp | obj $(CXX) $(SQXXFLAGS) -c -o $@ $< obj/%.o: $(QJSDIR)/%.c | obj $(CC) $(QJSFLAGS) $(QJSINC) -c -o $@ $< obj/%.o: $(BERRYDIR)/src/%.c | obj $(CC) $(BERRYFLAGS) $(BERRYINC) -c -o $@ $< obj/%.o: $(BERRYDIR)/default/%.c | obj $(CC) $(BERRYFLAGS) $(BERRYINC) -c -o $@ $< obj/s7.o: $(S7DIR)/s7.c | obj $(CC) $(S7FLAGS) $(S7INC) -c -o $@ $< obj/wren.o: $(WRENDIR)/wren.c | obj $(CC) $(WRENFLAGS) $(WRENINC) -c -o $@ $< obj/sqlite3.o: $(SQLITEDIR)/sqlite3.c | obj $(CC) $(SQLITEFLAGS) $(SQLITEINC) -c -o $@ $< obj/enet_%.o: $(ENETDIR)/%.c | obj $(CC) $(ENETFLAGS) $(ENETINC) -c -o $@ $< # ---- library archives ---- # libcalog.a is calog itself (core + actor + every engine adapter/binding). The # vendored engines are separate archives; a host links libcalog.a plus whichever # engine archives it uses -- unused adapters, and their engine deps, stay unlinked # (static members are pulled only when referenced). See examples/embed.c. CALOGLIB = obj/value.o obj/broker.o obj/context.o \ obj/luaAdapter.o obj/luaEngine.o obj/jsAdapter.o obj/jsEngine.o \ obj/squirrelAdapter.o obj/squirrelEngine.o obj/mybasicAdapter.o obj/mybasicEngine.o \ obj/berryAdapter.o obj/berryEngine.o obj/s7Adapter.o obj/s7Engine.o obj/wrenAdapter.o obj/wrenEngine.o lib/libcalog.a: $(CALOGLIB) | lib ar rcs $@ $^ lib/liblua.a: $(LUAOBJ) | lib ar rcs $@ $^ lib/libquickjs.a: $(QJSOBJ) | lib ar rcs $@ $^ lib/libsquirrel.a: $(SQOBJ) | lib ar rcs $@ $^ lib/libmybasic.a: obj/myBasic.o | lib ar rcs $@ $^ lib/libberry.a: $(BERRYOBJ) | lib ar rcs $@ $^ lib/libs7.a: $(S7OBJ) | lib ar rcs $@ $^ lib/libwren.a: $(WRENOBJ) | lib ar rcs $@ $^ lib/libsqlite3.a: $(SQLITEOBJ) | lib ar rcs $@ $^ lib/libenet.a: $(ENETOBJ) | lib ar rcs $@ $^ # ---- binaries (link libcalog.a + the vendored engine archives they use) ---- bin/testBroker: obj/testBroker.o lib/libcalog.a | bin $(CC) $(LDFLAGS) -o $@ $^ bin/testActor: obj/testActor.o lib/libcalog.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ bin/testLua: obj/testLua.o lib/libcalog.a lib/liblua.a | bin $(CC) $(LDFLAGS) -o $@ $^ $(LUALIBS) bin/testEngineLua: obj/testEngineLua.o lib/libcalog.a lib/liblua.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) # DB library test: calog + the DB library + vendored SQLite, driven from Lua. bin/testDb: obj/testDb.o obj/calogDb.o obj/calogHandle.o lib/libcalog.a lib/liblua.a lib/libsqlite3.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) $(SQLITELIBS) # network library test: calog + the network library + vendored ENet, driven from Lua # (TCP/UDP/ENet loopback). bin/testNet: obj/testNet.o $(NETADP) obj/calogHandle.o lib/libcalog.a lib/liblua.a lib/libenet.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) # --- optional Postgres + MySQL DB-client tests. They pull in the vendored client archives # + OpenSSL (PG archives need a link group), and their live round-trips need a running # server, so they are opt-in and NOT part of `make test`. Build both with `make db-clients`, # then run each with a connection string (see tests/testDbPg.c and tests/testDbMysql.c). --- PGINC = -Ivendor/postgres/src/interfaces/libpq -Ivendor/postgres/src/include PGARCHIVES = vendor/postgres/src/interfaces/libpq/libpq.a vendor/postgres/src/common/libpgcommon_shlib.a vendor/postgres/src/port/libpgport_shlib.a MYSQLINC = -Ivendor/mariadb/include -Ivendor/mariadb/build/include MYSQLARCH = vendor/mariadb/build/libmariadb/libmariadbclient.a SSLARCH = vendor/openssl/libssl.a vendor/openssl/libcrypto.a DBCLIENTOBJ = obj/testDbPg.o obj/testDbMysql.o obj/calogDbFull.o: libs/calogDb.c | obj $(CC) $(ADPFLAGS) $(INC) $(SQLITEINC) $(PGINC) $(MYSQLINC) -DCALOG_WITH_SQLITE -DCALOG_WITH_PG -DCALOG_WITH_MYSQL -c -o $@ $< $(DBCLIENTOBJ): obj/%.o: %.c | obj $(CC) $(COREFLAGS) $(INC) -pthread -c -o $@ $< bin/testDbPg: obj/testDbPg.o obj/calogDbFull.o obj/calogHandle.o lib/libcalog.a lib/liblua.a lib/libsqlite3.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ -Wl,--start-group $(PGARCHIVES) -Wl,--end-group $(MYSQLARCH) $(SSLARCH) $(LUALIBS) $(SQLITELIBS) bin/testDbMysql: obj/testDbMysql.o obj/calogDbFull.o obj/calogHandle.o lib/libcalog.a lib/liblua.a lib/libsqlite3.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ -Wl,--start-group $(PGARCHIVES) -Wl,--end-group $(MYSQLARCH) $(SSLARCH) $(LUALIBS) $(SQLITELIBS) .PHONY: db-clients db-clients: bin/testDbPg bin/testDbMysql bin/testMyBasic: obj/testMyBasic.o lib/libcalog.a lib/libmybasic.a | bin $(CC) $(LDFLAGS) -o $@ $^ -lm bin/testEngineMyBasic: obj/testEngineMyBasic.o lib/libcalog.a lib/libmybasic.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ -lm bin/testPolyglot: obj/testPolyglot.o lib/libcalog.a lib/liblua.a lib/libmybasic.a | bin $(CC) $(LDFLAGS) -o $@ $^ $(LUALIBS) bin/testSquirrel: obj/testSquirrel.o lib/libcalog.a lib/libsquirrel.a | bin $(CC) $(LDFLAGS) -o $@ $^ -lstdc++ -lm bin/testEngineSquirrel: obj/testEngineSquirrel.o lib/libcalog.a lib/libsquirrel.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ -lstdc++ -lm bin/testJs: obj/testJs.o lib/libcalog.a lib/libquickjs.a | bin $(CC) $(LDFLAGS) -o $@ $^ -lm bin/testEngineJs: obj/testEngineJs.o lib/libcalog.a lib/libquickjs.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ -lm bin/testEngineBerry: obj/testEngineBerry.o lib/libcalog.a lib/libberry.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ -lm bin/testEngineS7: obj/testEngineS7.o lib/libcalog.a lib/libs7.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(S7LIBS) bin/testEngineWren: obj/testEngineWren.o lib/libcalog.a lib/libwren.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(WRENLIBS) # example host: embeds calog + JS via calog.h only, linking the two archives. obj/embed.o: examples/embed.c src/calog.h | obj $(CC) $(COREFLAGS) -Isrc -pthread -c -o $@ $< bin/embed: obj/embed.o lib/libcalog.a lib/libquickjs.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ -lm # ---- fully-static build -------------------------------------------------------------- # A self-contained calog executable with NO shared-library dependencies at runtime. The # calog objects are recompiled without sanitizers (ASan does not support -static) into # obj/rel/; the vendored archives (lua/sqlite/enet) are already un-sanitized and reused. # The example embeds Lua + the SQLite DB library + the network library. Build + run with # `make static`. (Static glibc cannot resolve names or dlopen C modules -- see # examples/staticDemo.c; the dlopen/getaddrinfo link warnings are expected and harmless # for a binary that uses neither.) RELFLAGS = -std=c11 $(WARN) $(DEP) -O2 RELOBJ = obj/rel/value.o obj/rel/broker.o obj/rel/context.o obj/rel/luaEngine.o obj/rel/luaAdapter.o obj/rel/calogHandle.o obj/rel/calogDb.o obj/rel/calogNet.o obj/rel: mkdir -p obj/rel $(RELOBJ): obj/rel/%.o: %.c | obj/rel $(CC) $(RELFLAGS) $(INC) $(LUAINC) $(SQLITEINC) $(ENETINC) -DCALOG_WITH_SQLITE -DCALOG_WITH_ENET -pthread -c -o $@ $< obj/rel/staticDemo.o: examples/staticDemo.c src/calog.h libs/calogDb.h libs/calogNet.h | obj/rel $(CC) $(RELFLAGS) $(INC) -pthread -c -o $@ $< bin/calogStatic: obj/rel/staticDemo.o $(RELOBJ) lib/liblua.a lib/libsqlite3.a lib/libenet.a | bin $(CC) -static -pthread -o $@ $^ $(LUALIBS) $(SQLITELIBS) .PHONY: static static: bin/calogStatic @file bin/calogStatic | grep -q "statically linked" && echo "== bin/calogStatic is fully static ==" || { echo "== NOT statically linked! =="; exit 1; } @echo "runtime shared-lib deps:"; ldd bin/calogStatic 2>&1 | sed 's/^/ /' ./bin/calogStatic # load test: links every engine (compiled with all CALOG_WITH_* engine flags) so it # exercises calogContextLoad + calogRegisterBuiltinEngines across all four languages -- # including my-basic under the actor model. Uses only calog.h (the extern engine vtables). obj/testLoad.o: tests/testLoad.c src/calog.h | obj $(CC) $(COREFLAGS) -Isrc -pthread -DCALOG_WITH_LUA -DCALOG_WITH_JS -DCALOG_WITH_SQUIRREL -DCALOG_WITH_MYBASIC -DCALOG_WITH_BERRY -DCALOG_WITH_S7 -DCALOG_WITH_WREN -c -o $@ $< bin/testLoad: obj/testLoad.o lib/libcalog.a lib/liblua.a lib/libquickjs.a lib/libsquirrel.a lib/libmybasic.a lib/libberry.a lib/libs7.a lib/libwren.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) -lstdc++ -lm # task library test: the task lib names every engine, so (like testLoad) it links them all. bin/testTask: obj/testTask.o $(TASKADP) obj/calogHandle.o lib/libcalog.a lib/liblua.a lib/libquickjs.a lib/libsquirrel.a lib/libmybasic.a lib/libberry.a lib/libs7.a lib/libwren.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) -lstdc++ -lm # export library test: publish from Lua, call by bare name from Lua + via callExport from JS. bin/testExport: obj/testExport.o obj/calogExport.o lib/libcalog.a lib/liblua.a lib/libquickjs.a lib/libsquirrel.a lib/libs7.a lib/libmybasic.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) -lstdc++ -ldl -lm bin/testJson: obj/testJson.o obj/calogJson.o lib/libcalog.a lib/liblua.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) bin/testTime: obj/testTime.o obj/calogTime.o lib/libcalog.a lib/liblua.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) bin/testFs: obj/testFs.o obj/calogFs.o lib/libcalog.a lib/liblua.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) bin/testCrypto: obj/testCrypto.o obj/calogCrypto.o lib/libcalog.a lib/liblua.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(SSLARCH) $(LUALIBS) -ldl bin/testKv: obj/testKv.o obj/calogKv.o lib/libcalog.a lib/liblua.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) bin/testTimer: obj/testTimer.o obj/calogTimer.o lib/libcalog.a lib/liblua.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) bin/testPubsub: obj/testPubsub.o obj/calogPubsub.o lib/libcalog.a lib/liblua.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) bin/testHttp: obj/testHttp.o obj/calogHttp.o lib/libcalog.a lib/liblua.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(SSLARCH) $(LUALIBS) -ldl obj bin lib: mkdir -p $@ test: all ./bin/testBroker && ./bin/testLua && ./bin/testMyBasic && ./bin/testPolyglot && \ ./bin/testActor && ./bin/testEngineLua && ./bin/testEngineMyBasic && ./bin/testSquirrel && ./bin/testEngineSquirrel && \ ./bin/testJs && ./bin/testEngineJs && ./bin/testEngineBerry && ./bin/testEngineS7 && ./bin/testEngineWren && ./bin/testLoad && ./bin/testDb && ./bin/testNet && ./bin/testTask && ./bin/testExport && ./bin/testJson && ./bin/testTime && ./bin/testFs && ./bin/testCrypto && ./bin/testKv && ./bin/testTimer && ./bin/testPubsub && ./bin/testHttp # ThreadSanitizer build of the actor core and the Lua engine path (cannot combine # with ASan). Recompiled from source under TSan; the vendored Lua objects are # linked un-sanitized (each VM is single-threaded, so that is sound). Run under # `setarch -R` (ASLR off): some kernels hand out more mmap randomization than TSan's # shadow allocator tolerates, which aborts it before any test runs. tsan: $(LUAOBJ) | bin $(CC) -std=c11 $(WARN) -g -O1 -fsanitize=thread -pthread $(INC) -o bin/testActorTsan \ tests/testActor.c src/context.c src/value.c src/broker.c setarch -R ./bin/testActorTsan $(CC) -std=c11 $(WARN) -g -O1 -fsanitize=thread -pthread $(INC) $(LUAINC) -o bin/testEngineLuaTsan \ tests/testEngineLua.c src/lua/luaEngine.c src/lua/luaAdapter.c src/context.c src/value.c src/broker.c \ $(LUAOBJ) $(LUALIBS) setarch -R ./bin/testEngineLuaTsan # ThreadSanitizer build of the Squirrel engine path: the vendored VM is recompiled # under TSan here (throwaway obj/*.tsan.o) so races are caught across the whole # stack. Slower than `tsan`, so kept separate. tsansq: $(SQSRC) | bin obj for f in $(SQSRC); do $(CXX) $(SQXXFLAGS) -fsanitize=thread -c $$f -o obj/$$(basename $${f%.cpp}).tsan.o; done $(CC) -std=c11 $(WARN) -g -O1 -fsanitize=thread -pthread $(INC) $(SQDEF) $(SQINC) -o bin/testEngineSquirrelTsan \ tests/testEngineSquirrel.c src/squirrel/squirrelEngine.c src/squirrel/squirrelAdapter.c \ src/context.c src/value.c src/broker.c \ $(patsubst $(SQDIR)/squirrel/%.cpp,obj/%.tsan.o,$(SQSRC)) -lstdc++ -lm setarch -R ./bin/testEngineSquirrelTsan rm -f $(patsubst $(SQDIR)/squirrel/%.cpp,obj/%.tsan.o,$(SQSRC)) # ThreadSanitizer build of the JS engine path: the vendored QuickJS core is # recompiled under TSan (throwaway objs) so races are caught across the whole stack. tsanjs: | bin obj for f in quickjs libregexp libunicode dtoa; do $(CC) $(QJSFLAGS) $(QJSINC) -fsanitize=thread -c $(QJSDIR)/$$f.c -o obj/$$f.tsan.o; done $(CC) -std=c11 $(WARN) -g -O1 -fsanitize=thread -pthread $(INC) $(QJSINC) -o bin/testEngineJsTsan \ tests/testEngineJs.c src/js/jsEngine.c src/js/jsAdapter.c src/context.c src/value.c src/broker.c \ obj/quickjs.tsan.o obj/libregexp.tsan.o obj/libunicode.tsan.o obj/dtoa.tsan.o -lm setarch -R ./bin/testEngineJsTsan rm -f obj/quickjs.tsan.o obj/libregexp.tsan.o obj/libunicode.tsan.o obj/dtoa.tsan.o # ThreadSanitizer build of the my-basic engine path: the vendored interpreter is # recompiled under TSan (throwaway obj) so the engine's serialization of my-basic's # process-global state (mb_init singletons, the _mb_allocated counter) is verified # across the whole stack -- it races without the engine lock. tsanmb: | bin obj $(CC) $(MBFLAGS) -fsanitize=thread -c $(MBDIR)/myBasic.c -o obj/myBasic.tsan.o $(CC) -std=c11 $(WARN) -g -O1 -fsanitize=thread -pthread $(INC) $(MBINC) -DMB_DOUBLE_FLOAT -o bin/testEngineMyBasicTsan \ tests/testEngineMyBasic.c src/mybasic/mybasicEngine.c src/mybasic/mybasicAdapter.c src/context.c src/value.c src/broker.c \ obj/myBasic.tsan.o -lm setarch -R ./bin/testEngineMyBasicTsan rm -f obj/myBasic.tsan.o # ThreadSanitizer build of the Berry engine path: the vendored VM is recompiled under # TSan (throwaway objs) so races are caught across the whole stack. tsanberry: | bin obj for f in $(BERRYSRC); do $(CC) $(BERRYFLAGS) $(BERRYINC) -fsanitize=thread -c $$f -o obj/$$(basename $${f%.c}).tsan.o; done $(CC) -std=c11 $(WARN) -g -O1 -fsanitize=thread -pthread $(INC) $(BERRYINC) -o bin/testEngineBerryTsan \ tests/testEngineBerry.c src/berry/berryEngine.c src/berry/berryAdapter.c src/context.c src/value.c src/broker.c \ $(foreach f,$(BERRYSRC),obj/$(notdir $(f:.c=)).tsan.o) -lm setarch -R ./bin/testEngineBerryTsan rm -f $(foreach f,$(BERRYSRC),obj/$(notdir $(f:.c=)).tsan.o) # ThreadSanitizer build of the s7 engine path: the vendored interpreter is recompiled # under TSan (throwaway obj) so races are caught across the whole stack. tsans7: | bin obj $(CC) $(S7FLAGS) $(S7INC) -fsanitize=thread -c $(S7DIR)/s7.c -o obj/s7.tsan.o $(CC) -std=c11 $(WARN) -g -O1 -fsanitize=thread -pthread $(INC) $(S7INC) -o bin/testEngineS7Tsan \ tests/testEngineS7.c src/s7/s7Engine.c src/s7/s7Adapter.c src/context.c src/value.c src/broker.c \ obj/s7.tsan.o $(S7LIBS) setarch -R ./bin/testEngineS7Tsan rm -f obj/s7.tsan.o # ThreadSanitizer build of the Wren engine path: the vendored VM is recompiled under # TSan (throwaway obj) so races are caught across the whole stack. tsanwren: | bin obj $(CC) $(WRENFLAGS) $(WRENINC) -fsanitize=thread -c $(WRENDIR)/wren.c -o obj/wren.tsan.o $(CC) -std=c11 $(WARN) -g -O1 -fsanitize=thread -pthread $(INC) $(WRENINC) -o bin/testEngineWrenTsan \ tests/testEngineWren.c src/wren/wrenEngine.c src/wren/wrenAdapter.c src/context.c src/value.c src/broker.c \ obj/wren.tsan.o $(WRENLIBS) setarch -R ./bin/testEngineWrenTsan rm -f obj/wren.tsan.o # ThreadSanitizer build of the concurrent libraries (timer's background thread, pubsub's # callback fan-out, kv's shared store), each over a Lua context so callbacks marshal across # threads. The unsanitized liblua.a links in fine (TSan instruments only the calog code). tsanlibs: lib/liblua.a | bin $(CC) -std=c11 $(WARN) -g -O1 -fsanitize=thread -pthread $(INC) $(LUAINC) -o bin/testTimerTsan \ tests/testTimer.c libs/calogTimer.c src/context.c src/value.c src/broker.c src/lua/luaEngine.c src/lua/luaAdapter.c \ lib/liblua.a $(LUALIBS) setarch -R ./bin/testTimerTsan $(CC) -std=c11 $(WARN) -g -O1 -fsanitize=thread -pthread $(INC) $(LUAINC) -o bin/testPubsubTsan \ tests/testPubsub.c libs/calogPubsub.c src/context.c src/value.c src/broker.c src/lua/luaEngine.c src/lua/luaAdapter.c \ lib/liblua.a $(LUALIBS) setarch -R ./bin/testPubsubTsan $(CC) -std=c11 $(WARN) -g -O1 -fsanitize=thread -pthread $(INC) $(LUAINC) -o bin/testKvTsan \ tests/testKv.c libs/calogKv.c src/context.c src/value.c src/broker.c src/lua/luaEngine.c src/lua/luaAdapter.c \ lib/liblua.a $(LUALIBS) setarch -R ./bin/testKvTsan clean: rm -rf obj bin lib -include $(wildcard obj/*.d) -include $(wildcard obj/rel/*.d) .PHONY: all test tsan tsansq tsanjs tsanmb tsanberry tsans7 tsanwren clean