# How to Troubleshoot Startup Crashes in MulleObjC Applications

> Troubleshoot MulleObjC startup crashes by fixing missing static library dependencies, especially failed __register_mulle_objc_universe symbol linking before main. Resolve your MulleObjC app issues now.

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

---

**Startup crashes in MulleObjC applications are almost always caused by missing or mismatched static library dependencies, specifically when the `__register_mulle_objc_universe` symbol fails to link or execute before `main()`.**

The **mulle-objc/mulleobjc-startup** repository provides the critical static library that initializes the Objective-C universe before your application’s entry point runs. When this startup sequence fails, your program crashes with segmentation faults or "unrecognized selector" errors before any of your own code executes. Understanding the exact startup flow and verification techniques will help you diagnose these early initialization failures quickly.

## Understanding the MulleObjC Startup Flow

MulleObjC applications use a specific three-phase bootstrap process that occurs before `main()` is called.

### Phase 1: Link-Time Dependency Resolution

The `MulleObjC-startup` static library automatically pulls in two required helper libraries:

- **mulle-atinit** – Provides constructor functions that run before `main()`
- **mulle-atexit** – Registers cleanup handlers for graceful shutdown

These dependencies are defined in the CMake configuration and must be present in the final binary.

### Phase 2: Runtime Universe Registration

When the executable loads, the constructor generated by `mulle-atinit` calls the private function `__register_mulle_objc_universe`, defined in `src/MulleObjC-startup.m`. Inside this file, the helper function `bang()` creates a copy of the default universe configuration and invokes `MulleObjCBang()` to perform the actual universe initialization.

### Phase 3: Post-Initialization Execution

After successful registration, the runtime is fully initialized and `main()` can safely use any MulleObjC class or the Foundation layer. If any step in this chain fails, the application crashes before reaching your code.

## Verifying the Startup Library is Linked

The most common cause of startup crashes is a missing `__register_mulle_objc_universe` symbol. Verify its presence using the `nm` command:

```bash

# Show the symbols exported by the final executable

nm -g <your-executable> | grep __register_mulle_objc_universe

```

**Expected output:**

```

0000000000001234 T __register_mulle_objc_universe

```

If the symbol is absent, the `MulleObjC-startup` static library was not linked. Add it explicitly in your CMake target:

```cmake
target_link_libraries(${PROJECT_NAME} PUBLIC MulleObjC-startup)

```

This corresponds to the **Add** section in the repository README, which specifies how to integrate the startup library into your build system.

## Checking Required Dependencies

The startup library depends on three core libraries. Verify their objects are in the final binary:

```bash
nm -g <your-executable> | grep mulle_atinit
nm -g <your-executable> | grep mulle_atexit
nm -g <your-executable> | grep MulleObjC

```

Missing symbols indicate that the corresponding sub-projects were not added. Follow the **Legacy adds** or **Add sources** sections in the README to include `mulle-atinit`, `mulle-atexit`, and the core `MulleObjC` runtime.

## Resolving Version Compatibility Issues

`MulleObjC-startup` is compiled against a specific `MulleObjC` version using the `MULLE_OBJC__STARTUP_VERSION` constant, defined in `src/MulleObjC-startup.m`. If you link a newer or older runtime, the structures used by `MulleObjCBang()` may differ, causing a crash.

Validate version compatibility by printing the startup version at runtime:

```c
#include <stdio.h>
#include <MulleObjC-startup/MulleObjC-startup.h>

int main(void)
{
    printf("Startup version: %lu\n", MULLE_OBJC__STARTUP_VERSION);
    return 0;
}

```

If the printed version does not match the version reported by `MulleObjC` (`MulleObjCGetStartupVersion()`), rebuild all dependencies so they share the same tag.

## Enabling Diagnostic Tracing

MulleObjC offers optional tracing facilities that reveal early-init problems. Compile with the trace flag:

```cmake

# Add the define to your CFLAGS (or in CMake)

add_definitions(-DMULLE_OBJC_TRACE=1)

```

