Skip to content

Add buildbot profile for cross-compiling for linux-armv7 using external sysroot #75367

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

xtremekforever
Copy link
Contributor

  • Explanation:
    Added new buildbot profiles that allow cross-compiling Swift 6.0 for linux-armv7. This provides 2 different build steps that must be performed to cross compile:

    • buildbot_linux_crosscompile_armv7,llvm
    • buildbot_linux_crosscompile_armv7,stdlib,corelibs

    The first step is required to get some sort of llvm-linux-x86_64 directory created in the buildbot_linux_armv7 directory, which is required for the rest of the build.

    This does require an external sysroot to be provided, but creating it is simple when using Docker. This is how I created the sysroot for Debian 12 Bookworm for armv7:

    export DEBIAN_VERSION=bookworm
    docker run --platform linux/arm/v7 -it --name debian-$DEBIAN_VERSION-armv7 debian:$DEBIAN_VERSION /bin/bash
    # apt update
    # apt install build-essential libatomic1 libxml2-dev libcurl4-openssl-dev libz-dev
    # exit
      
    mkdir -p sysroot/usr/
    docker cp debian-$DEBIAN_VERSION-armv7:/lib sysroot/lib
    docker cp debian-$DEBIAN_VERSION-armv7:/usr/lib sysroot/usr/lib
    docker cp debian-$DEBIAN_VERSION-armv7:/usr/include sysroot/usr/include

    Then to build these profiles, the following commands can be used (assuming that the Swift 6.0 toolchain is installed):

    git clone https://github.com/xtremekforever/swift -b feature/swift-6.0-linux-armv7
    ./swift/utils/update-checkout --tag swift-6.0-DEVELOPMENT-SNAPSHOT-2024-07-17-a --clone --skip-repository cmake
    # Build LLVM
    ./swift/utils/build-script --preset=buildbot_linux_crosscompile_armv7,llvm
    # Build Stdlibs + Corelibs
    ./swift/utils/build-script --preset=buildbot_linux_crosscompile_armv7,stdlib,corelibs \
        install_destdir=$(pwd)/install \
        installable_package=$(pwd)/swift-linux-armv7-runtime.tar.gz \
        sysroot=$(pwd)/sysroot \
        workspace_dir=$(pwd) \
        toolchain_path=/path/to/swift-6.0/usr/bin
  • Scope:
    This mostly adds the new buildbot profiles, but also fixes an issue that prevented cross compilation starting in Swift 5.10, as well as tweaking the hardcoded --gcc-toolchain that prevented an external sysroot from being used to compile CXX interop modules.

    I also had to patch the COMMON_SWIFT_FLAGS that are passed to -DCMAKE_Swift_FLAGS since it was including extra quotes that made any usage of common-swift-flags= in the build-presets.ini file crash and burn when building libdispatch, foundation, etc.

  • Issues:

  • Original PRs:

    • release/6.0
  • Risk:
    As far as I can tell these changes should NOT negatively impact other builds, but we need to run the CIs against it.

  • Testing:
    All the existing CIs should be run against this to make sure that nothing was broken, especially with the CXX interop patch.
    I tested all of this on a Raspberry Pi 3B+ running Raspberry Pi OS 12 (32-bit) and it works. I did not try building these profiles on a macOS host- just on Ubuntu and Debian hosts with the correct dependencies installed.

  • Reviewers:

@MaxDesiatov
Copy link
Contributor

@swift-ci test

@MaxDesiatov
Copy link
Contributor

@swift-ci build toolchain

@xtremekforever
Copy link
Contributor Author

xtremekforever commented Jul 19, 2024

Looks like the tests failed trying to run the new buildbot preset:

======================================================================
ERROR: test_get_preset_buildbot_linux_crosscompile_armv7,stdlib,corelibs (tests.build_swift.test_presets.TestPresetParser)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/build-user/swift/utils/build_swift/build_swift/presets.py", line 362, in _interpolate_preset_vars
    value = _interpolate_string(value, vars)
  File "/home/build-user/swift/utils/build_swift/build_swift/presets.py", line 56, in _interpolate_string
    return string % values
