swift-server / async-http-client

HTTP client library built on SwiftNIO
https://swiftpackageindex.com/swift-server/async-http-client/main/documentation/asynchttpclient
Apache License 2.0
909 stars 116 forks source link

Build errors when building against a Static Linux SDK #773

Open briancoyner opened 2 days ago

briancoyner commented 2 days ago

Expected behavior

An application with a dependency on async-http-client successfully builds with a Swift 6 OSS toolchain + Static Linux SDK.

Note: The swift-6.0-DEVELOPMENT-SNAPSHOT-2024-09-17-a toolchain is used vs the swift-6.0-RELEASE because of another issue with swift-collections. That issue is fixed in the "09-17" toolchain release.

Note: The main branch of SwiftNIO is used because it contains a fix needed to compile SwiftNIO.

Note: Xcode 15.4.0 vs Xcode 16.0.0 because of an issue described here:

Actual behavior

main branch error and 1.22.2 error

$ xcrun --toolchain org.swift.600202409171a swift build --swift-sdk aarch64-swift-linux-musl
Building for debugging...
/Users/someuser/Developer/Temp/demo/.build/checkouts/async-http-client/Sources/AsyncHTTPClient/HTTPClient+HTTPCookie.swift:241:31: error: cannot find 'errno' in scope
239 |     }
240 |     let timestamp = Int64(timegm(&timeComponents))
241 |     return timestamp == -1 && errno == EOVERFLOW ? nil : timestamp
    |                               `- error: cannot find 'errno' in scope
242 | }
243 | 

/Users/someuser/Developer/Temp/demo/.build/checkouts/async-http-client/Sources/AsyncHTTPClient/HTTPClient+HTTPCookie.swift:241:40: error: cannot find 'EOVERFLOW' in scope
239 |     }
240 |     let timestamp = Int64(timegm(&timeComponents))
241 |     return timestamp == -1 && errno == EOVERFLOW ? nil : timestamp
    |                                        `- error: cannot find 'EOVERFLOW' in scope
242 | }

Steps to reproduce

  1. Install the Swift 6 OSS toolchain + SDK (swift-6.0-DEVELOPMENT-SNAPSHOT-2024-09-17-a).
  2. A simple application using SPM with a dependency on async-http-client (main or 1.22.2) and SwiftNIO (main).
  3. Execute the following to build the application.
$ xcrun --toolchain org.swift.600202409171a swift build --swift-sdk aarch64-swift-linux-musl
See errors noted above (for both `main` and `1.22.2`)

Also, building without the Static Linux SDK succeeds:

$ xcrun --toolchain org.swift.600202409171a swift build                                     
Building for debugging...
[977/977] Applying Demo
Build complete! (52.28s)

Example Swift Package

Here's a basic Package.swift manifest that can be used:

// swift-tools-version: 6.0
import PackageDescription

let package = Package(
    name: "Demo",
    platforms: [
       .macOS(.v14)
    ],
    dependencies: [
        // `main` fixes bug: https://github.com/apple/swift-nio/issues/2893
        .package(url: "https://github.com/apple/swift-nio.git", branch: "main"),
        .package(url: "https://github.com/swift-server/async-http-client.git", branch: "1.22.2")
        // .package(url: "https://github.com/swift-server/async-http-client.git", branch: "main")
    ],
    targets: [
        .executableTarget(
            name: "Demo",
            dependencies: [
                .product(name: "NIOPosix", package: "swift-nio"),
                .product(name: "AsyncHTTPClient", package: "async-http-client")
            ],
            swiftSettings: swiftSettings
        ),
    ],
    swiftLanguageModes: [
        .v6
    ]
)

// MARK: - Swift Settings

var swiftSettings: [SwiftSetting] {
    return [
        .enableUpcomingFeature("ExistentialAny")
    ]
}

System & version information

Sonoma 14.6.1

*****
***** Swift Toolchain
*****   Name: swift-6.0-DEVELOPMENT-SNAPSHOT-2024-09-17-a
*****   Path: /Library/Developer/Toolchains/swift-6.0-DEVELOPMENT-SNAPSHOT-2024-09-17-a.xctoolchain
*****     ID: org.swift.600202409171a
*****    SDK: aarch64-swift-linux-musl
*****    SPM: Swift Package Manager - Swift 6.0.0-dev
*****  Xcode: /Applications/Xcode15.4.0.app/Contents/Developer
*****
finagolfin commented 2 days ago

I've been seeing a lot of these import errors on Android over the last couple months, where repos that compiled fine in July with the trunk 6.1 snapshot toolchain started complaining about these imports with an early August snapshot toolchain.

There are two possibilities I can think of for why:

  1. Something changed in clang's importer or the Swift frontend which calls it, that made such lookups more strict. A brief look at the commit log didn't turn up anything though.
  2. The Foundation re-core in mid-July along with the module leaks related to clang re-exports, mean that different modules were exposed after the re-core, requiring these new imports to make up for it.

I investigated this a bit last month and am leaning towards 2. as the likely reason. It doesn't seem to affect non-modularized overlays like Glibc on linux servers, only modularized overlays like Musl and Android.

@al45tair, should we just start putting in a bunch of extra imports on these platforms to shut the compiler up? That's what I've started doing for Android.

al45tair commented 2 days ago

Possibly. I'll try to reproduce this today and see if I can work out what's going on, which should help inform our approach. The Glibc overlay isn't "non-modularised" so much as badly modularised, and that can cause its own problems. I think the difference is likely most that the CI and PR testing is set up for normal Linux, which uses Glibc, so the Foundation folks tested their changes against that (hence it works there), and not with the Static SDK or Android, which is where we're seeing problems.

finagolfin commented 2 days ago

I don't think it's just some normal changes from the Foundation update, as I see many Swift repos checked out at the exact same source tag and with the same Android overlay starting to report import errors after the Foundation update.

Something clearly changed in the modules re-exported after July. I'm speculating that the Foundation rewrite and that clang re-exports leak is the reason, as I have not dug into it, but it appears to be a more substantive issue.

barnard-b commented 23 hours ago

Appears to compile OK if import Musl is outside of canImport.

import NIOHTTP1
#if canImport(xlocale)
import xlocale
#elseif canImport(locale_h)
import locale_h
#elseif canImport(Darwin)
import Darwin
#elseif canImport(Musl)
import Musl
#elseif canImport(Glibc)
import Glibc
#endif
import CAsyncHTTPClient
import NIOCore
+ import Musl