How to Compile for OS X in Linux or Windows?
Asked Answered
M

10

87

I would like to port my C/C++ apps to OS X.

I don't have a Mac, but I have Linux and Windows. Is there any tool for this?

Meteoroid answered 29/3, 2009 at 1:37 Comment(0)
L
24

There appears to be some scripts that have been written to help get you set up cross compiling for the Mac; I can't say how good they are, or how applicable to your project. In the documentation, they refer to these instructions for cross-compiling for 10.4, and these ones for cross compiling for 10.5; those instructions may be more helpful than the script, depending on how well the script fits your needs.

If your program is free or open source software, then you may wish instead to create a MacPorts portfile (documentation here), and allow your users to build your program using MacPorts; that is generally the preferred way to install portable free or open source software on Mac OS X. MacPorts has been known to run on Linux in the past, so it may be possible to develop and test your Portfile on Linux (though it will obviously need to be tested on a Mac).

Lowminded answered 29/3, 2009 at 1:56 Comment(2)
Or homebrew nowadays instead of macports.Tympany
@jcoffland No, the other way around. It's for building OS X applications on Linux. Read the title. "Cross-Compiling on Linux for Mac OS X 10.3 - 10.5" (emphasis added). Note that this answer is very old by now (almost 7 years old, yikes!) and the later answers below have more up to date information.Lowminded
C
54

