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

[build] Add the flags to enable cross-compiling the corelibs #33724

Merged
merged 1 commit into from
Jun 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,9 @@ endif()

set(SWIFT_BUILD_HOST_DISPATCH FALSE)
if(SWIFT_ENABLE_DISPATCH AND NOT CMAKE_SYSTEM_NAME STREQUAL Darwin)
if(SWIFT_BUILD_SYNTAXPARSERLIB OR SWIFT_BUILD_SOURCEKIT)
# Only build libdispatch for the host if the host tools are being built and
# specifically if these two libraries that depend on it are built.
if(SWIFT_INCLUDE_TOOLS AND (SWIFT_BUILD_SYNTAXPARSERLIB OR SWIFT_BUILD_SOURCEKIT))
gottesmm marked this conversation as resolved.
Show resolved Hide resolved
set(SWIFT_BUILD_HOST_DISPATCH TRUE)
endif()

Expand Down
3 changes: 3 additions & 0 deletions utils/build-script
Original file line number Diff line number Diff line change
Expand Up @@ -841,6 +841,7 @@ class BuildScriptInvocation(object):
"""

args = self.args
args.build_root = self.workspace.build_root
Copy link
Member Author

Choose a reason for hiding this comment

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

I need this later in the new swift_flags() method.


options = {}
for host_target in [args.host_target] + args.cross_compile_hosts:
Expand All @@ -862,6 +863,8 @@ class BuildScriptInvocation(object):
config.swift_benchmark_run_targets),
"SWIFT_TEST_TARGETS": " ".join(
config.swift_test_run_targets),
"SWIFT_FLAGS": config.swift_flags,
"SWIFT_TARGET_CMAKE_OPTIONS": config.cmake_options,
}

return options
Expand Down
65 changes: 60 additions & 5 deletions utils/build-script-impl
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,6 @@ KNOWN_SETTINGS=(
common-cmake-options "" "CMake options used for all targets, including LLVM/Clang"
extra-cmake-options "" "Extra options to pass to CMake for all targets"
ninja-cmake-options "" "CMake options used for all ninja targets"
ninja-cmake-options "" "CMake options used for all ninja targets"

## Build ...
build-llvm "1" "set to 1 to build LLVM and Clang"
Expand Down Expand Up @@ -205,6 +204,7 @@ KNOWN_SETTINGS=(
swift-stdlib-os-versioning "1" "whether to build stdlib with availability based on OS versions (Darwin only)"
swift-stdlib-stable-abi "" "should stdlib be built with stable ABI, if not set defaults to true on Darwin, false otherwise"
swift-disable-dead-stripping "0" "turns off Darwin-specific dead stripping for Swift host tools"
common-swift-flags "" "Flags used for Swift targets other than the stdlib, like the corelibs"

## FREESTANDING Stdlib Options
swift-freestanding-sdk "" "which SDK to use when building the FREESTANDING stdlib"
Expand All @@ -229,6 +229,7 @@ KNOWN_SETTINGS=(
cross-compile-hosts "" "space-separated list of targets to cross-compile host Swift tools for"
cross-compile-with-host-tools "" "set to use the clang we build for the host to then build the cross-compile hosts"
cross-compile-install-prefixes "" "semicolon-separated list of install prefixes to use for the cross-compiled hosts. The list expands, so if there are more cross-compile hosts than prefixes, unmatched hosts use the last prefix in the list"
cross-compile-deps-path "" "path for CMake to look for cross-compiled library dependencies, such as libXML2"
Copy link
Member Author

Choose a reason for hiding this comment

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

I thought about making this a list like cross-compile-hosts but realistically only one cross-compilation host is ever passed in, so this will do for now. The issue is that each cross-compilation host will require its own separate C/C++ cross-compilation toolchain, which there's no way to pass in to build-script yet. We're able to handle a single cross-compilation host with hacked-in flags like --android-ndk and --native-clang-tools-path, but for example, we can't even build multiple Android architectures with a single build-script invocation yet.

Copy link
Contributor

Choose a reason for hiding this comment

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

@buttaface I think the last sentence is incorrect. I imagine that if one hacked in something similar to what we have on Darwin in the stdlib cmake (which is horrible btw and I am not suggesting this).

That being said, shouldn't this just be found in some notion of an SDK? I think that is how on Darwin this would work.

Copy link
Member Author

Choose a reason for hiding this comment

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

The reason I said "we can't even build multiple Android architectures with a single build-script invocation yet" in my last sentence is that, for example, we pass in the path to a particular libicu built for one arch when invoking build-script. Even on Darwin, only compiling the Swift compiler itself for macOS x86_64 was supported until recently, when support for cross-compiling it from macOS x86_64 to arm64 was added but not the other way, swiftlang/swift-package-manager#3500, but again only a single cross-compilation host is supported on Darwin. Of course, one could hack in further changes to support multiple hosts, but it is currently not supported.

As for this just being an SDK, it is more general than that. I use this flag below to find dependencies like libxml2 or libsqlite3, which are additional package dependencies that aren't usually included in cross-compilation SDKs. I found this useful when cross-compiling the toolchain for Android, as I pass in the Termux prefix with those prebuilt library packages installed to this flag and the separate Android NDK, that has the libc sysroot but no libraries like libxml2, to the --android-ndk flag above.

This gives the most flexibility because if they are all in one SDK, you can always pass the same SDK path in to both flags.

skip-merge-lipo-cross-compile-tools "" "set to skip running merge-lipo after installing cross-compiled host Swift tools"
coverage-db "" "If set, coverage database to use when prioritizing testing"
skip-local-host-install "" "If we are cross-compiling multiple targets, skip an install pass locally if the hosts match"
Expand Down Expand Up @@ -1249,6 +1250,8 @@ function calculate_targets_for_host() {
SWIFT_BENCHMARK_TARGETS=($(get_host_specific_variable ${host} SWIFT_BENCHMARK_TARGETS))
SWIFT_RUN_BENCHMARK_TARGETS=($(get_host_specific_variable ${host} SWIFT_RUN_BENCHMARK_TARGETS))
SWIFT_TEST_TARGETS=($(get_host_specific_variable ${host} SWIFT_TEST_TARGETS))
SWIFT_FLAGS=($(get_host_specific_variable ${host} SWIFT_FLAGS))
SWIFT_TARGET_CMAKE_OPTIONS=($(get_host_specific_variable ${host} SWIFT_TARGET_CMAKE_OPTIONS))
}


Expand Down Expand Up @@ -1390,6 +1393,14 @@ function swift_c_flags() {
fi
}

function common_swift_flags() {
if [ "${module_cache}" == "" ] ; then
echo "error: a module cache path has not been set"
exit 1
fi
echo -n "${SWIFT_FLAGS[@]} ${COMMON_SWIFT_FLAGS} -module-cache-path \"${module_cache}\" "
}

function cmake_config_opt() {
product=$1
if [[ "${CMAKE_GENERATOR}" == "Xcode" ]] ; then
Expand Down Expand Up @@ -1666,6 +1677,9 @@ for host in "${ALL_HOSTS[@]}"; do
-DCMAKE_BUILD_TYPE:STRING="${CMARK_BUILD_TYPE}"
"${cmark_cmake_options[@]}"
)
if [[ $(is_cross_tools_host ${host}) ]] ; then
cmake_options+=("${SWIFT_TARGET_CMAKE_OPTIONS[@]}")
fi
build_targets=(all)
;;

Expand Down Expand Up @@ -1793,6 +1807,7 @@ for host in "${ALL_HOSTS[@]}"; do
-DCLANG_TABLEGEN=$(build_directory "${LOCAL_HOST}" llvm)/bin/clang-tblgen
-DLLVM_NATIVE_BUILD=$(build_directory "${LOCAL_HOST}" llvm)
)
cmake_options+=("${SWIFT_TARGET_CMAKE_OPTIONS[@]}")
fi

;;
Expand Down Expand Up @@ -2205,7 +2220,7 @@ for host in "${ALL_HOSTS[@]}"; do
-DCMAKE_CXX_COMPILER:PATH="${CLANG_BIN}/clang++"
-DCMAKE_INSTALL_PREFIX:PATH="$(get_host_install_prefix ${host})"
-DCMAKE_Swift_COMPILER:PATH=${SWIFTC_BIN}
-DCMAKE_Swift_FLAGS:STRING="-module-cache-path \"${module_cache}\""
-DCMAKE_Swift_FLAGS:STRING="$(common_swift_flags)"

-DLLBUILD_ENABLE_ASSERTIONS:BOOL=$(true_false "${LLBUILD_ENABLE_ASSERTIONS}")
-DLLBUILD_SUPPORT_BINDINGS:=Swift
Expand All @@ -2221,6 +2236,22 @@ for host in "${ALL_HOSTS[@]}"; do
-DFoundation_DIR:PATH=$(build_directory ${host} foundation)/cmake/modules
)

if [[ $(is_cross_tools_host ${host}) ]] ; then
cmake_options+=("${SWIFT_TARGET_CMAKE_OPTIONS[@]}")

# llbuild looks for the SQlite3 library using find_package(),
# so search for it in CROSS_COMPILE_DEPS_PATH using the CMake
# process for doing so and don't use cross-compiled
# executables, see the linked CMake docs for more info:
#
# https://cmake.org/cmake/help/latest/command/find_package.html
# https://cmake.org/cmake/help/latest/command/find_program.html
Copy link
Contributor

Choose a reason for hiding this comment

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

Great comment! This is exactly what I wanted!

I think you put in the link twice. But feel free to fix in a subsequent commit.

Copy link
Member Author

Choose a reason for hiding this comment

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

If you mean the two links here, it is because llbuild calls both find_package and find_program, which is why I had to tell it not to look in the cross-compilation SDK for programs to run in the host, with CMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER.

cmake_options+=(
-DCMAKE_FIND_ROOT_PATH:PATH="${CROSS_COMPILE_DEPS_PATH}"
-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER
gottesmm marked this conversation as resolved.
Show resolved Hide resolved
)
fi

# Ensure on Darwin platforms that we consider only the SQLite headers
# from the SDK instead of picking ones found elsewhere
# (e.g. in /usr/include )
Expand Down Expand Up @@ -2287,7 +2318,7 @@ for host in "${ALL_HOSTS[@]}"; do
-DCMAKE_C_COMPILER:PATH="${CLANG_BIN}/clang"
-DCMAKE_CXX_COMPILER:PATH="${CLANG_BIN}/clang++"
-DCMAKE_Swift_COMPILER:PATH=${SWIFTC_BIN}
-DCMAKE_Swift_FLAGS:STRING="-module-cache-path \"${module_cache}\""
-DCMAKE_Swift_FLAGS:STRING="$(common_swift_flags)"
-DCMAKE_INSTALL_PREFIX:PATH="$(get_host_install_prefix ${host})"
-DCMAKE_INSTALL_LIBDIR:PATH="lib"

Expand All @@ -2303,6 +2334,9 @@ for host in "${ALL_HOSTS[@]}"; do

-DENABLE_TESTING=YES
)
if [[ $(is_cross_tools_host ${host}) ]] ; then
cmake_options+=("${SWIFT_TARGET_CMAKE_OPTIONS[@]}")
fi
;;
esac

Expand Down Expand Up @@ -2356,7 +2390,7 @@ for host in "${ALL_HOSTS[@]}"; do
-DCMAKE_CXX_COMPILER:PATH=${CLANG_BIN}/clang++
-DCMAKE_SWIFT_COMPILER:PATH=${SWIFTC_BIN}
-DCMAKE_Swift_COMPILER:PATH=${SWIFTC_BIN}
-DCMAKE_Swift_FLAGS:STRING="-module-cache-path \"${module_cache}\""
-DCMAKE_Swift_FLAGS:STRING="$(common_swift_flags)"
-DCMAKE_INSTALL_PREFIX:PATH=$(get_host_install_prefix ${host})

${LIBICU_BUILD_ARGS[@]}
Expand All @@ -2372,6 +2406,24 @@ for host in "${ALL_HOSTS[@]}"; do
-DBUILD_SHARED_LIBS=$([[ ${product} == foundation_static ]] && echo "NO" || echo "YES")
)

if [[ $(is_cross_tools_host ${host}) ]] ; then
cmake_options+=("${SWIFT_TARGET_CMAKE_OPTIONS[@]}")

# Foundation looks for the ICU, libXML2 and libcurl libraries
# using find_package(), so search for them in
# CROSS_COMPILE_DEPS_PATH using the CMake process for doing
# so, see the linked CMake docs for more info:
Copy link
Contributor

Choose a reason for hiding this comment

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

Great comment! This is exactly what I wanted!

#
# https://cmake.org/cmake/help/latest/command/find_package.html
cmake_options+=(
-DCMAKE_FIND_ROOT_PATH:PATH="${CROSS_COMPILE_DEPS_PATH}"
)
fi
if [[ "${host}" == "android-"* ]]; then
cmake_options+=(
-DCMAKE_HAVE_LIBC_PTHREAD=True
)
fi
;;
libdispatch|libdispatch_static)
LIBDISPATCH_BUILD_DIR=$(build_directory ${host} ${product})
Expand All @@ -2398,7 +2450,7 @@ for host in "${ALL_HOSTS[@]}"; do
-DCMAKE_CXX_COMPILER:PATH="${CLANG_BIN}/clang++"
-DCMAKE_SWIFT_COMPILER:PATH="${SWIFTC_BIN}"
-DCMAKE_Swift_COMPILER:PATH="${SWIFTC_BIN}"
-DCMAKE_Swift_FLAGS:STRING="-module-cache-path \"${module_cache}\""
-DCMAKE_Swift_FLAGS:STRING="$(common_swift_flags)"
-DCMAKE_INSTALL_PREFIX:PATH="$(get_host_install_prefix ${host})"
-DCMAKE_INSTALL_LIBDIR:PATH="lib"

Expand All @@ -2407,6 +2459,9 @@ for host in "${ALL_HOSTS[@]}"; do
-DENABLE_TESTING=YES
-DBUILD_SHARED_LIBS=$([[ ${product} == libdispatch_static ]] && echo "NO" || echo "YES")
)
if [[ $(is_cross_tools_host ${host}) ]] ; then
cmake_options+=("${SWIFT_TARGET_CMAKE_OPTIONS[@]}")
fi
;;
esac

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ def __init__(self, host_target, args):
self.swift_test_run_targets = []
self.swift_benchmark_build_targets = []
self.swift_benchmark_run_targets = []
self.swift_flags = ''
self.cmake_options = ''
for deployment_target_name in stdlib_targets_to_configure:
# Get the target object.
deployment_target = StdlibDeploymentTarget.get_target_for_name(
Expand Down Expand Up @@ -203,6 +205,16 @@ def __init__(self, host_target, args):
"check-swift{}-optimize_none_with_implicit_dynamic-{}"
.format(subset_suffix, name))

# Only pull in these flags when cross-compiling with
# --cross-compile-hosts.
if deployment_target_name != args.host_target and \
host_target != args.host_target:
self.add_flags_for_cross_compilation(args, deployment_target)

def add_flags_for_cross_compilation(self, args, deployment_target):
self.swift_flags = deployment_target.platform.swift_flags(args)
self.cmake_options = deployment_target.platform.cmake_options(args)

def __platforms_to_skip_build(self, args):
platforms_to_skip_build = set()
if not args.build_linux:
Expand Down
35 changes: 35 additions & 0 deletions utils/swift_build_support/swift_build_support/targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,18 @@ def contains(self, target_name):
return True
return False

def swift_flags(self, args):
"""
Swift compiler flags for a platform, useful for cross-compiling
"""
return ''

def cmake_options(self, args):
"""
CMake flags to build for a platform, useful for cross-compiling
"""
return ''
Copy link
Contributor

Choose a reason for hiding this comment

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

One question that I have (and I am fine with you doing this in a subsequent commit) is if it would be better to error and force people to specify this. That being said, I don't feel too wedded to this.

Copy link
Contributor

Choose a reason for hiding this comment

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

(and if we decide to change it, feel free to put it in a different PR)

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm, the problem is that wouldn't that break the current cross-compilation of the Apple Silicon toolchain on the macOS x86_64 CI? I tried to keep this as non-intrusive as possible, because I don't want to interfere with other use cases.



class DarwinPlatform(Platform):
def __init__(self, name, archs, sdk_name=None, is_simulator=False):
Expand Down Expand Up @@ -136,6 +148,29 @@ def uses_host_tests(self):
"""
return True

def swift_flags(self, args):
flags = '-target %s-unknown-linux-android%s ' % (args.android_arch,
args.android_api_level)

flags += '-resource-dir %s/swift-%s-%s/lib/swift ' % (
args.build_root, self.name, args.android_arch)

android_toolchain_path = '%s/toolchains/llvm/prebuilt/%s' % (
args.android_ndk, StdlibDeploymentTarget.host_target().name)

flags += '-sdk %s/sysroot ' % (android_toolchain_path)
flags += '-tools-directory %s/bin' % (android_toolchain_path)
return flags

def cmake_options(self, args):
options = '-DCMAKE_SYSTEM_NAME=Android '
options += '-DCMAKE_SYSTEM_VERSION=%s ' % (args.android_api_level)
options += '-DCMAKE_SYSTEM_PROCESSOR=%s ' % (args.android_arch if not
args.android_arch == 'armv7'
else 'armv7-a')
options += '-DCMAKE_ANDROID_NDK:PATH=%s' % (args.android_ndk)
return options


class Target(object):
"""
Expand Down
7 changes: 7 additions & 0 deletions validation-test/BuildSystem/android_cross_compile.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# REQUIRES: standalone_build

# RUN: %empty-directory(%t)
# RUN: SWIFT_BUILD_ROOT=%t %swift_src_root/utils/build-script --dry-run --cmake %cmake --libdispatch --cross-compile-hosts=android-aarch64 --skip-local-build --android --android-ndk %t/ndk/ --android-arch aarch64 --android-icu-uc %t/lib/libicuuc.so --android-icu-uc-include %t/include/ --android-icu-i18n %t/lib/libicui18n.so --android-icu-i18n-include %t/include/ --android-icu-data %t/lib/libicudata.so 2>&1 | %FileCheck %s
Copy link
Contributor

Choose a reason for hiding this comment

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

Thank you for adding a test!

Copy link
Member Author

Choose a reason for hiding this comment

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

No problem, I agree with you that it's good to have them. I was just being lazy to not add it, so good that you asked.


# CHECK: -DCMAKE_Swift_FLAGS{{.*}}-target {{.*}}unknown-linux-android{{.*}} -sdk
# CHECK: -DCMAKE_SYSTEM_NAME=Android {{.*}} -DCMAKE_ANDROID_NDK