How to Integrate mulle-objc-runtime with the mulle-clang Compiler
The mulle-objc-runtime requires the mulle-clang compiler to inject specific preprocessor macros (TPS, FCS, TAO) and generate metadata, making integration a matter of installing the mulle-objc-cc toolchain and compiling .m source files with the mulle-clang driver.
The mulle-objc-runtime is a modern Objective-C runtime designed specifically for use with the custom mulle-clang compiler front-end. Unlike standard Objective-C runtimes that compile with generic toolchains, mulle-objc-runtime depends on compiler-generated metadata and specific macro definitions that only mulle-clang provides. Attempting to compile the runtime headers with a standard C compiler or vanilla clang triggers explicit #error directives in src/mulle-objc-runtime.h that halt the build immediately.
Why mulle-clang is Mandatory
The runtime’s public header src/mulle-objc-runtime.h contains compile-time sanity checks that enforce the presence of compiler-injected symbols. Lines 45–51 validate that type-preserving-symbols (TPS) switches are defined, while lines 52–63 enforce fast class setup (FCS), TAO, and universe identifiers. These macros—__MULLE_OBJC_TPS__, __MULLE_OBJC_FCS__, __MULLE_OBJC_TAO__, and __MULLE_OBJC_UNIVERSEID__—are injected automatically by the mulle-clang driver during compilation.
Without these definitions, the header aborts with an error directing you to use mulle-clang. This design creates a closed loop where only code compiled through mulle-clang can successfully link against the runtime.
Architecture Overview
Understanding how the components interact helps clarify the integration requirements:
-
src/mulle-objc-runtime.h– The public API header that gate-keeps compilation. It performs sanity checks for mulle-clang-injected macros and includes all internal runtime headers. -
cmake/share/CompilerDetectionC.cmake– CMake logic that detects whether the invoked compiler is mulle-clang by searching forMULLECLANGin the compiler executable name (lines 15–31). It sets the internalMULLE_C_COMPILER_IDvariable for downstream flag handling. -
cmake/share/CompilerFlagsC.cmake– Adds common compiler definitions like-DMULLE_INCLUDE_DYNAMIC=1. While it does not currently add mulle-clang-specific flags, the detection step ensures the compiler ID is known for Objective-C-specific configurations. -
mulle-objc-cc package – Supplies the
mulle-clangdriver and auxiliary tooling. This package is typically installed viamulle-sdeand must be available on the PATH. -
Test suites – The
test-compilerandtest-compiler-runtimedirectories contain examples that explicitly require mulle-clang, as noted in their README files, demonstrating valid compiler usage patterns.
Step-by-Step Integration Guide
Follow these steps to configure a working build environment that correctly integrates the runtime with the compiler.
1. Install the Toolchain
Use mulle-sde to install the runtime and the compiler wrapper:
mulle-sde install --prefix /usr/local \
https://github.com/mulle-objc/mulle-objc-runtime/archive/latest.tar.gz
This command pulls in mulle-objc-runtime, mulle-objc-debug, mulle-objc-runtime-startup, and the mulle-objc-cc package containing the compiler driver.
2. Configure Your Project
For new or existing projects, add the required dependencies:
mulle-sde init -d my-project -m mulle-c/c-developer executable
cd my-project
mulle-sde dep add github:mulle-objc/mulle-objc-runtime
mulle-sde dep add github:mulle-objc/mulle-objc-debug
mulle-sde dep add --startup github:mulle-objc/mulle-objc-runtime-startup
mulle-sde dep add github:mulle-cc/mulle-objc-cc
mulle-sde mark mulle-objc-cc no-bequeath
mulle-sde mark mulle-objc-cc no-link
mulle-sde mark mulle-objc-cc no-import
mulle-sde mark mulle-objc-cc no-header
The mark commands ensure the compiler wrapper is used only for compilation, not linked as a library.
3. Write Objective-C Source Files
Rename any .c files to .m. The README explicitly warns that .c files will not work with mulle-clang and must use the Objective-C extension.
Create a source file that includes the runtime header:
// hello.m
#import <mulle-objc-runtime/mulle-objc-runtime.h>
int main(void)
{
struct _mulle_objc_universe *universe =
mulle_objc_global_get_universe_inline(__MULLE_OBJC_UNIVERSEID__);
if (universe && universe->name)
printf("Universe: %s\n", universe->name);
mulle_objc_global_finish();
return 0;
}
4. Build with mulle-clang
Compile using the mulle-clang driver, which automatically defines the required macros:
mulle-clang -Wall -Wextra -O2 -o hello hello.m -lmulle-objc-runtime
If you inspect the pre-processed output, you will see __MULLE_OBJC_TPS__, __MULLE_OBJC_FCS__, and __MULLE_OBJC_TAO__ injected at the top of the translation unit.
5. Run the Binary
Execute your program:
./hello
The default universe typically returns (null) for the name unless explicitly configured otherwise.
Working with Custom Universes
For applications requiring isolated runtime environments, create named universes using the TAO-enabled functions:
// custom-universe.m
#import <mulle-objc-runtime/mulle-objc-runtime.h>
static const char *MyUniverseName = "MyApp";
int main(void)
{
struct _mulle_objc_universe *universe;
universe = mulle_objc_universe_create(0, MyUniverseName);
mulle_objc_global_set_universe(universe);
printf("Created universe %s\n", MyUniverseName);
mulle_objc_global_finish();
return 0;
}
Compile using the same command. The mulle_objc_global_finish() call is mandatory for custom universes to release resources, though optional for the default universe.
Troubleshooting Common Integration Errors
| Symptom | Root Cause | Solution |
|---|---|---|
#error "Use the mulle-clang …" |
Compiling with standard clang/gcc or using .c extension |
Rename files to .m and ensure mulle-clang is the compiler executable |
Undefined __MULLE_OBJC_TPS__ |
Build system bypassing the mulle-clang driver | Configure CMake to use mulle-clang as both the C and ObjC compiler; verify CompilerDetectionC.cmake detects MULLECLANG |
Linker errors for mulle_objc_* |
Runtime library not linked | Add -lmulle-objc-runtime to linker flags or use mulle-sde link |
| Runtime crash on allocation | Universe not initialized or __MULLE_OBJC_NO_TPS__ manually defined |
Keep default TPS configuration; do not disable type-preserving symbols unless you understand the memory layout implications |
Summary
- mulle-clang is non-negotiable: The runtime headers in
src/mulle-objc-runtime.henforce this at compile time via#errordirectives. - Use
.mextensions: The README explicitly states that.cfiles fail; Objective-C mode is required. - Install mulle-objc-cc: This package provides the driver that defines
__MULLE_OBJC_TPS__,__MULLE_OBJC_FCS__, and__MULLE_OBJC_TAO__. - Link correctly: Always link against
-lmulle-objc-runtimewhen building executables. - Manage universes: Use
mulle_objc_global_get_universe_inlinefor the default universe ormulle_objc_universe_createfor isolated environments, ensuring proper cleanup withmulle_objc_global_finish.
Frequently Asked Questions
Can I compile mulle-objc-runtime with standard clang or GCC?
No. The header src/mulle-objc-runtime.h contains explicit checks for macros like __MULLE_OBJC_TPS__ and __MULLE_OBJC_FCS__ that only mulle-clang injects. Attempting to compile with standard compilers results in an immediate #error directive aborting the build.
Why must source files use the .m extension instead of .c?
According to the README (lines 60–68), mulle-clang treats .m files as Objective-C source and enables the specific language mode required to generate the metadata the runtime expects. Compiling .c files bypasses these code paths, leaving required symbols undefined.
How does CMake detect mulle-clang?
The build system uses cmake/share/CompilerDetectionC.cmake (lines 15–31) to inspect the compiler executable name for the substring MULLECLANG. When detected, it sets MULLE_C_COMPILER_ID to identify the compiler for downstream flag configuration in CompilerFlagsC.cmake.
What are TPS, FCS, and TAO in the context of mulle-objc?
These are compiler features that mulle-clang enables via injected macros: Type-Preserving-Symbols (TPS) maintains type information through the compilation pipeline; Fast Class Setup (FCS) optimizes class initialization; and TAO (Tiny/special Object handling) relates to universe and object lifecycle management. These must be present for the runtime in src/mulle-objc-runtime.h to compile successfully.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →