-
Notifications
You must be signed in to change notification settings - Fork 10.4k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
stdlib: add modulemap for Musl, add Musl platform module #62248
Conversation
@egorzhdan, weren't you planning on removing these libc headers altogether now that you're using VFS to find them? Could we try that for the Musl libc and see if it works with this pull, or will it require more work? |
Due to the long missing standardization of system module, Swift libraries now depend on We’re now hiding all the POSIX system libraries behind |
I'm not convinced that's the case. Musl is substantially different from Glibc, including its behavior. By making this a distinct module we're signaling to users that they need to audit their platform-specific code for any reliance on Glibc-specific behavior. Users not understanding or reporting bugs related to why their code behaves differently when not linked to Glibc, while they're led to believe they're somehow using Glibc, is something I'd like to avoid. The fact that some other platforms came to a place where they unexpectedly hide their differences in behavior under a single |
I 100% agree with the statement that @MaxDesiatov is saying. We shouldn't name Musl "Glibc", it's not. We have Swift-System, which is supposed to be a wrapper over the system libraries. It might be a good idea to point the corelibs at that instead of the raw LibC implementations. |
In most cases developers are just using C standard APIs by Another reason to postpone the introduction of |
This is a very small price to pay for correctness of code and its behavior.
Could you elaborate on this? There's no Swift code targeting Musl in existence yet, an addition of a module will not have an impact on anyone not using it. This is purely an additive change.
That's out of scope for this module. I also don't see how its addition could somehow conflict with what you're describing, which is already going on in the Swift System repository, if I understand correctly? Those who need Musl ASAP can import it freely and adapt their code to its behavior. Users who don't need Musl can just ignore its existence altogether, in the same way they did before, they won't be impacted in any way. |
I don’t think that’s a small price because we need 2 additional lines in nearly every file where C standard library is involved. And we’re not doing anything more correct by specializing When to
There are motivations for a bunch of libraries to update and support Musl. There’re a variety of "Linux-compatible" Swift packages and by introducing
No they won’t. An end user will have to wait for all dependent packages to update for Musl, or they’ll need to maintain their own forks. This is super unfortunate too, and could take even longer than |
Swift System is only abstracting some popular, key functionalities from each system library, and this is not enough in some specific cases where the user explicitly depends on a libc implementation. That is, ideally, the only place we need to |
I don't think there's anything here that prevents future modularization. If anything changes on that front, the If you have a concrete proposal for how the |
While @stevapple makes some valid points, I think splitting off Musl like this is better, as we should ideally do so for all the system C libraries. I would like to do so for Bionic one day- that would require proper deprecations and hopefully an easy future-proof solution like All those packages will be modified one day anyway, nothing wrong with the few beginning Musl users starting to do so after this pull. |
Can we introduce some (though ugly and hardcoded) compiler logic to downgrade “using I would prefer to either rush |
AFAIK, nobody is working on |
//===----------------------------------------------------------------------===// | ||
|
||
module SwiftMusl [system] { | ||
header "SwiftMusl.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be possible to inject this modulemap file into the Musl directory using LLVM VFS.
We already use this mechanism to inject glibc.modulemap
into the Glibc installation (swift::getClangInvocationFileMapping
). That way the Musl headers could be referenced directly from the modulemap instead of using an additional SwiftMusl.h
header, preventing another module from hijacking the system headers: with the current approach another C module that includes the same system header might take ownership over the header, which would cause compile errors in some cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any plans to remove the SwiftGlibc.h
header soon?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit confused here, is the approach suggested in https://forums.swift.org/t/problems-with-swiftglibc-and-proposed-fix/37594 no longer applicable? Wasn't a single header referenced from the modulemap, importing the rest of the headers the preferred solution?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That approach has a flaw that might cause a compile error related to the modularization in the following scenario:
Consider this modulemap:
module B {
header "b.h"
}
module C {
header "c.h"
}
and three headers:
// a.h
class Decl {}
// b.h
#include "a.h"
// c.h
#include "a.h"
Notice that a.h
is not referenced from the modulemap. As the forum post mentions, this is not an issue for Clang:
If the platform does not provide a module map for a given header, it will be included textually, both into the SwiftGlibc module and into any imported C / Objective-C / C++ modules that include the header. All of these modules will therefore contain the definitions from this header.
This is fine under Clang’s rules for modules; Clang has logic to deduplicate definitions caused by textual inclusion of the same header into multiple modules.
However, an important part that the forum post misses is that while Clang can handle this, Swift cannot. What Swift does in this case is it assumes that the first header to include a.h
owns the header, in a sense that a.h
is assigned to the same module as either b.h
or c.h
, but we can't really say which one is it.
This situation might occur in the system header scenario: assume we're compiling a Swift program that imports two C modules: SwiftGlibc
/SwiftMusl
and some other user-provided module. If the latter also contains an #include <some_stdlib_header.h>
, Swift might treat some_stdlib_header.h
as a part of the user-provided module. This will cause a compile error for a perfectly valid code:
import SwiftMusl
someFunctionFromTheStdlib()
// error: user-provided module not imported
The injection approach avoids both of the issues described in the forum post: symbols such as pid_t
are available, and there is no cyclic dependency between libc++ and SwiftGlibc. I can explain this in a bit more detail if you'd like.
At the moment libstdc++ modulemap relies on the new injection approach, while SwiftGlibc still has a SwiftGlibc.h
header with a list of #include<>
-s. The idea is to eventually get rid of SwiftGlibc.h
and refer to all of the glibc headers from the modulemap directly.
Any plans to remove the SwiftGlibc.h header soon?
@buttaface no specific timeline as of now, but contributions are welcome 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to clarify, I don't know if it's strictly necessary to use the injection approach for SwiftMusl right now, I'm just pointing out an issue that might arise in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@MaxDesiatov, I brought this up so that you could try out this new approach with Musl too, if interested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be possible to inject this modulemap file into the Musl directory using LLVM VFS.
We already use this mechanism to injectglibc.modulemap
into the Glibc installation (swift::getClangInvocationFileMapping
).
Slightly off-topic here, but does this mechanism work on Windows? Looks like it could solve a big pain on Windows installation. Nowadays Swift on Windows installer will copy the modulemap
s to UCRT/WinSDK/MSVC accordingly. This is somehow fragile because we need to repeat this process every time after the environment is updated, and since the detection is hard-coded we cannot support any version of Visual Studio at the time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(On the Windows front, I believe this is actually what the Windows build does now.)
@buttaface So I just finished talking with @mstokercricut a little about this. We don't know that we have the expertise with the compiler to do the |
@bscothern-Cricut, I was just looking into this and I don't think it will require any compiler expertise to add I'm looking into splitting off Bionic as its own module, which doesn't appear to require much either and given the current Musl work, shouldn't require going through Evolution either. But ideally we would switch all Swift packages to |
If adding support for a new libc amounted to adding only Creating a single |
That's irrelevant: the only benefit of
I disagree. For one, there is no way to specialize on Bionic right now, whereas adding
The benefit of We would just need to be careful to communicate that, but since such cross-platform support is an advanced feature, I suspect that most calling such C APIs would understand that. |
FWIW I don't consider myself anywhere near experienced enough with libc to want to direct or shape this effort in one way or another. I'd always appreciate reduced boilerplate, but tbh I rarely use I appreciate the move to support Musl and Alpine @MaxDesiatov |
This change is necessary to allow building Musl platform module when targeting Alpine Linux.
57e342e
to
0f5617e
Compare
@swift-ci test |
@swift-ci build toolchain |
@swift-ci test macos |
I don't think we should do a "minimal" In particular, I think we should aim to provide a uniform set of functionality that can be used anywhere, with reasonable affordances where functionality is missing on some platform or other. In particular, I don't think it'd be much to ask to make the types from the C standard library and (where supported) POSIX library import into Swift in a uniform manner. They're standardised in C, but for reasons to do with the way the Swift importer works we sometimes end up with variations on them. There are also a few areas, like stdio, where typical C libraries use macros to provide quite substantial acceleration for some functions, which right now doesn't happen if you use the same function from Swift because we don't import complex macros. (Note: there is some precedent for this kind of thing on the C side, in particular GNU's I have some ideas in that area and want to investigate it and write up a proper proposal for what I think we should do, but I think getting Musl support basically working first is a useful thing for us to do for other reasons. I'm aware that that, temporarily, means that various projects are going to gain yet another |
${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS} | ||
${swift_platform_compile_flags} | ||
LINK_FLAGS "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}" | ||
TARGET_SDKS ALPINE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this patch can go in like that, because ALPINE
isn't an SDK. I also don't think ALPINE
should be an SDK. I'll talk to you offline about this part.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that Alpine shouldn't be an SDK and suggested so a couple weeks ago, including removing Android as an SDK, but got no response.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the differences here are to do with libc, but I think it's not unreasonable for Swift to refer to that as an SDK. I just think it should probably be called MUSL
rather than ALPINE
, since the latter is just one distribution that happens to use musl in some configuration (I guess ANDROID
should really be BIONIC
on that basis, as it's probably using the same libc as Fuscia?).
But perhaps more pertinently, I'd like to be in a situation where we can build a compiler that has both the LINUX
and MUSL
SDKs available, where right now we tend to just configure a single SDK for the UNIX variant we're building on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just think it should probably be called
MUSL
rather thanALPINE
, since the latter is just one distribution that happens to use musl in some configuration
That's addressed in the latest commit of this PR. I'm not defining the SDK itself yet to make this PR smaller for easier review and for overall efforts to be incremental, so technically this PR is an NFC for all other platforms.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to be in a situation where we can build a compiler that has both the LINUX and MUSL SDKs available, where right now we tend to just configure a single SDK for the UNIX variant we're building on.
@al45tair, my suggestion in that prior comment was that we just use the LINUX
SDK for regular glibc distros, Android, and Alpine, but then provide a way to choose the libc we want to build against, similar to how you added choosing a threading library now.
I don't know what libc Fuchsia uses, but then switching the libc for other OS's should be easy, eg if one wants to use glibc on Windows someday.
That's what we do now for each libc, ie it is the status quo.
That much less ambitious pitch has been sitting there for two years now and nothing has been done, so naturally I wasn't expecting something more to be done.
Great, hope it goes through. |
@swift-ci test |
@swift-ci build toolchain |
This change is necessary to allow building Musl platform module when targeting Alpine Linux.