commit c2f9575135399104652d2be75470b74f696cf9a1
parent ed38bc5b19bb021847602b73dd62d26f79772cf9
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Mon, 25 May 2026 16:51:56 -0700
Add compile-time component knobs
Diffstat:
25 files changed, 1414 insertions(+), 214 deletions(-)
diff --git a/Makefile b/Makefile
@@ -82,19 +82,23 @@ TEST_HOST_CFLAGS = $(HOST_CFLAGS) -Iinclude -Ilang
include mk/config.mk
-# Non-arch lib sources: everything under src/ except gated component
-# directories/files. Shared arch/obj/abi infrastructure stays unconditional.
-LIB_SRCS_NONARCH = $(shell find src -name '*.c' \
- -not -path 'src/arch/aa64/*' \
- -not -path 'src/arch/x64/*' \
- -not -path 'src/arch/rv64/*' \
- -not -path 'src/arch/wasm/*' \
- -not -path 'src/arch/c_target/*' \
- -not -path 'src/obj/elf/*' \
- -not -path 'src/obj/macho/*' \
- -not -path 'src/obj/coff/*' \
- -not -path 'src/opt/*' \
- -not -path 'src/abi/abi_*.c')
+# Core lib sources. Optional subsystems, backend directories, object format
+# directories, and ABI implementations are added below from their own groups.
+LIB_SRCS_ABI_CORE = src/abi/abi.c src/abi/registry.c
+LIB_SRCS_API_CORE = $(filter-out src/api/archive.c src/api/disasm.c \
+ src/api/link.c src/api/stubs.c,$(wildcard src/api/*.c))
+LIB_SRCS_ARCH_CORE = $(filter-out src/arch/%_stubs.c,$(wildcard src/arch/*.c))
+LIB_SRCS_ASM_CORE = $(wildcard src/asm/*.c)
+LIB_SRCS_CG_CORE = $(wildcard src/cg/*.c)
+LIB_SRCS_CORE = $(wildcard src/core/*.c)
+LIB_SRCS_OBJ_CORE = $(filter-out src/obj/%_stubs.c,$(wildcard src/obj/*.c))
+LIB_SRCS_NONARCH = $(LIB_SRCS_ABI_CORE) \
+ $(LIB_SRCS_API_CORE) \
+ $(LIB_SRCS_ARCH_CORE) \
+ $(LIB_SRCS_ASM_CORE) \
+ $(LIB_SRCS_CG_CORE) \
+ $(LIB_SRCS_CORE) \
+ $(LIB_SRCS_OBJ_CORE)
LIB_SRCS_ARCH_AA64 = $(shell find src/arch/aa64 -name '*.c' 2>/dev/null)
LIB_SRCS_ARCH_X64 = $(shell find src/arch/x64 -name '*.c' 2>/dev/null)
@@ -106,12 +110,61 @@ LIB_SRCS_ARCH_AA64 := $(filter-out %/opt_coord.c,$(LIB_SRCS_ARCH_AA64))
LIB_SRCS_ARCH_X64 := $(filter-out %/opt_coord.c,$(LIB_SRCS_ARCH_X64))
LIB_SRCS_ARCH_RV64 := $(filter-out %/opt_coord.c,$(LIB_SRCS_ARCH_RV64))
endif
+ifneq ($(CFREE_DISASM_ENABLED),1)
+LIB_SRCS_ARCH_AA64 := $(filter-out %/disasm.c,$(LIB_SRCS_ARCH_AA64))
+LIB_SRCS_ARCH_X64 := $(filter-out %/disasm.c,$(LIB_SRCS_ARCH_X64))
+LIB_SRCS_ARCH_RV64 := $(filter-out %/disasm.c,$(LIB_SRCS_ARCH_RV64))
+LIB_SRCS_NONARCH += src/arch/disasm_stubs.c
+endif
+ifneq ($(CFREE_LINK_ENABLED),1)
+LIB_SRCS_ARCH_AA64 := $(filter-out %/link.c,$(LIB_SRCS_ARCH_AA64))
+LIB_SRCS_ARCH_X64 := $(filter-out %/link.c,$(LIB_SRCS_ARCH_X64))
+LIB_SRCS_ARCH_RV64 := $(filter-out %/link.c,$(LIB_SRCS_ARCH_RV64))
+LIB_SRCS_NONARCH += src/arch/link_stubs.c
+endif
+ifneq ($(CFREE_DBG_ENABLED),1)
+LIB_SRCS_ARCH_AA64 := $(filter-out %/dbg.c,$(LIB_SRCS_ARCH_AA64))
+LIB_SRCS_ARCH_X64 := $(filter-out %/dbg.c,$(LIB_SRCS_ARCH_X64))
+LIB_SRCS_ARCH_RV64 := $(filter-out %/dbg.c,$(LIB_SRCS_ARCH_RV64))
+LIB_SRCS_NONARCH += src/arch/dbg_stubs.c
+endif
+ifneq ($(CFREE_EMU_ENABLED),1)
+LIB_SRCS_ARCH_RV64 := $(filter-out %/emu.c,$(LIB_SRCS_ARCH_RV64))
+LIB_SRCS_NONARCH += src/arch/emu_stubs.c
+endif
LIB_SRCS_OBJ_ELF = $(shell find src/obj/elf -name '*.c' 2>/dev/null)
LIB_SRCS_OBJ_MACHO = $(shell find src/obj/macho -name '*.c' 2>/dev/null)
LIB_SRCS_OBJ_COFF = $(shell find src/obj/coff -name '*.c' 2>/dev/null)
+ifneq ($(CFREE_LINK_ENABLED),1)
+LIB_SRCS_OBJ_ELF := $(filter-out %/link.c %/link_dyn.c,$(LIB_SRCS_OBJ_ELF))
+LIB_SRCS_OBJ_MACHO := $(filter-out %/link.c,$(LIB_SRCS_OBJ_MACHO))
+LIB_SRCS_OBJ_COFF := $(filter-out %/link.c,$(LIB_SRCS_OBJ_COFF))
+LIB_SRCS_NONARCH += src/obj/link_stubs.c
+endif
+ifneq ($(CFREE_EMU_ENABLED),1)
+LIB_SRCS_OBJ_ELF := $(filter-out %/emu_load.c,$(LIB_SRCS_OBJ_ELF))
+LIB_SRCS_NONARCH += src/obj/emu_stubs.c
+endif
+ifneq ($(CFREE_AR_ENABLED),1)
+LIB_SRCS_OBJ_COFF := $(filter-out %/archive.c,$(LIB_SRCS_OBJ_COFF))
+LIB_SRCS_NONARCH += src/obj/archive_stubs.c
+endif
LIB_SRCS_OPT = $(shell find src/opt -name '*.c' 2>/dev/null)
+LIB_SRCS_WASM_CORE = $(shell find src/wasm -name '*.c' 2>/dev/null)
+LIB_SRCS_API_AR = src/api/archive.c
+LIB_SRCS_API_DISASM = src/api/disasm.c
+LIB_SRCS_API_LINK = src/api/link.c
+LIB_SRCS_DEBUG = $(shell find src/debug -name '*.c' 2>/dev/null)
+LIB_SRCS_DBG = $(shell find src/dbg -name '*.c' 2>/dev/null)
+LIB_SRCS_EMU = $(shell find src/emu -name '*.c' 2>/dev/null) \
+ $(shell find src/os -name '*.c' 2>/dev/null)
+LIB_SRCS_LINK = $(shell find src/link -name '*.c' 2>/dev/null)
+ifneq ($(CFREE_JIT_ENABLED),1)
+LIB_SRCS_LINK := $(filter-out %/link_jit.c,$(LIB_SRCS_LINK))
+endif
+LIB_SRCS_JIT_ASM = $(shell find src/jit -name '*.S' 2>/dev/null)
LIB_SRC_ABI_AAPCS64 = src/abi/abi_aapcs64.c
LIB_SRC_ABI_APPLE_ARM64 = src/abi/abi_apple_arm64.c
@@ -125,6 +178,24 @@ LIB_SRCS = $(LIB_SRCS_NONARCH)
ifeq ($(CFREE_OPT_ENABLED),1)
LIB_SRCS += $(LIB_SRCS_OPT)
endif
+ifeq ($(CFREE_AR_ENABLED),1)
+LIB_SRCS += $(LIB_SRCS_API_AR)
+endif
+ifeq ($(CFREE_DISASM_ENABLED),1)
+LIB_SRCS += $(LIB_SRCS_API_DISASM)
+endif
+ifeq ($(CFREE_DWARF_ENABLED),1)
+LIB_SRCS += $(LIB_SRCS_DEBUG)
+endif
+ifeq ($(CFREE_LINK_ENABLED),1)
+LIB_SRCS += $(LIB_SRCS_API_LINK) $(LIB_SRCS_LINK)
+endif
+ifeq ($(CFREE_DBG_ENABLED),1)
+LIB_SRCS += $(LIB_SRCS_DBG)
+endif
+ifeq ($(CFREE_EMU_ENABLED),1)
+LIB_SRCS += $(LIB_SRCS_EMU)
+endif
ifeq ($(CFREE_ARCH_AA64_ENABLED),1)
LIB_SRCS += $(LIB_SRCS_ARCH_AA64)
endif
@@ -140,6 +211,9 @@ endif
ifeq ($(CFREE_ARCH_C_TARGET_ENABLED),1)
LIB_SRCS += $(LIB_SRCS_ARCH_C_TARGET)
endif
+ifneq ($(filter 1,$(CFREE_ARCH_WASM_ENABLED) $(CFREE_OBJ_WASM_ENABLED) $(CFREE_LANG_WASM_ENABLED)),)
+LIB_SRCS += $(LIB_SRCS_WASM_CORE)
+endif
ifeq ($(CFREE_OBJ_ELF_ENABLED),1)
LIB_SRCS += $(LIB_SRCS_OBJ_ELF)
endif
@@ -199,17 +273,83 @@ ifeq ($(CFREE_LANG_TOY_ENABLED),1)
LANG_OBJS += $(patsubst lang/toy/%.c,$(BUILD_DIR)/lang/toy/%.o,$(LANG_TOY_SRCS))
endif
-LIB_ASMS = $(shell find src -name '*.S')
+LIB_ASMS =
+ifeq ($(CFREE_JIT_ENABLED),1)
+LIB_ASMS += $(LIB_SRCS_JIT_ASM)
+endif
LIB_OBJS = $(patsubst src/%.c,$(BUILD_DIR)/lib/%.o,$(LIB_SRCS)) \
$(LANG_OBJS) \
$(patsubst src/%.S,$(BUILD_DIR)/lib/%.o,$(LIB_ASMS))
LIB_DEPS = $(LIB_OBJS:.o=.d)
LIB_RELOC_OBJ = $(BUILD_DIR)/libcfree.o
-DRIVER_SRCS = $(wildcard driver/*.c)
-ifneq ($(CFREE_LANG_CPP_ENABLED),1)
-DRIVER_SRCS := $(filter-out driver/cpp.c,$(DRIVER_SRCS))
+DRIVER_SRCS = driver/main.c driver/env.c driver/target.c
+DRIVER_TOOL_SRCS =
+ifeq ($(CFREE_TOOL_CC_ENABLED),1)
+DRIVER_TOOL_SRCS += driver/cc.c
+endif
+ifeq ($(CFREE_TOOL_CHECK_ENABLED),1)
+DRIVER_TOOL_SRCS += driver/cc.c
+endif
+ifeq ($(CFREE_TOOL_CPP_ENABLED),1)
+DRIVER_TOOL_SRCS += driver/cpp.c
+endif
+ifeq ($(CFREE_TOOL_AS_ENABLED),1)
+DRIVER_TOOL_SRCS += driver/as.c
+endif
+ifeq ($(CFREE_TOOL_LD_ENABLED),1)
+DRIVER_TOOL_SRCS += driver/ld.c
+endif
+ifeq ($(CFREE_TOOL_AR_ENABLED),1)
+DRIVER_TOOL_SRCS += driver/ar.c
+endif
+ifeq ($(CFREE_TOOL_RANLIB_ENABLED),1)
+DRIVER_TOOL_SRCS += driver/ranlib.c
+endif
+ifeq ($(CFREE_TOOL_STRIP_ENABLED),1)
+DRIVER_TOOL_SRCS += driver/strip.c
+endif
+ifeq ($(CFREE_TOOL_OBJCOPY_ENABLED),1)
+DRIVER_TOOL_SRCS += driver/objcopy.c
+endif
+ifeq ($(CFREE_TOOL_OBJDUMP_ENABLED),1)
+DRIVER_TOOL_SRCS += driver/objdump.c
+endif
+ifeq ($(CFREE_TOOL_DBG_ENABLED),1)
+DRIVER_TOOL_SRCS += driver/dbg.c
+endif
+ifeq ($(CFREE_TOOL_RUN_ENABLED),1)
+DRIVER_TOOL_SRCS += driver/run.c
+endif
+ifeq ($(CFREE_TOOL_EMU_ENABLED),1)
+DRIVER_TOOL_SRCS += driver/emu.c
+endif
+ifeq ($(CFREE_TOOL_NM_ENABLED),1)
+DRIVER_TOOL_SRCS += driver/nm.c
+endif
+ifeq ($(CFREE_TOOL_SIZE_ENABLED),1)
+DRIVER_TOOL_SRCS += driver/size.c
+endif
+ifeq ($(CFREE_TOOL_ADDR2LINE_ENABLED),1)
+DRIVER_TOOL_SRCS += driver/addr2line.c
+endif
+DRIVER_SRCS += $(sort $(DRIVER_TOOL_SRCS))
+ifneq ($(filter 1,$(CFREE_TOOL_CC_ENABLED) $(CFREE_TOOL_CHECK_ENABLED) $(CFREE_TOOL_CPP_ENABLED) $(CFREE_TOOL_AS_ENABLED) $(CFREE_TOOL_DBG_ENABLED) $(CFREE_TOOL_RUN_ENABLED)),)
+DRIVER_SRCS += driver/cflags.c
+endif
+ifneq ($(filter 1,$(CFREE_TOOL_CC_ENABLED) $(CFREE_TOOL_CHECK_ENABLED) $(CFREE_TOOL_LD_ENABLED) $(CFREE_TOOL_RUN_ENABLED)),)
+DRIVER_SRCS += driver/lib_resolve.c
+endif
+ifneq ($(filter 1,$(CFREE_TOOL_CC_ENABLED) $(CFREE_TOOL_CHECK_ENABLED) $(CFREE_TOOL_RUN_ENABLED)),)
+DRIVER_SRCS += driver/hosted.c
+endif
+ifneq ($(filter 1,$(CFREE_TOOL_CC_ENABLED) $(CFREE_TOOL_CHECK_ENABLED)),)
+DRIVER_SRCS += driver/runtime.c
+endif
+ifneq ($(filter 1,$(CFREE_TOOL_AR_ENABLED) $(CFREE_TOOL_RANLIB_ENABLED) $(CFREE_TOOL_STRIP_ENABLED) $(CFREE_TOOL_DBG_ENABLED) $(CFREE_TOOL_RUN_ENABLED)),)
+DRIVER_SRCS += driver/inputs.c
endif
+DRIVER_SRCS := $(sort $(DRIVER_SRCS))
DRIVER_OBJS = $(patsubst driver/%.c,$(BUILD_DIR)/driver/%.o,$(DRIVER_SRCS))
DRIVER_DEPS = $(DRIVER_OBJS:.o=.d)
diff --git a/driver/main.c b/driver/main.c
@@ -4,112 +4,113 @@
/* Multi-call dispatch. Looks at argv[0]'s basename for a tool name; if argv[0]
* is the bare "cfree" binary, falls back to argv[1].
- * Preprocessor-only mode is `cc -E`.
*
- * Help routing is layered on top of dispatch:
- *
- * - `cfree` → driver_help_top()
- * - `cfree -h | --help | -help`
- * → driver_help_top()
- * - `cfree help` → driver_help_top()
- * - `cfree help <tool>` → driver_help_<tool>()
- * - any tool entry sees no args, --help, or -h (objdump excepted)
- * → driver_help_<tool>() and return 0.
- *
- * Each tool gates its own entry on argc < 2 / driver_argv_wants_help so
- * the same handling applies regardless of whether the user invoked the
- * multi-call form (`cfree cc --help`) or the symlinked form (`cc --help`).
+ * Tool availability is centralized here. The Makefile uses the same
+ * CFREE_TOOL_*_ENABLED flags to drop driver/<tool>.c objects, so disabled
+ * tools do not need #if checks scattered through each tool implementation.
*/
+typedef int (*DriverToolMain)(int argc, char** argv);
+typedef void (*DriverToolHelp)(void);
+
+typedef struct DriverToolDesc {
+ const char* name;
+ DriverToolMain main;
+ DriverToolHelp help;
+ const char* summary;
+} DriverToolDesc;
+
+static const DriverToolDesc driver_tools[] = {
+#if CFREE_TOOL_CC_ENABLED
+ {"cc", driver_cc, driver_help_cc,
+ "Compile (and link) C sources, with cpp / dep-emit / -shared modes"},
+#endif
+#if CFREE_TOOL_CHECK_ENABLED
+ {"check", driver_check, driver_help_check,
+ "Run C frontend checks without emitting code"},
+#endif
+#if CFREE_TOOL_CPP_ENABLED
+ {"cpp", driver_cpp, driver_help_cpp,
+ "Standalone C preprocessor (alias for `cc -E` minus link scaffold)"},
+#endif
+#if CFREE_TOOL_AS_ENABLED
+ {"as", driver_as, driver_help_as,
+ "Assemble a GAS-subset text source into a relocatable object"},
+#endif
+#if CFREE_TOOL_LD_ENABLED
+ {"ld", driver_ld, driver_help_ld,
+ "Link objects/archives into an executable or shared library"},
+#endif
+#if CFREE_TOOL_AR_ENABLED
+ {"ar", driver_ar, driver_help_ar,
+ "Create / modify / list / extract POSIX `ar` archives"},
+#endif
+#if CFREE_TOOL_RANLIB_ENABLED
+ {"ranlib", driver_ranlib, driver_help_ranlib,
+ "Refresh the symbol index of an `ar` archive"},
+#endif
+#if CFREE_TOOL_STRIP_ENABLED
+ {"strip", driver_strip, driver_help_strip,
+ "Drop debug sections and/or symbols from a .o or .a"},
+#endif
+#if CFREE_TOOL_OBJCOPY_ENABLED
+ {"objcopy", driver_objcopy, driver_help_objcopy,
+ "Copy and transform an object file (rename / remove / format)"},
+#endif
+#if CFREE_TOOL_OBJDUMP_ENABLED
+ {"objdump", driver_objdump, driver_help_objdump,
+ "Dump sections, symbols, disassembly, hex, and relocations"},
+#endif
+#if CFREE_TOOL_RUN_ENABLED
+ {"run", driver_run, driver_help_run,
+ "JIT-compile inputs and invoke the entry symbol in-process"},
+#endif
+#if CFREE_TOOL_DBG_ENABLED
+ {"dbg", driver_dbg, driver_help_dbg,
+ "Interactive JIT debugger (REPL on top of the JIT image)"},
+#endif
+#if CFREE_TOOL_EMU_ENABLED
+ {"emu", driver_emu, driver_help_emu,
+ "Run a guest user-mode ELF (aarch64/riscv64) on the host"},
+#endif
+#if CFREE_TOOL_NM_ENABLED
+ {"nm", driver_nm, driver_help_nm, "List symbols from object files"},
+#endif
+#if CFREE_TOOL_SIZE_ENABLED
+ {"size", driver_size, driver_help_size,
+ "Display section sizes of object files"},
+#endif
+#if CFREE_TOOL_ADDR2LINE_ENABLED
+ {"addr2line", driver_addr2line, driver_help_addr2line,
+ "Translate addresses to file:line using debug info"},
+#endif
+ {NULL, NULL, NULL, NULL},
+};
+
+static unsigned driver_tool_count(void) {
+ return (unsigned)(sizeof driver_tools / sizeof driver_tools[0]) - 1u;
+}
+
+static const DriverToolDesc* find_tool(const char* name) {
+ unsigned i;
+ for (i = 0; i < driver_tool_count(); ++i) {
+ if (driver_streq(name, driver_tools[i].name)) return &driver_tools[i];
+ }
+ return NULL;
+}
+
static int dispatch(const char* name, int argc, char** argv) {
- if (driver_streq(name, "cc")) return driver_cc(argc, argv);
- if (driver_streq(name, "check")) return driver_check(argc, argv);
-#if CFREE_LANG_CPP_ENABLED
- if (driver_streq(name, "cpp")) return driver_cpp(argc, argv);
-#endif
- if (driver_streq(name, "as")) return driver_as(argc, argv);
- if (driver_streq(name, "ld")) return driver_ld(argc, argv);
- if (driver_streq(name, "ar")) return driver_ar(argc, argv);
- if (driver_streq(name, "ranlib")) return driver_ranlib(argc, argv);
- if (driver_streq(name, "strip")) return driver_strip(argc, argv);
- if (driver_streq(name, "objcopy")) return driver_objcopy(argc, argv);
- if (driver_streq(name, "objdump")) return driver_objdump(argc, argv);
- if (driver_streq(name, "dbg")) return driver_dbg(argc, argv);
- if (driver_streq(name, "run")) return driver_run(argc, argv);
- if (driver_streq(name, "emu")) return driver_emu(argc, argv);
- if (driver_streq(name, "nm")) return driver_nm(argc, argv);
- if (driver_streq(name, "size")) return driver_size(argc, argv);
- if (driver_streq(name, "addr2line")) return driver_addr2line(argc, argv);
+ const DriverToolDesc* tool = find_tool(name);
+ if (tool) return tool->main(argc, argv);
return -1;
}
/* If `name` matches a tool, print its help and return 0. Otherwise return
* non-zero (caller reports the error). */
static int print_tool_help(const char* name) {
- if (driver_streq(name, "cc")) {
- driver_help_cc();
- return 0;
- }
- if (driver_streq(name, "check")) {
- driver_help_check();
- return 0;
- }
-#if CFREE_LANG_CPP_ENABLED
- if (driver_streq(name, "cpp")) {
- driver_help_cpp();
- return 0;
- }
-#endif
- if (driver_streq(name, "as")) {
- driver_help_as();
- return 0;
- }
- if (driver_streq(name, "ld")) {
- driver_help_ld();
- return 0;
- }
- if (driver_streq(name, "ar")) {
- driver_help_ar();
- return 0;
- }
- if (driver_streq(name, "ranlib")) {
- driver_help_ranlib();
- return 0;
- }
- if (driver_streq(name, "strip")) {
- driver_help_strip();
- return 0;
- }
- if (driver_streq(name, "objcopy")) {
- driver_help_objcopy();
- return 0;
- }
- if (driver_streq(name, "objdump")) {
- driver_help_objdump();
- return 0;
- }
- if (driver_streq(name, "dbg")) {
- driver_help_dbg();
- return 0;
- }
- if (driver_streq(name, "run")) {
- driver_help_run();
- return 0;
- }
- if (driver_streq(name, "emu")) {
- driver_help_emu();
- return 0;
- }
- if (driver_streq(name, "nm")) {
- driver_help_nm();
- return 0;
- }
- if (driver_streq(name, "size")) {
- driver_help_size();
- return 0;
- }
- if (driver_streq(name, "addr2line")) {
- driver_help_addr2line();
+ const DriverToolDesc* tool = find_tool(name);
+ if (tool) {
+ tool->help();
return 0;
}
return -1;
@@ -134,9 +135,8 @@ int driver_argv_wants_help(int argc, char** argv, int accept_short_h) {
}
void driver_help_top(void) {
+ unsigned i;
driver_printf(
- "%.*s",
- CFREE_SLICE_ARG(CFREE_SLICE_LIT(
"cfree — freestanding C compiler toolchain\n"
"\n"
"USAGE\n"
@@ -145,26 +145,11 @@ void driver_help_top(void) {
"symlink\n"
" cfree help [<tool>] this help, or per-tool help\n"
"\n"
- "TOOLS\n"
- " cc Compile (and link) C sources, with cpp / dep-emit / -shared "
- "modes\n"
- " check Run C frontend checks without emitting code\n"
- " cpp Standalone C preprocessor (alias for `cc -E` minus link "
- "scaffold)\n"
- " as Assemble a GAS-subset text source into a relocatable "
- "object\n"
- " ld Link objects/archives into an executable or shared library\n"
- " ar Create / modify / list / extract POSIX `ar` archives\n"
- " ranlib Refresh the symbol index of an `ar` archive\n"
- " strip Drop debug sections and/or symbols from a .o or .a\n"
- " objcopy Copy and transform an object file (rename / remove / format)\n"
- " objdump Dump sections, symbols, disassembly, hex, and relocations\n"
- " run JIT-compile inputs and invoke the entry symbol in-process\n"
- " dbg Interactive JIT debugger (REPL on top of the JIT image)\n"
- " emu Run a guest user-mode ELF (aarch64/riscv64) on the host\n"
- " nm List symbols from object files\n"
- " size Display section sizes of object files\n"
- " addr2line Translate addresses to file:line using debug info\n"
+ "TOOLS\n");
+ for (i = 0; i < driver_tool_count(); ++i) {
+ driver_printf(" %-9s %s\n", driver_tools[i].name, driver_tools[i].summary);
+ }
+ driver_printf(
"\n"
"GETTING HELP\n"
" cfree <tool> --help full per-tool help (also -h, except "
@@ -176,7 +161,7 @@ void driver_help_top(void) {
"EXIT CODES\n"
" 0 success\n"
" 1 tool-reported error (compile, link, I/O, ...)\n"
- " 2 bad command-line usage\n")));
+ " 2 bad command-line usage\n");
}
int driver_main(int argc, char** argv) {
diff --git a/include/cfree/config.h b/include/cfree/config.h
@@ -3,11 +3,13 @@
/* Build-time component configuration for libcfree and the cfree driver.
*
- * Four independent axes are gated here:
+ * Component axes are gated here:
* - Backend architectures
* - Object/image formats
* - Language frontends
* - Optional optimizer pipeline
+ * - Optional library subsystems
+ * - cfree driver tools
*
* ABIs are derived from (arch x obj-format) and are pulled in automatically
* when both sides are enabled (see src/abi/).
@@ -35,13 +37,16 @@
#define CFREE_OBJ_COFF_ENABLED 1
#define CFREE_OBJ_WASM_ENABLED 1
-/* Language frontends. The assembler frontend is unconditional: it lives
- * inside libcfree as part of the codegen substrate.
+/* Language frontends.
*
- * CFREE_LANG_CPP_ENABLED gates the C preprocessor (lang/cpp/). The C
- * frontend depends on it; enabling CFREE_LANG_C_ENABLED without
- * CFREE_LANG_CPP_ENABLED is a build-time error. The preprocessor can
- * be enabled standalone (e.g. for `cfree cpp` only). */
+ * CFREE_LANG_ASM_ENABLED only gates automatic registration of the asm
+ * frontend. The assembler parser/emitter substrate is still core today
+ * because inline/file-scope asm and the C frontend can depend on it.
+ *
+ * CFREE_LANG_CPP_ENABLED gates the C preprocessor (lang/cpp/). The C frontend
+ * depends on it; enabling CFREE_LANG_C_ENABLED without CFREE_LANG_CPP_ENABLED
+ * is a build-time error. The preprocessor can be enabled standalone. */
+#define CFREE_LANG_ASM_ENABLED 1
#define CFREE_LANG_CPP_ENABLED 1
#define CFREE_LANG_C_ENABLED 1
#define CFREE_LANG_TOY_ENABLED 1
@@ -51,4 +56,39 @@
* require this flag and the matching src/opt sources. */
#define CFREE_OPT_ENABLED 1
+/* Optional library subsystems. These are kept separate from driver tool flags:
+ * libcfree embedders care mostly about whether a public subsystem and its
+ * registry/vtables are present; the cfree binary additionally chooses which
+ * CLI entry points to compile and advertise.
+ *
+ * Some implementation directories are still shared by historically coupled
+ * subsystems. The build asserts the dependencies that are required by the
+ * current layout. */
+#define CFREE_AR_ENABLED 1
+#define CFREE_DISASM_ENABLED 1
+#define CFREE_DWARF_ENABLED 1
+#define CFREE_LINK_ENABLED 1
+#define CFREE_JIT_ENABLED 1
+#define CFREE_DBG_ENABLED 1
+#define CFREE_EMU_ENABLED 1
+
+/* cfree multi-call driver tools. These flags control both dispatch/help and
+ * the driver/<tool>.c objects included in the cfree binary. */
+#define CFREE_TOOL_CC_ENABLED 1
+#define CFREE_TOOL_CHECK_ENABLED 1
+#define CFREE_TOOL_CPP_ENABLED 1
+#define CFREE_TOOL_AS_ENABLED 1
+#define CFREE_TOOL_LD_ENABLED 1
+#define CFREE_TOOL_AR_ENABLED 1
+#define CFREE_TOOL_RANLIB_ENABLED 1
+#define CFREE_TOOL_STRIP_ENABLED 1
+#define CFREE_TOOL_OBJCOPY_ENABLED 1
+#define CFREE_TOOL_OBJDUMP_ENABLED 1
+#define CFREE_TOOL_DBG_ENABLED 1
+#define CFREE_TOOL_RUN_ENABLED 1
+#define CFREE_TOOL_EMU_ENABLED 1
+#define CFREE_TOOL_NM_ENABLED 1
+#define CFREE_TOOL_SIZE_ENABLED 1
+#define CFREE_TOOL_ADDR2LINE_ENABLED 1
+
#endif /* CFREE_CONFIG_H */
diff --git a/mk/config.mk b/mk/config.mk
@@ -16,9 +16,35 @@ CFREE_OBJ_MACHO_ENABLED := $(call cfg_flag,CFREE_OBJ_MACHO_ENABLED)
CFREE_OBJ_COFF_ENABLED := $(call cfg_flag,CFREE_OBJ_COFF_ENABLED)
CFREE_OBJ_WASM_ENABLED := $(call cfg_flag,CFREE_OBJ_WASM_ENABLED)
+CFREE_LANG_ASM_ENABLED := $(call cfg_flag,CFREE_LANG_ASM_ENABLED)
CFREE_LANG_CPP_ENABLED := $(call cfg_flag,CFREE_LANG_CPP_ENABLED)
CFREE_LANG_C_ENABLED := $(call cfg_flag,CFREE_LANG_C_ENABLED)
CFREE_LANG_TOY_ENABLED := $(call cfg_flag,CFREE_LANG_TOY_ENABLED)
CFREE_LANG_WASM_ENABLED := $(call cfg_flag,CFREE_LANG_WASM_ENABLED)
CFREE_OPT_ENABLED := $(call cfg_flag,CFREE_OPT_ENABLED)
+
+CFREE_AR_ENABLED := $(call cfg_flag,CFREE_AR_ENABLED)
+CFREE_DISASM_ENABLED := $(call cfg_flag,CFREE_DISASM_ENABLED)
+CFREE_DWARF_ENABLED := $(call cfg_flag,CFREE_DWARF_ENABLED)
+CFREE_LINK_ENABLED := $(call cfg_flag,CFREE_LINK_ENABLED)
+CFREE_JIT_ENABLED := $(call cfg_flag,CFREE_JIT_ENABLED)
+CFREE_DBG_ENABLED := $(call cfg_flag,CFREE_DBG_ENABLED)
+CFREE_EMU_ENABLED := $(call cfg_flag,CFREE_EMU_ENABLED)
+
+CFREE_TOOL_CC_ENABLED := $(call cfg_flag,CFREE_TOOL_CC_ENABLED)
+CFREE_TOOL_CHECK_ENABLED := $(call cfg_flag,CFREE_TOOL_CHECK_ENABLED)
+CFREE_TOOL_CPP_ENABLED := $(call cfg_flag,CFREE_TOOL_CPP_ENABLED)
+CFREE_TOOL_AS_ENABLED := $(call cfg_flag,CFREE_TOOL_AS_ENABLED)
+CFREE_TOOL_LD_ENABLED := $(call cfg_flag,CFREE_TOOL_LD_ENABLED)
+CFREE_TOOL_AR_ENABLED := $(call cfg_flag,CFREE_TOOL_AR_ENABLED)
+CFREE_TOOL_RANLIB_ENABLED := $(call cfg_flag,CFREE_TOOL_RANLIB_ENABLED)
+CFREE_TOOL_STRIP_ENABLED := $(call cfg_flag,CFREE_TOOL_STRIP_ENABLED)
+CFREE_TOOL_OBJCOPY_ENABLED := $(call cfg_flag,CFREE_TOOL_OBJCOPY_ENABLED)
+CFREE_TOOL_OBJDUMP_ENABLED := $(call cfg_flag,CFREE_TOOL_OBJDUMP_ENABLED)
+CFREE_TOOL_DBG_ENABLED := $(call cfg_flag,CFREE_TOOL_DBG_ENABLED)
+CFREE_TOOL_RUN_ENABLED := $(call cfg_flag,CFREE_TOOL_RUN_ENABLED)
+CFREE_TOOL_EMU_ENABLED := $(call cfg_flag,CFREE_TOOL_EMU_ENABLED)
+CFREE_TOOL_NM_ENABLED := $(call cfg_flag,CFREE_TOOL_NM_ENABLED)
+CFREE_TOOL_SIZE_ENABLED := $(call cfg_flag,CFREE_TOOL_SIZE_ENABLED)
+CFREE_TOOL_ADDR2LINE_ENABLED := $(call cfg_flag,CFREE_TOOL_ADDR2LINE_ENABLED)
diff --git a/src/api/config_stubs.c b/src/api/config_stubs.c
@@ -0,0 +1,800 @@
+#include <cfree/archive.h>
+#include <cfree/config.h>
+#include <cfree/dbg.h>
+#include <cfree/disasm.h>
+#include <cfree/dwarf.h>
+#include <cfree/emu.h>
+#include <cfree/jit.h>
+#include <cfree/link.h>
+
+#include "core/core.h"
+#include "debug/debug.h"
+#include "link/link.h"
+
+#if !CFREE_AR_ENABLED
+CfreeStatus cfree_ar_write(CfreeWriter* out, const CfreeArInput* members,
+ uint32_t nmembers, const CfreeArWriteOptions* opts) {
+ (void)out;
+ (void)members;
+ (void)nmembers;
+ (void)opts;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_ar_list(const CfreeSlice* archive, CfreeWriter* out) {
+ (void)archive;
+ (void)out;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_ar_iter_new(const CfreeContext* ctx,
+ const CfreeSlice* archive, CfreeArIter** out) {
+ (void)ctx;
+ (void)archive;
+ if (out) *out = NULL;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeIterResult cfree_ar_iter_next(CfreeArIter* it, CfreeArMember* out) {
+ (void)it;
+ (void)out;
+ return CFREE_ITER_ERROR;
+}
+
+void cfree_ar_iter_free(CfreeArIter* it) { (void)it; }
+#endif
+
+#if !CFREE_DISASM_ENABLED
+CfreeStatus cfree_disasm_iter_new(const CfreeDisasmContext* dctx,
+ const uint8_t* bytes, size_t len,
+ uint64_t vaddr,
+ const CfreeObjFile* annotations,
+ CfreeDisasmIter** out) {
+ (void)dctx;
+ (void)bytes;
+ (void)len;
+ (void)vaddr;
+ (void)annotations;
+ if (out) *out = NULL;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeIterResult cfree_disasm_iter_next(CfreeDisasmIter* it, CfreeInsn* out) {
+ (void)it;
+ (void)out;
+ return CFREE_ITER_ERROR;
+}
+
+void cfree_disasm_iter_free(CfreeDisasmIter* it) { (void)it; }
+
+CfreeStatus cfree_disasm_obj(const CfreeContext* ctx, const CfreeObjFile* obj,
+ CfreeWriter* out) {
+ (void)ctx;
+ (void)obj;
+ (void)out;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_disasm_obj_bytes(const CfreeContext* ctx,
+ const CfreeSlice* bytes, CfreeWriter* out) {
+ (void)ctx;
+ (void)bytes;
+ (void)out;
+ return CFREE_UNSUPPORTED;
+}
+#endif
+
+#if !CFREE_DWARF_ENABLED
+Debug* debug_new(Compiler* c, ObjBuilder* ob) {
+ (void)c;
+ (void)ob;
+ return NULL;
+}
+
+void debug_free(Debug* d) { (void)d; }
+u32 debug_file(Debug* d, u32 source_file_id) {
+ (void)d;
+ (void)source_file_id;
+ return 0;
+}
+
+DebugTypeId debug_type_base(Debug* d, Sym name, DebugBaseEncoding enc,
+ u32 byte_size) {
+ (void)d;
+ (void)name;
+ (void)enc;
+ (void)byte_size;
+ return DEBUG_TYPE_NONE;
+}
+
+DebugTypeId debug_type_void(Debug* d) {
+ (void)d;
+ return DEBUG_TYPE_NONE;
+}
+
+DebugTypeId debug_type_ptr(Debug* d, DebugTypeId pointee) {
+ (void)d;
+ (void)pointee;
+ return DEBUG_TYPE_NONE;
+}
+
+DebugTypeId debug_type_array(Debug* d, DebugTypeId elem, u32 count) {
+ (void)d;
+ (void)elem;
+ (void)count;
+ return DEBUG_TYPE_NONE;
+}
+
+DebugTypeId debug_type_const(Debug* d, DebugTypeId base) {
+ (void)d;
+ (void)base;
+ return DEBUG_TYPE_NONE;
+}
+
+DebugTypeId debug_type_volatile(Debug* d, DebugTypeId base) {
+ (void)d;
+ (void)base;
+ return DEBUG_TYPE_NONE;
+}
+
+DebugTypeId debug_type_restrict(Debug* d, DebugTypeId base) {
+ (void)d;
+ (void)base;
+ return DEBUG_TYPE_NONE;
+}
+
+DebugTypeId debug_type_typedef(Debug* d, Sym name, DebugTypeId base) {
+ (void)d;
+ (void)name;
+ (void)base;
+ return DEBUG_TYPE_NONE;
+}
+
+DebugTypeId debug_type_func(Debug* d, DebugTypeId ret,
+ const DebugTypeId* params, u32 nparams,
+ int variadic) {
+ (void)d;
+ (void)ret;
+ (void)params;
+ (void)nparams;
+ (void)variadic;
+ return DEBUG_TYPE_NONE;
+}
+
+DebugTypeBuilder* debug_type_record_begin(Debug* d, Sym tag, int is_union,
+ u32 byte_size, u32 align) {
+ (void)d;
+ (void)tag;
+ (void)is_union;
+ (void)byte_size;
+ (void)align;
+ return NULL;
+}
+
+void debug_type_record_field(DebugTypeBuilder* b, Sym name, DebugTypeId type,
+ u32 byte_offset) {
+ (void)b;
+ (void)name;
+ (void)type;
+ (void)byte_offset;
+}
+
+void debug_type_record_bitfield(DebugTypeBuilder* b, Sym name, DebugTypeId type,
+ u32 byte_offset, u16 bit_offset,
+ u16 bit_width) {
+ (void)b;
+ (void)name;
+ (void)type;
+ (void)byte_offset;
+ (void)bit_offset;
+ (void)bit_width;
+}
+
+DebugTypeId debug_type_record_end(DebugTypeBuilder* b) {
+ (void)b;
+ return DEBUG_TYPE_NONE;
+}
+
+DebugEnumBuilder* debug_type_enum_begin(Debug* d, Sym tag, DebugTypeId base) {
+ (void)d;
+ (void)tag;
+ (void)base;
+ return NULL;
+}
+
+void debug_type_enum_value(DebugEnumBuilder* b, Sym name, i64 value) {
+ (void)b;
+ (void)name;
+ (void)value;
+}
+
+DebugTypeId debug_type_enum_end(DebugEnumBuilder* b) {
+ (void)b;
+ return DEBUG_TYPE_NONE;
+}
+
+void debug_func_begin(Debug* d, ObjSymId sym, DebugTypeId fn_type,
+ SrcLoc decl) {
+ (void)d;
+ (void)sym;
+ (void)fn_type;
+ (void)decl;
+}
+
+void debug_func_pc_range(Debug* d, ObjSecId text_section_id, u32 begin_ofs,
+ u32 end_ofs) {
+ (void)d;
+ (void)text_section_id;
+ (void)begin_ofs;
+ (void)end_ofs;
+}
+
+void debug_func_end(Debug* d) { (void)d; }
+void debug_scope_begin(Debug* d, SrcLoc loc) {
+ (void)d;
+ (void)loc;
+}
+void debug_scope_end(Debug* d, SrcLoc loc) {
+ (void)d;
+ (void)loc;
+}
+
+void debug_param(Debug* d, Sym name, DebugTypeId type, SrcLoc loc, u32 idx,
+ DebugVarLoc var_loc) {
+ (void)d;
+ (void)name;
+ (void)type;
+ (void)loc;
+ (void)idx;
+ (void)var_loc;
+}
+
+void debug_local(Debug* d, Sym name, DebugTypeId type, SrcLoc loc,
+ DebugVarLoc var_loc) {
+ (void)d;
+ (void)name;
+ (void)type;
+ (void)loc;
+ (void)var_loc;
+}
+
+void debug_line(Debug* d, ObjSecId text_section_id, u32 text_offset, SrcLoc loc,
+ int is_stmt) {
+ (void)d;
+ (void)text_section_id;
+ (void)text_offset;
+ (void)loc;
+ (void)is_stmt;
+}
+
+void debug_set_pending_loc(Debug* d, SrcLoc loc) {
+ (void)d;
+ (void)loc;
+}
+
+void debug_emit_row(Debug* d, ObjSecId text_section_id, u32 text_offset,
+ SrcLoc loc) {
+ (void)d;
+ (void)text_section_id;
+ (void)text_offset;
+ (void)loc;
+}
+
+u32 debug_loclist_new(Debug* d) {
+ (void)d;
+ return 0;
+}
+
+void debug_loclist_add(Debug* d, u32 id, u32 begin_pc, u32 end_pc,
+ DebugVarLoc loc) {
+ (void)d;
+ (void)id;
+ (void)begin_pc;
+ (void)end_pc;
+ (void)loc;
+}
+
+void debug_emit(Debug* d) { (void)d; }
+
+CfreeStatus cfree_dwarf_open(const CfreeContext* ctx, const CfreeObjFile* obj,
+ CfreeDebugInfo** out) {
+ (void)ctx;
+ (void)obj;
+ if (out) *out = NULL;
+ return CFREE_UNSUPPORTED;
+}
+
+void cfree_dwarf_free(CfreeDebugInfo* d) { (void)d; }
+
+CfreeStatus cfree_dwarf_addr_to_line(CfreeDebugInfo* d, uint64_t pc,
+ CfreeSlice* file_out, uint32_t* line_out,
+ uint32_t* col_out) {
+ (void)d;
+ (void)pc;
+ (void)file_out;
+ (void)line_out;
+ (void)col_out;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_dwarf_line_to_addr(CfreeDebugInfo* d, CfreeSlice file,
+ uint32_t line, uint64_t* pc_out) {
+ (void)d;
+ (void)file;
+ (void)line;
+ (void)pc_out;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_dwarf_line_to_addr_all(CfreeDebugInfo* d, CfreeSlice file,
+ uint32_t line,
+ CfreeDwarfLineMatch* out, uint32_t cap,
+ uint32_t* n_out) {
+ (void)d;
+ (void)file;
+ (void)line;
+ (void)out;
+ (void)cap;
+ if (n_out) *n_out = 0;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_dwarf_func_at(CfreeDebugInfo* d, uint64_t pc,
+ CfreeSlice* name_out, uint64_t* low_pc_out,
+ uint64_t* high_pc_out) {
+ (void)d;
+ (void)pc;
+ (void)name_out;
+ (void)low_pc_out;
+ (void)high_pc_out;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_dwarf_subprogram_at(CfreeDebugInfo* d, uint64_t pc,
+ CfreeDwarfSubprogram* out) {
+ (void)d;
+ (void)pc;
+ (void)out;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_dwarf_subprogram_named(CfreeDebugInfo* d, CfreeSlice name,
+ CfreeDwarfSubprogram* out) {
+ (void)d;
+ (void)name;
+ (void)out;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_dwarf_unwind_step(CfreeDebugInfo* d,
+ CfreeUnwindFrame* frame) {
+ (void)d;
+ (void)frame;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeDwarfTypeInfo cfree_dwarf_type_info(const CfreeDwarfType* t) {
+ CfreeDwarfTypeInfo info;
+ (void)t;
+ info.kind = CFREE_DT_VOID;
+ info.byte_size = 0;
+ info.name = CFREE_SLICE_NULL;
+ info.element_count = 0;
+ info.inner = NULL;
+ return info;
+}
+
+CfreeStatus cfree_dwarf_field_iter_new(CfreeDebugInfo* d,
+ const CfreeDwarfType* t,
+ CfreeDwarfFieldIter** out) {
+ (void)d;
+ (void)t;
+ if (out) *out = NULL;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeIterResult cfree_dwarf_field_iter_next(CfreeDwarfFieldIter* it,
+ CfreeDwarfField* out) {
+ (void)it;
+ (void)out;
+ return CFREE_ITER_ERROR;
+}
+
+void cfree_dwarf_field_iter_free(CfreeDwarfFieldIter* it) { (void)it; }
+
+CfreeStatus cfree_dwarf_enum_iter_new(CfreeDebugInfo* d,
+ const CfreeDwarfType* t,
+ CfreeDwarfEnumIter** out) {
+ (void)d;
+ (void)t;
+ if (out) *out = NULL;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeIterResult cfree_dwarf_enum_iter_next(CfreeDwarfEnumIter* it,
+ CfreeDwarfEnumVal* out) {
+ (void)it;
+ (void)out;
+ return CFREE_ITER_ERROR;
+}
+
+void cfree_dwarf_enum_iter_free(CfreeDwarfEnumIter* it) { (void)it; }
+
+CfreeStatus cfree_dwarf_var_at(CfreeDebugInfo* d, uint64_t pc, CfreeSlice name,
+ CfreeDwarfVarLoc* out) {
+ (void)d;
+ (void)pc;
+ (void)name;
+ (void)out;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_dwarf_loc_read(CfreeDebugInfo* d, const CfreeDwarfVarLoc* loc,
+ const CfreeUnwindFrame* frame,
+ CfreeDwarfReadMemFn read_mem, void* read_user,
+ void* dst, size_t cap, size_t* read_out) {
+ (void)d;
+ (void)loc;
+ (void)frame;
+ (void)read_mem;
+ (void)read_user;
+ (void)dst;
+ (void)cap;
+ if (read_out) *read_out = 0;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_dwarf_vars_at_new(CfreeDebugInfo* d, uint64_t pc,
+ uint32_t role_mask,
+ CfreeDwarfVarIter** out) {
+ (void)d;
+ (void)pc;
+ (void)role_mask;
+ if (out) *out = NULL;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeIterResult cfree_dwarf_vars_at_next(CfreeDwarfVarIter* it,
+ CfreeDwarfVar* out) {
+ (void)it;
+ (void)out;
+ return CFREE_ITER_ERROR;
+}
+
+void cfree_dwarf_vars_at_free(CfreeDwarfVarIter* it) { (void)it; }
+
+CfreeStatus cfree_dwarf_param_iter_new(CfreeDebugInfo* d, uint64_t pc,
+ CfreeDwarfParamIter** out) {
+ (void)d;
+ (void)pc;
+ if (out) *out = NULL;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_dwarf_param_iter_new_named(CfreeDebugInfo* d, CfreeSlice name,
+ CfreeDwarfParamIter** out) {
+ (void)d;
+ (void)name;
+ if (out) *out = NULL;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeIterResult cfree_dwarf_param_iter_next(CfreeDwarfParamIter* it,
+ CfreeDwarfVar* out) {
+ (void)it;
+ (void)out;
+ return CFREE_ITER_ERROR;
+}
+
+void cfree_dwarf_param_iter_free(CfreeDwarfParamIter* it) { (void)it; }
+#endif
+
+#if !CFREE_LINK_ENABLED
+CfreeStatus cfree_link_script_parse(const CfreeContext* ctx, CfreeSlice text,
+ CfreeLinkScript** out) {
+ (void)ctx;
+ (void)text;
+ if (out) *out = NULL;
+ return CFREE_UNSUPPORTED;
+}
+
+void cfree_link_script_free(const CfreeContext* ctx, CfreeLinkScript* s) {
+ (void)ctx;
+ (void)s;
+}
+
+CfreeStatus cfree_link_session_new(CfreeCompiler* c,
+ const CfreeLinkSessionOptions* opts,
+ CfreeLinkSession** out) {
+ (void)c;
+ (void)opts;
+ if (out) *out = NULL;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_link_session_add_obj(CfreeLinkSession* s,
+ CfreeObjBuilder* ob) {
+ (void)s;
+ (void)ob;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_link_session_add_obj_bytes(CfreeLinkSession* s,
+ CfreeSlice name,
+ const CfreeSlice* bytes) {
+ (void)s;
+ (void)name;
+ (void)bytes;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_link_session_add_archive_bytes(
+ CfreeLinkSession* s, const CfreeLinkArchiveInput* archive) {
+ (void)s;
+ (void)archive;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_link_session_add_dso_bytes(CfreeLinkSession* s,
+ CfreeSlice name,
+ const CfreeSlice* bytes) {
+ (void)s;
+ (void)name;
+ (void)bytes;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_link_session_resolve(CfreeLinkSession* s) {
+ (void)s;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_link_session_emit(CfreeLinkSession* s, CfreeWriter* out) {
+ (void)s;
+ (void)out;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_link_session_jit(CfreeLinkSession* s, CfreeJit** out_jit) {
+ (void)s;
+ if (out_jit) *out_jit = NULL;
+ return CFREE_UNSUPPORTED;
+}
+
+void cfree_link_session_free(CfreeLinkSession* s) { (void)s; }
+#endif
+
+#if !CFREE_JIT_ENABLED
+CfreeJit* cfree_jit_from_image(LinkImage* img) {
+ (void)img;
+ return NULL;
+}
+
+const CfreeExecMem* cfree_jit_image_execmem(CfreeJit* jit) {
+ (void)jit;
+ return NULL;
+}
+
+int cfree_jit_image_contains(CfreeJit* jit, uint64_t runtime_addr) {
+ (void)jit;
+ (void)runtime_addr;
+ return 0;
+}
+
+CfreeArchKind cfree_jit_image_arch(CfreeJit* jit) {
+ (void)jit;
+ return CFREE_ARCH_X86_64;
+}
+
+Compiler* cfree_jit_compiler(CfreeJit* jit) {
+ (void)jit;
+ return NULL;
+}
+
+void cfree_jit_free(CfreeJit* jit) { (void)jit; }
+
+void* cfree_jit_lookup(CfreeJit* jit, CfreeSlice name) {
+ (void)jit;
+ (void)name;
+ return NULL;
+}
+
+uint64_t cfree_jit_generation(CfreeJit* jit) {
+ (void)jit;
+ return 0;
+}
+
+void cfree_jit_run_dtors(CfreeJit* jit) { (void)jit; }
+
+CfreeStatus cfree_jit_publish(CfreeJit* jit, const CfreeJitPublishOptions* opts,
+ CfreeJitPublishResult* result) {
+ (void)jit;
+ (void)opts;
+ (void)result;
+ return CFREE_UNSUPPORTED;
+}
+
+const CfreeObjFile* cfree_jit_view(CfreeJit* jit) {
+ (void)jit;
+ return NULL;
+}
+
+CfreeStatus cfree_jit_addr_to_sym(CfreeJit* jit, uint64_t addr,
+ CfreeSlice* name_out, uint64_t* off_out) {
+ (void)jit;
+ (void)addr;
+ (void)name_out;
+ (void)off_out;
+ return CFREE_UNSUPPORTED;
+}
+
+uint64_t cfree_jit_runtime_to_image(CfreeJit* jit, uint64_t runtime_pc) {
+ (void)jit;
+ (void)runtime_pc;
+ return 0;
+}
+
+uint64_t cfree_jit_image_to_runtime(CfreeJit* jit, uint64_t image_vaddr) {
+ (void)jit;
+ (void)image_vaddr;
+ return 0;
+}
+
+CfreeStatus cfree_jit_sym_iter_new(CfreeJit* jit, CfreeJitSymIter** out) {
+ (void)jit;
+ if (out) *out = NULL;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeIterResult cfree_jit_sym_iter_next(CfreeJitSymIter* it, CfreeJitSym* out) {
+ (void)it;
+ (void)out;
+ return CFREE_ITER_ERROR;
+}
+
+void cfree_jit_sym_iter_free(CfreeJitSymIter* it) { (void)it; }
+#endif
+
+#if !CFREE_DBG_ENABLED
+CfreeStatus cfree_jit_session_new(CfreeJit* jit, const CfreeDbgHost* host,
+ CfreeJitSession** out) {
+ (void)jit;
+ (void)host;
+ if (out) *out = NULL;
+ return CFREE_UNSUPPORTED;
+}
+
+void cfree_jit_session_free(CfreeJitSession* s) { (void)s; }
+
+CfreeStatus cfree_jit_session_attach_dwarf(CfreeJitSession* s,
+ CfreeDebugInfo* dwarf) {
+ (void)s;
+ (void)dwarf;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_jit_session_call(CfreeJitSession* s, void* entry,
+ CfreeEntryKind kind, int argc, char** argv,
+ CfreeStopInfo* stop_out) {
+ (void)s;
+ (void)entry;
+ (void)kind;
+ (void)argc;
+ (void)argv;
+ (void)stop_out;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_jit_session_call_u64(CfreeJitSession* s, void* entry,
+ const uint64_t* args, uint32_t nargs,
+ uint64_t* ret_out,
+ CfreeStopInfo* stop_out) {
+ (void)s;
+ (void)entry;
+ (void)args;
+ (void)nargs;
+ (void)ret_out;
+ (void)stop_out;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_jit_session_resume(CfreeJitSession* s, CfreeResumeMode mode,
+ CfreeStopInfo* stop_out) {
+ (void)s;
+ (void)mode;
+ (void)stop_out;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_jit_session_interrupt(CfreeJitSession* s) {
+ (void)s;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_jit_session_read_mem(CfreeJitSession* s, uint64_t addr,
+ void* dst, size_t n) {
+ (void)s;
+ (void)addr;
+ (void)dst;
+ (void)n;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_jit_session_write_mem(CfreeJitSession* s, uint64_t addr,
+ const void* src, size_t n) {
+ (void)s;
+ (void)addr;
+ (void)src;
+ (void)n;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_jit_session_get_regs(CfreeJitSession* s,
+ CfreeUnwindFrame* out) {
+ (void)s;
+ (void)out;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_jit_session_set_regs(CfreeJitSession* s,
+ const CfreeUnwindFrame* in) {
+ (void)s;
+ (void)in;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_jit_session_breakpoint_set(CfreeJitSession* s, uint64_t addr,
+ uint32_t* bp_id_out) {
+ (void)s;
+ (void)addr;
+ (void)bp_id_out;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_jit_session_breakpoint_clear(CfreeJitSession* s,
+ uint32_t bp_id) {
+ (void)s;
+ (void)bp_id;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_jit_session_breakpoint_set_spec(
+ CfreeJitSession* s, const CfreeBreakpointSpec* spec, uint32_t* bp_id_out) {
+ (void)s;
+ (void)spec;
+ (void)bp_id_out;
+ return CFREE_UNSUPPORTED;
+}
+#endif
+
+#if !CFREE_EMU_ENABLED
+CfreeStatus cfree_emu_run(CfreeCompiler* c, const CfreeEmuOptions* opts,
+ int* out_exit_code) {
+ (void)c;
+ (void)opts;
+ (void)out_exit_code;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_emu_new(CfreeCompiler* c, const CfreeEmuOptions* opts,
+ CfreeEmu** out) {
+ (void)c;
+ (void)opts;
+ if (out) *out = NULL;
+ return CFREE_UNSUPPORTED;
+}
+
+CfreeStatus cfree_emu_step(CfreeEmu* e, uint32_t nblocks) {
+ (void)e;
+ (void)nblocks;
+ return CFREE_UNSUPPORTED;
+}
+
+void* cfree_emu_lookup(CfreeEmu* e, uint64_t guest_pc) {
+ (void)e;
+ (void)guest_pc;
+ return NULL;
+}
+
+void cfree_emu_free(CfreeEmu* e) { (void)e; }
+#endif
diff --git a/src/api/lang_registry.c b/src/api/lang_registry.c
@@ -6,10 +6,8 @@
* compile/pipeline paths can dispatch by CfreeLanguage without any
* host-side bootstrap.
*
- * The asm frontend is unconditional and registered here too; there is
- * no fallback in frontend_for_language(), so an embedder that doesn't
- * want asm can drop the slot after compiler construction with
- * cfree_register_frontend(c, CFREE_LANG_ASM, NULL).
+ * The asm frontend lives inside the codegen substrate, but automatic
+ * registration is gated by CFREE_LANG_ASM_ENABLED.
*
* Third parties may still call cfree_register_frontend() to install or
* override any slot after construction; that public API is unchanged.
@@ -21,14 +19,13 @@
#include "cfree/config.h"
-_Static_assert(!CFREE_LANG_C_ENABLED || CFREE_LANG_CPP_ENABLED,
- "CFREE_LANG_C_ENABLED requires CFREE_LANG_CPP_ENABLED");
-
/* Defined in src/api/compile.c, alongside the asm frontend's
* new/compile/free functions. Treated as part of the codegen substrate
* (no per-frontend lang/ directory), so its declaration lives here
* rather than in a public header. */
+#if CFREE_LANG_ASM_ENABLED
extern const CfreeFrontendVTable cfree_asm_frontend_vtable;
+#endif
#if CFREE_LANG_C_ENABLED
#include "c/c.h"
@@ -41,7 +38,9 @@ extern const CfreeFrontendVTable cfree_asm_frontend_vtable;
#endif
void lang_registry_init(CfreeCompiler* c) {
+#if CFREE_LANG_ASM_ENABLED
(void)cfree_register_frontend(c, CFREE_LANG_ASM, &cfree_asm_frontend_vtable);
+#endif
#if CFREE_LANG_C_ENABLED
(void)cfree_register_frontend(c, CFREE_LANG_C, &cfree_c_frontend_vtable);
#endif
diff --git a/src/api/object_detect.c b/src/api/object_detect.c
@@ -1,5 +1,6 @@
/* Binary format and target detection from object header bytes. */
+#include <cfree/config.h>
#include <cfree/object.h>
#include "core/core.h"
@@ -244,12 +245,19 @@ CfreeStatus cfree_detect_target(const uint8_t* data, size_t len,
if (!data || !out) return CFREE_INVALID;
bin = cfree_detect_fmt(data, len);
switch (bin) {
+#if CFREE_OBJ_ELF_ENABLED
case CFREE_BIN_ELF:
return detect_elf(data, len, out);
+#endif
+#if CFREE_OBJ_COFF_ENABLED
case CFREE_BIN_COFF:
return detect_coff(data, len, out);
+#endif
+#if CFREE_OBJ_MACHO_ENABLED
case CFREE_BIN_MACHO:
return detect_macho(data, len, out);
+#endif
+#if CFREE_OBJ_WASM_ENABLED
case CFREE_BIN_WASM: {
CfreeTarget t;
t.big_endian = 0;
@@ -263,6 +271,7 @@ CfreeStatus cfree_detect_target(const uint8_t* data, size_t len,
*out = t;
return CFREE_OK;
}
+#endif
default:
return CFREE_UNSUPPORTED;
}
diff --git a/src/api/object_file.c b/src/api/object_file.c
@@ -24,17 +24,11 @@ struct CfreeObjFile {
u32 sec_data_n;
};
-static ObjBuilder* obj_read_bytes(Compiler* c, const char* name, const u8* data,
- size_t len, ObjFmt fmt) {
- const ObjFormatImpl* impl = obj_format_lookup(fmt);
- if (!impl || !impl->read) return NULL;
- return impl->read(c, name, data, len);
-}
-
CfreeStatus cfree_obj_open(const CfreeContext* ctx, CfreeSlice name,
const CfreeSlice* input, CfreeObjFile** out) {
Heap* h;
CfreeObjFile* f;
+ const ObjFormatImpl* impl;
CfreeTarget target;
CfreeStatus st;
@@ -45,6 +39,8 @@ CfreeStatus cfree_obj_open(const CfreeContext* ctx, CfreeSlice name,
st = cfree_detect_target(input->data, input->len, &target);
if (st != CFREE_OK) return st;
+ impl = obj_format_lookup(target.obj);
+ if (!impl || !impl->read) return CFREE_UNSUPPORTED;
h = ctx->heap;
f = (CfreeObjFile*)h->alloc(h, sizeof(*f), _Alignof(CfreeObjFile));
@@ -61,8 +57,7 @@ CfreeStatus cfree_obj_open(const CfreeContext* ctx, CfreeSlice name,
h->free(h, f, sizeof(*f));
return CFREE_MALFORMED;
}
- f->ob = obj_read_bytes(&f->compiler, name.s, input->data, input->len,
- target.obj);
+ f->ob = impl->read(&f->compiler, name.s, input->data, input->len);
if (!f->ob) {
compiler_fini(&f->compiler);
h->free(h, f, sizeof(*f));
diff --git a/src/api/stubs.c b/src/api/stubs.c
@@ -1,18 +0,0 @@
-/* Stub implementations for libcfree subsystems not yet implemented. */
-
-#include "core/core.h"
-#include "core/slice.h"
-#include "obj/obj.h"
-
-static _Noreturn void unimplemented(Compiler* c, const char* what) {
- SrcLoc loc = {0, 0, 0};
- compiler_panic(c, loc, "subsystem not implemented: %.*s",
- SLICE_ARG(slice_from_cstr(what)));
-}
-
-ObjBuilder* read_wasm(Compiler* c, const char* n, const u8* d, size_t l) {
- (void)n;
- (void)d;
- (void)l;
- unimplemented(c, "read_wasm");
-}
diff --git a/src/arch/aa64/arch.c b/src/arch/aa64/arch.c
@@ -11,6 +11,7 @@
extern const LinkArchDesc link_arch_aa64;
extern const ArchDbgOps aa64_dbg_ops;
+extern const ArchDwarfOps aa64_dwarf_ops;
static int aa64_register_at_public(uint32_t idx, CfreeArchReg* out) {
const char* nm = NULL;
@@ -29,11 +30,6 @@ static void aa64_wr_u64_target(Compiler* c, u8* p, u64 v) {
}
}
-static const ArchDwarfOps aa64_dwarf_ops = {
- .min_inst_len = 4u,
- .max_ops_per_inst = 1u,
-};
-
static int aa64_apply_label_fixup(Compiler* c, const ArchLabelFixup* fx) {
const Section* s;
u8 cur[4];
diff --git a/src/arch/cgtarget.c b/src/arch/cgtarget.c
@@ -3,6 +3,7 @@
* The lifecycle helpers (cgtarget_finalize, cgtarget_free) are arch-agnostic
* shims over the vtable. */
+#include <cfree/config.h>
#include <string.h>
#include "arch/arch.h"
@@ -31,14 +32,15 @@ void cgtarget_free(CGTarget* t) {
}
CfreeStatus cg_mc_debug_new(Compiler* c, ObjBuilder* o,
- const CfreeCodeOptions* opts,
- MCEmitter** out_mc, Debug** out_debug) {
+ const CfreeCodeOptions* opts, MCEmitter** out_mc,
+ Debug** out_debug) {
MCEmitter* mc;
Debug* debug = NULL;
*out_mc = NULL;
*out_debug = NULL;
mc = mc_new(c, o);
if (!mc) return CFREE_NOMEM;
+#if CFREE_DWARF_ENABLED
if (opts && opts->debug_info) {
debug = debug_new(c, o);
if (!debug) {
@@ -47,6 +49,13 @@ CfreeStatus cg_mc_debug_new(Compiler* c, ObjBuilder* o,
}
mc->debug = debug;
}
+#else
+ (void)o;
+ if (opts && opts->debug_info) {
+ mc_free(mc);
+ return CFREE_UNSUPPORTED;
+ }
+#endif
*out_mc = mc;
*out_debug = debug;
return CFREE_OK;
diff --git a/src/arch/dbg_stubs.c b/src/arch/dbg_stubs.c
@@ -0,0 +1,5 @@
+#include "arch/arch.h"
+
+const ArchDbgOps aa64_dbg_ops = {0};
+const ArchDbgOps x64_dbg_ops = {0};
+const ArchDbgOps rv64_dbg_ops = {0};
diff --git a/src/arch/disasm_stubs.c b/src/arch/disasm_stubs.c
@@ -0,0 +1,18 @@
+#include "arch/arch.h"
+
+ArchDisasm* aa64_disasm_new(Compiler* c) {
+ (void)c;
+ return NULL;
+}
+
+ArchDisasm* x64_disasm_new(Compiler* c) {
+ (void)c;
+ return NULL;
+}
+
+ArchDisasm* rv64_disasm_new(Compiler* c) {
+ (void)c;
+ return NULL;
+}
+
+const ArchDecodeOps rv64_decode_ops = {0};
diff --git a/src/arch/dwarf.c b/src/arch/dwarf.c
@@ -0,0 +1,16 @@
+#include "arch/arch.h"
+
+const ArchDwarfOps aa64_dwarf_ops = {
+ .min_inst_len = 4u,
+ .max_ops_per_inst = 1u,
+};
+
+const ArchDwarfOps x64_dwarf_ops = {
+ .min_inst_len = 1u,
+ .max_ops_per_inst = 1u,
+};
+
+const ArchDwarfOps rv64_dwarf_ops = {
+ .min_inst_len = 4u,
+ .max_ops_per_inst = 1u,
+};
diff --git a/src/arch/emu_stubs.c b/src/arch/emu_stubs.c
@@ -0,0 +1,3 @@
+#include "arch/arch.h"
+
+const ArchEmuOps rv64_emu_ops = {0};
diff --git a/src/arch/link_stubs.c b/src/arch/link_stubs.c
@@ -0,0 +1,5 @@
+#include "link/link_arch.h"
+
+const LinkArchDesc link_arch_aa64 = {0};
+const LinkArchDesc link_arch_x64 = {0};
+const LinkArchDesc link_arch_rv64 = {0};
diff --git a/src/arch/rv64/arch.c b/src/arch/rv64/arch.c
@@ -11,11 +11,7 @@
extern const LinkArchDesc link_arch_rv64;
extern const ArchDbgOps rv64_dbg_ops;
extern const ArchEmuOps rv64_emu_ops;
-
-static const ArchDwarfOps rv64_dwarf_ops = {
- .min_inst_len = 4u,
- .max_ops_per_inst = 1u,
-};
+extern const ArchDwarfOps rv64_dwarf_ops;
static int rv64_register_at_public(uint32_t idx, CfreeArchReg* out) {
const char* nm = NULL;
diff --git a/src/arch/wasm/internal.h b/src/arch/wasm/internal.h
@@ -26,9 +26,8 @@
#include "core/core.h"
#include "obj/obj.h"
-/* Forward references into lang/wasm. We use the existing in-memory module
- * representation rather than rebuilding one, so emit_wasm can reuse
- * wasm_encode unchanged. */
+/* Forward references into the shared src/wasm module representation. The
+ * target reuses that model so emit_wasm can flush through wasm_encode. */
struct WasmModule;
struct WasmFunc;
diff --git a/src/arch/x64/arch.c b/src/arch/x64/arch.c
@@ -10,11 +10,7 @@
extern const LinkArchDesc link_arch_x64;
extern const ArchDbgOps x64_dbg_ops;
-
-static const ArchDwarfOps x64_dwarf_ops = {
- .min_inst_len = 1u,
- .max_ops_per_inst = 1u,
-};
+extern const ArchDwarfOps x64_dwarf_ops;
static int x64_apply_label_fixup(Compiler* c, const ArchLabelFixup* fx) {
(void)c;
diff --git a/src/core/config_assert.c b/src/core/config_assert.c
@@ -4,15 +4,108 @@
#include "cfree/config.h"
_Static_assert(CFREE_ARCH_AA64_ENABLED + CFREE_ARCH_X64_ENABLED +
- CFREE_ARCH_RV64_ENABLED +
+ CFREE_ARCH_RV64_ENABLED + CFREE_ARCH_WASM_ENABLED +
CFREE_ARCH_C_TARGET_ENABLED >=
1,
"at least one backend architecture must be enabled");
_Static_assert(CFREE_OBJ_ELF_ENABLED + CFREE_OBJ_MACHO_ENABLED +
- CFREE_OBJ_COFF_ENABLED >=
+ CFREE_OBJ_COFF_ENABLED + CFREE_OBJ_WASM_ENABLED >=
1,
"at least one object/image format must be enabled");
+#define CFREE_ASSERT_BOOL(flag) \
+ _Static_assert((flag) == 0 || (flag) == 1, #flag " must be 0 or 1")
+
+CFREE_ASSERT_BOOL(CFREE_ARCH_AA64_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_ARCH_X64_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_ARCH_RV64_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_ARCH_WASM_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_ARCH_C_TARGET_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_OBJ_ELF_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_OBJ_MACHO_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_OBJ_COFF_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_OBJ_WASM_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_LANG_ASM_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_LANG_CPP_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_LANG_C_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_LANG_TOY_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_LANG_WASM_ENABLED);
_Static_assert(CFREE_OPT_ENABLED == 0 || CFREE_OPT_ENABLED == 1,
"CFREE_OPT_ENABLED must be 0 or 1");
+CFREE_ASSERT_BOOL(CFREE_AR_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_DISASM_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_DWARF_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_LINK_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_JIT_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_DBG_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_EMU_ENABLED);
+
+CFREE_ASSERT_BOOL(CFREE_TOOL_CC_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_TOOL_CHECK_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_TOOL_CPP_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_TOOL_AS_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_TOOL_LD_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_TOOL_AR_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_TOOL_RANLIB_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_TOOL_STRIP_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_TOOL_OBJCOPY_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_TOOL_OBJDUMP_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_TOOL_DBG_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_TOOL_RUN_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_TOOL_EMU_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_TOOL_NM_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_TOOL_SIZE_ENABLED);
+CFREE_ASSERT_BOOL(CFREE_TOOL_ADDR2LINE_ENABLED);
+
+#undef CFREE_ASSERT_BOOL
+
+_Static_assert(!CFREE_LANG_C_ENABLED || CFREE_LANG_CPP_ENABLED,
+ "CFREE_LANG_C_ENABLED requires CFREE_LANG_CPP_ENABLED");
+_Static_assert(!CFREE_ARCH_WASM_ENABLED || CFREE_OBJ_WASM_ENABLED,
+ "CFREE_ARCH_WASM_ENABLED requires CFREE_OBJ_WASM_ENABLED");
+
+_Static_assert(!CFREE_JIT_ENABLED || CFREE_LINK_ENABLED,
+ "CFREE_JIT_ENABLED requires CFREE_LINK_ENABLED");
+_Static_assert(!CFREE_DBG_ENABLED || (CFREE_JIT_ENABLED && CFREE_DWARF_ENABLED),
+ "CFREE_DBG_ENABLED requires CFREE_JIT_ENABLED and "
+ "CFREE_DWARF_ENABLED");
+_Static_assert(!CFREE_EMU_ENABLED ||
+ (CFREE_JIT_ENABLED && CFREE_LINK_ENABLED &&
+ CFREE_DISASM_ENABLED && CFREE_OBJ_ELF_ENABLED),
+ "CFREE_EMU_ENABLED requires JIT, link, disasm, and ELF "
+ "support");
+
+_Static_assert(!CFREE_TOOL_CC_ENABLED ||
+ (CFREE_LANG_C_ENABLED && CFREE_LINK_ENABLED &&
+ CFREE_AR_ENABLED),
+ "CFREE_TOOL_CC_ENABLED requires C, link, and ar support");
+_Static_assert(!CFREE_TOOL_CHECK_ENABLED || CFREE_LANG_C_ENABLED,
+ "CFREE_TOOL_CHECK_ENABLED requires C support");
+_Static_assert(!CFREE_TOOL_CPP_ENABLED || CFREE_LANG_CPP_ENABLED,
+ "CFREE_TOOL_CPP_ENABLED requires C preprocessor support");
+_Static_assert(!CFREE_TOOL_LD_ENABLED || CFREE_LINK_ENABLED,
+ "CFREE_TOOL_LD_ENABLED requires link support");
+_Static_assert(!CFREE_TOOL_AR_ENABLED || CFREE_AR_ENABLED,
+ "CFREE_TOOL_AR_ENABLED requires ar support");
+_Static_assert(!CFREE_TOOL_RANLIB_ENABLED || CFREE_AR_ENABLED,
+ "CFREE_TOOL_RANLIB_ENABLED requires ar support");
+_Static_assert(!CFREE_TOOL_STRIP_ENABLED || CFREE_AR_ENABLED,
+ "CFREE_TOOL_STRIP_ENABLED requires ar support");
+_Static_assert(!CFREE_TOOL_OBJCOPY_ENABLED || CFREE_AR_ENABLED,
+ "CFREE_TOOL_OBJCOPY_ENABLED requires ar support");
+_Static_assert(!CFREE_TOOL_OBJDUMP_ENABLED || CFREE_DISASM_ENABLED,
+ "CFREE_TOOL_OBJDUMP_ENABLED requires disasm support");
+_Static_assert(!CFREE_TOOL_RUN_ENABLED ||
+ (CFREE_JIT_ENABLED && CFREE_LINK_ENABLED),
+ "CFREE_TOOL_RUN_ENABLED requires JIT and link support");
+_Static_assert(!CFREE_TOOL_DBG_ENABLED || CFREE_DBG_ENABLED,
+ "CFREE_TOOL_DBG_ENABLED requires debugger support");
+_Static_assert(!CFREE_TOOL_EMU_ENABLED || CFREE_EMU_ENABLED,
+ "CFREE_TOOL_EMU_ENABLED requires emulator support");
+_Static_assert(!CFREE_TOOL_NM_ENABLED || CFREE_AR_ENABLED,
+ "CFREE_TOOL_NM_ENABLED requires ar support");
+_Static_assert(!CFREE_TOOL_SIZE_ENABLED || CFREE_AR_ENABLED,
+ "CFREE_TOOL_SIZE_ENABLED requires ar support");
+_Static_assert(!CFREE_TOOL_ADDR2LINE_ENABLED || CFREE_DWARF_ENABLED,
+ "CFREE_TOOL_ADDR2LINE_ENABLED requires DWARF support");
diff --git a/src/obj/archive_stubs.c b/src/obj/archive_stubs.c
@@ -0,0 +1,23 @@
+#include "obj/format.h"
+
+int obj_format_classify_obj_input_disabled(Compiler* c, ObjBuilder* ob,
+ Sym* soname_out) {
+ (void)c;
+ (void)ob;
+ if (soname_out) *soname_out = 0;
+ return 0;
+}
+
+Sym obj_format_archive_hint_disabled(Compiler* c, const char* archive_name) {
+ (void)c;
+ (void)archive_name;
+ return 0;
+}
+
+ObjFormatArchiveAction obj_format_archive_member_disabled(
+ Compiler* c, const ObjFormatArchiveMember* mem, ObjBuilder** out) {
+ (void)c;
+ (void)mem;
+ if (out) *out = NULL;
+ return OBJ_FORMAT_ARCHIVE_KEEP;
+}
diff --git a/src/obj/emu_stubs.c b/src/obj/emu_stubs.c
@@ -0,0 +1,3 @@
+#include "obj/format.h"
+
+const ObjFormatEmuOps elf_emu_ops = {0};
diff --git a/src/obj/link_stubs.c b/src/obj/link_stubs.c
@@ -0,0 +1,28 @@
+#include "core/core.h"
+#include "obj/format.h"
+
+void obj_format_link_emit_disabled(LinkImage* img, Writer* w) {
+ (void)img;
+ (void)w;
+}
+
+void obj_format_layout_dyn_disabled(Linker* l, LinkImage* img) {
+ (void)l;
+ (void)img;
+}
+
+void obj_format_free_dyn_disabled(LinkImage* img) { (void)img; }
+
+void obj_format_macho_stub_disabled(u8* dst, u64 stub_vaddr,
+ u64 got_slot_vaddr) {
+ (void)dst;
+ (void)stub_vaddr;
+ (void)got_slot_vaddr;
+}
+
+void obj_format_coff_stub_disabled(u8* dst, u64 stub_vaddr,
+ u64 iat_slot_vaddr) {
+ (void)dst;
+ (void)stub_vaddr;
+ (void)iat_slot_vaddr;
+}
diff --git a/src/obj/obj.h b/src/obj/obj.h
@@ -724,6 +724,5 @@ ObjBuilder* read_macho_dso(Compiler*, const char* name, const u8* data,
* The arch string ("arm64" or "x86_64") comes from Compiler.target. */
ObjBuilder* read_tbd(Compiler*, const char* name, const u8* data, size_t len,
Sym* install_name_out);
-ObjBuilder* read_wasm(Compiler*, const char* name, const u8* data, size_t len);
#endif
diff --git a/src/obj/registry.c b/src/obj/registry.c
@@ -8,30 +8,58 @@
#include "obj/macho/macho.h"
#include "obj/obj.h"
+#if CFREE_LINK_ENABLED
void link_emit_elf(LinkImage*, Writer*);
void link_emit_macho(LinkImage*, Writer*);
void link_emit_coff(LinkImage*, Writer*);
-
-#if CFREE_OBJ_ELF_ENABLED
void layout_dyn(Linker*, LinkImage*);
void link_dyn_state_free(LinkImage*);
-extern const ObjFormatEmuOps elf_emu_ops;
+#define OBJ_LINK_EMIT_ELF link_emit_elf
+#define OBJ_LINK_EMIT_MACHO link_emit_macho
+#define OBJ_LINK_EMIT_COFF link_emit_coff
+#define OBJ_LAYOUT_DYN layout_dyn
+#define OBJ_FREE_DYN link_dyn_state_free
+#else
+void obj_format_link_emit_disabled(LinkImage*, Writer*);
+void obj_format_layout_dyn_disabled(Linker*, LinkImage*);
+void obj_format_free_dyn_disabled(LinkImage*);
+#define OBJ_LINK_EMIT_ELF obj_format_link_emit_disabled
+#define OBJ_LINK_EMIT_MACHO obj_format_link_emit_disabled
+#define OBJ_LINK_EMIT_COFF obj_format_link_emit_disabled
+#define OBJ_LAYOUT_DYN obj_format_layout_dyn_disabled
+#define OBJ_FREE_DYN obj_format_free_dyn_disabled
#endif
-#if CFREE_OBJ_COFF_ENABLED
+extern const ObjFormatEmuOps elf_emu_ops;
+
+#if CFREE_AR_ENABLED
int coff_classify_obj_input(Compiler*, ObjBuilder*, Sym* soname_out);
Sym coff_archive_hint(Compiler*, const char* archive_name);
ObjFormatArchiveAction coff_archive_member(Compiler*,
const ObjFormatArchiveMember*,
ObjBuilder** out);
+#else
+int obj_format_classify_obj_input_disabled(Compiler*, ObjBuilder*,
+ Sym* soname_out);
+Sym obj_format_archive_hint_disabled(Compiler*, const char* archive_name);
+ObjFormatArchiveAction obj_format_archive_member_disabled(
+ Compiler*, const ObjFormatArchiveMember*, ObjBuilder** out);
+#define coff_classify_obj_input obj_format_classify_obj_input_disabled
+#define coff_archive_hint obj_format_archive_hint_disabled
+#define coff_archive_member obj_format_archive_member_disabled
#endif
-#if CFREE_ARCH_AA64_ENABLED
+#if CFREE_LINK_ENABLED
void aa64_emit_macho_stub(u8* dst, u64 stub_vaddr, u64 got_slot_vaddr);
void aa64_emit_coff_iat_stub(u8* dst, u64 stub_vaddr, u64 iat_slot_vaddr);
-#endif
-#if CFREE_ARCH_X64_ENABLED
void x64_emit_coff_iat_stub(u8* dst, u64 stub_vaddr, u64 iat_slot_vaddr);
+#else
+void obj_format_macho_stub_disabled(u8* dst, u64 stub_vaddr,
+ u64 got_slot_vaddr);
+void obj_format_coff_stub_disabled(u8* dst, u64 stub_vaddr, u64 iat_slot_vaddr);
+#define aa64_emit_macho_stub obj_format_macho_stub_disabled
+#define aa64_emit_coff_iat_stub obj_format_coff_stub_disabled
+#define x64_emit_coff_iat_stub obj_format_coff_stub_disabled
#endif
#if CFREE_OBJ_ELF_ENABLED
@@ -206,17 +234,22 @@ static const ObjCoffArchOps* obj_coff_machine(u16 machine) {
}
#endif
+#if CFREE_OBJ_WASM_ENABLED
static const ObjFormatImpl obj_format_impl_wasm = {
.kind = CFREE_OBJ_WASM,
.bin_fmt = CFREE_BIN_WASM,
.name = "wasm",
- .read_name = "read_wasm",
+ /* Wasm core modules are frontend inputs. A linkable Wasm object reader
+ * needs tool-conventions `linking` / `reloc.*` support and is still
+ * pending, so do not advertise a generic object reader here. */
+ .read_name = NULL,
.read_dso_name = NULL,
.emit = emit_wasm,
- .read = read_wasm,
+ .read = NULL,
.read_dso = NULL,
.link_emit = NULL,
};
+#endif
#if CFREE_OBJ_ELF_ENABLED
static const ObjFormatImpl obj_format_impl_elf = {
@@ -228,9 +261,9 @@ static const ObjFormatImpl obj_format_impl_elf = {
.emit = emit_elf,
.read = read_elf,
.read_dso = read_elf_dso,
- .link_emit = link_emit_elf,
- .layout_dyn = layout_dyn,
- .free_dyn = link_dyn_state_free,
+ .link_emit = OBJ_LINK_EMIT_ELF,
+ .layout_dyn = OBJ_LAYOUT_DYN,
+ .free_dyn = OBJ_FREE_DYN,
.emu = &elf_emu_ops,
.elf_arch = obj_elf_arch,
.elf_machine = obj_elf_machine,
@@ -247,7 +280,7 @@ static const ObjFormatImpl obj_format_impl_macho = {
.emit = emit_macho,
.read = read_macho,
.read_dso = read_macho_dso,
- .link_emit = link_emit_macho,
+ .link_emit = OBJ_LINK_EMIT_MACHO,
.macho_arch = obj_macho_arch,
.macho_cputype = obj_macho_cputype,
};
@@ -263,7 +296,7 @@ static const ObjFormatImpl obj_format_impl_coff = {
.emit = emit_coff,
.read = read_coff,
.read_dso = read_coff_dso,
- .link_emit = link_emit_coff,
+ .link_emit = OBJ_LINK_EMIT_COFF,
.coff_arch = obj_coff_arch,
.coff_machine = obj_coff_machine,
.classify_obj_input = coff_classify_obj_input,
@@ -282,7 +315,9 @@ static const ObjFormatImpl* const obj_format_impls[] = {
#if CFREE_OBJ_MACHO_ENABLED
&obj_format_impl_macho,
#endif
+#if CFREE_OBJ_WASM_ENABLED
&obj_format_impl_wasm,
+#endif
};
const ObjFormatImpl* obj_format_lookup(ObjFmt fmt) {