For Linux, there is a prebuilt GCC cross-compiler (from publicly available Apple's modified GCC sources).

https://launchpad.net/~flosoft/+archive/cross-apple

Update for 2015

  1. After so many years, the industry-standard IDE now supports OSX/iOS/Android.

http://channel9.msdn.com/Events/Visual-Studio/Connect-event-2014/311

  1. Embarcadero's RadStudio also supports building OSX/iOS/Android apps on Windows.

  2. This answer by Thomas also provides a cross-compilation tool.

For all these options you still need a real mac/i-device to test the application.

Chavers answered 26/4, 2012 at 21:7 Comment(6)
How well does it work? Would it allow compiling Qt for MacOSX for example?Disinclination
It is a perfectly valid GCC 4.2, capable of compiling large libraries. However, it has not been updated for 10.7, 10.8 or 10.9 SDKs, so right now it can be considered as outdated. I've been using it to compile my own project in C/C++ just to test if it can be ported and fix some obvious incompatibilities, then I've built it on the real mac.Chavers
How can I install this on Fedora?Quit
@panzi: I've used it only on CrunchBang (a variant of Debian), maybe you should unpack the .deb archives and try to configure the paths. Or, as usual, try to compile the sources. Maybe this answer provides better alternative now: https://mcmap.net/q/237955/-how-to-compile-for-os-x-in-linux-or-windowsChavers
Unfortunately, although Microsoft announced Visual Studio Connect that supports other compilers including clang, I can't find any information as to how to actually target MacOS.Messidor
Can someone please guide me on how to do cross compiling for MacOS from Windows using gcc or clang llvm?Humanize
G
35

I have created a project called OSXCross which aims to target OS X (10.4-10.9) from Linux.

It currently supports clang 3.2 up to 3.8 (trunk) (you can use your dist's clang).
In addition you can build an up-to-date vanilla GCC as well (4.6+).

LTO works as well, for both, clang and GCC.

Currently using cctools-870 with ld64-242.

https://github.com/tpoechtrager/osxcross

Gametangium answered 10/11, 2013 at 15:6 Comment(1)
I have used your project and it does what it promises. Tested with latest XCode (7.1) and latest OSX (10.11.1).Yawning
L
24

There appears to be some scripts that have been written to help get you set up cross compiling for the Mac; I can't say how good they are, or how applicable to your project. In the documentation, they refer to these instructions for cross-compiling for 10.4, and these ones for cross compiling for 10.5; those instructions may be more helpful than the script, depending on how well the script fits your needs.

If your program is free or open source software, then you may wish instead to create a MacPorts portfile (documentation here), and allow your users to build your program using MacPorts; that is generally the preferred way to install portable free or open source software on Mac OS X. MacPorts has been known to run on Linux in the past, so it may be possible to develop and test your Portfile on Linux (though it will obviously need to be tested on a Mac).

Lowminded answered 29/3, 2009 at 1:56 Comment(2)
Or homebrew nowadays instead of macports.Tympany
@jcoffland No, the other way around. It's for building OS X applications on Linux. Read the title. "Cross-Compiling on Linux for Mac OS X 10.3 - 10.5" (emphasis added). Note that this answer is very old by now (almost 7 years old, yikes!) and the later answers below have more up to date information.Lowminded
A
7
  1. Get "VMware Player"
  2. Get "Mac OS X vm image"
  3. Compile/Debug/Integrate-and-test your code on the new OS to make sure everything works

When you are trying to get something working on multiple platforms you absolutely must compile/run/integrate/test on the intended platform. You can not just compile/run on one platform and then say "oh it should work the same on the other platform".

Even with the a really good cross-platform language like Java you will run into problems where it won't work exactly the same on the other platform.

The only way I have found that respects my time/productivity/ability-to-rapidly iterate on multiple platforms is to use a VM of the other platforms.

There are other solutions like dual-boot and ones that I haven't mentioned but I find that they don't respect my productivity/time.

Take dual-booting as an example:

  1. I make a change on OS 1
  2. reboot into OS 2
  3. forget something on OS 1
  4. reboot into OS 1
  5. make a change on OS 1
  6. reboot into OS 2 ... AGAIN...

BAM there goes 30 minutes of my time and I haven't done anything productive.

Antonina answered 29/3, 2009 at 14:24 Comment(7)
When 3 boots take 30 minutes, you need new hardware; and probably the ability to access and edit one OS's filesystem from another. But I understand the sentiment and also prefer VMs because they allow me to mostly treat them as dedicated physical machines.Southsoutheast
The time taken to reboot isn't just the boot-up time, it's the shut-down time, restarting daemons, setting up your development environment, checking that you still have the most recent checkout from your version control system, etcetera.Belvabelvedere
Not to mention my brain loses all cache-coherency and needs to slowly re-cache everything I need to do... and most likely lose productivity when the web browser opens accidently.Antonina
@MartinKällman it is against the Apple license agreement. Legality of this depends on what country you're in.Swivet
@Swivet fair enough, I just personally find it to be unbefitting of SO :o)Intermission
It may be technically against a random license agreement, but you can always just buy a Mac Pro and run all three OS using VMs on it. So why shouldn't you be able to buy a nice Windows box and do the same? Allowing anything else is anti-competitive practice, and in my books, downright illegal (or it should be).Airboat
Sounds like a job for two computers to be honest. but I appreciate your suggestion. Apple sucks for being a "control freak" against their users and developers. :/Whiteside
H
5

Cross-compiling for Apple on Linux

For this project we will start by compiling LibreSSL. This is chosen because it offers a CMake build option and should generate a library, static and shared, from C-source that is generally cross-platform that will serve as a demonstration that it can be done.

Xcode SDKs

Xcode is Apple's toolchain and IDE. We however only need to grab the SDKs out of the bundle. Assuming you have access to a Mac with the Xcode you can quickly grab out the SDKs.

To determine which SDK version of for example iphoneos, iphonesimulator, or macosx you use xcrun.

% xcrun --sdk macosx --show-sdk-version
13.3

And where is Xcode installed?

% xcode-select --print-path
/Applications/Xcode.app/Contents/Developer

What platforms are available?

% ls -1 $(xcode-select --print-path)/Platforms
AppleTVOS.platform
AppleTVSimulator.platform
DriverKit.platform
MacOSX.platform
WatchOS.platform
WatchSimulator.platform
iPhoneOS.platform
iPhoneSimulator.platform

Then the SDKs for let's say iphoneos is in

% ls -1 $(xcode-select --print-path)/Platforms/MacOSX.platform/Developer/SDKs
MacOSX.sdk
MacOSX13.3.sdk
MacOSX13.sdk

The contents of MacOSX13.3.sdk (a symlink to MacOSX.sdk) are what will be referred to as Sysroot. Inside this folder you will find header files and TBDs (Text-based Definitions, which are YAML based stub libraries) that you compile and link against. These TBDs save a lot of space since the alternative might be shipping all of the various versions of the binaries. I created a tool to grab these SDKs out of an installed version of Xcode and create a gzipped tarball for convenience.

SDK Packager can be downloaded from GitHub

Move the tarball to your linux machine in any manner you see fit.

Building Clang/LLVM

Compiling Clang and LLVM on Linux is fairly straightforward. After checking out the project and switching to branch llvmorg-15.0.7 I created a script called build.sh in the root of the source directory.

#!/bin/bash

set -ex

function join_by { local IFS="$1"; shift; echo "$*"; }

PROJECTS=( clang lld clang-tools-extra ) 
RUNTIMES=( libcxx libcxxabi )
TARGETS=( X86 ARM AArch64 ) 

SOURCE_DIR=$( pwd )
BUILD_DIR=${SOURCE_DIR}/builddir
DIST_DIR=${SOURCE_DIR}/dist

rm -rf ${BUILD_DIR} ${DIST_DIR}
mkdir -p ${BUILD_DIR}
pushd ${BUILD_DIR}

cmake \
    -G Ninja \
    -D CMAKE_BUILD_TYPE=Release \
    -D CMAKE_INSTALL_PREFIX=${DIST_DIR} \
    -D CMAKE_VERBOSE_MAKEFILE=on \
    -D LLVM_TARGETS_TO_BUILD=$(join_by ";" "${TARGETS[@]}") \
    -D LLVM_ENABLE_PROJECTS=$(join_by ";" "${PROJECTS[@]}") \
    -D LLVM_ENABLE_RUNTIMES=$(join_by ";" "${RUNTIMES[@]}") \
    ${SOURCE_DIR}/llvm

cmake --build .
cmake --build . --target install

popd

Building Apple's cctools

Apple has a few 'special' tools that are used for manipulating binaries that are separate from those shipped with Clang/LLVM. Fortunately, these tools are open-source and the necessary porting work has been done. They are available at

Build libtapi and libxar first then build cctools.

#!/bin/bash

set -ex

./configure \
    --prefix=${HOME}/cctools \
    --with-libtapi=${HOME}/cctools \
    --with-libxar=${HOME}/cctools \
    --with-llvm-config=${HOME}/Development/llvm-project/dist/bin/llvm-config

make -j8
make install

The tools we need are ar, install_name_tool, libtool, lipo, ranlib, and ld. I suspect this additional step is no longer needed in part or in its entirety, but for this version of the tutorial we will stick with them.

Add the installed bin directory to your search path.

PATH=${HOME}/cctools/bin:${PATH}

Building LibreSSL for macOS

We will start by building for LibreSSL macOS for x86 and arm so we can run the 'apps' that ship with LibreSSL so we can prove it works.

It is not practical to check out LibreSSL from git since the project is not in the form of a release per se and relies upon OpenBSD. Hence, the tarball.

Download https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.7.2.tar.gz

Below is a bash script example on how to compile LibreSSL. Two additional files, the toolchain and launcher script follow.

#!/bin/bash

 APPLE_SDK_SYSROOT="${HOME}/Development/apple_sdks/MacOSX13.3.sdk"
LLVM_DIST="${HOME}/Development/llvm-project/dist"
CCTOOLS_DIST="${HOME}/cctools"

SOURCE_DIR=$( pwd )
BUILD_DIR=${SOURCE_DIR}/builddir
INSTALL_DIR=${SOURCE_DIR}/dist
CMAKE_DIR=${SOURCE_DIR}/cmake

rm -rf ${BUILD_DIR} ${DIST_DIR}
mkdir -p ${BUILD_DIR}
pushd ${BUILD_DIR}
    cmake \
        -G Ninja \
        -D CMAKE_VERBOSE_MAKEFILE=on \
        -D CMAKE_TOOLCHAIN_FILE=${CMAKE_DIR}/macosx.toolchain.cmake \
        -D LINKER_LAUNCHER=${SOURCE_DIR}/launcher.sh \
        -D LLVM_DIST=${LLVM_DIST} \
        -D CCTOOLS_DIST=${CCTOOLS_DIST} \
        -D APPLE_SDK_SYSROOT=${APPLE_SDK_SYSROOT} \
        -D CMAKE_INSTALL_PREFIX=${INSTALL_DIR} \
        -D BUILD_SHARED_LIBS=OFF \
        -D LIBRESSL_APPS=YES \
        -D LIBRESSL_TESTS=NO \
        ${SOURCE_DIR}
    cmake --build .
    cmake --build . --target install
popd

One of the truly great things about Clang/LLVM and CMake is the ease with which you can generate a cross-compiled build. The key component in cross-compiled builds is the CMake toolchain file. Most developers are used to installing a compiler / IDE environment like Xcode and relying 100% on the IDE to know how compilation and linking occurs. However, compiling without this environment is possible.

Using shared libraries AKA dylibs

If you decide to enable BUILD_SHARED_LIBS you will need to codesign the binaries and dylibs in order for them to run.

codesign -f -s - bin/openssl
for LIB in lib/*.dylib; do
    codesign -f -s - $LIB
done

When building the dylib version of the libraries you normally would adhere to some conventions regarding where the dynamic linker will look for them. In this case we will need to clue dyld into where they live since we don't want to install our experiment into /usr/local/lib or /usr/lib. On a Mac we use the DYLD_LIBRARY_PATH variable.

DYLD_LIBRARY_PATH=$(pwd)/lib; export DYLD_LIBRARY_PATH

The linker launcher

We use a tiny shell script to append the path to the linker

#!/bin/bash

set -ex

# -fuse-ld=/path/to/ld if pre-clang 12
"$@" --ld-path=${HOME}/cctools/bin/ld

The toolchain file

The compiler flag -arch x86_64 -arch arm64 is what convinces clang to create, in this case, a FAT Mach-O binary with x86_64 and arm64 architectures. The triple will then be generated in two invocations of clang (behind the scenes) and then lipo called to combine the objects.

cmake_minimum_required(VERSION 3.16)

# APPLE_SDK_SYSROOT, LLVM_DIST, CCTOOLS_DIST, LINKER_LAUNCHER

set(SDK_NAME macosx)
list(APPEND ARCHS x86_64 arm64)
set(DEPLOYMENT_TARGET "10.13")

# If you want clang to output universal binaries you must use
# multiple -arch flags. Doing so results in clang calling 
# itself multiple times with different target triples. Finally,    
# it will call lipo to combine the two object files into one.  
# Clang also complains if you don't use -isysroot on these
# Apple SDK builds. This leaves -m<sdk>-version-min=x.xx. 
# You can cover it in the triple or pass them through 
# CMAKE_OSX_DEPLOYMENT_TARGET to generate the version min 
# string. The target triple is necessary if you want to build
# Mac Catalyst and you'll need to add -macabi to the end of the
# triple and it will look like <arch>-apple-ios<version>-macabi
set(CMAKE_SYSTEM_NAME Darwin) # iOS if you're iOS or Simulator
set(CMAKE_OSX_SYSROOT "${APPLE_SDK_SYSROOT}" CACHE PATH "")
set(CMAKE_OSX_DEPLOYMENT_TARGET ${DEPLOYMENT_TARGET})
set(CMAKE_OSX_ARCHITECTURES ${ARCHS})

list(JOIN ARCHS "-" ARCHS_DASH)
set(APPLE_TARGET_TRIPLE ${ARCHS_DASH}-apple-${SDK_NAME}${DEPLOYMENT_TARGET})
set(CMAKE_C_COMPILER_TARGET ${APPLE_TARGET_TRIPLE})
set(CMAKE_ASM_COMPILER_TARGET ${APPLE_TARGET_TRIPLE})

set(CMAKE_C_COMPILER ${LLVM_DIST}/bin/clang CACHE FILEPATH "")

set(CMAKE_C_LINKER_LAUNCHER ${LINKER_LAUNCHER} CACHE FILEPATH "")
set(CMAKE_AR ${CCTOOLS_DIST}/bin/ar CACHE FILEPATH "" FORCE)
set(CMAKE_RANLIB ${CCTOOLS_DIST}/bin/ranlib CACHE FILEPATH "" FORCE)
set(CMAKE_STRIP ${CCTOOLS_DIST}/bin/strip CACHE FILEPATH "" FORCE)
set(BUILD_LIBTOOL ${CCTOOLS_DIST}/bin/libtool CACHE FILEPATH "")

set(CMAKE_INSTALL_NAME_TOOL ${CCTOOLS_DIST}/bin/install_name_tool CACHE FILEPATH "")
set(CMAKE_C_CREATE_STATIC_LIBRARY "${BUILD_LIBTOOL} -static -o <TARGET> <LINK_FLAGS> <OBJECTS> " CACHE INTERNAL "")

Testing with the OpenSSL command-line tool

Zip up and copy the install directory to a Mac and you can then test the binaries to see if they work.

The simplest thing to do is to output the -help, but for a more interesting test we can dump the DERs from an existing .app bundle and then pretty print them.

codesign -d --extract-certificates MyApp.app
/path/to/openssl x509 -inform der -in codesign0 -text
Heall answered 5/5, 2023 at 14:30 Comment(7)
thanks a lot @Cameron ! following your steps I get is when building with clang "not able to compile a simple test program." . With ld: library not found for -lSystem. Do you have an idea of what could be missing ?Marrero
Yes - it is missing -lSystem. Which is a Framework and that is in the Apple SDK. Did you set APPLE_SDK_SYSROOT correctly?Heall
Yes, I unziped th macOSX13.3.sdk , and made sure that CMAKE_OSX_SYSROOT point to the folder, both in the macosx.toolchain.cmake , and build script calling cmake. If I put a wrong path, I get 2 errors instead of 1: "ld: warning: directory not found for option '-F/System/Library/Frameworks/'" and " ld: library not found for -lSystem "Marrero
I noticed an error @EtienneSalimbeni and have updated the answerHeall
Many many thanks for this recipe. A small update for LLVM 17: target ARM is redundant (Aarch64 already results in arm64 being built) and Apple tools are no longer needed. You may want to add the libc runtime also. I didn't build LibreSSL, only a small test executable with path/to/new/clang -isysroot path/to/MacOSX.sdk -target arm64-apple-darwin23 -fuse-ld=lld -o app main.c. I don't know why MacOSX 14 = darwin23, but this was the triple that my M1 MacBook gave me.Sevenfold
Typically the triple is constructed by virtue of detection that clang is a mach-o binary, the -arch flags and -whatever_os_version_min.Heall
And Darwin is the kernel, macOS is the whole thing in marketing termsHeall
S
3

You will definitely need OS X somehow. Even if you don't own a Mac, you can still try some alternatives.

Seraglio answered 29/3, 2009 at 1:50 Comment(0)
S
3

You would need a toolchain to cross compile for mach-o, but even if you had that, you won't have the Apple libraries around to develop with. I'm not sure how you would be able to port without them, unfortunately.

Saldivar answered 29/3, 2009 at 1:52 Comment(2)
If you have the cross toolchain, you can simply copy the libs from OS X.Submerged
Copying is the way to go, though you'll need the headers/staticlibs too.Abisia
A
3

Apple development is a strange beast unto itself. OS X uses a port of GCC with some modifications to make it 'appley'. In theory, it's possible to the the sources to the Apple GCC and toolchain as well as the Apple kernel and library headers and build a cross compiler on your Windows machine.

Why you'd want to go down this path is beyond me. You can have a cheap Mac mini from $600. The time you invest getting a cross compiler working right (particularly with a Windows host for Unix tools) will probably cost more than the $600 anyway.

If you're really keen to make your app cross platform look into Qt, wxWidgets or FLTK. All provide cross-platform support with minimal changes to the base code. At least that way all you need to do is find a Mac to compile your app on, and that's not too hard to do if you have some technically minded friends who don't mind giving you SSH access to their Mac.

Aseity answered 29/3, 2009 at 2:26 Comment(3)
I have access to many Windows machines. Yet I prefer to generate the Windows binary at the same time I build for Linux. Of course then the program must be tested on Windows, but it's very convenient to see that the program at least builds for all targeted platforms in one step.Tympany
Not to mention you may not have a Mac, but be interested in allowing others (who want to use your application on a mac) to test the application, without having to compile it themselves.Airboat
I thought it worth noting that Apple no longer uses GCC in XCode, they now use Clang/LLVM.Circumnavigate
S
2

I found this small documentation on the net: http://devs.openttd.org/~truebrain/compile-farm/apple-darwin9.txt

This describes exactly what you want. I am interested in it myself, haven't tested it yet though (found it 10 minutes ago). The documentation seems good, though.

Smaragdine answered 8/5, 2009 at 11:47 Comment(1)
Your link is brokenHeall
T
2

You can hire a mac in the cloud from this website. You can hire them from $1, which should be enough (unless you need root access, then you are looking at $49+).

Tanto answered 17/12, 2014 at 15:56 Comment(2)
This assumes, though, that one wants to copy ones sources to some machine "in the cloud". Quite an assumption for non-FLOSS.Yukoyukon
Not very long term. After using it 30 times it would be cheaper to buy a mac.Greff

© 2022 - 2024 — McMap. All rights reserved.