GenerateDSYMFileで警告が出る件
Xcode7で出力したstaticライブラリをリンクすると、GenerateDSYMFileで大量の警告が出力されることがあります。
解決方法はこちらのエントリ
StaticLibraryを配布したらXcode7で大量にワーニングが出た
http://qiita.com/toguri/items/a0a05d2da67801470ecd
に書いてあるとおり、Enable Modules (C and Objective-C) (CLANG_ENABLE_MODULES) = NO
を設定するのもひとつの手です。
しかし、配布目的のライブラリということを考えると、strip
コマンドでデバッグ情報を削除してしまうのも有効です。
strip -S build/Release-iphoneos/libMyStaticLibrary.a
参考: stripコマンドのヘルプが置いてあるページ
http://kazmax.zpp.jp/cmd/s/strip.1.html
デバッグ情報には基本的にローカルのソースコードの行番号と、バイナリコードとの対応関係が記述されています。ここで作るライブラリが他の開発環境への配布目的のものなのであれば、デバッグ情報は削除してしまって構わないと思います。
もし心配であればstrip前のものも、ソースのバージョンと共に保存しておけばよいかと。
大切なことは以上です。
何が起きているのか
以下興味がある人だけお読みください。
理解を深めるために、何が起きているか調べてみようと思います。
小さな再現環境を作る
まずは問題の起きない環境
まずMyStaticLibraryという名前で簡単なライブラリプロジェクトを作ってみます。
% tree MyStaticLibrary
MyStaticLibrary
├── MyStaticLibrary
│ ├── MyStaticLibrary.h
│ └── MyStaticLibrary.m
└── MyStaticLibrary.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
└── xcuserdata
MyStaticLibrary.h/mには、あとでコールスタックを確認できるように、多少呼び出し関係がある関数を作っておきます。
#import <Foundation/Foundation.h>
@interface Hoge1 : NSObject
- (void)say1;
@end
@interface Hoge2 : NSObject
- (void)say2;
@end
#import "MyStaticLibrary.h"
@implementation Hoge1
- (void)say1 {
NSString *hello = [NSString stringWithFormat:@"hello 1! %@", [NSDate date]];
NSLog(@"%@", hello);
}
@end
@implementation Hoge2
- (void)say2 {
NSString *hello = [NSString stringWithFormat:@"hello 2! %@", [NSDate date]];
NSLog(@"%@", hello);
[[[Hoge1 alloc] init] say1];
}
@end
xcodebuildコマンドでビルドしてみましょう。
% xcodebuild
(中略)
CreateUniversalBinary build/Release-iphoneos/libMyStaticLibrary.a normal armv7\ arm64
(中略)
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool -static /Users/gamako/project/test/MyStaticLibrary/build/MyStaticLibrary.build/Release-iphoneos/MyStaticLibrary.build/Objects-normal/armv7/libMyStaticLibrary.a /Users/gamako/project/test/MyStaticLibrary/build/MyStaticLibrary.build/Release-iphoneos/MyStaticLibrary.build/Objects-normal/arm64/libMyStaticLibrary.a -o /Users/gamako/project/test/MyStaticLibrary/build/Release-iphoneos/libMyStaticLibrary.a
(中略)
** BUILD SUCCEEDED **
build/Release-iphoneos/libMyStaticLibrary.a にリリースビルドしたファイルが生成されました。
XcodeのGUI上でビルドした場合は、 /Users/xxx/Library/Developer/Xcode/DerivedData/MyStaticLibrary-xxxxxxxxxx
以下のどこかに生成されると思います。
これをリンクするiOSアプリプロジェクトを作ってみましょう。
% tree MyApp
MyApp
├── MyApp
│ ├── AppDelegate.h
│ ├── AppDelegate.m
│ ├── Assets.xcassets
│ │ └── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── Info.plist
│ ├── ViewController.h
│ ├── ViewController.m
│ └── main.m
└── MyApp.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
└── xcuserdata
先ほどのライブラリをリンクできて、ヘッダを探せるように、パスとライブラリを設定に追加しておきます。
% xcodebuild -showBuildSettings | egrep "(OTHER_LDFLAGS)|(HEADER_SEARCH_PATHS)|(LIBRARY_SEARCH_PATHS)"
HEADER_SEARCH_PATHS = ../MyStaticLibrary/build/Release-iphoneos/include/MyStaticLibrary
LIBRARY_SEARCH_PATHS = ../MyStaticLibrary/build/Release-iphoneos/
OTHER_LDFLAGS = -lMyStaticLibrary
ViewControllerでライブラリを呼び出すようにします。
#import "ViewController.h"
#import "MyStaticLibrary.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[[[Hoge2 alloc] init] say2];
}
@end
これで準備ができたので、iPhone実機で実行してみます。
ビルド時に警告は出ずに、デバッグメッセージが表示されました。ここまではOKです。
2016-03-17 23:55:01.349 MyApp[4463:1982532] hello 2! 2016-03-17 14:55:01 +0000
2016-03-17 23:55:01.349 MyApp[4463:1982532] hello 1! 2016-03-17 14:55:01 +0000
問題が起きる環境をつくる
ここで、もとのライブラリのプロジェクトにプリコンパイルヘッダー(プリフィックスヘッダー)を追加してみます
% tree MyStaticLibrary
MyStaticLibrary
├── MyStaticLibrary
│ ├── MyStaticLibrary.h
│ ├── MyStaticLibrary.m
│ └── PrefixHeader.pch <------ これ
└── MyStaticLibrary.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
└── xcuserdata
中身はほぼ空でも再現するようです。
#ifndef PrefixHeader_pch
#define PrefixHeader_pch
#endif /* PrefixHeader_pch */
プロジェクト設定にも、このPrefix Headerを指定します
% xcodebuild -showBuildSettings | egrep "GCC_PREFIX_HEADER"
GCC_PREFIX_HEADER = MyStaticLibrary/PrefixHeader.pch
この変更で、一旦cleanしてから再度buildしてみます。
% xcodebuild clean; xcodebuild
(中略)
** CLEAN SUCCEEDED **
(中略)
** BUILD SUCCEEDED **
このライブラリをもって、アプリのプロジェクトを再ビルドすると、まだ問題なくビルドできます。
違う環境でのビルドをシミュレート
ここで、違う環境でビルドした場合を想定して、ライブラリのビルド時にできた中間ファイルのパスを無効にしてみましょう。
% rm -rf MyStaticLibrary/build/MyStaticLibrary.build
これだと特に影響ないようです。
libMyStaticLibrary.aオブジェクトの中のデバッグ情報をdwarfdumpコマンドで覗いてみましょう
% dwarfdump MyStaticLibrary/build/Release-iphoneos/libMyStaticLibrary.a
(中略)
AT_GNU_dwo_name( "/var/folders/fd/kh0pf2w11w10t1j3qwvdrbwc0000gn/C/org.llvm.clang.gamako/ModuleCache/6FW3GUALCRZP/Foundation-A3SOD99KJ0S9.pcm" )
(中略)
AT_GNU_dwo_name( "/var/folders/fd/kh0pf2w11w10t1j3qwvdrbwc0000gn/C/org.llvm.clang.gamako/ModuleCache/6FW3GUALCRZP/ObjectiveC-2CD0WTQVXITO7.pcm" )
(中略)
AT_GNU_dwo_name( "/var/folders/fd/kh0pf2w11w10t1j3qwvdrbwc0000gn/C/org.llvm.clang.gamako/ModuleCache/1WQ7A71Y8Z1KR/Foundation-A3SOD99KJ0S9.pcm" )
(中略)
AT_GNU_dwo_name( "/var/folders/fd/kh0pf2w11w10t1j3qwvdrbwc0000gn/C/org.llvm.clang.gamako/ModuleCache/1WQ7A71Y8Z1KR/ObjectiveC-2CD0WTQVXITO7.pcm" )
/var/folders/fd/kh0pf2w11w10t1j3qwvdrbwc0000gn/... のパスが書かれています。このパスも無効にしてみましょう。
% rm -rf /var/folders/fd/kh0pf2w11w10t1j3qwvdrbwc0000gn/C/org.llvm.clang.gamako/ModuleCache/6FW3GUALCRZP
% rm -rf /var/folders/fd/kh0pf2w11w10t1j3qwvdrbwc0000gn/C/org.llvm.clang.gamako/ModuleCache/1WQ7A71Y8Z1KR
iOSアプリプロジェクトのほうを、一旦クリーンしてからビルドすると、GenerateDSYMFileで警告たくさん表示されました。
先ほど消したファイルが無いのが気に食わないようです。
% xcodebuild
(中略)
GenerateDSYMFile build/Release-iphoneos/MyApp.app.dSYM build/Release-iphoneos/MyApp.app/MyApp
(中略)
while processing /Users/gamako/project/test/MyApp/../MyStaticLibrary/build/Release-iphoneos/libMyStaticLibrary.a(MyStaticLibrary.o):
warning: /var/folders/fd/kh0pf2w11w10t1j3qwvdrbwc0000gn/C/org.llvm.clang.gamako/ModuleCache/6FW3GUALCRZP/Foundation-A3SOD99KJ0S9.pcm: No such file or directory
while processing /Users/gamako/project/test/MyApp/../MyStaticLibrary/build/Release-iphoneos/libMyStaticLibrary.a(MyStaticLibrary.o):
warning: /var/folders/fd/kh0pf2w11w10t1j3qwvdrbwc0000gn/C/org.llvm.clang.gamako/ModuleCache/6FW3GUALCRZP/Foundation-A3SOD99KJ0S9.pcm: No object file for requested architecture
while processing /Users/gamako/project/test/MyApp/../MyStaticLibrary/build/Release-iphoneos/libMyStaticLibrary.a(MyStaticLibrary.o):
warning: /var/folders/fd/kh0pf2w11w10t1j3qwvdrbwc0000gn/C/org.llvm.clang.gamako/ModuleCache/6FW3GUALCRZP/ObjectiveC-2CD0WTQVXITO7.pcm: No such file or directory
while processing /Users/gamako/project/test/MyApp/../MyStaticLibrary/build/Release-iphoneos/libMyStaticLibrary.a(MyStaticLibrary.o):
warning: /var/folders/fd/kh0pf2w11w10t1j3qwvdrbwc0000gn/C/org.llvm.clang.gamako/ModuleCache/6FW3GUALCRZP/ObjectiveC-2CD0WTQVXITO7.pcm: No object file for requested architecture
while processing /Users/gamako/project/test/MyApp/../MyStaticLibrary/build/Release-iphoneos/libMyStaticLibrary.a(MyStaticLibrary.o):
warning: Could not resolve external type c:objc(cs)NSObject
while processing /Users/gamako/project/test/MyApp/../MyStaticLibrary/build/Release-iphoneos/libMyStaticLibrary.a(MyStaticLibrary.o):
warning: Could not resolve external type c:objc(cs)NSObject
while processing /Users/gamako/project/test/MyApp/../MyStaticLibrary/build/Release-iphoneos/libMyStaticLibrary.a(MyStaticLibrary.o):
warning: Could not resolve external type c:objc(cs)NSString
while processing /Users/gamako/project/test/MyApp/../MyStaticLibrary/build/Release-iphoneos/libMyStaticLibrary.a(MyStaticLibrary.o):
warning: /var/folders/fd/kh0pf2w11w10t1j3qwvdrbwc0000gn/C/org.llvm.clang.gamako/ModuleCache/1WQ7A71Y8Z1KR/Foundation-A3SOD99KJ0S9.pcm: No such file or directory
while processing /Users/gamako/project/test/MyApp/../MyStaticLibrary/build/Release-iphoneos/libMyStaticLibrary.a(MyStaticLibrary.o):
warning: /var/folders/fd/kh0pf2w11w10t1j3qwvdrbwc0000gn/C/org.llvm.clang.gamako/ModuleCache/1WQ7A71Y8Z1KR/Foundation-A3SOD99KJ0S9.pcm: No object file for requested architecture
while processing /Users/gamako/project/test/MyApp/../MyStaticLibrary/build/Release-iphoneos/libMyStaticLibrary.a(MyStaticLibrary.o):
warning: /var/folders/fd/kh0pf2w11w10t1j3qwvdrbwc0000gn/C/org.llvm.clang.gamako/ModuleCache/1WQ7A71Y8Z1KR/ObjectiveC-2CD0WTQVXITO7.pcm: No such file or directory
while processing /Users/gamako/project/test/MyApp/../MyStaticLibrary/build/Release-iphoneos/libMyStaticLibrary.a(MyStaticLibrary.o):
warning: /var/folders/fd/kh0pf2w11w10t1j3qwvdrbwc0000gn/C/org.llvm.clang.gamako/ModuleCache/1WQ7A71Y8Z1KR/ObjectiveC-2CD0WTQVXITO7.pcm: No object file for requested architecture
while processing /Users/gamako/project/test/MyApp/../MyStaticLibrary/build/Release-iphoneos/libMyStaticLibrary.a(MyStaticLibrary.o):
warning: Could not resolve external type c:objc(cs)NSObject
while processing /Users/gamako/project/test/MyApp/../MyStaticLibrary/build/Release-iphoneos/libMyStaticLibrary.a(MyStaticLibrary.o):
warning: Could not resolve external type c:objc(cs)NSObject
while processing /Users/gamako/project/test/MyApp/../MyStaticLibrary/build/Release-iphoneos/libMyStaticLibrary.a(MyStaticLibrary.o):
warning: Could not resolve external type c:objc(cs)NSString```
このパスは何?
/var/folders/fd/kh0pf2w11w10t1j3qwvdrbwc0000gn/...というパスは何なのでしょうか?
このパスは、実はXcodeの設定をよく見ると、Precompiled Header Cache Pathというところのデフォルト設定に書いてありました。
もともとここにキャッシュを作るつもりだったようです。
しかし、ライブラリにキャッシュのパスを書くなんて、、という気もしますが、、、
AT_GNU_dwo_nameとは
libMyStaticLibrary.aに書いてあった、AT_GNU_dwo_nameというフィールドはなんなのでしょうか?
そもそも、dwarfdumpというのはオブジェクトファイルの中のデバッグ情報(DWARF)を表示してくれるツールです。
DWARFの仕様は以下にありますが、、、
公式
http://dwarfstd.org/Dwarf4Std.php
これらには書いていないようです。
先ほどのdwarfdumpのソースコードにヒントがありました。
https://github.com/tomhughes/libdwarf/blob/master/libdwarf/dwarf.h
/* The GNU DebugFission project: http://gcc.gnu.org/wiki/DebugFission */
#define DW_AT_GNU_dwo_name 0x2130 /* GNU */
#define DW_AT_GNU_dwo_id 0x2131 /* GNU */
gccのwikiのDebugFissionというページのURLが書いてあります。
http://gcc.gnu.org/wiki/DebugFission
こちらによると、DebugFissionプロジェクトは、デバッグ情報によりオブジェクトファイルが巨大になるのを避けるために、デバッグ情報を別ファイルを分離するための仕様だそうです。
この仕様に則って、別ファイルのリンクが書いてあったようです。
対応方法について
最初にも書きましたが、DWARFはstripコマンドで削除することができます。
strip -S build/Release-iphoneos/libMyStaticLibrary.a
この状態でiOSアプリプロジェクト側をビルドすることで、警告は出力されなくなりました。
DWARFの削除が、iOSアプリプロジェクト側のデバッグにどのように影響してくるかも書こうと思ったのですが、力尽きたのでまた別の機会に、、、