62
45

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

XCFrameworkに対応する際のポイント集

Last updated at Posted at 2020-03-09

これはなに?

2019年WWDCで発表された XCFramework に対応する際のポイント集です。

プロジェクト作成

【Tips】 新規プロジェクト作成から始める場合はEmptyを選択する

Emptyを選択すると、余計なビルド設定がない状態でプロジェクト作成が出来るので可読性が良くなります。

① File > New > Project... > Cross-platform > Other > Empty と選び、新規プロジェクトを作成する。

スクリーンショット 2020-02-25 19.59.41.png

②ターゲットが空のプロジェクトが作成されるので、サポートしたいプラットフォームの数だけターゲットを追加する。
File > New > Target... > [プラットフォーム] > Frameworks

スクリーンショット 2020-02-25 20.08.08.png

iOS macOS tvOS watchOS を追加した場合:
スクリーンショット 2020-02-25 20.12.36.png

③コマンドでプロジェクトの構成を確認するには

$ xcodebuild -list -json
{
  "project" : {
    "configurations" : [
      "Debug",
      "Release"
    ],
    "name" : "Sample",
    "schemes" : [
      "iOS",
      "macOS",
      "tvOS",
      "watchOS"
    ],
    "targets" : [
      "iOS",
      "macOS",
      "tvOS",
      "watchOS"
    ]
  }
}

ビルド設定

【必須】 Deployment Target を設定する

①フレームワークがサポートしたいOSバージョンの範囲の内、下限バージョンを指定します。

スクリーンショット 2020-02-25 20.48.09.png

【オプション】 プロセッサアーキテクチャを指定する

※この章の内容は必要に応じて設定してください。
※Xcode 12以降のバージョンで新規プロジェクトを作成した場合は、comment-1 も参照してください。

フレームワークがサポートするプロセッサアーキテクチャを初期値から変更したい場合は、ARCHSVALID_ARCHSにパラメータを指定します。
その2つの初期値はBase SDKDeployment Targetの値に合わせて変動する(i)ので、Deployment Targetを正しく設定してから行ってください。

i) xcodebuildがプラットフォームに合わせて、最低限必要なアーキテクチャを設定してくれる。

スクリーンショット 2020-02-25 20.48.08.png

①コマンドで現在の値を確認するには

$ xcodebuild -showBuildSettings -project Sample.xcodeproj -scheme iOS archive | grep -e ARCHS
    ARCHS = arm64
    ARCHS_STANDARD = arm64
    ARCHS_STANDARD_32_64_BIT = armv7 arm64
    ARCHS_STANDARD_32_BIT = armv7
    ARCHS_STANDARD_64_BIT = arm64
    ARCHS_STANDARD_INCLUDING_64_BIT = arm64
    ARCHS_UNIVERSAL_IPHONE_OS = armv7 arm64
    VALID_ARCHS = arm64 arm64e armv7 armv7s

②サポートしたいアーキテクチャを、ARCHSに指定します。(ii)
VALID_ARCHSにはARCHSで指定したパラメータを含めるように指定します。

ii) ARCHSにarm64eを含める対応をするには

活用例:

# IPHONEOS_DEPLOYMENT_TARGET=8.0 に設定した場合のビルド設定を出力する
# ARCHS = armv7 arm64 になっている
$ xcodebuild -showBuildSettings -project Sample.xcodeproj -scheme iOS archive 'IPHONEOS_DEPLOYMENT_TARGET=8.0' | grep -e ARCHS
    ARCHS = armv7 arm64
    ARCHS_STANDARD = armv7 arm64
    ARCHS_STANDARD_32_64_BIT = armv7 arm64
    ARCHS_STANDARD_32_BIT = armv7
    ARCHS_STANDARD_64_BIT = arm64
    ARCHS_STANDARD_INCLUDING_64_BIT = armv7 arm64
    ARCHS_UNIVERSAL_IPHONE_OS = armv7 arm64
    VALID_ARCHS = arm64 arm64e armv7 armv7s
