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

> Discover how Lighthouse handles platform-specific code for Windows, Linux, and macOS. Learn about its CMake-based OS detection and preprocessor guards for cross-platform C/C++ development.

- Repository: [Harbour Masters/Lighthouse](https://github.com/HarbourMasters/Lighthouse)
- Tags: internals
- Published: 2026-08-04

---

**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`](https://github.com/HarbourMasters/Lighthouse/blob/main/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:

```cmake

# 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:

```cmake
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:

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

```

**Linux** — lines 225-240:

```cmake
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):

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

```

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

```cmake
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`](https://github.com/HarbourMasters/Lighthouse/blob/main/src/port/Engine.cpp) (lines 535-566):

```c
#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:

```c
#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`](https://github.com/HarbourMasters/Lighthouse/blob/main/include/portable-file-dialogs.h) demonstrates comprehensive platform branching for UI components:

```c
#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`):

```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`](https://github.com/HarbourMasters/Lighthouse/blob/main/CMakeLists.txt) (lines 74-92):

```cmake
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`](https://github.com/HarbourMasters/Lighthouse/blob/main/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`](https://github.com/HarbourMasters/Lighthouse/blob/main/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.