如何在Linux或Windows中编译OS X?

Unk*_*own 68 c c++ macos cross-compiling

我想将我的C/C++应用程序移植到OS X.

我没有Mac,但我有Linux和Windows.这有什么工具吗?

Vik*_*pov 48

对于Linux,有一个预构建的GCC交叉编译器(来自公开提供的Apple修改后的GCC源代码).

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

2015年更新

  1. 经过这么多年,行业标准IDE现在支持OSX/iOS/Android.

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

  1. Embarcadero的RadStudio还支持在Windows上构建OSX/iOS/Android应用程序.

  2. 答案托马斯还提供了一个交叉编译工具.

对于所有这些选项,您仍然需要一个真正的mac/i设备来测试应用程序.

  • 它是一个完全有效的GCC 4.2,能够编译大型库.但是,它尚未针对10.7,10.8或10.9 SDK进行更新,因此现在可以将其视为过时的.我一直用它来编译我自己的C/C++项目,只是为了测试它是否可以被移植并修复一些明显的不兼容性,然后我在真正的mac上构建它. (4认同)
  • 效果如何?例如,它是否允许为 MacOSX 编译 Qt? (2认同)

Tho*_*mas 28

我创建了一个名为OSXCross的项目,旨在从Linux中定位OS X(10.4-10.9).

它目前支持clang3.2到3.8(主干)(你可以使用你的dist clang).
此外,您还可以构建最新的香草GCC(4.6+).

LTO也适用于两者clangGCC.

目前使用cctools-870和ld64-242.

https://github.com/tpoechtrager/osxcross


Bri*_*ell 22

似乎已经编写了一些脚本来帮助您为Mac设置交叉编译; 我不能说它们有多好,或者对你的项目有多适用.在文档中,他们参考了10.4的交叉编译这些指令,以及这些指令用于交叉编译10.5; 这些说明可能比脚本更有用,具体取决于脚本符合您的需求的程度.

如果您的程序是免费或开源软件,那么您可能希望创建一个MacPorts端口文件(此处的文档),并允许您的用户使用MacPorts构建您的程序; 这通常是在Mac OS X上安装便携式免费或开源软件的首选方式.过去已知MacPorts可以在Linux上运行,所以有可能在Linux上开发和测试你的Portfile(虽然它显然需要在Mac上测试).

  • 或者现在自制软件而不是macports. (11认同)

Tre*_*ith 6

  1. 获取" VMware Player "
  2. 获取" Mac OS X vm image "
  3. 在新操作系统上编译/调试/集成并测试您的代码,以确保一切正常

当您尝试在多个平台上运行时,您必须在目标平台上编译/运行/集成/测试.你不能只在一个平台上编译/运行然后说"哦,它应该在另一个平台上工作相同".

即使使用像Java这样非常好的跨平台语言,您也会遇到问题,而在其他平台上它将无法完全相同.

我发现尊重我的时间/生产力/能力以在多个平台上快速迭代的唯一方法是使用其他平台的VM.

还有其他解决方案,如双启动和我没有提到的解决方案,但我发现它们不尊重我的生产力/时间.

以双启动为例:

  1. 我在OS 1上做了一个改变
  2. 重启进入OS 2
  3. 忘了OS 1上的东西
  4. 重启进入OS 1
  5. 在OS 1上进行更改
  6. 重新启动到OS 2 ... 再次 ...

BAM有30分钟的时间,我没有做任何有成效的事情.

  • 更不用说我的大脑失去了所有缓存一致性,需要慢慢重新缓存我需要做的所有事情......而且当Web浏览器意外打开时,很可能会失去工作效率. (12认同)
  • 重启所花费的时间不仅仅是启动时间,关闭时间,重启守护进程,设置开发环境,检查您是否还有最新的版本控制系统结账等等. (11认同)
  • 它可能在技术上违反随机许可协议,但您可以随时购买Mac Pro并使用其上的VM运行所有三个操作系统.那么为什么你不能买一个漂亮的Windows盒子并做同样的事情呢?允许其他任何事情都是反竞争的做法,在我的书中,完全是非法的(或应该是). (6认同)
  • 当3个靴子需要30分钟时,你需要新的硬件; 并且可能是从另一个操作系统访问和编辑一个操作系统文件系统的能力.但我理解这种观点并且更喜欢VM,因为它们允许我将它们视为专用物理机器. (4认同)
  • @MartinKällman它违反了Apple许可协议.合法性取决于您所在的国家/地区. (3认同)

Cam*_*mer 5

Linux 上 Apple 的交叉编译

对于这个项目,我们将从编译 LibreSSL 开始。之所以选择它,是因为它提供了 CMake 构建选项,并且应该从 C 源代码生成一个静态和共享的库,该库通常是跨平台的,这将作为可以完成的演示。

Xcode SDK

Xcode 是Apple 的工具链和IDE。然而,我们只需要从捆绑包中获取 SDK。假设您可以使用 Xcode 访问 Mac,您可以快速获取 SDK。