# ARCHS=arm64 armv7 armv7s を指定する
$ xcodebuild -showBuildSettings -project Sample.xcodeproj -scheme iOS archive 'IPHONEOS_DEPLOYMENT_TARGET=8.0' 'ARCHS=arm64 armv7 armv7s' | grep -e ARCHS
    ARCHS = arm64 armv7 armv7s    # Build settings from command line: の出力
    ARCHS = arm64 armv7 armv7s    # Build settings for action archive and target iOS: の出力
    ARCHS_STANDARD = armv7 arm64
    ARCHS_STANDARD_32_64_BIT = armv7 arm64
    ARCHS_STANDARD_32_BIT = armv7
    ARCHS_STANDARD_64_BIT = arm64
    ARCHS_STANDARD_INCLUDING_64_BIT = armv7 arm64
    ARCHS_UNIVERSAL_IPHONE_OS = armv7 arm64
    VALID_ARCHS = arm64 arm64e armv7 armv7s

Architectures (ARCHS)

製品が構築されるアーキテクチャのリスト。 これは通常、プラットフォームによって提供される事前定義されたビルド設定に設定されます。 複数のアーキテクチャが指定されている場合、ユニバーサルバイナリが生成されます。

Valid Architectures (VALID_ARCHS)
ターゲットを実際に構築するアーキテクチャのスペースで区切られたリスト。 ターゲットごとに、これはアーキテクチャ(ARCHS)で指定されたリストと横断し、結果のセットが構築されます。 これにより、個々のターゲットが特定のアーキテクチャのビルドをオプトアウトできます。 結果のアーキテクチャのセットが空の場合、実行可能ファイルは生成されません。

Base SDK (SDKROOT)

ビルド中に使用されているベースSDKの名前またはパス。 製品は、指定されたSDK内にあるヘッダーとライブラリに対して構築されます。 このパスはすべての検索パスの前に追加され、環境を介してコンパイラーとリンカーに渡されます。 追加のSDKは、追加のSDK(ADDITIONAL_SDKS)設定で指定できます。

原文: Build settings reference - Xcode Help

デバイスのプロセッサアーキテクチャを調べるには:

Troubleshooting:

【必須】 Mach-O Type を設定する

①動的なXCFrameworkを生成したい場合は、Mach-ODynamic Libraryを指定します。
静的なXCFrameworkを生成したい場合は、Mach-OStatic Libraryを指定します。

スクリーンショット 2023-05-30 20.51.03.png

【必須】 ビットコードに対応する

ビットコードを有効にするために、この3つのビルド設定を指定します。

ENABLE_BITCODE=YES
BITCODE_GENERATION_MODE=bitcode
OTHER_CFLAGS=-fembed-bitcode

Enable Bitcode (ENABLE_BITCODE)

この設定を有効にすると、ターゲットまたはプロジェクトは、それをサポートするプラットフォームおよびアーキテクチャのコンパイル中にビットコードを生成する必要があります。 アーカイブビルドの場合、App Storeに送信するために、リンクされたバイナリでビットコードが生成されます。 他のビルドの場合、コンパイラーとリンカーは、コードがビットコード生成の要件を満たしているかどうかを確認しますが、実際のビットコードは生成しません。

BITCODE_GENERATION_MODE

Xcodeの隠しコマンドなのでXcode Helpには記載がないが、clangのヘルプには記述が少しあります。

$ clang --help | grep bitcode
  -fembed-bitcode-marker  Embed placeholder LLVM IR data as a marker
  -fembed-bitcode=<option>
                          Embed LLVM bitcode (option: off, all, bitcode, marker)
  -fembed-bitcode         Embed LLVM IR bitcode as data

Other C Flags (OTHER_CFLAGS)

CおよびObjective-Cファイルのコンパイラに渡す追加フラグのスペース区切りリスト。 スペースまたは特殊文字(スペースを含む可能性のあるパス名など)を含む引数は、必ずバックスラッシュでエスケープしてください。 Xcodeが特定のCまたはObjective-CコンパイラフラグのUIをまだ提供していない場合は、この設定を使用します。

【必須】 XCFrameworkに対応する

① XCFramework形式(.xcframework)で配布するために、この2つのビルド設定を指定します。

BUILD_LIBRARY_FOR_DISTRIBUTION=YES
SKIP_INSTALL=NO

Build Libraries for Distribution (BUILD_LIBRARY_FOR_DISTRIBUTION)

