Swift Digest
SE-0181 | Swift Evolution

Package Manager C/C++ Language Standard Support

Proposal
SE-0181
Authors
Ankit Aggarwal
Review Manager
Daniel Dunbar
Status
Implemented (Swift 4.0)

01 何が問題だったのか

Swift Package Manager では C/C++ のターゲットもビルドできますが、C/C++ のコンパイルにおいては どの言語標準(C89, C99, C11, C++98, C++11, C++14 など)を使うか の指定が非常に重要です。言語標準が違えば使える構文やライブラリ機能が変わり、同じソースでもコンパイルが通ったり通らなかったりします。

しかし従来の SwiftPM の Package.swift には、C や C++ の言語標準を指定する仕組みがありませんでした。そのため、特定の C++ バージョン(たとえば C++11 以降)を前提に書かれた C/C++ ソースを含むパッケージを、SwiftPM だけで素直にビルドすることができません。

本来はより汎用的な build settings 機能によってこの種の設定を扱うことが想定されていましたが、その機能は Swift 4 のスコープから外されました。そこで、build settings が入るまでのつなぎとして、C/C++ の言語標準だけでも先に指定できるようにする ことが求められました。

02 どのように解決されるのか

Package.swiftPackage イニシャライザに、C 用と C++ 用の言語標準を指定するための二つのパラメータ cLanguageStandardcxxLanguageStandard が追加されました。どちらもパッケージ全体の C/C++ ターゲットに一括で適用される設定です。

使い方

たとえば C++11 を標準として使いたい場合、次のように書きます。

let package = Package(
    name: "CHTTP",
    // ...
    cLanguageStandard: .c89,
    cxxLanguageStandard: .cxx11
)

既定値はどちらも nil で、何も指定しなければ従来どおり言語標準フラグを付けずにコンパイラが呼び出されます。既存のパッケージの挙動は変わりません。

指定できる言語標準

CLanguageStandardCXXLanguageStandard は enum として定義されていて、Clang がサポートする標準名がそのまま列挙されています。

public enum CLanguageStandard {
    case c89
    case c90
    case iso9899_1990
    case iso9899_199409
    case gnu89
    case gnu90
    case c99
    case iso9899_1999
    case gnu99
    case c11
    case iso9899_2011
    case gnu11
}

public enum CXXLanguageStandard {
    case cxx98
    case cxx03
    case gnucxx98
    case gnucxx03
    case cxx11
    case gnucxx11
    case cxx14
    case gnucxx14
    case cxx1z
    case gnucxx1z
}

cxx1z は当時の C++17 ドラフト(-std=c++1z)に相当し、GNU 拡張付きのバリアントには gnu プレフィックスが付きます。これらの列挙子は Clang 側の対応状況に合わせて今後も更新されます。

今後の位置づけ

この API はあくまで本格的な build settings 機能が入るまでの暫定的な手段として導入されたものであり、将来 build settings が利用可能になった時点で cLanguageStandard / cxxLanguageStandard プロパティは deprecated にする予定であるとされています。