# How to Customize the Universe Configuration During MulleObjC Startup

> Learn how to customize MulleObjC universe configuration at startup using global defaults or a custom registration function. Improve your MulleObjC application setup.

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

---

**You can customize the MulleObjC universe configuration by either modifying the global default configuration before startup using `mulle_objc_global_set_default_universeconfiguration()` or by providing a custom `__register_mulle_objc_universe` function to replace the default registration hook.**

The `mulle-objc/mulleobjc-startup` repository provides the entry point that initializes the Objective-C runtime when your executable launches. Understanding how to customize the universe configuration during MulleObjC startup allows you to tune cache sizes, debug flags, and runtime behavior before any Objective-C code executes.

## Understanding the MulleObjC Startup Sequence

### The Registration Hook in src/MulleObjC-startup.m

The startup process centers on the `__register_mulle_objc_universe` symbol defined in `src/MulleObjC-startup.m`. This file exports the registration function through `MULLE_OBJC_DEFINE__register_mulle_objc_universe`, which expands the private include `mulle-objc-startup-private.inc` to create the exported symbol.

When the runtime loads, it calls this registration function, which internally invokes a static helper function called `bang()`. The `bang()` function creates a local `struct _mulle_objc_universeconfiguration`, copies global defaults into it, and passes this structure to `MulleObjCBang()`—the actual function that creates and initializes the universe.

### The Universe Configuration Structure