ライブラリが配布用にビルドされていることを確認します。 Swiftの場合、これによりライブラリの進化とモジュールインターフェイスファイルの生成がサポートされます。

Skip Install (SKIP_INSTALL)
有効にした場合、展開場所がアクティブであってもビルドされた製品をインストールしません。

destination はこの様に指定します。

-destination 'generic/platform=iOS'
-destination 'generic/platform=iOS Simulator'
-destination 'generic/platform=macOS,variant=Mac Catalyst'
-destination 'generic/platform=iPadOS'
-destination 'generic/platform=iPadOS Simulator'
-destination 'generic/platform=macOS'
-destination 'generic/platform=tvOS'
-destination 'generic/platform=tvOS Simulator'
-destination 'generic/platform=watchOS'
-destination 'generic/platform=watchOS Simulator'
-destination 'generic/platform=carPlayOS'
-destination 'generic/platform=carPlayOS Simulator'

【ビルド設定のまとめ】

①まずxcodebuild archiveコマンドをサポートしたいフォーマット(-destination)の回数分実行します。そうすることで複数個の*.xcarchiveファイルが生成されます。
②その後xcodebuild -create-xcframeworkで、全ての*.xcarchiveファイルを1つのパッケージにまとめます(*.xcframework にします)。

STEP 1/2: xcodebuild archive

プロセッサアーキテクチャを指定しない場合

$ xcodebuild \
'ENABLE_BITCODE=YES' \
'BITCODE_GENERATION_MODE=bitcode' \
'OTHER_CFLAGS=-fembed-bitcode' \
'BUILD_LIBRARY_FOR_DISTRIBUTION=YES' \
'SKIP_INSTALL=NO' \
archive \
-project 'Sample.xcodeproj' \
-scheme 'iOS' \
-destination 'generic/platform=iOS' \
-configuration 'Release' \
-archivePath 'build/Sample-iOS.xcarchive'

プロセッサアーキテクチャを指定する場合

$ xcodebuild \
'ARCHS=arm64 armv7 armv7s' \
'VALID_ARCHS = arm64 arm64e armv7 armv7s' \
'ENABLE_BITCODE=YES' \
'BITCODE_GENERATION_MODE=bitcode' \
'OTHER_CFLAGS=-fembed-bitcode' \
'BUILD_LIBRARY_FOR_DISTRIBUTION=YES' \
'SKIP_INSTALL=NO' \
archive \
-project 'Sample.xcodeproj' \
-scheme 'iOS' \
-destination 'generic/platform=iOS' \
-configuration 'Release' \
-archivePath 'build/Sample-iOS.xcarchive'

STEP 2/2: xcodebuild -create-xcframework

-frameworkにはxcodebuild archiveで生成した全ての*.frameworkのパスを記述します。

$ xcodebuild \
-create-xcframework \
-framework 'build/Sample-iOS.xcarchive/Products/Library/Frameworks/iOS.framework' \
-framework 'build/Sample-iOS-Simulator.xcarchive/Products/Library/Frameworks/iOS.framework' \
-framework 'build/Sample-macOS.xcarchive/Products/Library/Frameworks/macOS.framework' \
...
...
-output 'build/Sample.xcframework'

成果物の確認方法

.xcframeworkファイルが、ビルド設定で指定した通りに生成出来たかの確認方法

cat コマンドでプロパティリストを出力するか、file または lipo -info を用いてバイナリ情報が対応しているアーキテクチャを出力出来ます。

cat の場合:

$ cat ./build/Sample.xcframework/Info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>AvailableLibraries</key>
	<array>
		<dict>
			<key>LibraryIdentifier</key>
			<string>watchos-armv7k_arm64_32</string>
			<key>LibraryPath</key>
			<string>watchOS.framework</string>
			<key>SupportedArchitectures</key>
			<array>
				<string>armv7k</string>
				<string>arm64_32</string>
			</array>
			<key>SupportedPlatform</key>
			<string>watchos</string>
		</dict>
		<dict>
			<key>LibraryIdentifier</key>
			<string>ios-arm64</string>
			<key>LibraryPath</key>
			<string>iOS.framework</string>
			<key>SupportedArchitectures</key>
			<array>
				<string>arm64</string>
			</array>
			<key>SupportedPlatform</key>
			<string>ios</string>
		</dict>
		<dict>
			<key>LibraryIdentifier</key>
			<string>ios-x86_64-simulator</string>
			<key>LibraryPath</key>
			<string>iOS.framework</string>
			<key>SupportedArchitectures</key>
			<array>
				<string>x86_64</string>
			</array>
			<key>SupportedPlatform</key>
			<string>ios</string>
			<key>SupportedPlatformVariant</key>
			<string>simulator</string>
		</dict>
		<dict>
			<key>LibraryIdentifier</key>
			<string>macos-x86_64</string>
			<key>LibraryPath</key>
			<string>macOS.framework</string>
			<key>SupportedArchitectures</key>
			<array>
				<string>x86_64</string>
			</array>
			<key>SupportedPlatform</key>
			<string>macos</string>
		</dict>
		<dict>
			<key>LibraryIdentifier</key>
			<string>watchos-i386-simulator</string>
			<key>LibraryPath</key>
			<string>watchOS.framework</string>
			<key>SupportedArchitectures</key>
			<array>
				<string>i386</string>
			</array>
			<key>SupportedPlatform</key>
			<string>watchos</string>
			<key>SupportedPlatformVariant</key>
			<string>simulator</string>
		</dict>
		<dict>
			<key>LibraryIdentifier</key>
			<string>tvos-x86_64-simulator</string>
			<key>LibraryPath</key>
			<string>tvOS.framework</string>
			<key>SupportedArchitectures</key>
			<array>
				<string>x86_64</string>
			</array>
			<key>SupportedPlatform</key>
			<string>tvos</string>
			<key>SupportedPlatformVariant</key>
			<string>simulator</string>
		</dict>
		<dict>
			<key>LibraryIdentifier</key>
			<string>tvos-arm64</string>
			<key>LibraryPath</key>
			<string>tvOS.framework</string>
			<key>SupportedArchitectures</key>
			<array>
				<string>arm64</string>
			</array>
			<key>SupportedPlatform</key>
			<string>tvos</string>
		</dict>
	</array>
	<key>CFBundlePackageType</key>
	<string>XFWK</string>
	<key>XCFrameworkFormatVersion</key>
	<string>1.0</string>
</dict>
</plist>

file の場合:

# 単一のアーキテクチャに対応しているバイナリの場合の出力結果
$ file ./build/Sample.xcframework/ios-arm64/iOS.framework/iOS
./build/Sample.xcframework/ios-arm64/iOS.framework/iOS: Mach-O 64-bit dynamically linked shared library arm64

# 複数のアーキテクチャに対応しているバイナリの場合の出力結果
$ file ./build/Sample.xcframework/watchos-armv7k_arm64_32/watchOS.framework/watchOS
./build/Sample.xcframework/watchos-armv7k_arm64_32/watchOS.framework/watchOS: Mach-O universal binary with 2 architectures: [arm_v7k:Mach-O dynamically linked shared library arm_v7k] [arm64_32_v8:Mach-O dynamically linked shared library arm64_32_v8]
./build/Sample.xcframework/watchos-armv7k_arm64_32/watchOS.framework/watchOS (for architecture armv7k):	Mach-O dynamically linked shared library arm_v7k
./build/Sample.xcframework/watchos-armv7k_arm64_32/watchOS.framework/watchOS (for architecture arm64_32):	Mach-O dynamically linked shared library arm64_32_v8

lipo -info の場合:

# 単一のアーキテクチャに対応しているバイナリの場合の出力結果
$ lipo -info ./build/Sample.xcframework/ios-arm64/iOS.framework/iOS
Non-fat file: ./build/Sample.xcframework/ios-arm64/iOS.framework/iOS is architecture: arm64

# 複数のアーキテクチャに対応しているバイナリの場合の出力結果
$ lipo -info ./build/Sample.xcframework/watchos-armv7k_arm64_32/watchOS.framework/watchOS
Architectures in the fat file: ./build/Sample.xcframework/watchos-armv7k_arm64_32/watchOS.framework/watchOS are: armv7k arm64_32 

また otool コマンドを用いると、バイナリ詳細情報が出力されます。

otoolコマンドでバイナリ詳細情報を出力し、LC_VERSION_MIN_IPHONEOSが出力されればiOS実機向けにコンパイルされているかクラスが含まれている。

$ otool -arch arm64 -lv ./build/Sample.xcframework/ios-arm64/iOS.framework/iOS | grep -A 5 LC_VERSION_MIN_IPHONEOS

      cmd LC_VERSION_MIN_IPHONEOS
  cmdsize 16
  version 11.0
      sdk 18.2
Load command 2
      cmd LC_LINKER_OPTIMIZATION_HINT
--
      cmd LC_VERSION_MIN_IPHONEOS
  cmdsize 16
  version 11.0
      sdk 18.2
Load command 2
      cmd LC_LINKER_OPTIMIZATION_HINT

otoolコマンドでバイナリ詳細情報を出力し、LC_BUILD_VERSIONが出力されればiOS Simulator向けにコンパイルされているかクラスが含まれている。

$ otool -arch arm64 -lv ./build/Sample.xcframework/ios-arm64_x86_64-simulator/iOS.framework/iOS | grep -A 5 LC_BUILD_VERSION

      cmd LC_BUILD_VERSION
  cmdsize 32
 platform IOSSIMULATOR
    minos 13.0
      sdk 17.5
   ntools 1
--
      cmd LC_BUILD_VERSION
  cmdsize 32
 platform IOSSIMULATOR
    minos 14.0
      sdk 17.5
   ntools 1

otool -arch が対応しているフラグ一覧:

any little big ppc64 x86_64 x86_64h arm64 ppc970-64 arm64_32 arm64e ppc i386 m68k hppa sparc m88k i860 veo arm ppc601 ppc603 ppc603e ppc603ev ppc604 ppc604e ppc750 ppc7400 ppc7450 ppc970 i486 i486SX pentium i586 pentpro i686 pentIIm3 pentIIm5 pentium4 m68030 m68040 hppa7100LC veo1 veo2 veo3 veo4 armv4t armv5 xscale armv6 armv6m armv7 armv7f armv7s armv7k armv7m armv7em arm64v8

Debug symbol (dSYM)

dSYMファイルとは:
アプリクラッシュ時に出力されるスタックトレースを復元する場合に必要な、シンボルファイルです。
復元される主な情報は、作成したframeworkのクラス名・メソッド名です。
必要に応じて、XCFrameworkと同様に配布するのがいいかと思います。

frameworkのdSYMファイルはどこに生成されるのか?

dSYMファイルは xcodebuild archive で生成した *.xcarchive ファイルの配下 (*.xcarchive/dSYMs/*.framework.dSYM) に保存されます。

Bitcode Symbol Maps (BCSymbolMaps)

BCSymbolMapsファイルとは:
ビットコードを有効にしたときに生成される、ビルド時の設定値が記述されたテキストファイルです。

frameworkのBCSymbolMapsファイルはどこに生成されるのか?

BCSymbolMapsファイルは xcodebuild archive で生成した *.xcarchive ファイルの配下 (*.xcarchive/BCSymbolMaps/*.bcsymbolmap) に保存されます。

XCFrameworkを配布する

CarthageやSwift PMなどで配布したい場合は、関連するソフトウェアの対応状況の各種リンクを参照してください。

CocoaPodsで配布する

XCFrameworkをCocoaPodsで配布するための手順と、追加で指定するパラメータについて。

① 生成した*.xcframeworkファイルをzipなどにアーカイブする。
② HTTP(S)で、zipファイルを配布します。
AWS S3や自社HTTPサーバー、GitHub Releasesなどでzipを配布するのが一般的だと思います。
sourcehttp を選択し、zipファイルのURLを指定する。

Using HTTP to download a compressed file of the code. It supports zip, tgz, bz2, txz and tar.
spec.source = { :http => 'http://dev.wechatapp.com/download/sdk/WeChat_SDK_iOS_en.zip'

vendored_frameworks や ios.vendored_frameworks などを指定する
platformdeployment_target を指定する
cocoapods_version>= 1.9.0 を指定する
swift_versions と swift_version を指定する

その他

参考にした資料

お手軽にXCFramework対応したい場合に良さそうなソフトウェア

関連するソフトウェアの対応状況

執筆時の環境

  • macOS: 10.14.5
  • Xcode: 11.3.1

今回作成したプロジェクトとスクリプト

62
45
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
62
45

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?