How to Create Executables that Use MulleObjC: A Complete Guide

Link your executable against the MulleObjC-startup static library to automatically register the __register_mulle_objc_universe function and initialize the runtime without pulling in the full Foundation stack.

The mulle-objc/mulleobjc-startup repository provides a lightweight bootstrap mechanism for building standalone executables that leverage the Mulle Objective-C runtime. By including this static library in your build, you obtain the minimal runtime initialization code required to boot the MulleObjC universe, along with automatic handling of mulle-atinit and mulle-atexit helpers.

What Is MulleObjC-startup?

MulleObjC-startup is a static library that supplies the mandatory __register_mulle_objc_universe function referenced by the MulleObjC runtime. When linked into an executable, this library ensures the Objective-C universe is properly initialized before your main() function executes. The core implementation resides in src/MulleObjC-startup.m, where the private registration symbol is defined and the bang routine invokes MulleObjCBang to perform the actual universe setup.

Unlike the full Foundation framework, this library provides only the essential startup mechanics, making it ideal for lightweight command-line tools and embedded applications.

Prerequisites and Project Setup

The recommended workflow uses the mulle-sde command-line tool to scaffold a CMake-based project preconfigured for MulleObjC development.

Initialize a new executable project:

mulle-sde init -d my-project -m mulle-objc/objc-developer executable
cd my-project

Enable colorful build output (optional):

mulle-sde vibecoding on

Add the startup library dependency:

mulle-sde add github:mulle-objc/MulleObjC-startup

If you require the complete Foundation stack later, you can additionally add github:mulle-objc/MulleFoundation-startup, though the basic MulleObjC-startup is sufficient for runtime-only executables.

Writing Your Executable Code

Include the public header in your source files to ensure proper registration:

#import <MulleObjC-startup/MulleObjC-startup.h>

A minimal executable looks like this:

#import <MulleObjC-startup/MulleObjC-startup.h>
#include <stdio.h>

int main( int argc, const char * argv[] )
{
   // The universe is automatically registered by the library's constructor
   printf( "Hello from MulleObjC!\n");
   return 0;
}

The runtime registration happens automatically through library constructors, so you do not need to manually invoke initialization functions in your main() routine.

CMake Configuration and Linker Flags

When using mulle-sde, the build system automatically configures the necessary linker flags through the templates in cmake/share/ExecutableObjC.cmake and cmake/share/InstallExecutable.cmake.

The generated CMakeLists.txt links your executable against the startup library:

cmake_minimum_required(VERSION 3.13)

project(my_project C)

add_executable( my_exe src/main.c )
target_link_libraries( my_exe PUBLIC MulleObjC-startup)

The CMake scripts automatically inject platform-specific linker directives:

  • Linux: --export-dynamic to expose symbols for runtime registration
  • macOS: -exported_symbol,__register_mulle_objc_universe to explicitly export the required registration symbol

These flags ensure the __register_mulle_objc_universe symbol remains visible to the dynamic linker during universe initialization.

Build and Run

Compile and link your executable using the standard mulle-sde workflow:

mulle-sde run

Alternatively, invoke CMake directly:

cmake --build . && ./my_exe

During the build process, the system:

  1. Pulls in the MulleObjC-startup static library from your dependencies
  2. Applies the linker flags defined in ExecutableObjC.cmake
  3. Produces an executable with the runtime pre-registered and ready for Objective-C code

Summary

  • MulleObjC-startup is a static library providing the __register_mulle_objc_universe symbol required to boot the MulleObjC runtime
  • Use mulle-sde init to scaffold projects with proper CMake configuration already in place
  • Include MulleObjC-startup/MulleObjC-startup.h to access the runtime registration interface
  • The cmake/share/ExecutableObjC.cmake template automatically handles platform-specific linker flags for symbol export
  • The initialization sequence in src/MulleObjC-startup.m invokes MulleObjCBang to configure the universe before main() executes

Frequently Asked Questions

Do I need to call any initialization functions in my main() function?

No. The MulleObjC-startup library uses constructor attributes to automatically register the universe during dynamic library loading. By including the header and linking the library, the __register_mulle_objc_universe function defined in src/MulleObjC-startup.m executes before your main() function, ensuring the runtime is ready when your code begins executing.

Why does my executable need special linker flags?

The MulleObjC runtime dynamically discovers and registers universes through the __register_mulle_objc_universe symbol. On Linux, --export-dynamic ensures this symbol is visible to the dynamic linker, while macOS requires -exported_symbol,__register_mulle_objc_universe to prevent symbol stripping. The ExecutableObjC.cmake file in the repository provides these flags automatically when using the recommended build system.

Can I use MulleObjC-startup without mulle-sde?

Yes, though you must manually configure your build system to link against the static library and include the appropriate linker flags. Clone the repository, build the library using the provided CMakeLists.txt, then add the library path to your executable's link step. You must also manually apply the platform-specific export flags found in cmake/share/ExecutableObjC.cmake to ensure proper symbol visibility.

What is the difference between MulleObjC-startup and MulleFoundation-startup?

MulleObjC-startup provides only the minimal runtime bootstrap code—the universe registration and basic initialization hooks. MulleFoundation-startup extends this with the full Foundation framework initialization, including standard library classes and utilities. For command-line tools that only need the Objective-C runtime without Foundation classes, MulleObjC-startup is the lighter and faster option.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →