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-dynamicto expose symbols for runtime registration - macOS:
-exported_symbol,__register_mulle_objc_universeto 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:
- Pulls in the MulleObjC-startup static library from your dependencies
- Applies the linker flags defined in
ExecutableObjC.cmake - 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_universesymbol required to boot the MulleObjC runtime - Use
mulle-sde initto scaffold projects with proper CMake configuration already in place - Include
MulleObjC-startup/MulleObjC-startup.hto access the runtime registration interface - The
cmake/share/ExecutableObjC.cmaketemplate automatically handles platform-specific linker flags for symbol export - The initialization sequence in
src/MulleObjC-startup.minvokesMulleObjCBangto configure the universe beforemain()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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →