Xcode7でビルドしたライブラリでGenerateDSYMFile時に警告が出る


# GenerateDSYMFileで警告が出る件

Xcode7で出力したstaticライブラリをリンクすると、GenerateDSYMFileで大量の警告が出力されることがあります。

解決方法はこちらのエントリ

StaticLibraryを配布したらXcode7で大量にワーニングが出た
http://qiita.com/toguri/items/a0a05d2da67801470ecd


に書いてあるとおり、`Enable Modules (C and Objective-C) (CLANG_ENABLE_MODULES) = NO`を設定するのもひとつの手です。

しかし、配布目的のライブラリということを考えると、`strip`コマンドでデバッグ情報を削除してしまうのも有効です。

```bash
strip -S build/Release-iphoneos/libMyStaticLibrary.a
```

参考: stripコマンドのヘルプが置いてあるページ
http://kazmax.zpp.jp/cmd/s/strip.1.html

デバッグ情報には基本的にローカルのソースコードの行番号と、バイナリコードとの対応関係が記述されています。ここで作るライブラリが他の開発環境への配布目的のものなのであれば、デバッグ情報は削除してしまって構わないと思います。

もし心配であればstrip前のものも、ソースのバージョンと共に保存しておけばよいかと。

大切なことは以上です。

# 何が起きているのか

以下興味がある人だけお読みください。

理解を深めるために、何が起きているか調べてみようと思います。


## 小さな再現環境を作る

### まずは問題の起きない環境

まずMyStaticLibraryという名前で簡単なライブラリプロジェクトを作ってみます。

```bash
% tree MyStaticLibrary
MyStaticLibrary
├── MyStaticLibrary
│   ├── MyStaticLibrary.h
│   └── MyStaticLibrary.m
└── MyStaticLibrary.xcodeproj
    ├── project.pbxproj
    ├── project.xcworkspace
    │   ├── contents.xcworkspacedata
    │   └── xcuserdata
    └── xcuserdata

```

MyStaticLibrary.h/mには、あとでコールスタックを確認できるように、多少呼び出し関係がある関数を作っておきます。


```objectivec:MyStaticLibrary.h
#import <Foundation/Foundation.h>

@interface Hoge1 : NSObject
- (void)say1;
@end

@interface Hoge2 : NSObject
- (void)say2;
@end
```

```objectivec:MyStaticLibrary.m
#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コマンドでビルドしてみましょう。

```bash
% 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アプリプロジェクトを作ってみましょう。

```bash
% 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
```

先ほどのライブラリをリンクできて、ヘッダを探せるように、パスとライブラリを設定に追加しておきます。

```bash
% 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でライブラリを呼び出すようにします。

```objectivec:ViewController.m
#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
```

### 問題が起きる環境をつくる

ここで、もとのライブラリのプロジェクトにプリコンパイルヘッダー（プリフィックスヘッダー）を追加してみます

```bash
% tree MyStaticLibrary
MyStaticLibrary
├── MyStaticLibrary
│   ├── MyStaticLibrary.h
│   ├── MyStaticLibrary.m
│   └── PrefixHeader.pch   <------ これ
└── MyStaticLibrary.xcodeproj
    ├── project.pbxproj
    ├── project.xcworkspace
    │   ├── contents.xcworkspacedata
    │   └── xcuserdata
    └── xcuserdata

```

中身はほぼ空でも再現するようです。

```objectivec:PrefixHeader.pch                                                                                                                                     
#ifndef PrefixHeader_pch
#define PrefixHeader_pch

#endif /* PrefixHeader_pch */
```

プロジェクト設定にも、このPrefix Headerを指定します

```bash
% xcodebuild -showBuildSettings | egrep "GCC_PREFIX_HEADER"
    GCC_PREFIX_HEADER = MyStaticLibrary/PrefixHeader.pch

```

この変更で、一旦cleanしてから再度buildしてみます。

```bash
% xcodebuild clean; xcodebuild

(中略)

** CLEAN SUCCEEDED **

(中略)

** BUILD SUCCEEDED **

```

このライブラリをもって、アプリのプロジェクトを再ビルドすると、まだ問題なくビルドできます。

### 違う環境でのビルドをシミュレート


ここで、違う環境でビルドした場合を想定して、ライブラリのビルド時にできた中間ファイルのパスを無効にしてみましょう。

```bash
% rm -rf MyStaticLibrary/build/MyStaticLibrary.build
```

これだと特に影響ないようです。

libMyStaticLibrary.aオブジェクトの中のデバッグ情報をdwarfdumpコマンドで覗いてみましょう

```bash
% 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/... のパスが書かれています。このパスも無効にしてみましょう。

```bash
% 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で警告たくさん表示されました。
先ほど消したファイルが無いのが気に食わないようです。

```bash
% 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というところのデフォルト設定に書いてありました。

![xcode-pch-cache.png](https://qiita-image-store.s3.amazonaws.com/0/55599/429fe126-edfd-bf77-6bd4-987b9b1d13fa.png "xcode-pch-cache.png")

もともとここにキャッシュを作るつもりだったようです。

しかし、ライブラリにキャッシュのパスを書くなんて、、という気もしますが、、、

## AT_GNU_dwo_nameとは

libMyStaticLibrary.aに書いてあった、AT_GNU_dwo_nameというフィールドはなんなのでしょうか？

そもそも、dwarfdumpというのはオブジェクトファイルの中のデバッグ情報(DWARF)を表示してくれるツールです。

DWARFの仕様は以下にありますが、、、

公式
http://dwarfstd.org/Dwarf4Std.php

日本語 解説ページ
https://osdn.jp/projects/drdeamon64/wiki/DWARF%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%83%88

これらには書いていないようです。

先ほどのdwarfdumpのソースコードにヒントがありました。
https://github.com/tomhughes/libdwarf/blob/master/libdwarf/dwarf.h

```c: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コマンドで削除することができます。

```bash
strip -S build/Release-iphoneos/libMyStaticLibrary.a
```

この状態でiOSアプリプロジェクト側をビルドすることで、警告は出力されなくなりました。


DWARFの削除が、iOSアプリプロジェクト側のデバッグにどのように影響してくるかも書こうと思ったのですが、力尽きたのでまた別の機会に、、、