From 75b8306f86e2526c9eb2828e0268ac1f78f0aad7 Mon Sep 17 00:00:00 2001 From: vixentael Date: Mon, 23 Nov 2020 01:44:32 +0200 Subject: [PATCH] Remove arm64e slice; return dyn linking for CocoaPods (#18) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Automatically enable Apple Silicon support Since Xcode 12.2 (stable) is out, Apple Silicon support can be enabled automatically there. Check the version of the command-line tools and set APPLE_SILICON_SUPPORT value automatically if possible. After a while, once Xcode 12.0.1 and earlier are not longer supported and widely used, this variable can be removed completely. Right now it won't be really necessary to set it explicitly, unless you want something strange. * Revert "Use static frameworks for CocoaPods (#13)" This reverts commit d21e3b7ee7ae5eaef8d3bb8355b06d644fdf7f83. We can't just migrate CLOpenSSL to static frameworks as that requires all upstream dependencies to migrate to static frameworks too, and that breaks builds left, right, and center. Instead, we have figured out what has been breaking dynamic linkage with CocoaPods, and now we're coming back to using dynamic linkage. If static versions of CLOpenSSL are published, they will be published in a separate podspec. * Drop arm64e to work around CocoaPods issues arm64e builds are included to test the pointer authentication feature of iOS devices. We have to include it in binary CLOpenSSL builds so that upstream users of CLOpenSSL might enable it themselves for testing. However, inclusion of this architecture slice causes issues with CocoaPods handling of vendored binary frameworks. arm64e builds include a certain linker command -- LC_DYLD_CHAINED_FIXUPS (0x80000034) -- which confuses CocoaPods' detector of dynamic binaries, making it believe that the vendored framework in a static one, not dynamic. This in turn causes issues when using CLOpenSSL as CocoaPods refuses to link "static" binary without "static_framework = true". This is a know issue in CocoaPods, stemming from the missing features in Homebrew's Mach-O parser [1][2]. [1]: https://github.com/Homebrew/brew/issues/7857 [2]: https://github.com/Homebrew/ruby-macho/issues/261 There is nothing we can do about it right now, other than disable "arm64e" builds for the time being. This does not affect deployment to App Store, but will break dependencies of CLOpenSSL which expect this architecture to be present. The dependencies will have to disable arm64e in their projects, if they have it explicitly enabled. (Considering that CocoaPods packaging of CLOpenSSL was never in good shape, the actual impact of this change should be minimal.) * Set install name during linkage Instead of using "install_name_tool" to fix the LC_ID_DYLIB value of the dylib, pass the "-install_name" parameter to the linker directly. This doesn't change anything in the resulting binary but looks a bit cleaner. * Use ABI-correct install name on macOS On macOS -- contrary to iOS, watchOS, and tvOS -- it is customary for frameworks to provide additional internal structure which helps with binary compatibility. For example, on iOS/watchOS/tvOS a framework typically has flat structure: openssl.framework ├── Headers ├── Info.plist └── openssl while on macOS it's a bit more involved: frameworks/MacOSX/openssl.framework ├── Headers -> Versions/Current/Headers ├── Resources -> Versions/Current/Resources ├── Versions │ ├── A │ └── Current -> A └── openssl -> Versions/Current/openssl Note that the top-level files are actually symlinks to the "Versions/Current" which in turn is a symlink to the "A" version, which actually contains the framework content: openssl.framework/Versions/A ├── Headers ├── Resources │ └── Info.plist └── openssl Currently, the 'install name' of all "openssl" binaries is set to "@rpath/openssl.framework/openssl", which makes the linked binaries remember and use this path when loading OpenSSL. On macOS this will involve two additional symlink resolutions. Another thing here is that if we will need to introduce a different version of OpenSSL framework on macOS, existing applications will still look up the current one, instead of using the A version that they should. Update the install name computation to use @rpath/openssl.framework/openssl for iOS, watchOS, tvOS while using more explicit @rpath/openssl.framework/Versions/A/openssl for macOS. This is how Apple's system frameworks do it. Though they have a pressing issue of supporting multiple possible ABIs and it's not that important in our case, you never know when this turns out to be necessary or whether some weird tool might choke on the symlinks. --- Makefile | 20 ++++++++++++++------ cocoapods/CLOpenSSL.podspec.template | 4 ---- config/20-all-platforms.conf | 6 ++++-- create-openssl-framework.sh | 11 ++++++++--- scripts/update-specs.sh | 8 ++++---- 5 files changed, 30 insertions(+), 19 deletions(-) diff --git a/Makefile b/Makefile index c3fa8ed0..363a3159 100644 --- a/Makefile +++ b/Makefile @@ -14,22 +14,30 @@ endif VERSION ?= 1.1.1h ## Extra version of the distributed package -PACKAGE_VERSION ?= 1 +PACKAGE_VERSION ?= 2 export PACKAGE_VERSION MIN_IOS_SDK = 10.0 MIN_OSX_SDK = 10.11 export MIN_IOS_SDK MIN_OSX_SDK -BUILD_ARCHS += ios_i386 ios_x86_64 ios_arm64 ios_arm64e ios_armv7s ios_armv7 +BUILD_ARCHS += ios_i386 ios_x86_64 ios_arm64 ios_armv7s ios_armv7 BUILD_ARCHS += mac_x86_64 BUILD_TARGETS += ios-sim-cross-i386 ios-sim-cross-x86_64 -BUILD_TARGETS += ios64-cross-arm64 ios64-cross-arm64e ios-cross-armv7s ios-cross-armv7 +BUILD_TARGETS += ios64-cross-arm64 ios-cross-armv7s ios-cross-armv7 BUILD_TARGETS += macos64-x86_64 -# Apple Silicon support is currently experimental. It is available only with -# beta Xcode versions installed. Once iOS 14 and macOS 11 are released and -# stable Xcode supports arm64, these settings are going to become default. +# Automatically enable Apple Silicon support if running with Xcode 12.2+ +# unless the user has decided explicitly. +ifeq ($(APPLE_SILICON_SUPPORT),) +xcode_version := $(shell xcodebuild -version | awk '/Xcode/ {print $$2}') +ifeq ($(shell printf '%s\n' "12.2" "$(xcode_version)" | sort -V | head -1),12.2) +APPLE_SILICON_SUPPORT := yes +endif +endif + +# Not all currently used Xcode versions support building for Apple Silicon. +# Enable this architecture only when requested. ifeq ($(APPLE_SILICON_SUPPORT),yes) BUILD_ARCHS += mac_arm64 BUILD_TARGETS += macos64-arm64 diff --git a/cocoapods/CLOpenSSL.podspec.template b/cocoapods/CLOpenSSL.podspec.template index 306e891b..376900dd 100644 --- a/cocoapods/CLOpenSSL.podspec.template +++ b/cocoapods/CLOpenSSL.podspec.template @@ -204,10 +204,6 @@ EOF done EOF - # Tell CocoaPods that the frameworks we publish are "static frameworks". - # This ensures correct resolution of transitive dependencies. - s.static_framework = true - # Set the minimum platform versions. We just know the right ones from the # prebuilt frameworks we download. s.ios.deployment_target = min_target_ios diff --git a/config/20-all-platforms.conf b/config/20-all-platforms.conf index 6e58d84d..928a5c37 100644 --- a/config/20-all-platforms.conf +++ b/config/20-all-platforms.conf @@ -38,13 +38,15 @@ my %targets = (); cflags => add(sub { defined($ENV{'MACOS_MIN_SDK_VERSION'}) ? '-mmacosx-version-min=$(MACOS_MIN_SDK_VERSION)' : '-mmacosx-version-min=10.11'; }), }, + # Apple Silicon support + # https://github.com/openssl/openssl/pull/12369 "darwin64-arm64-cc" => { - inherit_from => [ "darwin-common", asm("") ], + inherit_from => [ "darwin-common", asm("aarch64_asm") ], CFLAGS => add("-Wall"), cflags => add("-arch arm64"), lib_cppflags => add("-DL_ENDIAN"), bn_ops => "SIXTY_FOUR_BIT_LONG", - perlasm_scheme => "macosx", + perlasm_scheme => "ios64", }, ## Apple WatchOS diff --git a/create-openssl-framework.sh b/create-openssl-framework.sh index 275cadc3..97aafd20 100755 --- a/create-openssl-framework.sh +++ b/create-openssl-framework.sh @@ -128,8 +128,6 @@ function get_openssl_version() { if [ $FWTYPE == "dynamic" ]; then DEVELOPER=`xcode-select -print-path` - FW_EXEC_NAME="${FWNAME}.framework/${FWNAME}" - INSTALL_NAME="@rpath/${FW_EXEC_NAME}" COMPAT_VERSION="1.0.0" CURRENT_VERSION="1.0.0" NORMALIZE_OPENSSL_VERSION=yes @@ -178,6 +176,13 @@ if [ $FWTYPE == "dynamic" ]; then ar -x ../lib/libssl.a cd .. + # macOS frameworks have a bit different structure inside. + if [[ $PLATFORM == MacOSX* ]]; then + INSTALL_NAME="@rpath/${FWNAME}.framework/Versions/A/${FWNAME}" + else + INSTALL_NAME="@rpath/${FWNAME}.framework/${FWNAME}" + fi + ld obj/*.o \ -dylib \ -bitcode_bundle \ @@ -188,8 +193,8 @@ if [ $FWTYPE == "dynamic" ]; then -compatibility_version $COMPAT_VERSION \ -current_version $CURRENT_VERSION \ -application_extension \ + -install_name $INSTALL_NAME \ -o $FWNAME.dylib - install_name_tool -id $INSTALL_NAME $FWNAME.dylib cd .. done diff --git a/scripts/update-specs.sh b/scripts/update-specs.sh index c2de56df..d98797c0 100755 --- a/scripts/update-specs.sh +++ b/scripts/update-specs.sh @@ -71,10 +71,10 @@ sed -e "s/%%OPENSSL_VERSION%%/$version/g" \ -e "s!%%GITHUB_REPO%%!$GITHUB_REPO!g" \ -e "s/%%MIN_IOS_SDK%%/$MIN_IOS_SDK/g" \ -e "s/%%MIN_OSX_SDK%%/$MIN_OSX_SDK/g" \ - -e "s/%%IPHONE_ARCHIVE_NAME%%/$IPHONE_STATIC_NAME/g" \ - -e "s/%%IPHONE_ARCHIVE_HASH%%/$(shasum -a 256 "$OUTPUT/$IPHONE_STATIC_NAME" | awk '{print $1}')/g" \ - -e "s/%%MACOSX_ARCHIVE_NAME%%/$MACOSX_STATIC_NAME/g" \ - -e "s/%%MACOSX_ARCHIVE_HASH%%/$(shasum -a 256 "$OUTPUT/$MACOSX_STATIC_NAME" | awk '{print $1}')/g" \ + -e "s/%%IPHONE_ARCHIVE_NAME%%/$IPHONE_DYNAMIC_NAME/g" \ + -e "s/%%IPHONE_ARCHIVE_HASH%%/$(shasum -a 256 "$OUTPUT/$IPHONE_DYNAMIC_NAME" | awk '{print $1}')/g" \ + -e "s/%%MACOSX_ARCHIVE_NAME%%/$MACOSX_DYNAMIC_NAME/g" \ + -e "s/%%MACOSX_ARCHIVE_HASH%%/$(shasum -a 256 "$OUTPUT/$MACOSX_DYNAMIC_NAME" | awk '{print $1}')/g" \ $podspec.template > $podspec echo "Updated $podspec" echo