# 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 -Isrc/mruby -Isrc/tcl -Isrc/janet -Ilibs VPATH = src:src/lua:src/mybasic:src/squirrel:src/js:src/berry:src/s7:src/wren:src/mruby:src/tcl:src/janet:libs:tests # --- vendored our-basic: calog's fork of MY-BASIC (see vendor/ourbasic/NOTICE) --- MBDIR = vendor/ourbasic 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) PLATFORM = windows LUAPLAT = LUAPLATLIBS = DLLIB = SOCKETLIBS = -lws2_32 -lwinmm else UNAMES := $(shell uname -s) ifeq ($(UNAMES),Linux) PLATFORM = linux LUAPLAT = -DLUA_USE_LINUX LUAPLATLIBS = -ldl DLLIB = -ldl SOCKETLIBS = else ifeq ($(UNAMES),Darwin) PLATFORM = darwin LUAPLAT = -DLUA_USE_MACOSX LUAPLATLIBS = DLLIB = SOCKETLIBS = else PLATFORM = posix LUAPLAT = -DLUA_USE_POSIX LUAPLATLIBS = DLLIB = -ldl SOCKETLIBS = endif endif # Extra link flags for the `release` target (empty for the default dev build): the C++ runtime # and libgcc linked statically so the CLI's only shared-library dependency is the system libc. # CXXLIB is how the explicit C++ runtime is pulled in; release wraps it in -Bstatic/-Bdynamic so # the STATIC libstdc++.a is used (a driver -static-libstdc++ does not override an explicit -lstdc++). RELEASELD = CXXLIB = -lstdc++ # macOS ships libc++ (LLVM), not libstdc++; the Squirrel C++ engine links against it there. ifeq ($(PLATFORM),darwin) CXXLIB = -lc++ 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 QJSNAMES = quickjs libregexp libunicode dtoa QJSOBJ = $(patsubst %,obj/%.o,$(QJSNAMES)) # --- 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 = $(DLLIB) -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 Janet 1.41.2 (Lisp, single-file amalgamation like s7/wren: janet.c + janet.h + # janetconf.h). Its whole state is a JANET_THREAD_LOCAL janet_vm (__thread on gcc), so one # independent VM per context thread -- the actor model exactly. Lean build: no net/process/dynamic- # modules (calog provides IO). Links -lm -lpthread. MIT license. --- JANETDIR = vendor/janet JANETINC = -I$(JANETDIR) JANETFLAGS = -std=c11 -w -g -O2 -DJANET_NO_NET -DJANET_NO_PROCESSES -DJANET_NO_DYNAMIC_MODULES JANETOBJ = obj/janet.o JANETLIBS = -lm -lpthread # --- vendored mruby 4.0.0 (Ruby). UNLIKE every other engine, libmruby.a is GENERATED by mruby's # own Rake build (needs a host Ruby >=2.5 + bison), not compiled from .c here. The embed gembox # is the core language + runtime eval (mruby-compiler) + stdlib/math/metaprog, with no executables # and no file/socket IO (calog provides those). MRB_INT64 keeps script integers 64-bit. Links -lm. # The build config lives in src/mruby/ (calog-owned), NOT in vendor/mruby/, so re-vendoring a new # mruby version cannot clobber it. --- MRUBYDIR = vendor/mruby # Both the static headers AND the build-generated ones (mruby/presym.h -- pre-interned symbols # -- and mrbconf.h are emitted per-build under build/calog/include). MRUBYINC = -I$(MRUBYDIR)/include -I$(MRUBYDIR)/build/calog/include MRUBYCONF = $(CURDIR)/src/mruby/build_config.rb MRUBYLIB = $(MRUBYDIR)/build/calog/lib/libmruby.a MRUBYLIBS = -lm $(MRUBYLIB): $(MRUBYCONF) cd $(MRUBYDIR) && MRUBY_CONFIG=$(MRUBYCONF) ruby ./minirake -j4 # --- vendored Tcl 9.0.4 (Tool Command Language). Like libssh2/mruby, libtcl is produced by the # engine's own build (autoconf): configure --disable-shared + make the static-lib target, OUT of # tree into vendor/tcl/build/ (so the vendored source stays pristine). No host deps beyond a C # toolchain; Tcl bundles zlib fallback + libtommath. Apartment threading (one Tcl_Interp per # thread, no GIL) is mandatory in 9.0. Links -ldl -lz -lpthread -lm. tcl.h needs no generated # header (config is compiled in via -D), so the adapter builds against generic/ + unix/. --- TCLDIR = vendor/tcl TCLINC = -I$(TCLDIR)/generic -I$(TCLDIR)/unix TCLLIB = $(TCLDIR)/build/libtcl9.0.a TCLLIBS = $(DLLIB) -lz -lpthread -lm $(TCLLIB): mkdir -p $(TCLDIR)/build && cd $(TCLDIR)/build && ../unix/configure --disable-shared >/dev/null && $(MAKE) libtcl9.0.a # --- 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 # ENet's platform backend: unix.c on Linux/macOS, win32.c on Windows (which also needs -lwinmm). ENETBACKEND = unix ifeq ($(PLATFORM),windows) ENETBACKEND = win32 endif ENETNAMES = callbacks compress host list packet peer protocol $(ENETBACKEND) ENETOBJ = $(foreach n,$(ENETNAMES),obj/enet_$(n).o) # --- vendored winpthreads (WINDOWS ONLY): POSIX threads over the Win32 API, so calog's pthread # code (actor model, timer, pubsub, ...) builds on Windows. Built from source like every # dependency; unused on Linux/macOS, which have native pthreads. A Windows build sets CC to a # mingw-w64 compiler (or uses tools/crossBuild.sh with zig). See vendor/winpthreads/NOTICE.calog. --- WPTHDIR = vendor/winpthreads WPTHINC = -I$(WPTHDIR)/include -DWINPTHREAD_STATIC=1 WPTHLIB = lib/libwinpthreads.a WPTHSRC = $(wildcard $(WPTHDIR)/src/*.c) WPTHOBJ = $(patsubst $(WPTHDIR)/src/%.c,obj/wpth_%.o,$(WPTHSRC)) obj/wpth_%.o: $(WPTHDIR)/src/%.c | obj $(CC) -O2 -w -I$(WPTHDIR)/include -I$(WPTHDIR)/src -DWINPTHREAD_STATIC=1 -DIN_WINPTHREAD=1 -c -o $@ $< $(WPTHLIB): $(WPTHOBJ) | lib $(AR) rcs $@ $(WPTHOBJ) # --- vendored zlib -> a single lib/libz.a: the one source of truth for DEFLATE in the tree, and # the gzip/zip backend for the archive/compression library. No configure step -- the shipped # zconf.h is portable. Built from source like every dependency (permissive zlib license). --- ZLIBDIR = vendor/zlib ZLIBINC = -I$(ZLIBDIR) ZLIBSRC = $(wildcard $(ZLIBDIR)/*.c) ZLIBOBJ = $(patsubst $(ZLIBDIR)/%.c,obj/z_%.o,$(ZLIBSRC)) ZLIBLIB = lib/libz.a obj/z_%.o: $(ZLIBDIR)/%.c | obj $(CC) -std=c11 -w -O2 $(ZLIBINC) -c -o $@ $< $(ZLIBLIB): $(ZLIBOBJ) | lib $(AR) rcs $@ $(ZLIBOBJ) # --- vendored bzip2 -> lib/libbz2.a (bzip2 filter backend). Pure object-rules, no configure. --- BZIP2DIR = vendor/bzip2 BZIP2INC = -I$(BZIP2DIR) BZIP2SRC = $(wildcard $(BZIP2DIR)/*.c) BZIP2OBJ = $(patsubst $(BZIP2DIR)/%.c,obj/bz2_%.o,$(BZIP2SRC)) BZIP2LIB = lib/libbz2.a obj/bz2_%.o: $(BZIP2DIR)/%.c | obj $(CC) -std=c11 -w -O2 $(BZIP2INC) -c -o $@ $< $(BZIP2LIB): $(BZIP2OBJ) | lib $(AR) rcs $@ $(BZIP2OBJ) # --- vendored lz4 -> lib/liblz4.a (lz4 filter backend; needs lz4.h + lz4frame.h). Object-rules. --- LZ4DIR = vendor/lz4 LZ4INC = -I$(LZ4DIR) LZ4SRC = $(wildcard $(LZ4DIR)/*.c) LZ4OBJ = $(patsubst $(LZ4DIR)/%.c,obj/l4_%.o,$(LZ4SRC)) LZ4LIB = lib/liblz4.a obj/l4_%.o: $(LZ4DIR)/%.c | obj $(CC) -std=c11 -w -O2 $(LZ4INC) -c -o $@ $< $(LZ4LIB): $(LZ4OBJ) | lib $(AR) rcs $@ $(LZ4OBJ) # --- vendored zstd -> lib/libzstd.a (zstd filter backend). Object-rules across its lib subdirs. # ZSTD_DISABLE_ASM: the x86-64 asm decode path is not vendored. MULTITHREAD left UNSET (single- # threaded encoder -> tsan-clean; defining it even to 0 would enable worker threads). --- ZSTDDIR = vendor/zstd ZSTDINC = -I$(ZSTDDIR) ZSTDOBJ = $(patsubst $(ZSTDDIR)/common/%.c,obj/zstd_%.o,$(wildcard $(ZSTDDIR)/common/*.c)) $(patsubst $(ZSTDDIR)/compress/%.c,obj/zstd_%.o,$(wildcard $(ZSTDDIR)/compress/*.c)) $(patsubst $(ZSTDDIR)/decompress/%.c,obj/zstd_%.o,$(wildcard $(ZSTDDIR)/decompress/*.c)) ZSTDLIB = lib/libzstd.a obj/zstd_%.o: $(ZSTDDIR)/common/%.c | obj $(CC) -std=c11 -w -O2 -DZSTD_DISABLE_ASM $(ZSTDINC) -c -o $@ $< obj/zstd_%.o: $(ZSTDDIR)/compress/%.c | obj $(CC) -std=c11 -w -O2 -DZSTD_DISABLE_ASM $(ZSTDINC) -c -o $@ $< obj/zstd_%.o: $(ZSTDDIR)/decompress/%.c | obj $(CC) -std=c11 -w -O2 -DZSTD_DISABLE_ASM $(ZSTDINC) -c -o $@ $< $(ZSTDLIB): $(ZSTDOBJ) | lib $(AR) rcs $@ $(ZSTDOBJ) # --- vendored XZ Utils / liblzma -> vendor/xz/build/liblzma.a (xz/lzma filter + 7-zip backend). # Like Tcl/libssh2, produced by the codec's own CMake OUT OF TREE (source stays pristine); only the # liblzma target is built (never the xz CLI). ENABLE_THREADS=OFF -> single-threaded, tsan-clean. --- XZDIR = vendor/xz XZINC = -I$(XZDIR)/src/liblzma/api XZLIB = $(XZDIR)/build/liblzma.a $(XZLIB): cmake -S $(XZDIR) -B $(XZDIR)/build -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF \ -DENABLE_THREADS=OFF -DENABLE_NLS=OFF -DENABLE_DOXYGEN=OFF >/dev/null cmake --build $(XZDIR)/build --target liblzma -j >/dev/null # --- vendored libxml2 -> vendor/libxml2/build/libxml2.a. The XML backend for libarchive's XAR # format (read AND write) AND for libs/calogXml.c. XAR additionally needs OpenSSL (MD5/SHA1, already # vendored) and glibc iconv (ENABLE_ICONV in the libarchive block below). Its own CMake OUT OF TREE # (source pristine); static and lean (no python/programs/http/icu/modules; UTF-8 needs no iconv). The # generated xmlversion.h lands in build/, the rest of the API in include/, so both are on the path. --- LIBXML2DIR = vendor/libxml2 LIBXML2INC = -I$(LIBXML2DIR)/include -I$(LIBXML2DIR)/build LIBXML2LIB = $(LIBXML2DIR)/build/libxml2.a $(LIBXML2LIB): cmake -S $(LIBXML2DIR) -B $(LIBXML2DIR)/build -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF \ -DLIBXML2_WITH_PYTHON=OFF -DLIBXML2_WITH_PROGRAMS=OFF -DLIBXML2_WITH_TESTS=OFF \ -DLIBXML2_WITH_HTTP=OFF -DLIBXML2_WITH_FTP=OFF -DLIBXML2_WITH_ICU=OFF \ -DLIBXML2_WITH_LZMA=OFF -DLIBXML2_WITH_ZLIB=OFF -DLIBXML2_WITH_ICONV=OFF \ -DLIBXML2_WITH_MODULES=OFF -DLIBXML2_WITH_CATALOG=OFF -DLIBXML2_WITH_THREADS=ON >/dev/null cmake --build $(LIBXML2DIR)/build --target LibXml2 -j >/dev/null # --- vendored libarchive -> the compression/archive backend for libs/calogArchive.c. Built by its # own CMake OUT OF TREE (like libssh2), static, with each codec pinned to our vendored copy so no # system codec is ever picked up. CLI tools + tests disabled. XAR (read + write) is enabled via the # vendored libxml2, vendored OpenSSL (its required MD5/SHA1), and glibc iconv (ENABLE_ICONV -- which # libarchive gates the libxml2 detection on). LIBXML2_INCLUDE_DIR is a two-entry list: the source API # headers plus the build dir holding the generated xmlversion.h. --- LIBARCHIVEDIR = vendor/libarchive LIBARCHIVEINC = -I$(LIBARCHIVEDIR)/libarchive LIBARCHIVELIB = $(LIBARCHIVEDIR)/_cmk/libarchive/libarchive.a $(LIBARCHIVELIB): $(ZLIBLIB) $(BZIP2LIB) $(LZ4LIB) $(ZSTDLIB) $(XZLIB) $(LIBXML2LIB) cmake -S $(LIBARCHIVEDIR) -B $(LIBARCHIVEDIR)/_cmk -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF -DENABLE_TEST=OFF -DENABLE_INSTALL=OFF \ -DENABLE_TAR=OFF -DENABLE_CPIO=OFF -DENABLE_CAT=OFF -DENABLE_UNZIP=OFF \ -DENABLE_ACL=OFF -DENABLE_XATTR=OFF -DENABLE_ICONV=ON -DENABLE_LIBB2=OFF \ -DENABLE_LIBXML2=ON "-DLIBXML2_INCLUDE_DIR=$(CURDIR)/vendor/libxml2/include;$(CURDIR)/vendor/libxml2/build" -DLIBXML2_LIBRARY=$(CURDIR)/$(LIBXML2LIB) \ -DENABLE_OPENSSL=ON -DOPENSSL_ROOT_DIR=$(CURDIR)/vendor/openssl -DOPENSSL_INCLUDE_DIR=$(CURDIR)/vendor/openssl/include \ -DOPENSSL_SSL_LIBRARY=$(CURDIR)/vendor/openssl/libssl.a -DOPENSSL_CRYPTO_LIBRARY=$(CURDIR)/vendor/openssl/libcrypto.a \ -DENABLE_LZO=OFF -DENABLE_NETTLE=OFF -DENABLE_MBEDTLS=OFF -DENABLE_PCREPOSIX=OFF -DENABLE_PCRE2POSIX=OFF \ -DENABLE_ZLIB=ON -DZLIB_INCLUDE_DIR=$(CURDIR)/vendor/zlib -DZLIB_LIBRARY=$(CURDIR)/$(ZLIBLIB) \ -DENABLE_BZip2=ON -DBZIP2_INCLUDE_DIR=$(CURDIR)/vendor/bzip2 -DBZIP2_LIBRARIES=$(CURDIR)/$(BZIP2LIB) \ -DENABLE_LZMA=ON -DLIBLZMA_INCLUDE_DIR=$(CURDIR)/vendor/xz/src/liblzma/api -DLIBLZMA_LIBRARY=$(CURDIR)/$(XZLIB) \ -DENABLE_ZSTD=ON -DZSTD_INCLUDE_DIR=$(CURDIR)/vendor/zstd -DZSTD_LIBRARY=$(CURDIR)/$(ZSTDLIB) \ -DENABLE_LZ4=ON -DLZ4_INCLUDE_DIR=$(CURDIR)/vendor/lz4 -DLZ4_LIBRARY=$(CURDIR)/$(LZ4LIB) >/dev/null cmake --build $(LIBARCHIVEDIR)/_cmk --target archive_static -j >/dev/null # The whole compression stack for the archive library link line. # libarchive first (references the rest), then libxml2 + codecs; XAR's MD5/SHA1 resolve against # $(SSLARCH), which the archive-linked binaries add after this group. ARCHIVELIBS = $(LIBARCHIVELIB) $(LIBXML2LIB) $(XZLIB) $(ZSTDLIB) $(LZ4LIB) $(BZIP2LIB) $(ZLIBLIB) # --- vendored PCRE2 10.45 (Perl-compatible regex) -> vendor/pcre2/build/libpcre2-8.a, the regex # backend for libs/calogRegex.c. Like Tcl/XZ, produced by PCRE2's own CMake OUT OF TREE: pcre2.h + # config.h are GENERATED from .in templates (baking in version/config), so the source stays pristine # and the generated pcre2.h a consumer includes is under build/. 8-bit width only, static, NO JIT # (JIT needs W^X executable memory calog does not want). A consumer defines PCRE2_CODE_UNIT_WIDTH 8 # before . License: BSD-3-Clause with exception. --- PCRE2DIR = vendor/pcre2 PCRE2INC = -I$(PCRE2DIR)/build PCRE2LIB = $(PCRE2DIR)/build/libpcre2-8.a $(PCRE2LIB): cmake -S $(PCRE2DIR) -B $(PCRE2DIR)/build -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF \ -DPCRE2_BUILD_PCRE2_8=ON -DPCRE2_BUILD_PCRE2_16=OFF -DPCRE2_BUILD_PCRE2_32=OFF \ -DPCRE2_SUPPORT_JIT=OFF -DPCRE2_BUILD_TESTS=OFF -DPCRE2_BUILD_PCRE2GREP=OFF >/dev/null cmake --build $(PCRE2DIR)/build --target pcre2-8-static -j >/dev/null BINS = bin/testBroker bin/testLua bin/testMyBasic bin/testPolyglot bin/testActor bin/testHooks \ bin/testEngineLua bin/testEngineMyBasic bin/testSquirrel bin/testEngineSquirrel bin/testJs bin/testEngineJs \ bin/testEngineBerry bin/testEngineS7 bin/testEngineWren bin/testEngineMruby bin/testEngineTcl bin/testEngineJanet bin/testLoad bin/testDb bin/testNet bin/testTask bin/testExport bin/testJson bin/testXml bin/testTime bin/testFs bin/testCrypto bin/testKv bin/testTimer bin/testPubsub bin/testHttp bin/testHttps bin/testArchive bin/testUtil bin/testSandbox bin/testTrace bin/testHttpd bin/embed bin/calog 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/mrubyEngine.o obj/tclEngine.o obj/janetEngine.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/testEngineMruby.o obj/testEngineTcl.o obj/testEngineJanet.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 obj/testSsh.o obj/calogCsv.o obj/calogProc.o obj/testSandbox.o obj/testTrace.o obj/calogHttpd.o obj/testHttpd.o obj/testHooks.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/testHttps.o: obj/%.o: %.c | obj $(CC) $(COREFLAGS) $(INC) $(OSSLINC) -pthread -c -o $@ $< # calogSsh binds vendored libssh2 (static, built via CMake against our vendored OpenSSL). LIBSSH2DIR = vendor/libssh2 LIBSSH2INC = -I$(LIBSSH2DIR)/include LIBSSH2LIB = $(LIBSSH2DIR)/build/src/libssh2.a $(LIBSSH2LIB): | $(LIBSSH2DIR) cmake -S $(LIBSSH2DIR) -B $(LIBSSH2DIR)/build -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF \ -DLIBSSH2_EXAMPLES=OFF -DBUILD_TESTING=OFF -DBUILD_EXAMPLES=OFF -DCRYPTO_BACKEND=OpenSSL \ -DOPENSSL_ROOT_DIR=$(CURDIR)/vendor/openssl -DOPENSSL_INCLUDE_DIR=$(CURDIR)/vendor/openssl/include \ -DOPENSSL_SSL_LIBRARY=$(CURDIR)/vendor/openssl/libssl.a -DOPENSSL_CRYPTO_LIBRARY=$(CURDIR)/vendor/openssl/libcrypto.a \ -DENABLE_ZLIB_COMPRESSION=OFF cmake --build $(LIBSSH2DIR)/build -j obj/calogSsh.o: calogSsh.c | obj $(CC) $(COREFLAGS) $(INC) $(LIBSSH2INC) -pthread -c -o $@ $< # calogArchive needs the vendored libarchive headers (outside $(INC)). obj/calogArchive.o obj/testArchive.o: obj/%.o: %.c | obj $(CC) $(COREFLAGS) $(INC) $(LIBARCHIVEINC) -pthread -c -o $@ $< # calogXml needs the vendored libxml2 headers (outside $(INC)): the source API plus the build dir # with the GENERATED xmlversion.h, so $(LIBXML2LIB) (which runs the CMake that generates it) is an # order-only prerequisite -- like PCRE2 below, whose pcre2.h is likewise generated. obj/calogXml.o obj/testXml.o: obj/%.o: %.c | obj $(LIBXML2LIB) $(CC) $(COREFLAGS) $(INC) $(LIBXML2INC) -pthread -c -o $@ $< # calogRegex needs the vendored (generated) PCRE2 header under vendor/pcre2/build, so the PCRE2 # build (which generates pcre2.h) is an order-only prerequisite. obj/calogRegex.o obj/testUtil.o: obj/%.o: %.c | obj $(PCRE2LIB) $(CC) $(COREFLAGS) $(INC) $(PCRE2INC) -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 $@ $< JANETADP = obj/janetAdapter.o $(JANETADP): obj/%.o: %.c | obj $(CC) $(ADPFLAGS) $(INC) $(JANETINC) -c -o $@ $< # relaxed C + Wren headers WRENADP = obj/wrenAdapter.o $(WRENADP): obj/%.o: %.c | obj $(CC) $(ADPFLAGS) $(INC) $(WRENINC) -c -o $@ $< # relaxed C + mruby headers. Ordered after $(MRUBYLIB): mruby's Rake build emits generated # headers (mruby/presym.h) under build/calog/include that the adapter includes. MRUBYADP = obj/mrubyAdapter.o $(MRUBYADP): obj/%.o: %.c | obj $(MRUBYLIB) $(CC) $(ADPFLAGS) $(INC) $(MRUBYINC) -c -o $@ $< # relaxed C + Tcl headers (tcl.h needs no generated header, so no $(TCLLIB) order dependency). TCLADP = obj/tclAdapter.o $(TCLADP): obj/%.o: %.c | obj $(CC) $(ADPFLAGS) $(INC) $(TCLINC) -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) -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 -DCALOG_WITH_MRUBY -DCALOG_WITH_TCL -DCALOG_WITH_JANET TASKADP = obj/calogTask.o $(TASKADP): obj/%.o: %.c | obj $(CC) $(COREFLAGS) $(INC) $(ENGINEDEFS) -pthread -c -o $@ $< # the calog CLI runner: strict C with every engine name compiled in, so # calogRegisterBuiltinEngines registers all seven (it links every engine archive + library). obj/calogMain.o: calogMain.c src/calog.h | 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/ourBasic.o: $(MBDIR)/ourBasic.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/janet.o: $(JANETDIR)/janet.c | obj $(CC) $(JANETFLAGS) $(JANETINC) -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 \ obj/mrubyAdapter.o obj/mrubyEngine.o obj/tclAdapter.o obj/tclEngine.o obj/janetAdapter.o obj/janetEngine.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/ourBasic.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/libjanet.a: $(JANETOBJ) | 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/testHooks: obj/testHooks.o lib/libcalog.a lib/liblua.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) 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 # All three archive groups together -- listed as real prerequisites (so a rebuilt vendored # archive triggers a relink) but filtered out of $^ where the recipe needs a link group. DBARCH = $(PGARCHIVES) $(MYSQLARCH) $(SSLARCH) 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 $(DBARCH) | bin $(CC) $(LDFLAGS) -pthread -o $@ $(filter-out $(DBARCH),$^) -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 $(DBARCH) | bin $(CC) $(LDFLAGS) -pthread -o $@ $(filter-out $(DBARCH),$^) -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 $@ $^ $(CXXLIB) -lm bin/testEngineSquirrel: obj/testEngineSquirrel.o lib/libcalog.a lib/libsquirrel.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(CXXLIB) -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) bin/testEngineMruby: obj/testEngineMruby.o lib/libcalog.a $(MRUBYLIB) | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(MRUBYLIBS) bin/testEngineTcl: obj/testEngineTcl.o lib/libcalog.a $(TCLLIB) | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(TCLLIBS) bin/testEngineJanet: obj/testEngineJanet.o lib/libcalog.a lib/libjanet.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(JANETLIBS) # 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 # the calog CLI runner: every engine archive + every library object + their vendored deps. # The DB library is compiled with ALL backends (calogDbFull.o: SQLite + PostgreSQL + MySQL/ # MariaDB), so the shipped runner speaks every driver out of the box. The PG archives need a # link group; MariaDB Connector/C is LGPL-2.1, so a redistributor who wants an all-permissive # binary can drop the MySQL backend (see LICENSE.md). libssh2 precedes OpenSSL (it depends on # it); SSLARCH follows the archives that reference it. bin/calog: obj/calogMain.o \ obj/calogArchive.o obj/calogCrypto.o obj/calogCsv.o obj/calogDbFull.o obj/calogExport.o obj/calogFs.o obj/calogHttp.o obj/calogHttpd.o obj/calogJson.o obj/calogKv.o obj/calogNet.o obj/calogProc.o obj/calogPubsub.o obj/calogRegex.o obj/calogSsh.o obj/calogTask.o obj/calogTime.o obj/calogTimer.o obj/calogXml.o 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 lib/libjanet.a $(MRUBYLIB) $(TCLLIB) \ lib/libsqlite3.a lib/libenet.a $(LIBSSH2LIB) $(ARCHIVELIBS) $(PCRE2LIB) $(DBARCH) | bin $(CC) $(LDFLAGS) $(RELEASELD) -pthread -o $@ $(filter-out $(DBARCH),$^) -Wl,--start-group $(PGARCHIVES) -Wl,--end-group $(MYSQLARCH) $(SSLARCH) $(CXXLIB) $(DLLIB) -lm -lpthread $(SOCKETLIBS) # ---- release build (fewest system dependencies while keeping DNS) -------------------- # The full CLI with sanitizers off and the C++/gcc runtimes linked statically, so `ldd` collapses # to just the system libc (glibc stays dynamic, so getaddrinfo/DNS keeps working -- see PORTING.md). # A `clean` first keeps build modes from mixing; the slow vendored archives (OpenSSL/Tcl/mruby/ # libssh2) live under vendor/ and survive it, so this is a moderate rebuild, not a full one. release: $(MAKE) clean $(MAKE) SAN= RELEASELD='-static-libgcc' CXXLIB='-Wl,-Bstatic -lstdc++ -Wl,-Bdynamic' bin/calog @echo "== release bin/calog shared-library dependencies (want just libc/libm + loader) ==" @ldd bin/calog 2>&1 | sed 's/^/ /' @echo "== note: run 'make clean && make' to return to the sanitized dev build ==" # ---- 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 -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 $(ENGINEDEFS) -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 lib/libjanet.a $(MRUBYLIB) $(TCLLIB) | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) $(CXXLIB) -lm $(MRUBYLIBS) $(TCLLIBS) # 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 lib/libjanet.a $(MRUBYLIB) $(TCLLIB) | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) $(CXXLIB) -lm $(MRUBYLIBS) $(TCLLIBS) # 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) $(CXXLIB) $(DLLIB) -lm bin/testJson: obj/testJson.o obj/calogJson.o lib/libcalog.a lib/liblua.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) bin/testXml: obj/testXml.o obj/calogXml.o lib/libcalog.a lib/liblua.a $(LIBXML2LIB) | 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 $(SSLARCH) | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) $(DLLIB) 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 $(SSLARCH) | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) $(DLLIB) bin/testArchive: obj/testArchive.o obj/calogArchive.o obj/calogHandle.o lib/libcalog.a lib/liblua.a $(ARCHIVELIBS) $(SSLARCH) | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) $(DLLIB) bin/testUtil: obj/testUtil.o obj/calogCsv.o obj/calogProc.o obj/calogRegex.o lib/libcalog.a lib/liblua.a $(PCRE2LIB) | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) bin/testSandbox: obj/testSandbox.o lib/libcalog.a lib/liblua.a lib/libquickjs.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) bin/testTrace: obj/testTrace.o obj/calogExport.o lib/libcalog.a lib/liblua.a lib/libquickjs.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) bin/testHttpd: obj/testHttpd.o obj/calogHttpd.o obj/calogHandle.o lib/libcalog.a lib/liblua.a lib/libquickjs.a | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) bin/testHttps: obj/testHttps.o obj/calogHttp.o lib/libcalog.a lib/liblua.a $(SSLARCH) | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) $(DLLIB) # SSH/SFTP over vendored libssh2 (before OpenSSL in the link line: libssh2 depends on it). bin/testSsh: obj/testSsh.o obj/calogSsh.o obj/calogHandle.o lib/libcalog.a lib/liblua.a $(LIBSSH2LIB) $(SSLARCH) | bin $(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) $(DLLIB) # The SSH test spawns a throwaway unprivileged sshd (needs system sshd + ssh-keygen), so it is # NOT part of `make test`. Run it explicitly. .PHONY: ssh-test ssh-test: bin/testSsh ./bin/testSsh obj bin lib: mkdir -p $@ test: all ./bin/testBroker && ./bin/testLua && ./bin/testMyBasic && ./bin/testPolyglot && \ ./bin/testActor && ./bin/testHooks && ./bin/testEngineLua && ./bin/testEngineMyBasic && ./bin/testSquirrel && ./bin/testEngineSquirrel && \ ./bin/testJs && ./bin/testEngineJs && ./bin/testEngineBerry && ./bin/testEngineS7 && ./bin/testEngineWren && ./bin/testEngineMruby && ./bin/testEngineTcl && ./bin/testEngineJanet && ./bin/testLoad && ./bin/testDb && ./bin/testNet && ./bin/testTask && ./bin/testExport && ./bin/testJson && ./bin/testXml && ./bin/testTime && ./bin/testFs && ./bin/testCrypto && ./bin/testKv && ./bin/testTimer && ./bin/testPubsub && ./bin/testHttp && ./bin/testHttps && ./bin/testArchive && ./bin/testUtil && ./bin/testSandbox && ./bin/testTrace && ./bin/testHttpd # 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. TSANFLAGS = -std=c11 $(WARN) -g -O1 -fsanitize=thread -pthread TSANCORE = src/context.c src/value.c src/broker.c tsan: $(LUAOBJ) | bin $(CC) $(TSANFLAGS) $(INC) -o bin/testActorTsan \ tests/testActor.c $(TSANCORE) setarch -R ./bin/testActorTsan $(CC) $(TSANFLAGS) $(INC) $(LUAINC) -o bin/testEngineLuaTsan \ tests/testEngineLua.c src/lua/luaEngine.c src/lua/luaAdapter.c $(TSANCORE) \ $(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 || exit 1; done $(CC) $(TSANFLAGS) $(INC) $(SQDEF) $(SQINC) -o bin/testEngineSquirrelTsan \ tests/testEngineSquirrel.c src/squirrel/squirrelEngine.c src/squirrel/squirrelAdapter.c \ $(TSANCORE) \ $(patsubst $(SQDIR)/squirrel/%.cpp,obj/%.tsan.o,$(SQSRC)) $(CXXLIB) -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 $(QJSNAMES); do $(CC) $(QJSFLAGS) $(QJSINC) -fsanitize=thread -c $(QJSDIR)/$$f.c -o obj/$$f.tsan.o || exit 1; done $(CC) $(TSANFLAGS) $(INC) $(QJSINC) -o bin/testEngineJsTsan \ tests/testEngineJs.c src/js/jsEngine.c src/js/jsAdapter.c $(TSANCORE) \ $(patsubst %,obj/%.tsan.o,$(QJSNAMES)) -lm setarch -R ./bin/testEngineJsTsan rm -f $(patsubst %,obj/%.tsan.o,$(QJSNAMES)) # 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)/ourBasic.c -o obj/ourBasic.tsan.o $(CC) $(TSANFLAGS) $(INC) $(MBINC) -DMB_DOUBLE_FLOAT -o bin/testEngineMyBasicTsan \ tests/testEngineMyBasic.c src/mybasic/mybasicEngine.c src/mybasic/mybasicAdapter.c $(TSANCORE) \ obj/ourBasic.tsan.o -lm setarch -R ./bin/testEngineMyBasicTsan rm -f obj/ourBasic.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 || exit 1; done $(CC) $(TSANFLAGS) $(INC) $(BERRYINC) -o bin/testEngineBerryTsan \ tests/testEngineBerry.c src/berry/berryEngine.c src/berry/berryAdapter.c $(TSANCORE) \ $(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) $(TSANFLAGS) $(INC) $(S7INC) -o bin/testEngineS7Tsan \ tests/testEngineS7.c src/s7/s7Engine.c src/s7/s7Adapter.c $(TSANCORE) \ 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) $(TSANFLAGS) $(INC) $(WRENINC) -o bin/testEngineWrenTsan \ tests/testEngineWren.c src/wren/wrenEngine.c src/wren/wrenAdapter.c $(TSANCORE) \ obj/wren.tsan.o $(WRENLIBS) setarch -R ./bin/testEngineWrenTsan rm -f obj/wren.tsan.o # ThreadSanitizer build of the mruby engine path. Unlike the other engines, mruby's VM is a # separate Rake-built archive, so it links UN-sanitized (like tsanlibs with liblua.a) -- TSan # instruments the calog adapter/engine/actor code, which is where the cross-context risk lives; # each mrb_state is independent (one per thread), the concurrency gate mruby was chosen on. tsanmruby: $(MRUBYLIB) | bin obj $(CC) $(TSANFLAGS) $(INC) $(MRUBYINC) -o bin/testEngineMrubyTsan \ tests/testEngineMruby.c src/mruby/mrubyEngine.c src/mruby/mrubyAdapter.c $(TSANCORE) \ $(MRUBYLIB) $(MRUBYLIBS) setarch -R ./bin/testEngineMrubyTsan # ThreadSanitizer build of the Tcl engine path. Like tsanmruby, libtcl is a separately-built # archive linked UN-sanitized; TSan instruments the calog adapter/engine/actor code, where the # cross-context risk lives. Tcl's apartment model gives each thread its own interpreter. tsantcl: $(TCLLIB) | bin obj $(CC) $(TSANFLAGS) $(INC) $(TCLINC) -o bin/testEngineTclTsan \ tests/testEngineTcl.c src/tcl/tclEngine.c src/tcl/tclAdapter.c $(TSANCORE) \ $(TCLLIB) $(TCLLIBS) setarch -R ./bin/testEngineTclTsan # ThreadSanitizer build of the Janet engine path (janet.o linked un-sanitized). This is the GATE-A # race check: N thread-local janet_vm VMs on N threads must not alias -- the concurrent-contexts # test is the gate. tsanjanet: lib/libjanet.a | bin obj $(CC) $(TSANFLAGS) $(INC) $(JANETINC) -o bin/testEngineJanetTsan \ tests/testEngineJanet.c src/janet/janetEngine.c src/janet/janetAdapter.c $(TSANCORE) \ lib/libjanet.a $(JANETLIBS) setarch -R ./bin/testEngineJanetTsan # 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 for n in Timer Pubsub Kv; do \ $(CC) $(TSANFLAGS) $(INC) $(LUAINC) -o bin/test$${n}Tsan \ tests/test$$n.c libs/calog$$n.c $(TSANCORE) src/lua/luaEngine.c src/lua/luaAdapter.c \ lib/liblua.a $(LUALIBS) || exit 1; \ setarch -R ./bin/test$${n}Tsan || exit 1; \ done 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 tsanmruby tsantcl tsanjanet tsanlibs release clean