SwiftPM packages can declare their C and C++ standards
SE-0181 adds package-wide C and C++ language-standard settings for Swift 4. Its limited scope addresses a pressing build requirement while the broader build-settings design remains deferred.
A package manager that builds C++ source needs a way to express which language dialect that source requires. Depending on the compiler's default leaves an important input outside the package description. Swift Package Manager's SE-0181 addresses that problem with two manifest properties, without waiting for a complete system of build settings.
The July 19 acceptance decision approves the proposal for Swift 4. Its review ran from July 11 through July 14. General support focused on the usefulness of the setting, while discussion of spelling produced a revision to the property names. The accepted API uses cLanguageStandard and cxxLanguageStandard.
I like Swift's attention to explicit program meaning, and the same principle applies to the non-Swift code in a package. A C++ dialect requirement belongs beside the package's other build requirements. Leaving it to a compiler default makes the manifest less informative than the source it is supposed to describe.
A deliberately limited build setting
Ankit Aggarwal's accepted proposal says the complete build-settings feature has been deferred from Swift 4. C++ language-standard selection is important enough to provide separately. The resulting API is a specific answer to that immediate requirement, with a stated intention to deprecate these properties when the broader feature arrives.
The properties belong to the package declaration. A complete small manifest can select C89 and C++11 while declaring a target that uses the relevant native source files.
// swift-tools-version:4.0
import PackageDescription
let package = Package(
name: "NativeSupport",
targets: [
.target(name: "NativeSupport")
],
cLanguageStandard: .c89,
cxxLanguageStandard: .cxx11
)
Each property applies to all targets of its language in that package. Declaring a target does not give it a separate dialect setting. This package-wide scope is an important part of the design, especially for repositories that contain native components with different historical requirements.
The proposal considered putting the property on targets. It rejected that approach because of the additional names it would introduce there and because the API is intended as an interim measure. The accepted form therefore avoids establishing a more elaborate per-target arrangement before the general build-settings work has been designed.
That constraint is a tradeoff. One package can state its C standard and its C++ standard, but this proposal cannot express different C++ standards for different targets in the same package. Reading the property as a general compiler-flag mechanism would also overstate its scope. It selects a language standard through a defined enumeration.
Omission preserves the compiler default
Both properties default to nil. In that state SwiftPM passes no language-standard flag to the C or C++ compiler. Existing packages retain their previous behavior because the new API is additive and an omitted property does not introduce a new selection.
There is a useful distinction between preserving behavior and documenting a requirement. Leaving the value unset preserves reliance on the compiler's default. Setting it makes the requested dialect visible in the manifest. A package that has always happened to compile with a particular compiler default may still benefit from stating which dialect its source actually requires.
The new setting does not claim to make every compiler equivalent. It controls one input to compiler invocation. The proposal does not promise identical diagnostics, optimizations or library implementations across toolchains. Its benefit is narrower and concrete, because language-standard selection no longer has to remain implicit when the source needs a particular setting.
This is also why adopting the property need not accompany a source rewrite. An author can declare the standard already required by existing code. A change in the requested standard is a separate source-compatibility decision. The API gives the manifest a place to record either decision explicitly.
The enumeration preserves distinctions in Clang's choices
The C enumeration includes names such as c89, c99, c11 and corresponding GNU forms. The C++ enumeration includes cxx98, cxx03, cxx11 and cxx14, along with GNU variants and the cxx1z spellings. These are the cases in the accepted design at this date. The proposal says the definitions follow the Clang compiler's language-standard definitions.
The review considered simpler case names but did not redesign them. Dunbar's decision says that doing so would require substantial design for little practical benefit at this stage. The team leaves that question for the future build-settings proposal. Users should therefore follow the accepted spellings when writing a manifest instead of shortening them by analogy with another tool.
The property-name revision is separate. The core team found cLanguageStandard more consistent than the original cStandard wording and adopted that change. This distinction matters when reading review discussions or examples from an earlier draft. Approval of the feature did not preserve every original identifier.
Native dependencies become easier to describe
SwiftPM's June manifest redesign already makes targets explicit and allows custom source paths. This proposal adds another piece of information needed to describe an existing native library. Its source can retain its layout while the manifest states the dialect used to compile it. Neither capability requires pretending that every package contains only Swift code.
The tools-version declaration also gives the new API a defined context. A manifest using the Swift 4 format requests that version of the package description, while older package versions can retain the earlier format. That separation allows a library author to publish new packaging metadata without implying that an older package manager understands the new properties. The native dialect setting belongs to the manifest selected by the tools requirement.
I value this restrained scope because a small setting can resolve a concrete packaging obstacle without fixing the shape of every future build option. The package-wide limitation remains visible, and the proposal states its temporary role. That gives package authors enough information to use the setting without mistaking it for the deferred general design.
For a consuming project, the practical change is that a dependency can carry its native-language requirement in its own package declaration. The caller no longer needs to infer that requirement solely from source errors or external instructions. Existing packages that omit both properties continue to invoke the native compiler without an added language-standard flag, while packages that require an explicit dialect can now name it.