Confused by unsafe flags being disallowed in dependencies

That notably isn't an unstable Swift flag; it's a perfectly stable clang flag. Not being able to set clang and linker flags has been the main pain-point for us, incidentally.


Does the Swift frontend consider 100% of it's command-line interface outside of the handful of things exposed by SPM to be unstable and experimental?

2 Likes

No, I believe we could expose more driver flags, only frontend flags are a concern in terms of compatibility. We probably want to be careful with flags that could lead to breaking the build or dependency model (e.g. allowing arbitrary search paths), but there are still a lot of things on the table to potentially be added.

In fact, the original proposal promised adding more settings, we just haven't actually done that. One we discussed internally last year was e.g. -enable-bare-slash-regex which currently can't be used in a package.

If it helps to add first-class API for some missing settings that are commonly used and we can come up with a list on this thread, I am definitely open to writing up a proposal and implementation to add them. I have seen the occasional specific requests here and there, but nothing had risen to the point that it became a priority so far. That may have been the wrong approach though and we should just start adding what's needed.

1 Like

I think ideally it should be up to the driver (or the various tools invoked by the driver) to determine what flags are safe. There could be something like a -package-safe-flags-only flag which tells the driver that all subsequent flags are from packages rather than SPM itself, and it would reject any not flagged as PackageSafe in Options.td. This would avoid the need for SPM to be able to parse the command-line flags and means that there's always a single source of truth for what compiler flags are available rather than duplicating that list.

This should be possible with Swift 5.8 using the spelling .upcomingFeatures(["BareSlashRegexLiterals"]), should it not?

2 Likes

It'd help somewhat, but not completely (see e.g. the swift-atomics use case, there could be other similar things like the compiler bug I pointed out as well where you definitely want to be able to work around it to support a new/old toolchain even after you've shipped 1.0). I think it might just push people to never do 1.0 in that case, which would be a bit sad.

I think that could go a long way to alleviate the issues, as some escape hatch for when the existing functionality of SwiftPM just not enough would be useful - just the word unsafe in unsafeFlags at least tells me that I need to be careful and consider the long term effects of using them, but if even more clarity is desired, it's fine by me - in this case I just want us to be able to be unblocked and use SwiftPM dependencies properly even if we need to use some unsafe flag.

That would be super nice of course, thanks a lot for offering to consider that.

I just did a quick canvassing of the types of unsafe flags we've used recently (some might be much more useful implemented as different SwiftPM first-class features for sure, but just to give some input and to provide some background context, in no order of priority:

  1. The ability to enable library evolution mode and module versioning, related to
    Dynamic library support on Linux with library evolution · Issue #5714 · apple/swift-package-manager · GitHub
    and
    Availability annotations for third party libraries when using Library evolution/ resilience · Issue #60458 · apple/swift · GitHub
            swiftSettings: [.unsafeFlags(["-enable-library-evolution",
                                         "-emit-module-interface",
                                          "-user-module-version", "1.0"
  1. Additional linker settings
  linkerSettings: [
                // for M1 based Macs
                .unsafeFlags(["-Xlinker", "-L/opt/homebrew/lib"], .when(platforms: [.macOS])),
                // for Intel based Macs
                .unsafeFlags(["-Xlinker", "-L/usr/local/lib"], .when(platforms: [.macOS])),
            ]
  1. Overriding optimization level by target
    This is very commonly desired. Several times we want to do this, e.g. for dependencies of a Command plugin so that the executable dependency will be built optimised always when used by consumers of the package (I view the command plugin and related dependencies as part of the toolchain, just as I want my swift compiler to have been built with optimization turned on, I want the helper tool for the command plugin that processes tons of json to be optimised for a 2-3x speedup of post processing) - we have run into this in various settings, not just in this case (sometimes a specific part of the code will make debug runs so slow to be unusable, so it makes sense to turn that target to optimized, and conversely, something might need debug stuff).
swiftSettings: [SwiftSetting.unsafeFlags(["-Osize"])]
  1. Enabling experimental features
    (as pointed out by @xwu this now will be in 5.8 thanks to yourself, @Douglas_Gregor and others)
                .unsafeFlags(["-Xfrontend", "-enable-experimental-distributed"]),
            ]
  1. Working around compiler issues
swiftSettings: [
   .unsafeFlags(["-Xfrontend", "-validate-tbd-against-ir=none"]), // due to https://bugs.swift.org/browse/SR-15629
 ]
1 Like

Upcoming features are going to be enabled; those are not experimental. Experimental features aren’t intended to be part of that.

Thanks for the clarification @xwu, I guess then it could be kept as a point of something that is needed and not solved by the upcoming-feature support, as sometime you want to enable an experimental feature even in a package that is versioned after 1.0 (like in our case, distributed actors).

To add a sixth point to @hassila's list above (a lot of which I've also run into): enabling CPU features can currently only be done with unsafe flags ([SR-11660] Umbrella: function multiversioning and dispatch on CPU features · Issue #54069 · apple/swift · GitHub). This means it's currently not possible to package Swift code that uses e.g. AVX support or hardware FMA.

2 Likes

Actually, there are two different flags added as it seems:

So both should (hopefully) be supported with unsafe flags :slight_smile: