How Lighthouse Handles Platform-Specific Code for Windows, Linux, and macOS Development

Lighthouse uses CMake-based OS detection combined with preprocessor guards in source files to build a single cross-platform C/C++ codebase that adapts to Windows, Linux, and macOS targets.

This article examines how the HarbourMasters/Lighthouse repository manages platform-specific code across three major desktop operating systems. Whether you're targeting MSVC on Windows, Clang on macOS, or GCC on Linux, Lighthouse demonstrates a proven pattern for keeping cross-platform projects maintainable.

CMake OS Detection and Build Configuration

The foundation of Lighthouse's platform handling lives in the root CMakeLists.txt file. This build script detects the target operating system at configure time and sets up the appropriate toolchain, compiler flags, and linked libraries.

Platform-Specific Language Support

Lighthouse enables Objective-C++ for Apple platforms, which allows mixing C++ with Cocoa framework calls:


# From CMakeLists.txt lines 12-15

if(APPLE)
    enable_language(OBJCXX)
endif()

This single conditional ensures that .mm files compile correctly on macOS and iOS targets without breaking builds on other platforms.

Compiler and Linker Flags by Platform

The build system applies distinct flag sets for each target:

Windows (MSVC) — lines 27-33:

if(MSVC)
    add_compile_options(/W4 /WX- /MP /MT)
    add_definitions(-DWIN32_LEAN_AND_MEAN -DNOMINMAX)
endif()

The /MT flag statically links the C runtime, while WIN32_LEAN_AND_MEAN reduces Windows header bloat.

macOS/iOS — lines 181-190:

if(APPLE)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20 -stdlib=libc++")
    set(CMAKE_MACOSX_RPATH ON)
endif()

Linux — lines 225-240:

if(UNIX AND NOT APPLE)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
    find_library(DL_LIBRARY dl)
    target_link_libraries(${PROJECT_NAME} ${DL_LIBRARY})
endif()

These conditionals ensure each platform receives appropriate threading support, runtime linking, and standard library configurations.

Platform-Specific Library Dependencies

Lighthouse pulls in different external libraries depending on the target OS. This prevents unnecessary dependencies and simplifies packaging.

Windows dependencies (lines 46-52):

if(WIN32)
    find_package(Ogg REQUIRED)
    find_package(Vorbis REQUIRED)
    find_package(SDL2_net REQUIRED)
endif()

Linux/macOS shared dependencies (lines 78-88):

if(NOT WIN32)
    find_package(PkgConfig REQUIRED)
    pkg_check_modules(OGG ogg REQUIRED)
    pkg_check_modules(VORBIS vorbisfile REQUIRED)
endif()

The Windows path uses CMake's native find_package, while Unix platforms leverage pkg-config for system library discovery.

Preprocessor Guards in Source Code

When source code must call OS-specific APIs, Lighthouse uses standard preprocessor conditionals. This keeps platform-specific logic adjacent in the same file rather than scattered across the codebase.

Windows-Specific Implementation

From src/port/Engine.cpp (lines 535-566):

#ifdef _WIN32
#include <windows.h>

void SetHighDPIAwareness() {
    // Windows Vista and later
    typedef BOOL (WINAPI *SetProcessDPIAwareFunc)(void);
    HMODULE hUser32 = GetModuleHandleA("user32.dll");
    if (hUser32) {
        SetProcessDPIAwareFunc setDPIAware = 
            (SetProcessDPIAwareFunc)GetProcAddress(hUser32, "SetProcessDPIAware");
        if (setDPIAware) {
            setDPIAware();
        }
    }
}
#endif

This pattern gracefully degrades on older Windows versions while enabling crisp rendering on high-DPI displays.

macOS-Specific Cocoa Integration

Objective-C++ files use __APPLE__ guards for framework calls:

#if defined(__APPLE__)
#import <Cocoa/Cocoa.h>

