Xcodeでプロジェクト間共通のマクロを定義する

SDKなどの複数のライブラリやプログラムで構成されるモジュールを開発しているときなど、複数のプロジェクト間で共通のマクロ定義を参照することがあります。

たとえば、ある特定の機器と通信するSDKを開発しているときに、対象となる機器によって定数を切り替える必要があるとします。どの機器用にビルドするのかを、ヘッダファイルのマクロで切り替えられるようになっているとします。

このようなとき、共通のヘッダファイルをインクルードしているのであれば、そこで定義します。マクロを定義します。たとえば、Configuration.hファイルなどを用意するなどです。しかし、複数のプロジェクトファイルで構成され、そのような共通ファイルを置くことも難しいというケースではどうでしょうか?たとえば、Swiftであればヘッダファイルは使用しないですね。

このような場合にはビルド設定ファイルを使用します。記事を見ながらコードを実行してみたい方は、次のリンクからサンプルファイルをダウンロードしてください。

目次

ビルド設定ファイルを作成する

ビルド設定ファイルの作成方法とプロジェクトへの設定方法については、以下の記事を参照してください。

ここでは、例として次のようなディレクトリ構成で3つのプロジェクトを作成しました。

Modules
├── Common.xcconfig
├── Module1
│   ├── Module1
│   │   ├── Debug.xcconfig
│   │   ├── Release.xcconfig
│   │   └── main.swift
│   └── Module1.xcodeproj
├── Module2
│   ├── Module2
│   │   ├── Debug.xcconfig
│   │   ├── Release.xcconfig
│   │   └── main.m
│   └── Module2.xcodeproj
└── Module3
    ├── Module3
    │   ├── Debug.xcconfig
    │   ├── Release.xcconfig
    │   └── main.cpp
    └── Module3.xcodeproj

Module1Module2Module3はそれぞれ別々のプロジェクトファイルによりビルドされるプログラムになっており、お互いは参照していません。各プロジェクトはDebug.xcconfigRelease.xcconfigというビルド設定ファイルを持っています。名前の通り、デバッグ用とリリース用です。Debug.xcconfigRelease.xcconfigは次のように書かれており、Modules/Common.xcconfigを参照するようになっています。

#include "../Common.xcconfig"

これにより、Modules/Common.xcconfigファイルを編集することで、Module1.xcodeprojModule2.xcodeprojModule3.xcodeprojのビルド設定が変更できるようになります。

Swiftのコード

Swiftはシンボルの定義だけできるようになっています。Xcode上で定義するときは、ビルド設定のSwift Compiler - Custom FlagsOther Swift Flags-Dシンボル名の書式で定義します。複数あるときは、スペース区切りで列挙します。

Other Swift Flags で定義する

ビルド設定ファイルで定義するには

Other Swift Flagsをビルド設定ファイルで定義するときは、OTHER_SWIFT_FLAGSを使用します。たとえば、スクリーショットと同様に、USE_PHYSICAL_DEVICEを定義するときは次のように記述します。

OTHER_SWIFT_FLAGS = $(inherited) -DUSE_PHYSICAL_DEVICE

ビルド設定ファイルに上記のように記述すると、スクリーンショットのようにXcodeで表示したビルド設定画面にも反映されます。

コードでの分岐方法

Swiftのコードで定義したシンボルによってコードを分岐させるには、#if文を使用します。

#if シンボル

シンボルが定義されているときにビルドされるコード

#else

シンボルが定義されていないときにビルドされるコード

#endif

#if文とif文の大きな違いは、#ifで分岐されて実行されないコードは、バイナリに含まれないということです。つまりコンパイル対象になりません。一方、if文の場合はどちらもコンパイルされバイナリに含まれて実行されないというだけです。

次のコードは、USE_PHYSICAL_DEVICEが定義されているかどうかをチェックしています。

import Foundation

#if USE_PHYSICAL_DEVICE
print("Module1 DeviceType: Physical Device")
#else
print("Module1 DeviceType: Simulator")
#endif

Objective-Cのコード

Objective-CはC言語およびC++と共通の定義を参照します。Xcode上で定義するには、ビルド設定のApple Clang - Custom Compiler FlagsOther C Flags-Dマクロの書式で定義します。-Dマクロ=値で定義した場合は、マクロに値を割り当てます。複数あるときは、スペース区切りで列挙します。

Other C Flagsで定義する

ビルド設定ファイルで定義するには

Other C Flagsをビルド設定ファイルで定義するときは、OTHER_CFLAGSを使用します。たとえば、スクリーンショットと同様に、USE_PHYSICAL_DEVICEを定義するときは次のように記述します。

OTHER_CFLAGS = $(inherited) -DUSE_PHYSICAL_DEVICE

ビルド設定ファイルに上記のように記述すると、Xcodeのビルド設定画面にも反映されます。

コードでの分岐方法

コードもObjective-Cと同じです。#ifdef#if definedを使用します。次のコードは、USE_PHYSICAL_DEVICEが定義されているかによって切り替えているコード例です。

#ifdef マクロ

マクロが定義されているときにビルドされるコード

#else

マクロが定義されていないときにビルドされるコード

#endif

次のコードは、USE_PHYSICAL_DEVICEが定義されているかどうかによって切り替えているコードです。

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
#ifdef USE_PHYSICAL_DEVICE
        NSLog(@"Module2 DeviceType: Physical Device");
#else
        NSLog(@"Module2 DeviceType: Simulator");
#endif
    }
    return 0;
}

C言語/C++のコード

C言語とC++の場合は、Objective-Cと同じです。

コードでの分岐方法

コードもObjective-Cと同じです。#ifdef#if definedを使用します。次のコードはUSE_PHYSICAL_DEVICEが定義されているかどうかによって切り替えているコード例です。

#include <iostream>

int main(int argc, const char * argv[]) {
#ifdef USE_PHYSICAL_DEVICE
    std::cout << "Module3 DeviceType: Physical Device" << std::endl;
#else
    std::cout << "Module3 DeviceType: Simulator" << std::endl;
#endif
    return 0;
}

実行結果

ここまでのサンプルコードをCommon.xcconfigファイルを空にして実行すると、次のように出力されます。

Module1 DeviceType: Simulator
2022-07-19 16:03:43.534012+0900 Module2[3808:159692] Module2 DeviceType: Simulator
Module3 DeviceType: Simulator

Common.xcconfigに以下のように記述して、マクロを定義します。

OTHER_SWIFT_FLAGS = $(inherited) -DUSE_PHYSICAL_DEVICE
OTHER_CFLAGS = $(inherited) -DUSE_PHYSICAL_DEVICE

あらためてサンプルコードをビルドして実行すると、次のように出力され、複数のプロジェクトのマクロを1つのファイルで定義できていることが確認できます。

Module1 DeviceType: Physical Device
2022-07-19 16:04:36.900064+0900 Module2[3843:162776] Module2 DeviceType: Physical Device
Module3 DeviceType: Physical Device

著書紹介

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

Akira Hayashi (林 晃)のアバター Akira Hayashi (林 晃) Representative(代表), Software Engineer(ソフトウェアエンジニア)

アールケー開発代表。Appleプラットフォーム向けの開発を専門としているソフトウェアエンジニア。ソフトウェアの受託開発、技術書執筆、技術指導・セミナー講師。note, Medium, LinkedIn
-
Representative of RK Kaihatsu. Software Engineer Specializing in Development for the Apple Platform. Specializing in contract software development, technical writing, and serving as a tech workshop lecturer. note, Medium, LinkedIn

目次