Skip to content
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

[static][stdlib] Any ELF platform can build static binaries. #32736

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

3405691582
Copy link
Contributor

Currently, building static binaries is gated to Linux. In order for this to work, the compiler looks for a file with a list of flags and uses them to generate a statically linked binary. This is a static file copied from the repository.

However, when building stdlib statically, the link files are generated dynamically from the cmakefiles; specifically, this is necessary to get the correct reference to the ICU libraries, as ICU is not a mandatory part of the build process. Therefore, we use the same dynamic generation of the linker flag file used in static stdlib generation for static binary generation.

Additionally, libdl is apparently necessary for Linux, but is not for OpenBSD, so this is conditioned here in a similar way that the ICU libraries are referenced.

Some unit tests are fouled up by this change because for some reason ImageInspectionELF.cpp is split out of swiftCore and put into its own library, and there still remain references from swiftCore to lookupSymbol in ImageInspectionELF. This causes lazy binding errors at runtime which mess up the expectations in these unit tests. This PR doesn't take a position yet as to whether such a split is necessary, so mark these unit tests UNSUPPORTED for now.

One unit test on OpenBSD is marked XFAIL for now because the test refers to lld at HEAD and not the platform lld; the lld at HEAD on OpenBSD does not link static binaries properly but the platform lld works fine if manually tested.

Instead of copying a static file from the repository, do what the
cmakefile already does for static-stdlib-args.lnk and generate it
dynamically. This means we can utilize the libicu flags set from the
prior commit rather than requiring libicu be built as part of the Swift
build just to ensure that the static link flags are correct.
@lin7sh
Copy link

lin7sh commented Jul 7, 2020

Thanks for moving swift to BSD world further. Do you have plan to support FreeBSD as well?

@@ -1,3 +1,4 @@
// UNSUPPORTED: static_stdlib
Copy link
Contributor

@gribozavr gribozavr Jul 7, 2020

Choose a reason for hiding this comment

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

This is not obvious, could you add a comment explaining why it is not supported? (Here and in every other test, please.)

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. Since the explanation is somewhat wordy, I've created a Jira bug for the UNSUPPORTED annotations and referenced to the bug.

Do you think the (unrelated) XFAIL elsewhere needs a comment as well?

@3405691582 3405691582 force-pushed the MoreStaticBinaries branch from 1cf411d to 67c1479 Compare July 7, 2020 14:23
@3405691582
Copy link
Contributor Author

cc @spevans, who may have some context on the splitting issue.

@3405691582
Copy link
Contributor Author

@mko-io: I have sent you a pm on forums.swift.org.

Copy link
Member

@compnerd compnerd left a comment

Choose a reason for hiding this comment

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

We had static-executable-args just laying around or did I miss a reference to the removal of it from the command line?

else()
find_package(ICU REQUIRED COMPONENTS uc i18n)
get_filename_component(ICU_UC_LIBDIR "${ICU_UC_LIBRARIES}" DIRECTORY)
get_filename_component(ICU_I18N_LIBDIR "${ICU_I18N_LIBRARIES}" DIRECTORY)
Copy link
Member

Choose a reason for hiding this comment

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

This is code motion from further below.

Not your fault, but this really is not what it should be doing. The additional find_package(ICU) doesn't account for the custom build system.

In order to deal with the custom build system in Swift, the project added the custom variables to specify the library - SWIFT_${SWIFT_HOST_VARIANT_SDK}_${SWIFT_HOST_VARIANT_ARCH}_ICU_{UC,I18N}. I think that we should continue to use this existing path rather than add all this additional complexity. SWIFT_${SWIFT_HOST_VARIANT_SDK}_${SWIFT_HOST_VARIANT_ARCH}_ICU_{I18N,UC} should give you the path to the library. Setting that appropriately should wire the path all the way through. We should use that rather than the different paths for -licu... and the find_package.

Would be wonderful if you felt like doing that cleanup!

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. Added two commits in this PR to do this, since they are slightly non-trivial.

if(SWIFT_BUILD_STATIC_STDLIB AND "${sdk}" STREQUAL "LINUX")
set(libdl -ldl)
Copy link
Member

Choose a reason for hiding this comment

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

Ugh; I really wish that we could use CMAKE_DL_LIBS, unfortunately, the custom cross-compilation build system in Swift doesn't support that. We already have the special handling for dl in _add_target_variant_link_flags, can we re-use that rather than duplicate knowledge of libdl here? Alternatively, perhaps we should consider creating a SWIFT_DL_LIBS_${SWIFT_HOST_VARIANT_SDK}_${SWIFT_HOST_VARIANT_ARCH} variable to indicate if/when libdl is needed on a platform?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This one's a little more complex, since it appears (to me) that _add_target_variant_link_flags works with a CMake target, and maybe there's a way to create a dummy target and pull the link libraries. The latter is probably simpler, but I'll probably need to spin up a Linux build to do this properly.

Added a TODO and I'll take a look at this in a later PR. Does that sound reasonable?

@compnerd
Copy link
Member

compnerd commented Jul 7, 2020

Never mind on the file comment - I missed the fact that you had removed the custom command.

Static binaries can be built on other platforms, not just Linux; we use
the same check for ELF output to condition static binaries like for
static stdlib. However, since some ELF platforms don't need -ldl, pull
this out into a conditionally set variable.

As a side note: on OpenBSD, lld at HEAD does not work to link the test
binary, but the platform lld works fine, so XFAIL this temporarily.
In the prior commit we opened static binaries for all ELF platforms when
requested. For some reason, the ImageInspectionELF module is split out
into its own library when building stdlib as a static library. However,
there are still references to lookupSymbol from swiftCore to
ImageInspectionELF, which cause lazy binding errors at runtime which
foul up these unit tests. Currently it is unknown whether it is
necessary to keep splitting out ImageInspectionELF like this; on its
face, this seems rather unnecessary.

Until then, mark these tests unsupported when stdlib exists as a static
library, since these tests use the dynamic version of stdlib, and won't
have the correct references to ImageInspectionELF.
As suggested in swiftlang#32736, it would be ideal to use the FindICU generated
variables to refer to the ICU library paths. However, as it stands, this
only finds the dynamic libraries, so here we find the static libraries
as well.
@3405691582 3405691582 force-pushed the MoreStaticBinaries branch from a51b67f to 4183d5f Compare July 7, 2020 19:19
@spevans
Copy link
Contributor

spevans commented Jul 7, 2020

The only reason it was ever gated on Linux was that I had no way to test on other ELF platforms and so couldnt correctly construct the static-executable-args file for non-Linux OSes.

Note -static-executable doesnt really work correctly on Linux at the moment and -ldl shouldnt actually be linked in. This is because dlopen() doesnt work in static binaries (used for stack traces in fatalError). The fix for this is in #29039 although that PR needs a refresh.

This is why there are 2 libImageInspectionELF{Shared,Static}.a files, the Static one implements it own version of dladdr (in swift::lookupSymbol).

Instead of deriving the static library paths twice, use the variables generated by the FindICU cmake module.

The base cmakefiles only find icui18n and icuuc, but icudata is required to complete a static link, so we have to invoke find_package again here to ensure the variable is set.
@3405691582 3405691582 force-pushed the MoreStaticBinaries branch from 4183d5f to e1c8011 Compare July 7, 2020 19:51
@3405691582
Copy link
Contributor Author

Right. Maybe I haven't looked into it too deeply, but does it not make sense not have lookupSymbol fallback to the static mechanism if dlopen fails, rather than replacing lookupSymbol entirely?

@spevans
Copy link
Contributor

spevans commented Jul 9, 2020

It been a while since I looked at it but I believe my thinking was that on Linux with Glibc and static binaries, using the dl* functions should be avoided at all costs. However I will see if I can rework my PR to just use the static symbol lookup as a fall back to dladdr() and see how that goes.

@spevans
Copy link
Contributor

spevans commented Jul 9, 2020

@3405691582 btw there is an integration test @ swiftlang/swift-integration-tests#69 that hasnt been merged but you could modify for OpenBSD to act as a test for this PR

@3405691582
Copy link
Contributor Author

@spevans unfortunately, Dispatch needs a lot of work to be done for OpenBSD, but something similar might work instead. Thanks for the pointer, I'll take a look.

@shahmishal
Copy link
Member

Please update the base branch to main by Oct 5th otherwise the pull request will be closed automatically.

  • How to change the base branch: (Link)
  • More detail about the branch update: (Link)

@3405691582 3405691582 changed the base branch from master to main October 2, 2020 17:31
@finagolfin
Copy link
Member

Still needed? Please rebase if parts of this would still be useful.

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.

7 participants