# How MulleObjC-startup Provides Automatic Startup Code for MulleObjC

> Learn how MulleObjC-startup provides automatic startup code for MulleObjC. Discover the linker-preserved constructor symbol and platform runtime invocation that initializes the MulleObjC universe without user intervention.

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

---

**MulleObjC-startup exports a constructor symbol `__register_mulle_objc_universe` that the linker preserves and the platform runtime invokes before `main`, automatically initializing the MulleObjC universe without requiring explicit user code.**

The **mulle-objc/mulleobjc-startup** repository solves the bootstrap problem of the MulleObjC runtime by supplying the necessary startup code through a minimal static library. By exposing a specially-named symbol that the dynamic loader recognizes as a constructor, the library ensures the Objective-C environment is fully operational before the first line of `main` executes.

## The Core Mechanism: Exported Symbols and Linker Integration

MulleObjC-startup operates by injecting a single exported function into the final binary. This function acts as a hook that the platform runtime calls during program initialization.

### Defining the Exported Symbol in `src/MulleObjC-startup.m`

The implementation centers on the source file `src/MulleObjC-startup.m`, which defines the macro `MULLE_OBJC_DEFINE__register_mulle_objc_universe`. This macro causes the private include `<MulleObjC/mulle-objc-startup-private.inc>` to emit the symbol `__register_mulle_objc_universe` with **dllexport** visibility. The symbol serves as the entry point for all runtime initialization activities.

### Enforcing Linker Visibility with CMake

Static libraries typically do not export symbols unless explicitly requested. To ensure `__register_mulle_objc_universe` survives the linking process and remains visible to the dynamic loader, the CMake helper `cmake/share/ExecutableObjC.cmake` adds the linker flag `-exported_symbol,___register_mulle_objc_universe`. This flag guarantees the symbol is present in the final binary even though the library itself contains no other public interfaces.

## Runtime Initialization Sequence

Once the symbol is exported, the platform runtime handles the rest of the initialization chain automatically.

### The Constructor Hook and `bang()` Function

The private header included by `src/MulleObjC-startup.m` registers `__register_mulle_objc_universe` as a **constructor**—a function the platform runtime executes automatically during program load, prior to `main`. This constructor immediately forwards execution to the static helper function `bang()`, defined in the same source file.

### Universe Creation via `MulleObjCBang()`

Inside `bang()`, the current global universe configuration is copied using `mulle_objc_global_get_default_universeconfiguration()`, then the helper `MulleObjCBang()` performs the heavy lifting. This function creates the *universe* object, installs the default allocator, and registers all built-in MulleObjC classes, method tables, and exception handlers.

```c
static void bang( struct _mulle_objc_universe *universe,
                  struct mulle_allocator *allocator,
                  void *userinfo )
{
    struct _mulle_objc_universeconfiguration config;
    memcpy( &config,
            mulle_objc_global_get_default_universeconfiguration(),
            sizeof( config ));
    MulleObjCBang( universe, allocator, &config );
}

```

After `MulleObjCBang()` returns, the full MulleObjC runtime is operational and ready to receive messages.

## Integrating MulleObjC-startup Into Your Build

No explicit initialization calls are required in application code. Simply linking against the static library injects the constructor into the final binary, ensuring automatic initialization.

```objc
/* No explicit call needed – just link the static library */
#include <MulleObjC/MulleObjC.h>

int main(void)
{
    // At this point the MulleObjC universe is already set up.
    id obj = [NSObject new];
    NSLog(@"Created %@", obj);
    [obj release];
    return 0;
}

```

Link the library using the provided CMake integration or manually:

```bash
clang -o myprog main.c -lMulleObjC-startup -lMulleObjC

```

## Summary

- **Exported Symbol**: The macro `MULLE_OBJC_DEFINE__register_mulle_objc_universe` in `src/MulleObjC-startup.m` creates the entry point `__register_mulle_objc_universe`.
- **Linker Enforcement**: The flag `-exported_symbol,___register_mulle_objc_universe` in `cmake/share/ExecutableObjC.cmake` prevents symbol stripping.
- **Automatic Execution**: The runtime calls the exported constructor before `main`, invoking `bang()` and subsequently `MulleObjCBang()`.
- **Zero Configuration**: Developers link the library and immediately have a fully initialized MulleObjC environment available at program start.

## Frequently Asked Questions

### What is the exact symbol that enables automatic MulleObjC initialization?

The symbol is `__register_mulle_objc_universe` (with two leading underscores). This function is emitted by the `MULLE_OBJC_DEFINE__register_mulle_objc_universe` macro and acts as the constructor that triggers the runtime bootstrap sequence.

### Why does the CMake configuration use a special linker flag?

The flag `-exported_symbol,___register_mulle_objc_universe` (three leading underscores in this context) is required because static library symbols are typically internal to the linked binary. Without this explicit export directive, the linker would strip the symbol, preventing the platform runtime from locating and executing the constructor during program load.

### At what point during program execution does the MulleObjC universe become available?

The MulleObjC universe is fully initialized **before** `main()` begins execution. The platform runtime processes constructor functions during the loading phase, meaning `bang()` and `MulleObjCBang()` complete their work—setting up the universe, allocator, and class tables—prior to any application code running.

### Can I customize the universe configuration during startup?

The `bang()` function copies the default configuration via `mulle_objc_global_get_default_universeconfiguration()` before passing it to `MulleObjCBang()`. While the default startup sequence uses global defaults, advanced users can modify the universe configuration by intercepting the initialization flow or providing a custom configuration structure before the constructor executes, though this requires deeper integration with the runtime internals.