KeyError: 'sysroot'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/build-user/swift/utils/build_swift/tests/build_swift/test_presets.py", line 152, in test
    preset_parser.get_preset(preset_name, vars=PRESET_DEFAULTS)
  File "/home/build-user/swift/utils/build_swift/build_swift/presets.py", line 394, in get_preset
    preset = self._interpolate_preset_vars(preset, vars)
  File "/home/build-user/swift/utils/build_swift/build_swift/presets.py", line 364, in _interpolate_preset_vars
    raise InterpolationError(
build_swift.presets.InterpolationError: no value found for sysroot in "%(sysroot)s"

To fix this is it sufficient to just add a sysroot value to swift/utils/build_swidt/tests/build_swift/test_presets.py?

PRESET_DEFAULTS = {
    'darwin_toolchain_alias': 'Alias',
    'darwin_toolchain_bundle_identifier': 'BundleIdentifier',
    'darwin_toolchain_display_name': 'DisplayName',
    'darwin_toolchain_display_name_short': 'DisplayNameShort',
    'darwin_toolchain_version': '1.0',
    'darwin_toolchain_xctoolchain_name': 'default',
    'extra_swift_args': '',
    'install_destdir': '/tmp/install',
    'install_symroot': '/tmp/install/symroot',
    'install_all': False,
    'install_toolchain_dir': '/tmp/install/toolchain',
    'install_prefix': '/usr',
    'installable_package': '/tmp/install/pkg',
    'swift_install_destdir': '/tmp/install/swift',
    'symbols_package': '/path/to/symbols/package',
    'ndk_path': '/path/to/ndk',
    'arm_dir': '/path/to/arm',
    'toolchain_path': '/tmp/toolchain',
}

@finagolfin
Copy link
Member

Good to see you got all this working, however, it appears this is overly long because you're not that familiar with the fairly complex build-script flags. I'll be happy to work with you to pare this down and get it in, but I have some questions first:

  1. It is unusual to not get a patch into trunk before submitting it for the 6.0 branch. Any reason this wasn't submitted to the main branch first?
  2. What happens if you don't run the LLVM preset you listed first? It should not be necessary to build any LLVM tools to build the Swift corelibs with a prebuilt Swift compiler, indeed my Android CI does so without those newly-built LLVM tools every day.

Some of these flags are redundant or are better set in the build-script itself. For example, there is already some support for building for linux armv7 that is best used or extended, rather than simply overriding it with all these externally passed-in flags.

Again, I can work with you to adjust this pull, let me know if you prefer chatting on matrix.org to do that.

@@ -373,7 +373,7 @@ def get_linux_target_components(self, arch):
def get_linux_sysroot(self, platform, arch):
if not self.is_cross_compile_target('{}-{}'.format(platform, arch)):
return None
sysroot_arch, abi = self.get_linux_target_components(arch)
sysroot_arch, _, abi = self.get_linux_target_components(arch)
Copy link
Member

Choose a reason for hiding this comment

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

Your change seems correct, but it might break the Alpine usecase it was added for in #61376 last year? @MaxDesiatov, wdyt?

@xtremekforever
Copy link
Contributor Author

xtremekforever commented Jul 21, 2024

@finagolfin thanks for the review. The reason why this isn't in trunk is that I'm unable to cross compile on main- so the hope here is that it could be included in 6.0 now, then moved over to main once we figure out what the issue is with cross compiling.

I'd love to figure out a way to pare this down to not require the extra LLVM build step. It's been annoying but I haven't figured out how to get it to NOT require the llvm-linux-x86_64 directory. Also, all the flags I included are there because the default ones from the cross compilation profile did not work. In some cases I had to override what was passed by default, and in the other cases I simply had to provide them because they were simply not provided to the stdlib and corelibs. Maybe the better solution would be to patch the build-scripts themselves to pass the correct flags under the linux-armv7 cross compilation profile.

I'd love to find the best way to do this, if you have some time to help me out and maybe try a few things- perhaps a better discussion on matrix.org to try a few things, then come back and update the pull request once something else is working.

@finagolfin
Copy link
Member

I'd love to find the best way to do this, if you have some time to help me out and maybe try a few things- perhaps a better discussion on matrix.org to try a few things

Sounds good, I'm available at this username on there: feel free to ping me when you want to discuss.

@xtremekforever
Copy link
Contributor Author

@MaxDesiatov I have some further improvements for this buildbot but I wanted to ask if it's even worth trying to get this into Swift 6.0 at this late stage. I think I may have found what was causing main to not build, and it appears to be related to some of the Swift for Embedded work going on with new build flags being passed when building the stdlib and dispatch and so forth. Perhaps it's better to just skip this for Swift 6.0 and do it correctly in main to ensure that cross compilation works correctly on our different architectures. What do you think?

@finagolfin helped me significantly but it seems like we'll be stuck with passing all the flags (target, sysroot) to the buildbot without changing the build scripts themselves (which is more changes in more files), and maybe there's a better opportunity to get this working in main and do it right. Please let me know what you feel would be the best course of action here.

@MaxDesiatov
Copy link
Contributor

@xtremekforever would you be able to clarify the exact issues you're having on main? After chatting to folks, it seems it'll be pretty much required to land on main first before it's considered for release/6.0.

Copy link
Member

@etcwilde etcwilde left a comment

Choose a reason for hiding this comment

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

Like @MaxDesiatov said, this should go to main first to ensure that it doesn't break anything, or if it does, it won't be on a time-sensitive branch.

The naming of the llvm preset is a bit confusing to me.
Seeing buildbot_linux_crosscompile_armv7,llvm followed by skip-build-llvm sends mixed messages about what it's actually building. I like the idea of splitting the runtime and compiler builds, but that isn't what's happening here.
If I'm understanding this correctly, this is to prebuild tablegen and generate the intrinsics and clang resource headers? What is the error if you don't pre-build these?

@finagolfin
Copy link
Member

@etcwilde, that's no longer needed, I showed him how to skip the llvm step.

We're looking at main now, will submit a pull there next.

@xtremekforever
Copy link
Contributor Author

xtremekforever commented Jul 22, 2024

@MaxDesiatov makes sense, so guess we'll have to do that. For one, I noticed that some incorrect flags were being passed to clang++ when compiling some objects. Here is what I saw in the failed clang++ calls: -target armv7-unknown-linux-gnu --sysroot=. This crashes the build since the flags I had in the buildbot of this pull request are overridden by these, and then clang++ can't find the correct headers. And also, the armv7-unknown-linux-gnu target is more ambiguous, and clang isn't sure if -mfloat-abi=soft or -mfloat-abi=hard, so it chooses soft, which doesn't work for what we're building. So I think these build flags will need to be patched up so they work properly under the linux-armv7 profile? I will have a deeper look.

@etcwilde yeah we figured out how to disable the LLVM build step, I did not realize that there was a way to skip that entirely by setting build-llvm=0.

@xtremekforever
Copy link
Contributor Author

I'll close this since we need to go back to main to get this profile in. Maybe it can be done in a better/more correct way as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants