# env/makefile.env — single cross-platform build environment for Klammertext. # # Included identically by every component Makefile: # include $(KLAMMERTEXT_HOME)/env/makefile.env # # The platform is auto-detected with uname; the compiler is chosen with # make COMPILER=gcc (default) # make COMPILER=clang # There is no per-host/per-OS file and no DESKTOP_SESSION/HOST/SITE selector. ifndef KLAMMERTEXT_HOME $(error KLAMMERTEXT_HOME is not set -- source env/runtime.env first) endif include $(KLAMMERTEXT_HOME)/env/optimize.env UNAME_S := $(shell uname -s) CPP_VERSION := c++20 # Default compiler: clang on macOS, gcc elsewhere. gcc-built Klammertext # binaries crash at runtime on macOS (a documented gcc/macOS codegen issue), so # gcc there is only a compile-time conformance check (via `./dev/rebuild.sh # gcc`, which compiles under g++ then rebuilds with clang). Override with # `make COMPILER=...`. ifeq ($(UNAME_S),Darwin) COMPILER ?= clang # gcc | clang else COMPILER ?= gcc # gcc | clang endif # Python: version- and platform-agnostic, no hardcoded paths. On Windows the # interpreter is python.org's (the one PyPI wheels -- OpenImageIO -- are built # for); it ships no python3-config, so its prefix is asked of the interpreter # itself and its import library named by version (libs/python312.lib). ifneq (,$(filter MINGW% MSYS%,$(UNAME_S))) PYTHON := python PYTHON_PREFIX := $(shell cygpath -m "$$($(PYTHON) -c 'import sys; print(sys.base_prefix)')") PYTHON_INC := -I"$(PYTHON_PREFIX)/Include" PYTHON_LIB := -L"$(PYTHON_PREFIX)/libs" -l$(shell $(PYTHON) -c 'import sys; print("python%d%d" % sys.version_info[:2])') else PYTHON := python3 PYTHON_INC := $(shell python3-config --includes) PYTHON_LIB := $(shell python3-config --ldflags --embed) endif # Flags common to all platforms. CPPFLAGS = -I$(KLAMMERTEXT_HOME)/mac $(PYTHON_INC) CXXFLAGS = -Wall -Wextra -Weffc++ -Wshadow -std=$(CPP_VERSION) -fPIC $(OPTIMIZE) $(SANITIZE) ifeq ($(UNAME_S),Darwin) # ---------- macOS (Apple Silicon) ---------- # Package-manager prefix, auto-detected: Homebrew (/opt/homebrew) or MacPorts # (/opt/local). Override with `make MACOS_PREFIX=...`. Only the prefix differs # between the two: the compiler is Apple Clang either way, and all Python flags # come from python3-config (prefix-agnostic), so nothing else is PM-specific. MACOS_PREFIX ?= $(shell test -d /opt/homebrew && echo /opt/homebrew || (test -d /opt/local && echo /opt/local || echo /opt/homebrew)) # Newest optional gcc (conformance check only): Homebrew g++-NN or MacPorts g++-mp-NN. GCC := $(shell g=$$(ls $(MACOS_PREFIX)/bin/g++-[0-9]* $(MACOS_PREFIX)/bin/g++-mp-[0-9]* 2>/dev/null | sort -V | tail -1); echo $${g:-g++}) CLANG := clang++ # Apple clang (or brew/port llvm) CPPFLAGS += -I$(MACOS_PREFIX)/include LDFLAGS = -L$(MACOS_PREFIX)/lib LDLIBS = $(if $(NOPYTHON),,$(PYTHON_LIB)) SHARED = -dynamiclib SONAME = -install_name @rpath/$(notdir $@) ORIGIN := @loader_path EXPORT_DYNAMIC = -Wl,-export_dynamic EXE := DSO := .so KLAMMERTEXT_LIBFILE := libklammertext.so else ifneq (,$(filter MINGW% MSYS%,$(UNAME_S))) # ---------- Windows (MSYS2, UCRT64 environment; native PE binaries) ---------- # uname says MINGW64_NT-... under UCRT64 too. The compilers come from the # environment's PATH (/ucrt64/bin). libdl.a is the mingw-w64-dlfcn shim over # LoadLibrary, linked statically so no libdl.dll travels with the products. # PE has no soname and no rpath; a DLL is found through PATH or # the executable's own directory. GCC := g++ CLANG := clang++ LDFLAGS = LDLIBS = -l:libdl.a $(if $(NOPYTHON),,$(PYTHON_LIB)) SHARED = -shared SONAME = ORIGIN := $$ORIGIN EXPORT_DYNAMIC = -Wl,--export-all-symbols EXE := .exe DSO := .dll KLAMMERTEXT_LIBFILE := klammertext.dll # A Windows program finds a DLL through PATH or its own directory, never an # rpath. So every directory that holds a program or a Python extension also # holds the DLLs it needs: klammertext.dll and the three gcc runtime DLLs # the toolchain links (from the compiler's own bin/). com/ and kpy/ copy them. GCC_BIN := $(dir $(shell cygpath -m "$$(command -v g++)")) GCC_RUNTIME_DLLS := libstdc++-6.dll libgcc_s_seh-1.dll libwinpthread-1.dll else # ---------- Linux ---------- EXE := DSO := .so KLAMMERTEXT_LIBFILE := libklammertext.so GCC := /usr/bin/g++ CLANG := $(shell command -v clang++-18 2>/dev/null || command -v clang++ 2>/dev/null) LDFLAGS = -L/usr/lib/x86_64-linux-gnu LDLIBS = -ldl $(if $(NOPYTHON),,$(PYTHON_LIB)) SHARED = -shared SONAME = -Wl,-soname,$(notdir $@) ORIGIN := $$ORIGIN EXPORT_DYNAMIC = -rdynamic endif # Product names (decided 2026-09-25: Windows users get Windows names). The # three variables above are set per platform: EXE is the executable suffix # (".exe" on Windows, none elsewhere), DSO the suffix of a shared object # loaded at run time (".dll" / ".so": document$(DSO), reflect$(DSO)), and # KLAMMERTEXT_LIBFILE the library's file name (klammertext.dll / # libklammertext.so). A make target carries the suffix so that the file the # compiler writes IS the target: bin/ktext never existed on Windows -- gcc # wrote ktext.exe -- and every make relinked the three commands. The engine's # own copy of the DSO suffix is shared_library_suffix in mac/file.h. # # One link form everywhere: GNU ld's -l search list on PE ends with # ".dll", so -lklammertext finds klammertext.dll as it finds # libklammertext.so on Linux (it did NOT find a DLL called libklammertext.so, # which needed the exact-name -l: form). KLAMMERTEXT_LIB = -lklammertext # Resolve the compiler choice (gcc by default; clang with COMPILER=clang). CXX := $(if $(filter clang,$(COMPILER)),$(CLANG),$(GCC))