Compiler flags in Package.swift

Hi

It may be very useful to specify swift/cc/cxx compiler flags and linker flags in Package.swift
Maybe even per target/configuration like Xcode does.

For example flags like -DDEBUG or -DUNIT_TEST
Or something like this https://github.com/apple/swift-llbuild/blob/1d39af91f8d6fc7d29e0e530f57a3aa3812cea5e/Package.swift#L9
Or enable some experimental feature for a specific package in dependency graph
Or disable broken optimization pass

5 Likes

This would be very helpful. I was wanting this feature the other day and was going to ask if this had been discussed yet.

The use case I had was when working on a project that is both a Swift Package and Xcode Framework that depend on C code in the same git repository. I have it setup such that the C code is one target of the Package and the Swift target depends on the C target.

But this resulted in me needing to use import to get my C module when compiling with swift build and the import being invalid when compiling with Xcode and the need for different #import statements in the C code. I could have made the Xcode project compile in such a way that it uses import as well, but I’ve had undefined symbol issues when sharing the framework binary with other people when taking that approach, so I avoid it.

My solution was to make swift build just work by doing the extra flags in Xcode by passing in -DXCODE_FRAMEWORK=1 to both C and Swift. Then using #if to determine if I import the C module and how to #import my headers.

In addition to per target basis it would be nice if you could specify flags for different compilation modes such as debug and release. I have seen quite a few people suggest adding -DDebug as a debug swift build flag for Xcode projects so you can use #if Debug to make decisions.

It’s not exactly what you’re asking for, but it is possible to specify a .json destination file via the --destination file.json argument to swift build. In that, you can configure flags for the linker, swiftc, and clang.

I can’t find the documentation right now, but the source file within swiftpm is here, and all of the members of the Destination struct can be set through the json file.

It’s also possible to set Xcode-specific configuration flags through the --xcconfig-overrides argument to swift build, using an xcconfig file.

An example json destination file looks something like this:

{
    "version": 1,
    "sdk": "/swift/usr/bin/swift",
    "toolchain-bin-dir": "/swift/usr/bin",
    "target": "x86_64-unknown-windows-msvc",
    "dynamic-library-extension": "lib",
    "extra-cc-flags": [
    ],
    "extra-swiftc-flags": [
        "-static-stdlib",
        "-use-ld=lld",
        "-ILibraries/CVulkan/"
    ],
    "extra-cpp-flags": []
}
3 Likes

destination.json is for quite different purpose
As you see toolchain-bin-dir, target, sdk all is required all configure “custom target”
For example we use global destination.json for build for android

Dont see xcconfig overrides
error: unknown option --xcconfig-overrides

This is definitely something we need. Some of the devs have discussed this in the past and started working on a proposal for a real build settings model, which I think is the right way to support this sort of thing. We put that on hold for a while due to other priorities, but I hope we’ll be able to get back to it and kick off a discussion here with an initial proposal before too long.

3 Likes

I've been thinking about this a bit as part of some experiments.

My current thinking is that for it to generalize properly, you need two things:

  • a high level key/value way of specifying settings
  • a series of mappings which convert/transform them so that they can be supplied in whatever form any given tool requires

For example you might specify something like the minimum platform setting as

 .setting("minimum-target", "macosx10.12"),

or even

 .minimumTarget(.macosx10.12),

but you want to be able to then transform it depending on what you're doing.

When invoking the Swift compiler you want it to be transformed to "-Xswiftc", "-target", "-Xswiftc", "x86_64-apple-macosx10.12".

But you might also want to generate an xcconfig (as part of swift package generate-xcodeproj), in which case you'd want it to be transformed into MACOSX_DEPLOYMENT_TARGET = "10.12".

You might also want to pass it to a bundler tool to inject the same value into the Info.plist file, in which case you'd probably need another transformation again.

And so on...

For any non-trivial project you probably need to be able to sub-divide settings into groups that are applied in certain contexts: "here are the common settings", "here are the ones that only apply in debug", "here are the ones that only apply on the Mac", etc.

This could be done with straight inheritance (xcconfig-style), but in Xcode it tends to lead to a combinatorial explosion where you have to define a top-level xcconfig file for every combination you care about, and then #include the relevant bits into it. You end up with files like MyProjReleaseWithAssertionStatic.xcconfig, which includes MyProjReleaseWithAssertion.xcconfig and MyProjCommon.xcconfig, which in turn import other things, etc, etc. This can get messy if you're also importing settings from sub-projects or libraries, and they also have the same explosion.

I started thinking it might be more flexible to allow some kind of conditional-filtering which lets you mix-in / import settings under certain conditions - without having to explicitly specify every combination.

Terms of Service

Privacy Policy

Cookie Policy