diff options
author | Dmitry Shevchenko <dmishe@google.com> | 2017-03-09 22:00:00 +0000 |
---|---|---|
committer | Vladimir Moskva <vladmos@google.com> | 2017-03-10 10:28:04 +0000 |
commit | 701ff40ad9d1b6c1e3beb52064e2ae2fe27b7e29 (patch) | |
tree | c41547aee42e499012bac4f5e3f6959b5d5b913f /src/tools/xcode | |
parent | 4050dca289a72dce7d09509da56b34e688a02a73 (diff) |
Introduce swift-stdlib-tool replacement
* swift-stdlib-tool is a utility that, given a binary, walks its dynamic library deps graph and picks everything that is used by Swift runtime. This tool is being removed from Xcode 8.3, hence the replacement.
* The new tool has a different command line interface, but keeps backwards compatibility with native Bazel code through changes in the wrapper script. The wrapper script is still needed to handle xcrun ENV stuff.
--
PiperOrigin-RevId: 149691879
MOS_MIGRATED_REVID=149691879
Diffstat (limited to 'src/tools/xcode')
3 files changed, 103 insertions, 14 deletions
diff --git a/src/tools/xcode/swiftstdlibtoolwrapper/BUILD b/src/tools/xcode/swiftstdlibtoolwrapper/BUILD index a4af5932c8..e76fe9313a 100644 --- a/src/tools/xcode/swiftstdlibtoolwrapper/BUILD +++ b/src/tools/xcode/swiftstdlibtoolwrapper/BUILD @@ -5,10 +5,20 @@ filegroup( srcs = glob(["**"]), ) +# Sources that need to be packaged into embedded tools. +filegroup( + name = "swiftstdlibtoolwrapper_srcs", + srcs = [ + "swift_stdlib_tool.py", + "swiftstdlibtoolwrapper.sh", + ], +) + sh_binary( name = "swiftstdlibtoolwrapper", srcs = ["swiftstdlibtoolwrapper.sh"], data = [ + ":swift_stdlib_tool.py", "//src/tools/xcode/realpath", "//src/tools/xcode/xcrunwrapper", ], diff --git a/src/tools/xcode/swiftstdlibtoolwrapper/swift_stdlib_tool.py b/src/tools/xcode/swiftstdlibtoolwrapper/swift_stdlib_tool.py new file mode 100644 index 0000000000..6320d21211 --- /dev/null +++ b/src/tools/xcode/swiftstdlibtoolwrapper/swift_stdlib_tool.py @@ -0,0 +1,72 @@ +# pylint: disable=g-bad-file-header +# Copyright 2017 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""A tool to find Swift runtime libraries required by a binary. + +This tool is modeled after Xcode's swift-stdlib-tool. Given a binary, it +scans its transitive dylib dependencies to figure out the full set of Swift +runtime libraries (usually named libswift*.dylib) required to run the binary. +The libraries are then copied into the output directory. + +This tool is used by the Apple packaging rules to properly construct macOS, iOS, +watchOS and tvOS app bundles. + +Usage: + swift-stdlib-tool.py BINARY_TO_SCAN PLATFORM_DIRECTORY OUTPUT_PATH +""" + +import os +import shutil +import sys +from macholib.MachO import MachO + + +def dylib_full_path(platform_dir, relative_path): + """Constructs an absolute path to a platform dylib. + + Args: + platform_dir: A path to the platforms directory in the Swift toolchain. + relative_path: A path to a dylib relative to the platforms directory. + + Returns: + A normalized, absolute path to a dylib. + """ + return os.path.abspath(os.path.join(platform_dir, relative_path)) + + +def main(): + binary_path = sys.argv[1] + platform_dir = sys.argv[2] + out_path = sys.argv[3] + + # We want any dylib linked against which name starts with "libswift" + seen = set() + queue = [binary_path] + while queue: + path = queue.pop() + m = MachO(path) + for header in m.headers: + for _, _, other in header.walkRelocatables(): + if other.startswith("@rpath/libswift"): + full_path = dylib_full_path(platform_dir, other.lstrip("@rpath/")) + if full_path not in seen: + queue.append(full_path) + seen.add(full_path) + + for dylib in seen: + shutil.copy(dylib, out_path) + +if __name__ == "__main__": + main() diff --git a/src/tools/xcode/swiftstdlibtoolwrapper/swiftstdlibtoolwrapper.sh b/src/tools/xcode/swiftstdlibtoolwrapper/swiftstdlibtoolwrapper.sh index 99c920543e..9bf325f810 100755 --- a/src/tools/xcode/swiftstdlibtoolwrapper/swiftstdlibtoolwrapper.sh +++ b/src/tools/xcode/swiftstdlibtoolwrapper/swiftstdlibtoolwrapper.sh @@ -27,9 +27,6 @@ MY_LOCATION=${MY_LOCATION:-"$0.runfiles/bazel_tools/tools/objc"} REALPATH="${MY_LOCATION}/realpath" WRAPPER="${MY_LOCATION}/xcrunwrapper.sh" -CMD_ARGS=("$@") - -TOOL_ARGS=() while [[ $# -gt 0 ]]; do ARG="$1" shift @@ -49,29 +46,39 @@ while [[ $# -gt 0 ]]; do shift TOOLCHAIN=${ARG} ;; - # Remaining args are swift-stdlib-tool args - *) - TOOL_ARGS+=("$ARG") - ;; + --scan-executable) + ARG="$1" + shift + BINARY=${ARG} + ;; + --platform) + ARG="$1" + shift + PLATFORM=${ARG} + ;; esac done +# Prepare destination directory TEMPDIR=$(mktemp -d "${TMPDIR:-/tmp}/swiftstdlibtoolZippingOutput.XXXXXX") trap "rm -rf \"$TEMPDIR\"" EXIT FULLPATH="$TEMPDIR/$PATH_INSIDE_ZIP" - -XCRUN_ARGS=() +mkdir -p "${FULLPATH}" if [ -n "${TOOLCHAIN:-}" ]; then - XCRUN_ARGS+=(--toolchain "$TOOLCHAIN") + readonly swiftc_dir=$(dirname "$("${WRAPPER}" -f swiftc --toolchain "${TOOLCHAIN}")") +else + readonly swiftc_dir=$(dirname "$("${WRAPPER}" -f swiftc)") fi -XCRUN_ARGS+=(swift-stdlib-tool --copy --verbose ) -XCRUN_ARGS+=(--destination "$FULLPATH") -XCRUN_ARGS+=( "${TOOL_ARGS[@]}" ) +# Each toolchain has swift libraries directory located at +# /path/to/swiftc/../../lib/swift/<platform>/ +# This is the same relative path that Xcode uses and is considered to be stable. +readonly platform_dir="${swiftc_dir}/../lib/swift/${PLATFORM}" -$WRAPPER "${XCRUN_ARGS[@]}" +# Always use macOS system Python as it comes with macholib module. +/usr/bin/python "${MY_LOCATION}/swift_stdlib_tool.py" "${BINARY}" "${platform_dir}" "${FULLPATH}" # Need to push/pop tempdir so it isn't the current working directory # when we remove it via the EXIT trap. |