# How to Integrate mulle-objc-runtime with the mulle-clang Compiler

> Integrate mulle-objc-runtime with mulle-clang by installing the mulle-objc-cc toolchain and compiling .m files using the mulle-clang driver for essential preprocessor macros and metadata generation.

- Repository: [mulle-objc/mulle-objc-runtime](https://github.com/mulle-objc/mulle-objc-runtime)
- Tags: how-to-guide
- Published: 2026-03-07

---

**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`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/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`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/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`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/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 for `MULLECLANG` in the compiler executable name (lines 15–31). It sets the internal `MULLE_C_COMPILER_ID` variable 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-clang` driver and auxiliary tooling. This package is typically installed via `mulle-sde` and must be available on the PATH.

- **Test suites** – The `test-compiler` and `test-compiler-runtime` directories 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:

```bash
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:

```bash
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:

```objc
// 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:

```bash
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:

```bash
./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:

```objc
// 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.h`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-runtime.h) enforce this at compile time via `#error` directives.
- **Use `.m` extensions**: The README explicitly states that `.c` files 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-runtime` when building executables.
- **Manage universes**: Use `mulle_objc_global_get_universe_inline` for the default universe or `mulle_objc_universe_create` for isolated environments, ensuring proper cleanup with `mulle_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`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/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`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-runtime.h) to compile successfully.