void ShowPlatformAlert(const char* message) {
    NSAlert* alert = [[NSAlert alloc] init];
    [alert setMessageText:[NSString stringWithUTF8String:message]];
    [alert runModal];
    [alert release];
}
#endif

The enable_language(OBJCXX) CMake directive makes this compilation possible.

Portable File Dialog Abstraction

The header include/portable-file-dialogs.h demonstrates comprehensive platform branching for UI components:

#if _WIN32
    // Use COM-based IFileDialog on Windows Vista+
    #include <windows.h>
    #include <shobjidl.h>
    
    class file_dialog {
        IFileDialog* dialog;
        // Windows implementation...
    };
#elif __APPLE__
    // Use Cocoa NSOpenPanel/NSSavePanel
    #import <Cocoa/Cocoa.h>
    
    class file_dialog {
        // macOS implementation...
    };
#else
    // Use GTK3 or zenity fallback on Linux
    #include <gtk/gtk.h>
    // Linux implementation...
    };
#endif

This single header provides a unified C++ API while encapsulating three completely different native dialog implementations.

Cross-Compilation Toolchains

Lighthouse supports building for non-native targets through dedicated toolchain files.

MinGW Windows cross-compile (cmake/toolchain-x86_64-w64-mingw32.cmake):

set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++)
set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32)

iOS/macOS unified toolchain (cmake/ios.toolchain.cmake):

  • Sets CMAKE_SYSTEM_NAME to iOS or Darwin
  • Configures code signing and bundle identifiers
  • Enables bitcode and thinning for App Store submission

These toolchains let developers build Windows binaries from Linux hosts or iOS binaries from macOS CI runners.

Post-Build Platform Packaging

The final stage adapts output artifacts to platform conventions. The cmake/packaging.cmake module handles:

Platform Output Format Key Step
Windows .zip with .exe Copy SDL2.dll and asset folder beside executable
macOS .app bundle Generate Info.plist, embed iconset, code sign
Linux AppImage or tarball linuxdeploy integration for portable binaries

macOS icon generation from CMakeLists.txt (lines 74-92):

if(APPLE)
    set(MACOSX_BUNDLE_ICON_FILE lighthouse.icns)
    set_source_files_properties(${ICON_PATH} PROPERTIES 
        MACOSX_PACKAGE_LOCATION Resources)
endif()

Summary

  • CMake OS detection (WIN32, APPLE, UNIX) drives conditional configuration in CMakeLists.txt
  • Preprocessor guards (#ifdef _WIN32, #ifdef __APPLE__, #ifdef __linux__) isolate OS-specific API calls in source files
  • Objective-C++ enablement on Apple platforms permits native Cocoa integration without breaking other builds
  • Separate toolchain files support cross-compilation scenarios including MinGW and iOS
  • Packaging automation produces platform-native distribution formats from a single build pipeline

Frequently Asked Questions

How does Lighthouse detect which platform it's building for?

CMake sets automatic variables based on the target system: WIN32 for Windows, APPLE for macOS/iOS, and UNIX (with NOT APPLE) for Linux and other Unix variants. These appear throughout CMakeLists.txt to branch configuration logic.

Can Lighthouse be built on Linux for Windows targets?

Yes. The repository includes cmake/toolchain-x86_64-w64-mingw32.cmake which configures MinGW-w64 cross-compilation. Run cmake -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-x86_64-w64-mingw32.cmake .. from a Linux host to produce Windows binaries.

Why does Lighthouse use preprocessor guards instead of separate source files?

Adjacent code in the same file improves maintainability—developers see all platform variants of a function together. Guards also minimize file count and ensure API consistency across implementations. Only substantial platform subsystems (like the portable-file-dialogs abstraction) warrant separate headers.

Does Lighthouse support iOS in addition to macOS?

Yes. The cmake/ios.toolchain.cmake file configures iOS builds, and the same __APPLE__ guards in source code cover both macOS and iOS. The CMake APPLE variable is true for both platforms, with additional IOS checks where differentiation matters.

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 →