The configuration is defined in [`include/MulleObjC/mulle-objc-universeconfiguration-private.h`](https://github.com/mulle-objc/mulleobjc-startup/blob/main/include/MulleObjC/mulle-objc-universeconfiguration-private.h) as `struct _mulle_objc_universeconfiguration`. This structure contains fields for object cache sizes, class table capacity, debug flags, and other runtime parameters that control memory usage and diagnostic output.

## Method 1: Modify Global Defaults Before Startup

### Using the Global Configuration Setter

The runtime provides two key functions for accessing and modifying the default configuration:

```c
const struct _mulle_objc_universeconfiguration *
     mulle_objc_global_get_default_universeconfiguration(void);

void
     mulle_objc_global_set_default_universeconfiguration(
             const struct _mulle_objc_universeconfiguration *config);

```

These functions are declared in [`mulle-objc-universeconfiguration-private.h`](https://github.com/mulle-objc/mulleobjc-startup/blob/main/mulle-objc-universeconfiguration-private.h). By calling `mulle_objc_global_set_default_universeconfiguration()` before the startup registration runs, you replace the default values that `bang()` copies into the local configuration structure.

### Code Example: Constructor-Based Configuration

You can use a GCC constructor attribute to ensure your configuration runs before Objective-C initialization:

```c
#include <MulleObjC/mulle-objc-universeconfiguration-private.h>
#include <MulleObjC/mulle-objc-startup-private.h>
#include <stdio.h>

/* This runs before any Objective-C code */
static void __attribute__((constructor)) configure_universe(void)
{
    struct _mulle_objc_universeconfiguration custom = {
        .object_cache_size = 64,                 /* smaller cache */
        .debug_flags      = MULLE_OBJC_DEBUG_CALLS /* enable tracing */
    };

    mulle_objc_global_set_default_universeconfiguration(&custom);
    printf("Custom MulleObjC universe configured\n");
}

```

The constructor executes before `__register_mulle_objc_universe` from `MulleObjC-startup.m`, ensuring your values are picked up when `bang()` calls `MulleObjCBang()`.

## Method 2: Provide a Custom Registration Function

### Replacing the Default bang() Implementation

Because `__register_mulle_objc_universe` is defined through a macro that creates a weak symbol, you can provide your own implementation. The linker will prefer your definition if it appears later in the link order.

Alternatively, you can replace the internal `bang()` callback that the default registration uses. This approach keeps the registration machinery but swaps the configuration building logic.

### Code Example: Custom Universe Initialization

Here is how to replace the default behavior with a custom initialization:

```c
#define MULLE_OBJC_DEFINE__register_mulle_objc_universe
#include <MulleObjC/mulle-objc-startup-private.inc>

#include <MulleObjC/mulle-objc-universeconfiguration-private.h>
#include <stdio.h>

static void my_universe_init(struct _mulle_objc_universe *universe,
                            struct mulle_allocator *allocator,
                            void *userinfo)
{
    struct _mulle_objc_universeconfiguration cfg = {
        .object_cache_size = 128,
        .debug_flags      = MULLE_OBJC_DEBUG_NONE
    };
    printf("my custom universe init\n");
    MulleObjCBang(universe, allocator, &cfg);
}

/* Replace the default static “bang” with our version */
static void __attribute__((constructor)) replace_bang(void)
{
    extern void (*_MulleObjC_startup_bang)(
            struct _mulle_objc_universe *,
            struct mulle_allocator *,
            void *);

    _MulleObjC_startup_bang = my_universe_init;
}

```

This example demonstrates both the macro definition to prevent duplicate symbols and the callback replacement technique.

## Key Configuration Fields

When you customize the universe configuration during MulleObjC startup, these are the primary fields available in `struct _mulle_objc_universeconfiguration`:

- **object_cache_size** — Controls the size of the per-thread object cache, affecting memory usage and allocation performance.
- **class_table_initial_capacity** — Sets the initial hash table size for class lookups, which impacts method dispatch speed.
- **debug_flags** — A bitmask enabling various runtime diagnostics such as `MULLE_OBJC_DEBUG_CALLS` for call tracing or `MULLE_OBJC_DEBUG_NONE` for production builds.

Consult [`mulle-objc-universeconfiguration-private.h`](https://github.com/mulle-objc/mulleobjc-startup/blob/main/mulle-objc-universeconfiguration-private.h) in the MulleObjC repository for the complete structure definition and additional tuning parameters.

## Summary

- The `mulleobjc-startup` repository provides `__register_mulle_objc_universe` in `src/MulleObjC-startup.m`, which initializes the runtime by calling `MulleObjCBang()` with a configuration structure.
- You can customize the universe configuration during MulleObjC startup by calling `mulle_objc_global_set_default_universeconfiguration()` before registration, typically using a GCC constructor attribute.
- Alternatively, provide your own `__register_mulle_objc_universe` implementation or replace the internal `bang()` callback to build a completely custom configuration structure.
- Key configuration fields include `object_cache_size`, `class_table_initial_capacity`, and `debug_flags`, all defined in [`mulle-objc-universeconfiguration-private.h`](https://github.com/mulle-objc/mulleobjc-startup/blob/main/mulle-objc-universeconfiguration-private.h).

## Frequently Asked Questions

### What is the MulleObjC universe?

The MulleObjC universe is the runtime environment that manages all Objective-C classes, objects, method caches, and thread-local storage within the Mulle Objective-C implementation. It is created during startup and persists for the lifetime of the process, governing memory allocation, method dispatch, and runtime diagnostics.

### When does the universe configuration get applied?

The universe configuration is applied during the execution of `__register_mulle_objc_universe`, which runs automatically when the executable starts. Inside `src/MulleObjC-startup.m`, the `bang()` function copies the global default configuration into a local structure and passes it to `MulleObjCBang()` immediately before the universe is created.

### Can I modify the universe after startup?

No, the universe configuration is immutable after initialization. The `struct _mulle_objc_universeconfiguration` is consumed during the creation of the universe in `MulleObjCBang()`, and the runtime does not provide APIs to reconfigure cache sizes or debug flags dynamically. You must customize the universe configuration during MulleObjC startup using the methods described above.

### Where are the configuration functions declared?

The configuration accessor functions `mulle_objc_global_get_default_universeconfiguration()` and `mulle_objc_global_set_default_universeconfiguration()` are declared in [`include/MulleObjC/mulle-objc-universeconfiguration-private.h`](https://github.com/mulle-objc/mulleobjc-startup/blob/main/include/MulleObjC/mulle-objc-universeconfiguration-private.h) within the MulleObjC repository. The registration macro `MULLE_OBJC_DEFINE__register_mulle_objc_universe` is provided in `include/MulleObjC/mulle-objc-startup-private.inc`.