要确定您使用 xcrun 的 SDK 版本,例如 iphoneos、iphonesimulator 或 macosx。

% xcrun --sdk macosx --show-sdk-version
13.3
Run Code Online (Sandbox Code Playgroud)

Xcode 安装在哪里?

% xcode-select --print-path
/Applications/Xcode.app/Contents/Developer
Run Code Online (Sandbox Code Playgroud)

有哪些平台可用?

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

然后假设 iphoneos 的 SDK 就在

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

MacOSX13.3.sdk(到 的符号链接)的内容MacOSX.sdk将被称为 Sysroot。在此文件夹中,您将找到您编译和链接的头文件和 TBD(基于文本的定义,它们是基于 YAML 的存根库)。这些 TBD 节省了大量空间,因为替代方案可能是传送所有不同版本的二进制文件。为了方便起见,我创建了一个工具来从已安装的 Xcode 版本中获取这些 SDK,并创建一个 gzip 压缩包。

SDK打包器可以从GitHub下载

以您认为合适的任何方式将 tarball 移至您的 Linux 计算机。

构建 Clang/LLVM

在 Linux 上编译 Clang 和 LLVM 相当简单。检查项目并切换到分支后,llvmorg-15.0.7我创建了一个build.sh在源目录的根目录中调用的脚本。

#!/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
Run Code Online (Sandbox Code Playgroud)

构建 Apple 的 cctools

Apple 有一些“特殊”工具,用于操作与 Clang/LLVM 附带的二进制文件不同的二进制文件。幸运的是,这些工具都是开源的,并且已经完成了必要的移植工作。它们可以在

构建libtapilibxar首先构建 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
Run Code Online (Sandbox Code Playgroud)

我们需要的工具是ar、、、、、和。我怀疑不再部分或全部需要这个额外的步骤,但对于本版本的教程,我们将坚持使用它们。install_name_toollibtoolliporanlibld

将安装的 bin 目录添加到您的搜索路径。

PATH=${HOME}/cctools/bin:${PATH}
Run Code Online (Sandbox Code Playgroud)

为 macOS 构建 LibreSSL

我们将从为 x86 和 arm 构建 LibreSSL macOS 开始,这样我们就可以运行 LibreSSL 附带的“应用程序”,从而证明它是有效的。

从 git 查看 LibreSSL 是不切实际的,因为该项目本身并不是发行版的形式,而是依赖于 OpenBSD。因此,压缩包。

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

以下是有关如何编译 LibreSSL 的 bash 脚本示例。接下来是两个附加文件,即工具链和启动器脚本。

#!/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
Run Code Online (Sandbox Code Playgroud)

Clang/LLVM 和 CMake 真正伟大的事情之一是您可以轻松生成交叉编译的构建。交叉编译构建中的关键组件是 CMake 工具链文件。大多数开发人员习惯于安装像 Xcode 这样的编译器/IDE 环境,并 100% 依赖 IDE 来了解编译和链接是如何发生的。但是,在没有此环境的情况下进行编译也是可能的。

使用共享库(又名 dylib)

如果您决定启用,BUILD_SHARED_LIBS则需要对二进制文件和 dylib 进行协同设计才能运行。

codesign -f -s - bin/openssl
for LIB in lib/*.dylib; do
    codesign -f -s - $LIB
done
Run Code Online (Sandbox Code Playgroud)

在构建dylib库的版本时,您通常会遵守一些关于动态链接器将在何处查找它们的约定。在这种情况下,我们需要了解dyld它们的位置,因为我们不想将实验安装到/usr/local/lib或中/usr/lib。在 Mac 上我们使用该DYLD_LIBRARY_PATH变量。

DYLD_LIBRARY_PATH=$(pwd)/lib; export DYLD_LIBRARY_PATH
Run Code Online (Sandbox Code Playgroud)

链接器启动器

我们使用一个小型 shell 脚本将路径附加到链接器

#!/bin/bash

set -ex

# -fuse-ld=/path/to/ld if pre-clang 12
"$@" --ld-path=${HOME}/cctools/bin/ld
Run Code Online (Sandbox Code Playgroud)

工具链文件

在本例中,编译器标志-arch x86_64 -arch arm64说服 clang 创建具有 x86_64 和 arm64 架构的 FAT Mach-O 二进制文件。然后,将通过两次 clang 调用(在幕后)生成三元组,然后调用 lipo 来组合对象。

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 "")
Run Code Online (Sandbox Code Playgroud)

使用 OpenSSL 命令行工具进行测试

压缩并将安装目录复制到 Mac,然后您可以测试二进制文件以查看它们是否有效。

最简单的做法是输出 .app 文件-help,但为了进行更有趣的测试,我们可以从现有的 .app 包中转储 DER,然后漂亮地打印它们。

codesign -d --extract-certificates MyApp.app
/path/to/openssl x509 -inform der -in codesign0 -text
Run Code Online (Sandbox Code Playgroud)