-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Do not depend on the HAVE_STRLCAT and HAVE_STRLCPY preprocessor definitions. #5013
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
These checks are required because glibc 2.38+ added strlcat and strlcpy functions. swift-corelibs-foundation should use these functions if they are available. The checks originally existed in commit 8d1a679, but were not added to the new CMakeLists.txt in commit c772413. Fixes swiftlang#5012
CMakeLists.txt
Outdated
include(CheckLinkerFlag) | ||
|
||
check_symbol_exists(strlcat "string.h" HAVE_STRLCAT) | ||
check_symbol_exists(strlcpy "string.h" HAVE_STRLCPY) |
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.
Is there a way that we can replicate this behavior in the package manifest as well so that when building via SwiftPM we get the same behavior? Or a way that we can add this check into the code itself rather than on the CMake/SwiftPM side?
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.
Generally, no, SwiftPM doesn't have a way to add such checks or generate "config.h" files.
However, in these cases (HAVE_STRLCAT and HAVE_STRLCPY in Swift), I think we can change swift-corelibs-foundation (and other projects) to use local versions of these functions only if certain conditions are not met. Below is an example of how we can do this:
#if !TARGET_OS_MAC
#if defined(__linux__) && ((defined(__GLIBC__) && __GLIBC__ >= 2 && defined(__GLIBC_MINOR__) && __GLIBC_MINOR__ >= 38) || !defined(__GLIBC__))
// strlcat and strlcpy are available in the system
#else
// Define local versions of strlcpy and strlcat for glibc < 2.38
CF_INLINE size_t
strlcpy(char * dst, const char * src, size_t maxlen) {
...
}
#endif
#endif // !TARGET_OS_MAC
This code assumes the following things:
- Swift is supported on macOS (and other Apple platforms), Linux, and Windows.
- Android's bionic supports strlcpy and strlcat. Link
- Other than Android, Linux uses glibc or musl. Musl supports strlcpy and strlcat. Link
- glibc 2.38 and later supports strlcpy and strlcat.
- Windows doesn't have strlcpy and strlcat.
This approach is somewhat error-prone and may not be the best way to handle this, but I think this is the only way to handle this in SwiftPM. Also, I don't think supported platforms change frequently, so this approach should be fine with appropriate compile flags. Do you think this approach is acceptable?
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 think this is an alright way to right this given that SwiftPM can't perform a check - assuming there's no other macro defined in the header that we can use to indicate the presence or lack of this function. @parkera had to do something similar for CURL: https://github.com/apple/swift-corelibs-foundation/blob/15ee5c32d2b808fd912c586c535feaf9af2eb2d5/Sources/_CFURLSessionInterface/include/CFURLSessionInterface.h#L39-L57
The only tweak I'd suggest - rather than doing this for !TARGET_OS_MAC
, should we just only do this for TARGET_OS_LINUX
(or whatever the right macro is for that)? In other words, do we need to define strlcpy
for Windows/Android or does the source code in Foundation already handle not calling that function?
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.
If you think it is a good idea to remove autoconf-style feature test preprocessor macros and check features in the code for compatibility with SwiftPM, I'll revisit this patch to do so.
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.
👍 yep since the alternative would break the SwiftPM build of this project, checking conditionally in the code is the way to go here to avoid breaking the build
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.
This definitely seems like a good improvement once we add the Swift case as well.
CMakeLists.txt
Outdated
endif() | ||
if(HAVE_STRLCPY) | ||
add_compile_definitions($<$<OR:$<COMPILE_LANGUAGE:C>,$<COMPILE_LANGUAGE:CXX>>:HAVE_STRLCPY>) | ||
endif() |
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 think that we need to have an entry for Swift as well to pass this to the ClangImporter. Something like $<$<COMPILE_LANGUAGE:Swift>:SHELL:-Xcc -DHAVE_STRLCPY>
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.
All changes within CMakeLists.txt were reverted in the latest commit. Please check the header file for the changes.
…itions. While checking whether the system provides the `strlcat` and `strlcpy` functions, using an autoconf-style check to determine their availability does not seem to be a good idea. This is because the code is also used with SwiftPM, which does not have a similar feature test. Instead, we should directly check the availability of these functions in the system. Given that `strlcpy` and `strlcat` are not standard C functions, we should check whether the system is macOS, Linux with Bionic or Musl libc, or glibc version 2.38 or later. This patch adds the necessary checks in the header file so that SwiftPM can use these checks as well. Fixes swiftlang#5012
@swift-ci test |
#if !TARGET_OS_MAC | ||
#if !HAVE_STRLCPY | ||
#if TARGET_OS_MAC || \ | ||
(TARGET_OS_LINUX && \ |
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.
Is this going to be a problem for platforms which are not Linux but do have strlcat
(FreeBSD, e.g.)?
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.
(maybe not depending on the definition of __GLIBC__
but I'm unsure of where that's set)
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's the weakness of this approach, and that's also why every project has a list of supporting platforms. From what I know, Swift isn't officially supported on BSD variants (obviously, except for Darwin). So, I think it's not a problem. I don't even have a FreeBSD machine to test it. But if it is absolutely necessary, I may add another check for BSD variants based on https://sourceforge.net/p/predef/wiki/OperatingSystems/ and other sources, but honestly, I don't think it's necessary.
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.
FreeBSD does have a port as does Haiku, PS4, etc. I think that the target os macros do not work even on Linux. Does this cover uclibc and newlib? There is a plethora of libcs, and the fact that this "breaks" on SPM is fine - you can mirror this into SPM as:
cSettings: [
.define("HAVE_STRLCAT", .when(platforms: [.linux]))),
.define("HAVE_STRLCPY", .when(platforms: [.linux]))),
]
@jmschonfeld - I think that this is a sufficient means of mapping this in SPM, which will need to be changed if your environment is different as SPM does not have the necessary flexibility.
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.
What if this (swift-corelibs-foundation) library is used as a transitive dependency in a Swift Package Manager project? Since SPM can't replace dependencies on the consumer side, it is extremely annoying to patch existing projects, as all dependent projects need to be patched as well. If we had a similar mechanism like go mod replace
or npm's override mechanism, it would be much easier to handle this kind of situation, but that is a different topic.
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.
You would need to update the dependency. Fortunately, swift-corelibs-foundation cannot be used as a package dependency and is shipped as part of the toolchain.
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 seems that the annoyance of replacing transitive dependencies is not a problem for the swift-corelibs-foundation repository. However, I'm still unsure about defining HAVE_STRLCAT
and HAVE_STRLCPY
in the SwiftPM manifest file. Even though it's the same OS (Linux), the actual availability of these functions can vary. I think it would be better to define these macros in the source code, even though it might be a bit messy.
I also wish Swift had clearer documentation on which platforms are supported and which are not, so we can avoid confusions with platforms like FreeBSD. I have made a post on the Swift forums to clarify this: https://forums.swift.org/t/clarifying-supported-platforms-for-swift/73309
Hi there, I'm wondering if there are any updates regarding this change landing. I'm a little out of my depth wrt the discussion of multiple techniques of implementing the conditional checks required, but it sounds to me that there is some consensus on a preferred solution that would require a new capability of SwiftPM. If that is true, is there an issue or discussion of to spec out this new capability? If someone were able to volunteer some guidance, I may even be able to pitch or implement such a change. I'm interested in using swift-corelibs-foundation as a package dependency instead of using the binaries within the toolchain so that I can more easily debug issues by stepping into the source. I believe this is aligned with the project and work group's goal of minimizing this compatibility layer over time, since it will help people debug issues, find inconsistencies, and contribute changes to swift-foundation. |
This change was landed, in effect, in some other PRs I believe. The current state is:
If you're hitting build failures related to this, I'd be interested to know your build setup (which platform/SDK, which build system - CMake or SwiftPM, etc.)
A word of caution here: the SwiftPM build of this project is intended to be used for development of this project but not as a stable dependency for other projects. Other projects need to use the Foundation from the toolchain so that everybody "agrees" on which Foundation to use. If your project imports Foundation from a package dependency and uses another package dependency that also imports Foundation from the toolchain, you will end up with "two Foundations" that are not compatible with each other. You can definitely use the SwiftPM build as a dependency for small test projects to debug issues (I often use it as a dependency for a small CLI that I can use to test out reported problematic code) but using it as a dependency for a full project with a tree of dependencies (especially in any production use cases) is not supported and likely will not work due to the "two Foundations" problem. Hopefully that clears this up a bit just to make sure you don't accidentally end up in unsupported territory 🙂. |
I confirmed that this patch is no longer necessary, as the relevant PR has already landed in #5113. Closing this. |
While checking whether the system provides the
strlcat
andstrlcpy
functions, using an autoconf-style check to determine their availability
does not seem to be a good idea. This is because the code is also
used with SwiftPM, which does not have a similar feature test.
Instead, we should directly check the availability of these functions
in the system.
Given that
strlcpy
andstrlcat
are not standard C functions,we should check whether the system is macOS, Linux with Bionic or
Musl libc, or glibc version 2.38 or later. This patch adds the necessary
checks in the header file so that SwiftPM can use these checks as well.
Fixes #5012