调研这个的原因,是因为有个同事在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 target
clang/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 target
clang的这个参数也可通过环境变量来设置。命令行参数优先于环境变量。
MACOSX_DEPLOYMENT_TARGET
IPHONEOS_DEPLOYMENT_TARGET
TVOS_DEPLOYMENT_TARGET
WATCHOS_DEPLOYMENT_TARGET
DRIVERKIT_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版本的更多相关文章

  1. Linux源码与编译出的目标文件汇编代码的一致性问题

    start_kernel是内核启动时比较重要的一个函数,然而我发现一个问题,我编译出来的目标文件中的汇编代码与C源码并不完全对应,这是怎么一回事呢? asmlinkage void __init st ...

  2. webRTC中回声消除(AEC)模块编译时aec_rdft.c文件报错:

    webRTC中回声消除(AEC)模块编译时aec_rdft.c文件报错. 原因是: 局部变量ip跟全局变量冲突的问题,可以将局部变量重新命名一下,就可以通过编译了. aec_rdft.c修改以后文件代 ...

  3. gcc编译时指定链接库的查找目录

    gcc编译时,如果需要链接的库的目录不在标准目录,则需要通过将保护库的目录/aa/bb/cc通过-L/aa/bb/cc 添加到搜索路径中,如: gcc -o xmltest xml_test.cpp ...

  4. SQL Server2017还原数据库时指定mdf文件及日志文件的名称

    由于需要还原同一个数据库的不同备份到不同数据库中,可是在还原的时候,可是在指定目标数据库时,填写不同的数据库名称,在SQL Server Data文件夹中生成的.mdf文件还是同一个,如图,虽然是很简 ...

  5. 使用CMake,且在GCC编译时指定相对源代码路径选项BUG的问题

    CMake的build.make,每次都是cd xxx目录,然后再编译 而编译时,GCC会取当前路径保存进调试信息的DT_AT_comp_dir,GCC的编译器选项-fdebug-prefix-map ...

  6. 一点一点学写Makefile(4) - 编译时指定宏参数

    我们在项目中有时为了方便会自定义一些与项目无关的功能,例如打印输出一些提示信息.将关键协议生成文件等,但是如果每次都通过修改代码的方法来实现,测试部门就会认为你改的这些代码可能会带来其他问题.对于这种 ...

  7. C# 1.将整个文件夹复制到目标文件夹中 2.将指定文件复制到指定目标文件夹中

    ].Items.Clear(); string filePath = Application.StartupPath; string sourcePath = Path.Combine(filePat ...

  8. Linux 执行ll命令时指定按文件时间或大小排序

    按时间排序: $ ll -ht 按大小排序: $ ll -hS 使用--help查看命令的用法,如 $ ll --help

  9. gcc编译时头文件库文件搜索顺序(转)

    原文: http://blog.csdn.net/silentfly1987/article/details/6119195

随机推荐

  1. 【Java】学习路径55-练习:制作一个聊天室(多线程、UDP、双向传输数据)

    创建四个类,实现双向聊天的功能. 接收线程: import java.io.IOException; import java.net.*; public class ReceiveThread imp ...

  2. Paperask一键获取A币

    又到了毕业季,查论文是一件很头疼的事情,网上免费查重检测力度又很一般┑( ̄Д  ̄)┍ 因为一次偶然同学推荐了解到这个网站,只要做新手任务就能得到很多积分,再进行抽奖就可以得到A币或者是至尊券可以免费使 ...

  3. 【ASP.NET Core】在Blazor中获取 HTTP 上下文信息

    今天咱们来扯一下 Blazor 应用程序怎么访问 HttpContext.其实这句话有坑,为了避免大伙伴们掉茅坑,老周直接说明:Blazor 是不能访问 HttpContext 的.哪怕你在服务容器中 ...

  4. KingbaseES V8R6集群维护案例之--修改securecmdd工具服务端口

    案例说明: 在一些生产环境,为了系统安全,不支持ssh互信,或限制root用户使用ssh登录,KingbaseES V8R6可以使用securecmdd工具支持主机之间的通讯.securecmdd工具 ...

  5. git 根据历史 commitID 拉分支

    1. git log -g 查看已commit的信息 2. 根据commit信息找到对应的commitID 3. 执行一下命令来创建新的分支 ### 1. 方法一:创建一个基于commitId的分支, ...

  6. 通过VS下载的NuGet包,如何修改其下载存放路径?

    一.了解NuGet包的默认存放路径 我们通过NuGet包管理器下载的引用包,默认是存放在C盘的,存储路径一般是: C:\Users\{系统用户名}\.nuget\packages 我们都知道,C盘的存 ...

  7. day35-IO流02

    JavaOI流02 4.常用的类 4.1文件字节流输入流-FileInputStream InputStream抽象类是所有类字节输入流的超类 InputStream常用的子类: FileInputS ...

  8. day37-IO流04

    JavaIO流04 4.常用的类03 4.4节点流和处理流02 4.4.5对象处理流-ObjectInputStream和ObjectOutputStream 1.序列化和反序列化 例子1: 看一个需 ...

  9. H5页面调用admob激励视频,用户获取奖励

    应用前提条件 使用 Android Studio 3.2 或更高版本 确保您应用的 build 文件使用以下值: minSdkVersion 为 16 或更高版本 compileSdkVersion  ...

  10. G&GH02 储存库创建/同步

    注意事项与声明 平台: Windows 10 作者: JamesNULLiu 邮箱: jamesnulliu@outlook.com 博客: https://www.cnblogs.com/james ...