Skip to content

Conversation

DmT021
Copy link
Contributor

@DmT021 DmT021 commented Feb 27, 2025

This change adds warning control settings as described in the proposal. The flags for Swift targets are described by SE-0443, for Clang targets - here.

@DougGregor
Copy link
Member

@swift-ci test

Copy link
Member

@DougGregor DougGregor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aside from the two places where we can go quadratic in the number of command-line arguments, this is looking good to me. But I'm not super familiar with the SwiftPM code base.

Comment on lines 367 to 378
// `-w` (suppress warnings) and the other warning control flags are mutually exclusive
for index in args.indices.reversed() {
let arg = args[index]
if arg.starts(with: "-W"), arg.count > 2 {
// we consider the following flags:
// -Wxxxx
// -Wno-xxxx
// -Werror
// -Werror=xxxx
// -Wno-error
// -Wno-error=xxxx
args.remove(at: index)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This loop could be a filter, which would make it linear-time rather than quadratic.

Comment on lines 626 to 652
for index in args.indices.reversed() {
let arg = args[index]
switch arg {
case "-warnings-as-errors", "-no-warnings-as-errors":
args.remove(at: index)
case "-Wwarning", "-Werror":
guard args.indices.contains(index + 1) else {
throw InternalError("Unexpected '\(arg)' at the end of args")
}
args.remove(at: index + 1)
args.remove(at: index)
default:
break
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also technically quadratic. Even though it's a little ugly, I think I'd still rather do it with a filter

var removeNextArg = false
args = args.filter { arg in
  if removeNextArg {
    removeNextArg = true
    return false
  }
  switch arg {
  case "-warnings-as-errors", "-no-warnings-as-errors":
    return false
  case "-Wwarning", "-Werror":
    removeNextArg = true
    return false
  default:
    return true
  }
}

Copy link
Contributor Author

@DmT021 DmT021 Mar 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the quadratic complexity is an oversight on my part. Good thing you noticed.
TBH, using an external state in a filter makes me a bit uneasy. The documentation for filter doesn't guarantee that the predicate will be invoked in any particular order, so I'd try to avoid it.
I don't insist though. If you think a filter here is fine, I don't mind. But what do you think about something more "manual", e.g:

var readIndex = args.startIndex
var writeIndex = args.startIndex
let endIndex = args.endIndex
while readIndex < endIndex {
    let arg = args[readIndex]
    switch arg {
    case "-warnings-as-errors", "-no-warnings-as-errors":
        break
    case "-Wwarning", "-Werror":
        readIndex += 1  // -Wwarning and -Werror have an argument
        if readIndex >= endIndex {
            throw InternalError("Unexpected '\(arg)' at the end of args")
        }
    default:
        if readIndex != writeIndex {
            args[writeIndex] = args[readIndex]
        }
        writeIndex += 1
    }
    readIndex += 1
}
if writeIndex < endIndex {
    args.removeSubrange(writeIndex..<endIndex)
}

@dschaefer2
Copy link
Member

A couple of general questions. Placing these flags in the package manifest, means all consumers of this package will build with the same settings. I was just wondering if it's a concern that consumers may want to set them differently. For example, if they are specifying additional warning setting flags on the swift build command lines, which ones take precedence.

Also, as we're working on adopting Swift Build to replace our native build system, we would need to make sure this is handled there as well.

@dschaefer2
Copy link
Member

Mind you the pitch and evolution proposal predates my participation so maybe this has already been addressed. I'll need to catch up.

@DmT021
Copy link
Contributor Author

DmT021 commented Mar 12, 2025

I was just wondering if it's a concern that consumers may want to set them differently. For example, if they are specifying additional warning setting flags on the swift build command lines, which ones take precedence.

That's a good question. AFAIK, the additional flags (-Xcc, -Xcxx, -Xswiftc) are placed after the internally generated flags, but I didn't really check that. I'll dive into it later. If it's not the case, I think we should make it so. However, I need a confirmation from the maintainers that that's really the desired behavior.
If that's the guaranteed order of flags, then users will be able to either override or extend the warning treating rules. The rules are evaluated left to right in the compilers. So appending -[no-]warning-as-errors overrides everything that is earlier in the command line.

Also, as we're working on adopting Swift Build to replace our native build system, we would need to make sure this is handled there as well.

I've raised a discussion about that, but it seems like the Swift Build maintainers prefer a simpler approach to these flags. swiftlang/swift-build#248

Mind you the pitch and evolution proposal predates my participation so maybe this has already been addressed. I'll need to catch up.

The original proposal (SE-0443) doesn't address this API, but we're working on fixing that. We will probably write a new pitch.

@DmT021
Copy link
Contributor Author

DmT021 commented Mar 15, 2025

@swift-ci Please test

@dschaefer2
Copy link
Member

@swift-ci please test windows

@DmT021
Copy link
Contributor Author

DmT021 commented Mar 18, 2025

For example, if they are specifying additional warning setting flags on the swift build command lines, which ones take precedence.

Following up on this question. The additional arguments the used provided are placed after the ones SwiftPM generates.
The code responsible for this behavior has comments about that, which leads me to believe it was intentional.
For C/C++
For Swift

So if we consider the following Package.swift:

let package = Package(
    name: "MyExecutable",
    platforms: [
        .macOS(.v13),
    ],
    targets: [
        .target(
            name: "cfoo",
            cSettings: [
                .enableWarning(name: "all"),
                .disableWarning(name: "unused-parameter"),
                .treatAllWarnings(as: .error),
                .treatWarning(name: "unused-variable", as: .warning),
            ]
        ),
        .target(
            name: "cxxfoo",
            cxxSettings: [
                .enableWarning(name: "all"),
                .disableWarning(name: "unused-parameter"),
                .treatAllWarnings(as: .error),
                .treatWarning(name: "unused-variable", as: .warning),
            ]
        ),
        .executableTarget(
            name: "swiftfoo",
            swiftSettings: [
                .treatAllWarnings(as: .error),
                .treatWarning(name: "DeprecatedDeclaration", as: .warning),
            ]
        ),
    ]
)

And build it with additional arguments like this:

swift-build --very-verbose -Xcc -Wno-error -Xswiftc -no-warnings-as-errors

We will get the following invocations of the compilers:

For cfoo:
clang ... -Wall -Wno-unused-parameter -Werror -Wno-error=unused-variable ... -Wno-error ...
For cxxfoo:
clang ... -Wall -Wno-unused-parameter -Werror -Wno-error=unused-variable ... -Wno-error ...
For swiftfoo:
swiftc ... -warnings-as-errors -Wwarning DeprecatedDeclaration ... -no-warnings-as-errors -Xcc -Wno-error ...

Given that these flags are evaluated left-to-right it gives the user some control here at the build stage.
However, it doesn't compose well with -suppress-warnings, as it's mutually exclusive with the other flags:

swift-build --very-verbose -Xswiftc -suppress-warnings

swiftc ... -warnings-as-errors -Wwarning DeprecatedDeclaration ... -suppress-warnings ...

error: conflicting options '-warnings-as-errors' and '-suppress-warnings'
error: conflicting options '-Wwarning' and '-suppress-warnings'

@DmT021
Copy link
Contributor Author

DmT021 commented Mar 26, 2025

@swift-ci Please test

@DmT021
Copy link
Contributor Author

DmT021 commented Mar 26, 2025

@swift-ci Please test macOS

@DmT021 DmT021 force-pushed the wp/warning-rules branch from a51a5de to 5bbc023 Compare March 27, 2025 05:09
@DmT021
Copy link
Contributor Author

DmT021 commented Mar 27, 2025

@swift-ci Please test

@DmT021
Copy link
Contributor Author

DmT021 commented Mar 27, 2025

@swift-ci Please test macOS

@DmT021
Copy link
Contributor Author

DmT021 commented Mar 27, 2025

@swift-ci Please test windows

@DmT021 DmT021 force-pushed the wp/warning-rules branch from 5bbc023 to b78ab2c Compare June 10, 2025 15:04
@DmT021
Copy link
Contributor Author

DmT021 commented Jun 10, 2025

@swift-ci Please test

@DmT021 DmT021 force-pushed the wp/warning-rules branch from b78ab2c to d6c1f61 Compare June 10, 2025 22:19
@DmT021
Copy link
Contributor Author

DmT021 commented Jun 10, 2025

@swift-ci Please test

@DmT021 DmT021 force-pushed the wp/warning-rules branch from d6c1f61 to 13e33e9 Compare June 11, 2025 12:32
@DmT021
Copy link
Contributor Author

DmT021 commented Jun 11, 2025

@swift-ci Please test

@DmT021 DmT021 changed the title Build settings for warning treating rules (SE-0443, draft) [SE-0480] Build settings for warning control flags Jun 11, 2025
@DmT021
Copy link
Contributor Author

DmT021 commented Jun 11, 2025

@swift-ci Please smoke test

@DmT021
Copy link
Contributor Author

DmT021 commented Jun 12, 2025

@swift-ci Please clean smoke test

@DmT021
Copy link
Contributor Author

DmT021 commented Jun 12, 2025

@swift-ci Please smoke test

@DmT021
Copy link
Contributor Author

DmT021 commented Jun 12, 2025

@swift-ci Please test

@DmT021
Copy link
Contributor Author

DmT021 commented Jun 12, 2025

@swift-ci Please test macOS platform

}

func testWarningControlFlags() async throws {
try XCTSkipOnWindows(because: "https://github.com/swiftlang/swift-package-manager/issues/8543: there are compilation errors")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: The references GitHub issue does not appear to be related to this test. Are we certain this test fails on Windows?

Copy link
Contributor Author

@DmT021 DmT021 Jun 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, both testManifestGenerationWithWarningControlFlags and this test fail on Windows. And I think it is related to the issue. The CI job with the errors is already removed from the dashboard, so I can't provide you with the link, but it was showing the same type of errors as in the linked issue:

type 'CSetting' has no member 'enableWarning'
type 'SwiftSetting' has no member 'treatAllWarnings'
...

If I understand the issue right, for some reason, tests on Windows use the wrong version of PackageDescription, not the one we build, so we don't see the newly added functions.

Copy link
Contributor

@bkhouri bkhouri Jun 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out of curiosity, do you recall if the failure occurred in the windows self hosted, windows smoke test, or both?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it only fails in the windows self hosted builds. But I'm not certain.
I can remove the skips and rerun the tests if you want.

import _InternalTestSupport
import XCTest

final class PackageDescription6_2LoadingTests: PackageDescriptionLoadingTests {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (non-blocking): Since this is a new test, consider migrating to Swift Testing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. I've marked it as an expected failure on Windows, so it will record the issue. A copy of the log is below

}

func testManifestGenerationWithWarningControlFlags() async throws {
try XCTSkipOnWindows(because: "https://github.com/swiftlang/swift-package-manager/issues/8543: there are compilation errors")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: The references GitHub issue does not appear to be related to this test. Are we certain this test fails on Windows?

@DmT021
Copy link
Contributor Author

DmT021 commented Jun 14, 2025

@swift-ci Please test

@DmT021
Copy link
Contributor Author

DmT021 commented Jun 14, 2025

The error on Swift Test Windows Platform (self hosted) (Swift 6.1)

Log
[2025-06-14T04:58:51.211Z] × Test warningControlFlags() recorded a known issue at PD_6_2_LoadingTests.swift:71:33: Caught error: Invalid manifest (compiled with: ["C:\\Users\\ContainerAdministrator\\AppData\\Local\\Programs\\Swift\\Toolchains\\6.1.0+Asserts\\usr\\bin\\swiftc.exe", "-vfsoverlay", "C:\\Users\\ContainerAdministrator\\AppData\\Local\\Temp\\TemporaryDirectory.k11eCm\\vfs.yaml", "-L", "C:\\Users\\ContainerAdministrator\\AppData\\Local\\Programs\\Swift\\Toolchains\\6.1.0+Asserts\\usr\\lib\\swift\\pm\\ManifestAPI", "-lPackageDescription", "-sdk", "C:\\Users\\ContainerAdministrator\\AppData\\Local\\Programs\\Swift\\Platforms\\6.1.0\\Windows.platform\\Developer\\SDKs\\Windows.sdk\\", "-libc", "MD", "-I", "C:\\Users\\ContainerAdministrator\\AppData\\Local\\Programs\\Swift\\Platforms\\6.1.0\\Windows.platform\\Developer\\Library\\XCTest-development\\usr\\lib\\swift\\windows", "-I", "C:\\Users\\ContainerAdministrator\\AppData\\Local\\Programs\\Swift\\Platforms\\6.1.0\\Windows.platform\\Developer\\Library\\XCTest-development\\usr\\lib\\swift\\windows\\x86_64", "-L", "C:\\Users\\ContainerAdministrator\\AppData\\Local\\Programs\\Swift\\Platforms\\6.1.0\\Windows.platform\\Developer\\Library\\XCTest-development\\usr\\lib\\swift\\windows\\x86_64", "-I", "C:\\Users\\ContainerAdministrator\\AppData\\Local\\Programs\\Swift\\Platforms\\6.1.0\\Windows.platform\\Developer\\Library\\Testing-development\\usr\\lib\\swift\\windows", "-L", "C:\\Users\\ContainerAdministrator\\AppData\\Local\\Programs\\Swift\\Platforms\\6.1.0\\Windows.platform\\Developer\\Library\\Testing-development\\usr\\lib\\swift\\windows\\x86_64", "-use-ld=lld", "-swift-version", "6", "-I", "C:\\Users\\ContainerAdministrator\\AppData\\Local\\Programs\\Swift\\Toolchains\\6.1.0+Asserts\\usr\\lib\\swift\\pm\\ManifestAPI", "-package-description-version", "6.2.0", "C:\\Package.swift", "-o", "C:\\Users\\ContainerAdministrator\\AppData\\Local\\Temp\\TemporaryDirectory.tyetO8\\-manifest.exe"])
[2025-06-14T04:58:51.211Z] C:\Package.swift:9:18: error: type 'CSetting' has no member 'enableWarning'
[2025-06-14T04:58:51.211Z]  7 |             name: "Foo",
[2025-06-14T04:58:51.211Z]  8 |             cSettings: [
[2025-06-14T04:58:51.211Z]  9 |                 .enableWarning("implicit-fallthrough"),
[2025-06-14T04:58:51.211Z]    |                  `- error: type 'CSetting' has no member 'enableWarning'
[2025-06-14T04:58:51.211Z] 10 |                 .disableWarning("unused-parameter"),
[2025-06-14T04:58:51.211Z] 11 |                 .treatAllWarnings(as: .error),
[2025-06-14T04:58:51.211Z] 
[2025-06-14T04:58:51.211Z] C:\Package.swift:10:18: error: type 'CSetting' has no member 'disableWarning'
[2025-06-14T04:58:51.211Z]  8 |             cSettings: [
[2025-06-14T04:58:51.211Z]  9 |                 .enableWarning("implicit-fallthrough"),
[2025-06-14T04:58:51.211Z] 10 |                 .disableWarning("unused-parameter"),
[2025-06-14T04:58:51.211Z]    |                  `- error: type 'CSetting' has no member 'disableWarning'
[2025-06-14T04:58:51.211Z] 11 |                 .treatAllWarnings(as: .error),
[2025-06-14T04:58:51.211Z] 12 |                 .treatWarning("deprecated-declarations", as: .warning),
[2025-06-14T04:58:51.211Z] 
[2025-06-14T04:58:51.211Z] C:\Package.swift:11:18: error: type 'CSetting' has no member 'treatAllWarnings'
[2025-06-14T04:58:51.211Z]  9 |                 .enableWarning("implicit-fallthrough"),
[2025-06-14T04:58:51.211Z] 10 |                 .disableWarning("unused-parameter"),
[2025-06-14T04:58:51.211Z] 11 |                 .treatAllWarnings(as: .error),
[2025-06-14T04:58:51.211Z]    |                  `- error: type 'CSetting' has no member 'treatAllWarnings'
[2025-06-14T04:58:51.211Z] 12 |                 .treatWarning("deprecated-declarations", as: .warning),
[2025-06-14T04:58:51.211Z] 13 |             ],
...

@DmT021
Copy link
Contributor Author

DmT021 commented Jun 14, 2025

@swift-ci Please test Windows platform

3 similar comments
@DmT021
Copy link
Contributor Author

DmT021 commented Jun 15, 2025

@swift-ci Please test Windows platform

@DmT021
Copy link
Contributor Author

DmT021 commented Jun 15, 2025

@swift-ci Please test Windows platform

@DmT021
Copy link
Contributor Author

DmT021 commented Jun 16, 2025

@swift-ci Please test Windows platform

@DmT021
Copy link
Contributor Author

DmT021 commented Jun 19, 2025

@bkhouri can you review this again, please? Or tag someone

Copy link
Contributor

@bkhouri bkhouri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm more familiar with the SwiftPM tests.

@dschaefer2 would be in a better position to approve this PR than me.

results.checkIsEmpty()
}
} when: {
isWindows
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note (non-blocking): In SwiftPM, we can also use ProcessInfo.hostOperatingSystem == .windows

import _InternalTestSupport
import Testing

struct PackageDescription6_2LoadingTests {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: It's great to a a new test suite being written in Swift Testing. thanks for this.

Copy link
Member

@dschaefer2 dschaefer2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still concerned we're changing the Package Manifest without having a cohesive vision for it that we can measure this feature against. Unfortunately that's vision is going to take some time to put together.

Approving since it was an accepted evolution proposal. But I reserve the right to adjust it in the future :). Big things I'm wondering about are things like build configuration and platform specific build settings, build setting visibility like CMake has, etc. Not sure the current build settings syntax scales to that level of optionality, but that needs to be studied.

@dschaefer2 dschaefer2 merged commit 065df19 into swiftlang:main Jun 24, 2025
6 checks passed
marcprux pushed a commit to swift-everywhere/swift-package-manager that referenced this pull request Jul 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants