Cross Compile Darwin Target Under Linux Troubleshooting

Cross Compile Darwin Target Under Linux Troubleshooting

之前为了方便解密客户端日志,我基于 https://github.com/Tencent/mars/tree/master/mars/xlog/crypt/decode_log_file_c_impl 写了个简单的命令行工具 xlog-decode

这个工具很简单, 就是支持递归地解密当前目录及其下所有的 xlog 文件 (由于是公司项目,因此 xlog 文件的后缀是统一且固定的)。

foo/xxx.xlog 会自动解密在同级目录下,变成 foo/xxx.xlog.log

最近一次编译还是几年前,这不有童鞋需要我给他编译一个 Mac (Intel CPU版) 版的(ps: 我是 Linux 用户),于是有了这个文章。

原本,这应该也是一个一两分钟的活儿, 不过最终折腾的结果是花了接近2个小时。

原来的 CMakeLists.txt 如下:

cmake_minimum_required (VERSION 3.0)
project (xlog-decode)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -ggdb")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lz")

# for log
add_definitions(-DLOG_USE_COLOR)

add_definitions(-DBUILD_SHARED_LIBS=OFF)

# for zstd
# option(ZSTD_BUILD_STATIC "BUILD STATIC LIBRARIES" ON)
# option(ZSTD_BUILD_SHARED "BUILD SHARED LIBRARIES" OFF)

include(GNUInstallDirs)

add_executable(xlog-decode main.c log.c micro-ecc-master/uECC.c)
target_link_libraries(xlog-decode zstd z)

Makefile 主要是方便编译的脚本 (没错,当时我主力还是 ArchLinux, 还没怎么用 Fedora. paru! paru!):

build:
	cmake -B build .
	cd build && make

deps/arch:
	paru -S --needed zstd

deps/ubuntu:
	apt install -y make cmake g++ gcc zlib1g-dev zlib1g libzstd-dev libzstd1

install: build
	install -vD -m 755 build/xlog-decode /usr/local/bin/xlog-decode

clean:
	-rm -rf ./build

这两个文件都没啥问题。

然后我有一个 mac.sh 用于执行 Mac 交叉编译的:

mac.sh
#!/usr/bin/env bash

set -eou pipefail


# Don't forget to adjust this to your standalone toolchain path
export TOOLCHAIN_PATH=/usr/local/darwin-ndk-x86_64

# There should be no need to edit anything between this line and the next
# -----------------------------------------------------------------------
export CROSS_COMPILE=x86_64-apple-darwin22.2
export CROSS_PATH=${TOOLCHAIN_PATH}/bin
# Set the compiler and linker
export CPP=${CROSS_PATH}/${CROSS_COMPILE}-c++
export AR=${CROSS_PATH}/${CROSS_COMPILE}-ar
export AS=${CROSS_PATH}/${CROSS_COMPILE}-as
export NM=${CROSS_PATH}/${CROSS_COMPILE}-nm
export CC=${CROSS_PATH}/${CROSS_COMPILE}-cc
export CXX=${CROSS_PATH}/${CROSS_COMPILE}-c++
export LD=${CROSS_PATH}/${CROSS_COMPILE}-ld
export RANLIB=${CROSS_PATH}/${CROSS_COMPILE}-ranlib

export CFLAGS="-I/home/ttys3/repo/cpp/xlog-decode/zstd/lib"
export LDFLAGS="-L/usr/local/darwin-ndk-x86_64/lib -L/home/ttys3/repo/cpp/xlog-decode/zstd/lib"

export LD_LIBRARY_PATH=/usr/local/darwin-ndk-x86_64/lib:/home/ttys3/repo/cpp/xlog-decode/zstd/lib

make

toolchain 我也是已经安装好的,并且确定是工作的.

注: 这里有个 zstd 库是单独静态编译好的 (因为要交叉编译,所以不能用动态链接,会很麻烦)

然后,其实这个脚本本身也是没啥问题的。

但是为什么编译报错了呢?

/usr/bin/ld: unknown option: -dynamic

为什么, 明明已经指定了 export LD=${CROSS_PATH}/${CROSS_COMPILE}-ld, 但是 cmake 就是不用呢?

所以, 编译失败的原因显然是, cmake 对于这个 LD env 的识别出现了破坏性的变更。不过都过了2年多了,咱也不常用 cmake 这玩意, 也不知道它做了啥改变。

因此,足足折腾了近2个小时,才找到了一个朴素的修复方法:

ln -s /usr/local/darwin-ndk-x86_64/bin/x86_64-apple-darwin22.2-ld /usr/local/darwin-ndk-x86_64/bin/ld

没错,就是要把 x86_64-apple-darwin22.2-ld 链接为 ld, 这样, cmake 在生成 makefile 的时候,就自动用上了 apple toolchain 里的 ld 了。

结论:

if ld not exists, cmake will always try to use /usr/bin/ld, which will fuck you up

这个解决办法和思路来自: https://github.com/rust-lang/rust/issues/52657#issuecomment-407481607

另, 由于当初图方便,在 main.c 里面内嵌了解密的密钥,因此这个仓库暂时是没有公开的。

如果有人有需要,后面有空我再整理开源吧。 很多时候不开源,只是为了避免麻烦,因为涉及到安全和隐私,开源之前都是要再三检查所有 commit log, 这挺费时间的。