Writing CMake-based Tests for mulle-objc on Windows

· nat's blog


If you're writing CMake-based tests for mulle-objc and targeting Windows, there are a few gotchas that may bite you. Here's some tips to have it easy in a MulleObjC/mulle-sde based test suite.

The _mulle_atinit is not available yet Problem #

When building Windows executables that link against mulle-objc DLLs, may have DLLs trying to call _mulle_atinit (which lives in the executable) but they fail with:

_mulle_atinit is not available yet, bummer

Possibly followed by a universe initialization crash. Not fun.

The Solution: Export Your Symbols #

On Windows, executables need to explicitly export symbols that DLLs will call. Add this to your CMakeLists.txt:

1# Export symbols needed for Windows DLL dynamic linking
2if( WIN32)
3   target_link_options( your-test.exe
4      PUBLIC
5         "-Wl,--export-all-symbols"
6   )
7endif()

This exports _mulle_atinit, _mulle_atexit, and ___register_mulle_objc_universe so DLLs can find them during initialization.

Enable TAO for Debug Builds #

If you're testing in Debug you are testing with Thread Affine Objects (TAO), make sure to enable the flag for Debug builds:

1if( CMAKE_BUILD_TYPE MATCHES "^Debug|^Test")
2   target_compile_options( your-test.exe PRIVATE -fobjc-tao)
3   message( STATUS "TAO enabled via compiler flag")
4endif()

Complete CMakeLists.txt Template #

Here's a minimal working example:

 1cmake_minimum_required( VERSION 3.13...99.99)
 2
 3set(CMAKE_C_COMPILER_WORKS 1)
 4
 5project( your-test C)
 6
 7set( SOURCES
 8   main.m
 9   Foo.m
10)
11
12add_executable( your-test.exe
13   ${SOURCES}
14)
15
16# Enable TAO for Debug/Test builds
17if( CMAKE_BUILD_TYPE MATCHES "^Debug|^Test")
18   target_compile_options( "your-test.exe" PRIVATE -fobjc-tao)
19   message( STATUS "TAO enabled via compiler flag")
20endif()
21
22# Link against test libraries
23target_link_libraries( your-test.exe
24   ${TEST_LIBRARIES}
25)
26
27# Export symbols for Windows DLL dynamic linking
28if( WIN32)
29   target_link_options( your-test.exe
30      PUBLIC
31         "-Wl,--export-all-symbols"
32   )
33endif()

File Structure #

Place your CMake test in the test directory:

test/
  test-category/
    your-test/
      CMakeLists.txt
      main.m
      Foo.m
      Foo.h
      your-test.stdout    # Expected output

The test name comes from the CMake project name, not the directory name.

Why This Matters #

Without proper symbol exports, Windows DLLs can't find the initialization functions they need. The runtime tries to use mulle_dlsym_exe() to locate _mulle_atinit, but if it's not exportedy.

On Linux/macOS, this "just works" because of different dynamic linking semantics. Windows requires explicit exports.

Testing #

Run your test with:

1cd test && mulle-sde test run --platform windows YourCategory/your-test/your-test

Or for the full suite:

1cd test && mulle-sde test run --platform windows

The Gotcha #

If you see TAO mismatch errors like:

the runtime is compiled for thread affine objects -fobjc-tao, 
but these objects are compiled -fno-objc-tao

You forgot to enable TAO for Debug builds. Add the target_compile_options block above.

This text is mostly AI written, with some edits

last updated: