Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 12255] ファイルの概要

このコミットは、Go言語のcrypto/tlsパッケージにおけるmacOS固有のビルド設定に関するものです。具体的には、macOSのターゲットバージョンを10.6に強制することで、APIの互換性問題を解決しています。これにより、古いmacOSバージョン(10.6)でGoのバイナリが正しく動作しない問題(Issue #3131)に対処しています。

コミット

commit fb1a5fcacf837f1004cebc392dfbc2594c2ead65
Author: Mikkel Krautz <mikkel@krautz.dk>
Date:   Tue Feb 28 11:34:48 2012 -0500

    crypto/tls: force OS X target version to 10.6 for API compatibility
    
    This is a band-aid until we can use weak imports with cgo.
    
    Fixes #3131.
    
    R=minux.ma, rsc
    CC=golang-dev
    https://golang.org/cl/5700083

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/fb1a5fcacf837f1004cebc392dfbc2594c2ead65

元コミット内容

crypto/tls: force OS X target version to 10.6 for API compatibility

このコミットは、Goのcrypto/tlsパッケージがmacOS上でビルドされる際に、ターゲットとなるOS Xのバージョンを10.6に強制することを目的としています。これは、APIの互換性問題を回避するための暫定的な措置であり、将来的にはcgoでの弱いインポート(weak imports)が利用可能になるまでの「応急処置」とされています。この変更は、GoリポジトリのIssue #3131を修正します。

変更の背景

この変更の背景には、Goのcrypto/tlsパッケージがmacOS上で証明書ストア(特にルート証明書)にアクセスする際に使用するSecurityフレームワークのAPIの互換性問題があります。macOS 10.7 (Lion) で導入されたSecItemExportという新しいAPIと、それ以前のバージョン(macOS 10.6 Snow Leopardなど)で利用されていたSecKeychainItemExportという古い(そして10.7以降で非推奨となった)APIが存在しました。

Goのビルドシステムが、より新しいSDK(例えばmacOS 10.7 SDK)を使用してビルドされると、コンパイラはデフォルトで新しいAPIを使用しようとします。しかし、その結果生成されたバイナリをmacOS 10.6のような古いシステムで実行しようとすると、新しいAPIが利用できないために「シンボルが見つからない」といったエラーが発生し、プログラムがクラッシュする問題が発生していました。これがIssue #3131で報告された問題です。

このコミットは、cgo(GoとC言語の相互運用機能)が弱いインポート(weak imports)をサポートするまでの間、この問題を回避するための「バンドエイド(band-aid)」として導入されました。弱いインポートが利用できれば、実行時にAPIの存在をチェックし、利用可能な方を選択するといったより柔軟な対応が可能になります。

前提知識の解説

  • crypto/tlsパッケージ: Go言語の標準ライブラリの一部で、TLS (Transport Layer Security) プロトコルを実装しています。これには、HTTPS通信などで使用される証明書の検証機能も含まれます。macOSでは、システムにインストールされているルート証明書ストアにアクセスするために、AppleのSecurityフレームワークを利用します。
  • cgo: Go言語の機能の一つで、C言語のコードをGoプログラムから呼び出すことを可能にします。これにより、OS固有のAPIや既存のCライブラリを利用できます。
  • macOS Security Framework: Appleが提供するセキュリティ関連のサービスとAPIの集合体です。証明書の管理、キーチェーンへのアクセス、暗号化操作などを担当します。
  • SecKeychainItemExportSecItemExport: これらはmacOS SecurityフレームワークのAPIで、キーチェーンアイテム(この場合は証明書)をエクスポートするために使用されます。
    • SecKeychainItemExport: macOS 10.6以前で主に使用されていたAPI。
    • SecItemExport: macOS 10.7で導入された新しいAPI。SecKeychainItemExportの代替として推奨されています。
  • 弱いインポート (Weak Imports): プログラムが特定のライブラリ関数を動的にリンクする際に、その関数が実行時に存在しない場合でもプログラムがクラッシュしないようにするメカニズムです。関数が存在しない場合は、その関数への呼び出しがスキップされるか、代替の処理が実行されます。C言語のダイナミックリンカーの機能として存在しますが、cgoでは当時直接サポートされていませんでした。
  • #cgo CFLAGS: cgoを使用する際に、Cコンパイラに渡すフラグを指定するためのディレクティブです。
    • -mmacosx-version-min=10.6: コンパイルされたバイナリがmacOS 10.6以降で動作するように指定します。これにより、コンパイラは指定されたバージョンで利用可能なAPIのみを使用するように制限されます。
    • -D__MAC_OS_X_VERSION_MAX_ALLOWED=1060: プリプロセッサマクロを定義します。__MAC_OS_X_VERSION_MAX_ALLOWEDは、コンパイル時に利用可能なmacOS SDKの最大バージョンを示すマクロで、これを10.60(10.6)に設定することで、コンパイラが新しいAPI(例えば10.7で導入されたもの)を使用しないように強制します。
  • Issue #3131: Go言語の公式リポジトリgolang/goにおけるIssueで、「cmd/go: go command failed with missing symbol on OS X 10.6」というタイトルでした。これは、macOS 10.6環境でgoコマンドが、存在しないシンボル(API)を参照しようとして失敗するというバグ報告でした。

技術的詳細

このコミットは、src/pkg/crypto/tls/root_darwin.goファイルに対して行われました。このファイルは、macOS上でシステムルート証明書ストアからPEM形式の証明書をフェッチするロジックを含んでいます。

以前のコードでは、macOS 10.7以降のSDKでビルドされた場合にSecItemExportを優先的に使用し、それが利用できない場合(例えばmacOS 10.6で実行される場合)にSecKeychainItemExportにフォールバックする条件付きコンパイルロジックが含まれていました。これは#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1070というプリプロセッサディレクティブによって制御されていました。

しかし、このアプローチでは、コンパイル時に新しいAPIがリンクされてしまい、古いOSバージョンで実行する際にシンボルが見つからない問題が発生していました。

このコミットでは、以下の変更が加えられました。

  1. #cgo CFLAGSの変更:
    • 削除: -Wno-error -Wno-deprecated-declarations
      • これは、非推奨APIの使用による警告やエラーを抑制するためのフラグでした。
    • 追加: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1060
      • これらのフラグは、コンパイラに対して、生成されるバイナリがmacOS 10.6以降で動作することを保証し、かつコンパイル時に利用可能なAPIの最大バージョンを10.6に制限するよう指示します。これにより、コンパイラはSecItemExportのような10.7以降で導入されたAPIをコード生成に使用しなくなります。
  2. API呼び出しロジックの簡素化:
    • 以前の#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1070による条件付きコンパイルブロックが削除されました。
    • 代わりに、SecKeychainItemExportへの直接的な呼び出しのみが残されました。これにより、常にmacOS 10.6で利用可能な古いAPIが使用されるようになります。
  3. コメントの更新:
    • SecKeychainItemExportが10.7で非推奨になったこと、そしてcgoが弱いインポートをサポートした際にはSecItemExportを優先すべきであるという旨のコメントが追加されました。

これらの変更により、Goのcrypto/tlsパッケージは、macOS 10.6環境でもシンボルエラーなしに動作するようになります。これは、新しいAPIへの依存をコンパイル時に排除し、古いAPIに固定することで実現されています。

コアとなるコードの変更箇所

変更はsrc/pkg/crypto/tls/root_darwin.goファイルに集中しています。

--- a/src/pkg/crypto/tls/root_darwin.go
+++ b/src/pkg/crypto/tls/root_darwin.go
@@ -5,11 +5,9 @@
 package tls
 
 /*
-// Note: We disable -Werror here because the code in this file uses a deprecated API to stay
-// compatible with both Mac OS X 10.6 and 10.7. Using a deprecated function on Darwin generates
-// a warning.
-#cgo CFLAGS: -Wno-error -Wno-deprecated-declarations
+#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1060
 #cgo LDFLAGS: -framework CoreFoundation -framework Security
+\n
 #include <CoreFoundation/CoreFoundation.h>\n #include <Security/Security.h>\n 
@@ -40,26 +38,12 @@ int FetchPEMRoots(CFDataRef *pemRoots) {
 			continue;
 		}
 
-		// SecKeychainImportExport is deprecated in >= OS X 10.7, and has been replaced by
-		// SecItemExport.  If we're built on a host with a Lion SDK, this code gets conditionally
-		// included in the output, also for binaries meant for 10.6.
-		//
-		// To make sure that we run on both Mac OS X 10.6 and 10.7 we use weak linking
-		// and check whether SecItemExport is available before we attempt to call it. On
-		// 10.6, this won't be the case, and we'll fall back to calling SecKeychainItemExport.
-#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
-		if (SecItemExport) {
-			err = SecItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
-			if (err != noErr) {
-				continue;
-			}
-		} else
-#endif
-		if (data == NULL) {
-			err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
-			if (err != noErr) {
-				continue;
-			}
+		// Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
+		// Once we support weak imports via cgo we should prefer that, and fall back to this
+		// for older systems.
+		err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
+		if (err != noErr) {
+			continue;
 		}
 
 		if (data != NULL) {

コアとなるコードの解説

  1. #cgo CFLAGSの変更:
    • #cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1060
      • この行が追加されたことで、Goコンパイラがcgoを介してCコードをコンパイルする際に、macOSのターゲットバージョンを10.6に設定し、利用可能なAPIの最大バージョンも10.6に制限します。これにより、コンパイラはmacOS 10.7以降で導入されたSecItemExportのような新しいAPIのプロトタイプや定義を無視し、古いAPIのみを考慮するようになります。
  2. API呼び出しロジックの簡素化:
    • 以前のコードには、#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1070というプリプロセッサディレクティブを用いた条件付きコンパイルブロックがありました。このブロックは、ビルド環境のSDKがmacOS 10.7以降の場合にSecItemExportを使用しようとし、それ以外の場合やSecItemExportが利用できない場合にSecKeychainItemExportにフォールバックするロジックを含んでいました。
    • このコミットでは、この条件付きブロックが完全に削除されました。
    • 代わりに、err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);という行が直接呼び出されるようになりました。これにより、常にSecKeychainItemExport(macOS 10.6で利用可能)が使用されることが保証されます。
  3. コメントの追加:
    • // Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
    • // Once we support weak imports via cgo we should prefer that, and fall back to this
    • // for older systems.
      • このコメントは、SecKeychainItemExportが非推奨であること、そして将来的にcgoが弱いインポートをサポートした際には、より新しいSecItemExportを優先し、古いシステムのためにSecKeychainItemExportにフォールバックするべきであるという、この変更が暫定的なものであることを明確にしています。

これらの変更により、Goのcrypto/tlsパッケージは、macOS 10.6環境でも正しくビルドされ、実行時にAPIのシンボルが見つからないという問題を回避できるようになりました。

関連リンク

参考にした情報源リンク