XcodeのExcluded Source File Namesを使って不要なファイルを除外する

Xcodeの`Build Settings`の`Excluded Source File Names`を利用する事で、対象のビルドから指定したファイルを取り除くことが出来ます。

`#if DEBUG`のようなマクロは、おそらく、いろんなプロジェクトで利用されていると思いますが、`Excluded Source File Names`は意外と使われていない印象を受けたので、記事にしてみようと思いました。

最近関わったプロジェクトでも、`Excluded Source File Names`ではなく、ファイルの先頭と末尾に、`#if DEBUG`と`#endif`を書いて運用していました。
こんな感じですね。

```swift
#if DEBUG

import SwiftUI

/// Data for the top style charts.
struct DebugTopStyleDataB {
    /// Sales by pancake style for the last 30 days, sorted by amount.
    static let last30Days = [
        (name: "Demo001", sales: 200),
        (name: "Demo002", sales: 300),
        (name: "Demo003", sales: 500),
        (name: "Demo004", sales: 700),
        (name: "Demo005", sales: 100),
        (name: "Demo006", sales: 400)
    ]

    /// Sales by pancake style for the last 12 months, sorted by amount.
    static let last12Months = [
        (name: "Demo001", sales: 9000),
        (name: "Demo002", sales: 7000),
        (name: "Demo003", sales: 6000),
        (name: "Demo004", sales: 5000),
        (name: "Demo005", sales: 8000),
        (name: "Demo006", sales: 4000)
    ]
}
#endif
```
これでも、もちろん、DEBUGの場合しか該当コードはビルドされないので、要件は満たせていると思います。
ただ、デバッグ用のJSONフィイルや画像ファイルについては、どうすればいいのでしょうか？

そんな場合に`Excluded Source File Names`が活用できます。

例えば、以下のようなフォルダ構成の場合、
![スクリーンショット 2022-08-15 14.26.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30834/e88e62da-742d-aac0-1205-98d42d498157.png)
`Excluded Source File Names`の`Release`に対して、以下のように、`$PROJECT_DIR/SwiftChartsExample/Stub/Data/*`と指定すると、
![スクリーンショット 2022-08-15 14.29.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30834/1643058e-0735-a4ca-adb7-6bbcfcb48412.png)
そのフォルダに含まれているファイル、今回で言うと、`imageB.png`、`SampleB.json`、`DebugDataB.swift`が、リリースビルドをおこなった場合に、除外されます。（JSONや画像ファイルはコピーされなくなり、Swiftファイルはコンパイルされなくなります。）

実際にDebugとReleaseでビルドを行い、ビルドログを確認してみます。

まずはBuild ConfigurationをDebugのままでビルドを実行します。
![スクリーンショット 2022-08-15 14.36.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30834/ad16990c-302a-17da-9d67-00619978e2d1.png)
![スクリーンショット 2022-08-15 14.36.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30834/3936d727-b5ad-1f5d-b2d1-eb3155eee777.png)
![スクリーンショット 2022-08-15 14.36.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30834/6ea4ba94-72f1-b21f-6ca3-b66835f34ff1.png)
上記スクリーンショットのように、ビルドログを確認すると、`imageB.png`、`SampleB.json`はコピーされ、`DebugDataB.swift`はコンパイルされていることが分かります。

では次に、Build ConfigurationをReleaseに変更します。
![スクリーンショット 2022-08-15 14.37.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30834/c9f5dea7-ec2f-5d58-4291-c7251a50bbf1.png)

そして、同じようにビルドを実行します。
![スクリーンショット 2022-08-15 14.38.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30834/babecbd9-5921-2395-8d9a-e2858c66330e.png)
![スクリーンショット 2022-08-15 14.38.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30834/e45a94ac-89b4-516f-097d-173134060f96.png)
![スクリーンショット 2022-08-15 14.37.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30834/0e3613da-6640-d1b3-761b-a087d1672592.png)
同じようにビルドログを確認すると、上記スクリーンショットのように、`imageB.png`、`SampleB.json`がコピーされたと言うログは見つからず、`DebugDataB.swift`についても、コンパイルされたと言うログは見当たりません。

このように、`Excluded Source File Names`を活用する事で、リソースファイルをコピーしないようにしたり、ファイル自体をコンパイルしないようにする事が可能となります。
この仕組みを利用すれば、ファイルの先頭と末尾に、`#if DEBUG`と`#endif`を書く、という作業は不要になるかもしれませんね。


## 補足
最後に、`Excluded Source File Names`について少し補足しておきます。

### 指定方法
上記の説明では、除外対象のファイルパスを`$PROJECT_DIR/SwiftChartsExample/Stub/Data/*`のように絶対パスで指定していましたが、手元で試したところ、`SwiftChartsExample/Stub/Data/*`として相対パスでの指定も可能でした。

### XcodeGen
`Excluded Source File Names`の設定は、XcodeGenでも可能です。
`settings`の`configs`に、`EXCLUDED_SOURCE_FILE_NAMES`を追加して、除外したい内容を定義することが出来ます。

```yml
    settings:
      configs:
        Debug:
          EXCLUDED_SOURCE_FILE_NAMES: SwiftChartsExample/Stub/** SwiftChartsExample/Stub/Data/**
```

### 除外設定のワイルドカードの挙動について
`Excluded Source File Names`の設定は、　サブフォルダに対しては動作しないようです。
`**`を指定すれば良いと言う内容を見かけましたが、実際に手元で試したところ、うまく除外ができませんでした。

以下、`Stub`と`Stub/Data`フォルダに対して、実際に指定した内容とビルドの結果を記載しておきます。

| 設定内容 | `Stub`フォルダ内のファイル | `Stub/Data`フォルダのファイル |
|------------------|------------------|------------------|
| `**/Stub*`                    | 除外されなかった     | 除外されなかった     |
| `**/Stub/**/*`                | 除外されなかった     | 除外されなかった     |
| `SwiftChartsExample/Stub**`   | 除外されなかった     | 除外されなかった     |
| `SwiftChartsExample/Stub*`  　　　　| 除外されなかった     | 除外されなかった     |
| `SwiftChartsExample/Stub/**`  | 除外された          | 除外されなかった     |
| `SwiftChartsExample/Stub/*`　　  | 除外された          | 除外されなかった     |
| `SwiftChartsExample/Stub/**/*`　　| 除外されなかった     | 除外された     |
| `SwiftChartsExample/Stub/**/**`　　| 除外されなかった     | 除外された     |
| `SwiftChartsExample/Stub/*/**`　　| 除外されなかった     | 除外された     |
| `SwiftChartsExample/Stub/*` `SwiftChartsExample/Stub/Data/*`　| 除外された     | 除外された     |
| `SwiftChartsExample/Stub/**` `SwiftChartsExample/Stub/Data/**`　| 除外された     | 除外された     |

以上の結果、サブフォルダがある場合は、サブフォルダの記述も行っておく方が良いと思います。
今回のサンプルでは、`SwiftChartsExample/Stub/*`と`SwiftChartsExample/Stub/Data/*`を指定する感じになると思います。

ワイルドカードでサブフォルダも含めて指定できる方法をご存知の方は、是非、情報提供をお願い致します。