When enabled, the startup code prints messages from `MulleObjCBang()`. The tracing infrastructure is imported via [`MulleObjCExceptionHandler-Private.h`](https://github.com/mulle-objc/mulleobjc-startup/blob/main/MulleObjCExceptionHandler-Private.h) in the startup file.

**Typical output:**

```

[MulleObjC] initializing universe …
[MulleObjC] default configuration copied
[MulleObjC] universe ready – class table size 1024

```

If the program aborts before these lines appear, the crash occurs **before** the universe is constructed, indicating a missing `__register_mulle_objc_universe` symbol or a failure in the `mulle-atinit` constructor chain.

## Common Startup Crash Scenarios

| Symptom | Likely Cause | Solution |
|---|---|---|
| **Segmentation fault before `main`** | `__register_mulle_objc_universe` missing or mismatched | Ensure `MulleObjC-startup` is linked; verify symbol with `nm`. |
| **"Unrecognized selector" early in execution** | Wrong `MulleObjC` runtime version | Re‑build all dependencies from the same tag. |
| **No diagnostic output with `MULLE_OBJC_TRACE` enabled** | Startup library not loaded | Add `MulleObjC-startup` to `target_link_libraries`. |
| **Linker errors about `mulle_atinit` / `mulle_atexit`** | Dependency libraries not added | Follow the **Add sources** steps in the README. |

## Minimal Reproducible Example

Use this minimal program to verify your startup configuration:

```c
/* main.c – minimal program that uses MulleObjC-startup */
#import <MulleObjC-startup/MulleObjC-startup.h>
#import <MulleObjC/MulleObjC.h>

int main(void)
{
    // The universe is already registered by the startup library.
    if (!MulleObjCGetUniverse())
    {
        fprintf(stderr, "Error: MulleObjC universe not initialized\n");
        return 1;
    }

    printf("MulleObjC startup succeeded – universe %p\n",
           (void *)MulleObjCGetUniverse());
    return 0;
}

```

**Build with CMake:**

```cmake
add_executable(myapp main.c)
target_link_libraries(myapp PUBLIC MulleObjC-startup)

```

Running `myapp` should print the success message. If it crashes, apply the diagnostic steps outlined above.

## Summary

- **Link verification** is the first step: use `nm -g` to confirm `__register_mulle_objc_universe` exists in your binary.
- **Dependency chain** requires `mulle-atinit`, `mulle-atexit`, and the core `MulleObjC` runtime to be linked alongside `MulleObjC-startup`.
- **Version alignment** between `MULLE_OBJC__STARTUP_VERSION` and the runtime prevents structure mismatches in `MulleObjCBang()`.
- **Diagnostic tracing** via `-DMULLE_OBJC_TRACE=1` reveals whether the universe initialization reaches `src/MulleObjC-startup.m` or fails earlier in the constructor chain.

## Frequently Asked Questions

### Why does my MulleObjC application crash before reaching main()?

This occurs when the `__register_mulle_objc_universe` symbol is missing or when the constructor chain fails to execute. The startup library must be linked as a static library so that its constructor runs before `main()`. Verify the symbol is present using `nm -g <executable> | grep __register_mulle_objc_universe`.

### How do I check if MulleObjC-startup is properly linked?

Run `nm -g` on your final executable and search for `__register_mulle_objc_universe`, `mulle_atinit`, and `mulle_atexit`. All three should appear as global text symbols (marked with `T`). If any are missing, add `MulleObjC-startup` to your CMake `target_link_libraries` and ensure `mulle-atinit` and `mulle-atexit` are included in your dependency tree.

### What version compatibility issues should I watch for?

The `MULLE_OBJC__STARTUP_VERSION` constant defined in `src/MulleObjC-startup.m` must match the version expected by the core `MulleObjC` runtime. Mismatches cause `MulleObjCBang()` to access incompatible structure layouts, resulting in immediate crashes. Always build `MulleObjC-startup` and `MulleObjC` from the same release tag.

### How can I enable debug output to trace the startup sequence?

Define `MULLE_OBJC_TRACE=1` during compilation to activate diagnostic messages from `MulleObjCBang()`. In CMake, use `add_definitions(-DMULLE_OBJC_TRACE=1)`. When enabled, the runtime prints initialization steps to stderr, allowing you to see whether the universe creation begins or fails before reaching `src/MulleObjC-startup.m`.