目標檔案所需的最低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即可。