Help us understand the problem. What is going on with this article?

プロジェクトファイルからXcodeGenのproject.ymlを生成する

はじめに

数年経つプロジェクトに途中からXcodeGenを入れるのは骨折れる作業が、、、

そんな中、気になる内容を見つけた

スクリーンショット 2020-02-03 2.16.36.png

お、やってみよ!

導入

0. 前提

#735は、まだマージされていないので未完成です。
PRの説明でもそれは記載されています。

スクリーンショット 2020-02-01 16.19.42.png

いくつか対応がなされていないようです。
なので、使用してみてメリデメの調査を含めてやっていきます。

1. インストール

PRのブランチを指定してXcodeGenを落としてきます。
その後、インストールしましょう。

$ git clone -b spec-generation https://github.com/yonaskolb/XcodeGen.git

$ cd XcodeGen

$ make install

※ make install で少し時間がかかるので注意
※ ブランチ指定するために普通にcloneしていますが、他の方法でも指定できるならそれでも問題ありません

2. project.ymlの生成

プロジェクトのルートディレクトリまで移動し、コマンドを実行します。

$ xcodegen migrate --project xxx.xcodeproj --spec project.yml

xxx.xcodeprojは各自のプロジェクト名に変更してください)

すると、ルートディレクトリにproject.ymlが生成されているはずです。

と言うわけで簡単に行えました!

問題点と解決策

実際に運用するとなるといくつかの問題点が見えてきました。
(まだPRが未完成なので、当たり前っちゃ当たり前ですが、、笑)

1. 設定したConfigurationが生成されない

以下のように、3つを設定していましたが

スクリーンショット 2020-02-01 19.00.46.png

実際にymlに生成されたものは以下でした。

スクリーンショット 2020-02-01 18.56.51.png

これは他のプロジェクトでも試しましたが、debug/releaseしか生成されないようです。

なので自前で書く必要があります。が、configsの部分だけで問題ありません。
なぜなら、設定やアプリへの紐付け部分は吐き出されています。

スクリーンショット 2020-02-01 19.11.35 2.png

(長いので間を省略しています)

このようにdebug/develop/releaseの3つ分の設定が、吐き出されているのがわかります。
なので、configsで定義し直しあげることで、ちゃんと動くようになります。

設定してあげないと、Xcodegen generateコマンドでこんなエラーが出ます。

スクリーンショット 2020-02-01 19.19.58.png

設定に関しては、この記事を参考にすると良いでしょう。
Xcodeプロジェクトの生成ツール「XcodeGen」のセットアップ&操作方法

2. 設定したschemeが生成されない

以下のように、3つを設定していましたが

スクリーンショット 2020-02-01 19.02.51.png

実際にymlには何も生成されていませんでした。
こちらもConfiguration同様に追加する必要があります。

最低限、動くようになる例を置いておきます。

schemes:
  MailerTestAppDebug:
    build:
      targets:
        MailerTestApp: all
        MailerTestAppTests: [test]
        MailerTestAppUITests: [test]
  MailerTestAppDevelop:
    build:
      targets:
        MailerTestApp: all
  MailerTestAppRelease:
    build:
      targets:
        MailerTestApp: all

アプリ名は各自のでお願いします。
実際はもっと細かく設定してください。

3. xcconfigの紐付けが生成されない

こちらも自前で追加しましょう

configFiles:
  Debug: configs/Debug.xcconfig
  Develop: configs/Develop.xcconfig
  Release: configs/Release.xcconfig

そもそもymlに全て移行してしまうのも手ではありますが、、

4. 生成されたymlが肥大化

余計なコードが入ってしまい肥大化がみられました。

では、何が余計なのでしょうか、、?

以下、いくつかの例を紹介します。

① Clang(コンパイラ)の設定

Xcodeにデフォルトで設定されている、コンパイラの部分が吐き出されることで肥大化します。
SchemeやTestのTargetごとに吐かれるため、以下のようなコード群がいくつも生成されます。

    CLANG_ANALYZER_NONNULL: YES
    CLANG_CXX_LANGUAGE_STANDARD: gnu++0x
    CLANG_CXX_LIBRARY: libc++
    CLANG_ENABLE_MODULES: YES
    CLANG_ENABLE_OBJC_ARC: YES
    CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING: YES
    CLANG_WARN_BOOL_CONVERSION: YES
    CLANG_WARN_COMMA: YES
    CLANG_WARN_CONSTANT_CONVERSION: YES
    CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS: YES
    CLANG_WARN_DIRECT_OBJC_ISA_USAGE: YES_ERROR
    CLANG_WARN_EMPTY_BODY: YES
    CLANG_WARN_ENUM_CONVERSION: YES
    CLANG_WARN_INFINITE_RECURSION: YES
    CLANG_WARN_INT_CONVERSION: YES
    CLANG_WARN_NON_LITERAL_NULL_CONVERSION: YES
    CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF: YES
    CLANG_WARN_OBJC_LITERAL_CONVERSION: YES
    CLANG_WARN_OBJC_ROOT_CLASS: YES_ERROR
    CLANG_WARN_RANGE_LOOP_ANALYSIS: YES
    CLANG_WARN_STRICT_PROTOTYPES: YES
    CLANG_WARN_SUSPICIOUS_MOVE: YES
    CLANG_WARN_UNREACHABLE_CODE: YES
    CLANG_WARN__DUPLICATE_METHOD_MATCH: YES

特定の意図がない限りはいじることがないので、ymlからごっそり消して良いかと思います。
(ymlに記載しなくても、デフォルトで設定されるので)

② GCC(コンパイラ)の設定

①と同じですが、以下のようなコード群がいくつも生成されます。

    GCC_WARN_64_TO_32_BIT_CONVERSION: YES
    GCC_WARN_ABOUT_RETURN_TYPE: YES_ERROR
    GCC_WARN_UNDECLARED_SELECTOR: YES
    GCC_WARN_UNINITIALIZED_AUTOS: YES_AGGRESSIVE
    GCC_WARN_UNUSED_FUNCTION: YES
    GCC_WARN_UNUSED_VARIABLE: YES

こちらもymlからごっそり消して良いかと思います。

③ Carthege(framework)の設定が入ってしまう

このように列挙されてしまいます。

    - inputFiles:
      - $(SRCROOT)/Carthage/Build/iOS/Alamofire.framework
      - $(SRCROOT)/Carthage/Build/iOS/Realm.framework
      - $(SRCROOT)/Carthage/Build/iOS/RealmSwift.framework
      - $(SRCROOT)/Carthage/Build/iOS/SwiftyStoreKit.framework
      - $(SRCROOT)/Carthage/Build/iOS/Reachability.framework
      - $(SRCROOT)/Carthage/Build/iOS/KeychainAccess.framework
      - $(SRCROOT)/Carthage/Build/iOS/RxSwift.framework
      - $(SRCROOT)/Carthage/Build/iOS/RxCocoa.framework
      - $(SRCROOT)/Carthage/Build/iOS/Nuke.framework
      - $(SRCROOT)/Carthage/Build/iOS/NukeWebP.framework

dependenciesにライブラリ(framework)を記載しておけば、XcodeGenが勝手に紐づけてくれるのでごっそり消してしまいましょう。

④ Cocoapod(framework)の設定が入ってしまう

    - inputFiles:
      - ${PODS_ROOT}/Target Support Files/Pods-delish/Pods-delish-frameworks.sh
      - ${BUILT_PRODUCTS_DIR}/FBSDKCoreKit/FBSDKCoreKit.framework
      - ${BUILT_PRODUCTS_DIR}/FBSDKLoginKit/FBSDKLoginKit.framework
      - ${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework
     name: '[CP] Embed Pods Frameworks'
      outputFiles:
      - ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CocoaLumberjack.framework
      - ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBSDKCoreKit.framework
      - ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBSDKLoginKit.framework
      - ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework
      runOnlyWhenInstalling: false
      script: '"${PODS_ROOT}/Target Support Files/Pods-delish/Pods-delish-frameworks.sh"'
      shell: /bin/sh
      showEnvVars: false
    OTHER_LDFLAGS:
    - $(inherited)
    - -ObjC
    - -l"c++"
    - -l"sqlite3"
    - -l"stdc++"
    - -l"z"
    - -framework
    - '"AVFoundation"'
    - -framework
    - '"Accounts"'
    - -framework
    - '"AddressBook"'
           
           
           

pod installで勝手に追加されるので、ごっそり消してしまいましょう。

⑤ 1ファイルごとに登録されてしまう

以下のように列挙された形で出力されます。

    sources:
    - app/AppDelegate.swift
    - app/Extensions/UIImageView+Extensions.swift
    - app/Extensions/UIView+Extensions.swift
    - app/Extensions/UITableView+Extensions.swift
    - app/Extensions/UICollectionView+Extensions.swift
                
                
                

このように一覧で出るため、グループ化はされていないのです。

なので、以下のようにしてまとめてあげると良いでしょう。

    sources:
    - path: app
    - path: Extensions
      type: directory

XcodeGentype directoryで簡潔になりました。

4. すべてのファイルがルートディレクトリにきてしまう(Xcode上で)

これは「③ 1ファイルごとに登録されてしまう」に付随しますが、1ファイルごとに登録されてしまうために起こります。

こちらは、sourcesで読み込みたいファイルを指定することで解決できます。
(なので、同様に不要なpathの参照をまとめるなり・消すなりする必要があります)

考察

メリット

かゆいオプションを描き出さなくて済む
これに尽きるかと思います。

buildのsettingsもそうですが、たとえば、

- Run script
- Notification/today などのextension

など、見比べてymlに書いていくのは以外に面倒だったりします。笑

デメリット

問題点に基本的に集約されますが、

PRがまだ未完成
  - 一部の設定が反映されない
  - ymlの肥大化

一部」の設定と書いてますが、まあまああるのでなんとも言えないラインではあります、、

現状

既存プロジェクトにおいては、こちらを使ってみるのはアリだと思います。

というのも、基本的には吐き出されないScheme/Configurationの設定だけ、自分で追記すればビルドできるので、ymlが肥大化しようが関係ないです。
(sourcesでディレクトリ構成も設定する必要あり)

既存でこちらを導入する場合は、こちら(PRのXocdeGen)でつくったymlを叩き台にして、ymlファイルを整理していくのが良いかと思います。

ただ、新規アプリでXcodeGenを導入するなら、自前でymlを書いた方良いかと思います。
行数も少なくてすみ、なにより読みやすいかと思います。
(作ったばかりのプロジェクトも含む)

終わりに

XcodeGenのメリットは、よく「コンフリクトしなくなること」が例に挙げられますが、そこはそんなにメリットではなく
(普通に開発ルールを守っていればそんなに大きくおきないし、解消するのも難しくない)

こちらの記事にもありますが
(株式会社キュリオシティソフトウェア - 2019年上半期のiOSアプリ開発振り返り)

わざわざSchemeで設定を変えるみたいな変なことやっててもConfigurationに差し替え可能
Scheme間やConfiguration間の設定値の差分がコードなのでわかりやすい

つまり、XcodeのGUIでしか閲覧・編集できなかったことが、一覧で見れることの方が大きいです。

既存でこちらを導入する場合は、その一覧で見れるメリットが少し薄れてしまいます。
(行数多いし、無駄なコードが設定が増えてしまうため比較しづらい)

まだまだ、開発途中なので本体にmergeされることを期待しつつ、、と言う感じでしょうか笑

hcrane
iOS Developer
fablic
満足度No.1 のフリマアプリ「ラクマ」を運営しています。
https://fril.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away