clang在编译时指定目标文件所需的最低macOS版本

调研这个的原因,是因为有个同事在macOS 12.2上打包好的程序,放在macOS 10.15上运行时报错:
Dyld Error Message:  Symbol not found: __ZNKSt3__115basic_stringbufIcNS_11char_traitsIcEENS_9allocatorIcEEE3strEv  Referenced from: /Library/Application Support/XXX.dylib (which was built for Mac OS X 12.2)  Expected in: /usr/lib/libc++.1.dylib
调研了一番,发现这个是因为Apple的SDK使用weak linking来支持不同版本的macOS 。
目标文件所需的最低macOS版本有个专有名称“deployment target” 。 查看库的deployment target查看*.dylib、*.a或者主程序的deployment target属性、sdk版本:otool -l 7z.dylib | grep -E "(minos|sdk)"find . -name "*.a" | xargs otool -l | grep -E "(minos|sdk)"通过命令行参数设置deployment targetclang/clang++在编译时指定deployment target的命令行参数是-mmacos-version-min,比如:-mmacos-version-min=10.15,指定最低为Catalina的最后一个版本10.15 。针对iOS等有类似的开关如-miphoneos-version-min、-mtvos-version-min、 -mwatchos-version-min 。-mmacos-version-min有个别名-mmacosx-version-min,别名只是为了兼容,尽量不使用这个别名 。clang会根据这个命令行参数来定义编译器内置宏MAC_OS_X_VERSION_MIN_REQUIRED等,而SDK头文件<AvailabilityMacros.h>、<Availability.h>中有对这些宏的检查,根据宏决定哪些符号采用weak linking 。weak linking的符号在编译时不会报错,dylib加载时也不会报错,在用到对应的符号时如果不存在才会报错 。 通过环境变量设置deployment targetclang的这个参数也可通过环境变量来设置 。命令行参数优先于环境变量 。MACOSX_DEPLOYMENT_TARGETIPHONEOS_DEPLOYMENT_TARGETTVOS_DEPLOYMENT_TARGETWATCHOS_DEPLOYMENT_TARGETDRIVERKIT_DEPLOYMENT_TARGET 我们的工程以及我们的工程所直接/间接依赖的所有静态库/动态库,都需要在编译时指定相同的deployment target 。省事的办法是通过环境变量来统一设置,在开始整个打包之前设置一下 。其次是命令行开关 。不同工程类型的命令行开关设置方法有差异 。以下是命令行开关的设置 。 通过vcpkg install编译的库需要更改vcpkg/triplets/x64-osx.cmake文件的内容,增加下面三行(理论上只要第一行即可,但vcpkg目前貌似有bug,导致VCPKG_OSX_DEPLOYMENT_TARGET只对CMake工程生效,对其他类型的工程不生效 。所以需要第二行、第三行):set(VCPKG_OSX_DEPLOYMENT_TARGET "10.15")set(VCPKG_C_FLAGS -mmacosx-version-min=10.15)set(VCPKG_CXX_FLAGS -mmacosx-version-min=10.15)也可以复制这个文件到某个目录下,在复制出来的文件中增加上面这三行,然后给vcpkg install传递--overlay-triplets参数以使用这个修改过的triplet文件 。这样通过vcpkg install安装的所有库的deployment target都是10.15 。 autoconf类型的工程比如libiconv库是手动执行autoconf编译的,需要在configure时增加参数:./configure CFLAGS=-mmacos-version-min=10.15 CPPFLAGS=-mmacos-version-min=10.15 CMake工程在CMakeLists.txt里的project()语句之前增加一句:set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15")或者set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "" FORCE) Xcode工程在界面的工程属性中可以设置deployment target 。 Makefile工程在makefile里自行给clang传递参数-mmacos-version-min=10.15即可 。【clang在编译时指定目标文件所需的最低macOS版本】

    经验总结扩展阅读