diff options
author | 2016-05-05 20:24:13 +0000 | |
---|---|---|
committer | 2016-05-06 09:30:03 +0000 | |
commit | 87846c72372447ac9a3eb88bcd18a1d00bdcc595 (patch) | |
tree | aaf73eb15ec33c6167c14ea17c541946edd97f90 | |
parent | 76c58128251f39c7d1fe4cae412e7ca9a8447e3b (diff) |
Attempt 3 at deduping libtool inputs with the same basename. Libtool wrapper overrides old previous symlinks it created.
--
MOS_MIGRATED_REVID=121609372
-rwxr-xr-x | src/tools/xcode/xcrunwrapper/xcrunwrapper.sh | 77 | ||||
-rwxr-xr-x | tools/objc/j2objc_dead_code_pruner.py | 34 |
2 files changed, 102 insertions, 9 deletions
diff --git a/src/tools/xcode/xcrunwrapper/xcrunwrapper.sh b/src/tools/xcode/xcrunwrapper/xcrunwrapper.sh index dfb36aa4ef..ecd2ef60c6 100755 --- a/src/tools/xcode/xcrunwrapper/xcrunwrapper.sh +++ b/src/tools/xcode/xcrunwrapper/xcrunwrapper.sh @@ -14,14 +14,29 @@ # See the License for the specific language governing permissions and # limitations under the License. # -# xcrunwrapper runs the command passed to it using xcrun. -# It replaces __BAZEL_XCODE_DEVELOPER_DIR__ with $DEVELOPER_DIR (or reasonable -# default) and __BAZEL_XCODE_SDKROOT__ with a valid path based on SDKROOT (or -# reasonable default). +# xcrunwrapper runs the command passed to it using xcrun. The first arg +# passed is the name of the tool to be invoked via xcrun. (For example, libtool +# or clang). +# xcrunwrapper replaces __BAZEL_XCODE_DEVELOPER_DIR__ with $DEVELOPER_DIR (or +# reasonable default) and __BAZEL_XCODE_SDKROOT__ with a valid path based on +# SDKROOT (or reasonable default). # These values (__BAZEL_XCODE_*) are a shared secret withIosSdkCommands.java. set -eu +TOOLNAME=$1 +shift + +# Creates a symbolic link to the input argument file and returns the symlink +# file path. +function hash_objfile() { + ORIGINAL_NAME="$1" + ORIGINAL_HASH="$(/sbin/md5 -q "${ORIGINAL_NAME}")" + SYMLINK_NAME="${ORIGINAL_NAME%.o}_${ORIGINAL_HASH}.o" + ln -sf "$(basename "$ORIGINAL_NAME")" "$SYMLINK_NAME" + echo "$SYMLINK_NAME" +} + # Pick values for DEVELOPER_DIR and SDKROOT as appropriate (if they weren't set) WRAPPER_DEVDIR="${DEVELOPER_DIR:-}" @@ -47,8 +62,60 @@ if [[ -z "${WRAPPER_SDKROOT:-}" ]] ; then WRAPPER_SDKROOT="$(/usr/bin/xcrun --show-sdk-path --sdk ${WRAPPER_SDK})" fi +ARGS=("$TOOLNAME") +while [[ $# -gt 0 ]]; do + ARG="$1" + shift + + # Libtool artifact symlinking. Apple's libtool has a bug when there are two + # input files with the same basename. We thus create symlinks that are named + # with a hash suffix for each input, and pass them to libtool. + # See b/28186497. + # TODO(b/28347228): Handle this in a separate wrapper. + if [ "$TOOLNAME" = "libtool" ] ; then + case "${ARG}" in + # Filelist flag, need to symlink each input in the contents of file and + # pass a new filelist which contains the symlinks. + -filelist) + ARGS+=("${ARG}") + ARG="$1" + shift + HASHED_FILELIST="${ARG%.objlist}_hashes.objlist" + rm -f "${HASHED_FILELIST}" + while read INPUT_FILE || [ -n "$INPUT_FILE" ]; do + echo "$(hash_objfile "${INPUT_FILE}")" >> "$HASHED_FILELIST" + done < "${ARG}" + ARGS+=("${HASHED_FILELIST}") + ;; + # Flags with no args + -static|-s|-a|-c|-L|-T|-no_warning_for_no_symbols) + ARGS+=("${ARG}") + ;; + # Single-arg flags + -o|-arch_only|-syslibroot) + ARGS+=("${ARG}") + ARG="$1" + shift + ARGS+=("${ARG}") + ;; + # Any remaining flags are unexpected and may ruin flag parsing. + -*) + echo "Unrecognized libtool flag ${ARG}" + exit 1 + ;; + # Remaining args are input objects + *) + ARGS+=("$(echo "$(hash_objfile "${ARG}")")") + ;; + esac + else + ARGS+=("${ARG}") + fi +done + +# Subsitute toolkit path placeholders. UPDATEDARGS=() -for ARG in "$@" ; do +for ARG in "${ARGS[@]}" ; do ARG="${ARG//__BAZEL_XCODE_DEVELOPER_DIR__/${WRAPPER_DEVDIR}}" ARG="${ARG//__BAZEL_XCODE_SDKROOT__/${WRAPPER_SDKROOT}}" UPDATEDARGS+=("${ARG}") diff --git a/tools/objc/j2objc_dead_code_pruner.py b/tools/objc/j2objc_dead_code_pruner.py index 503d818c01..9f787cbf0a 100755 --- a/tools/objc/j2objc_dead_code_pruner.py +++ b/tools/objc/j2objc_dead_code_pruner.py @@ -30,6 +30,7 @@ from collections import OrderedDict import multiprocessing import os import Queue +import re import shutil import subprocess import threading @@ -295,10 +296,34 @@ def PruneSourceFiles(input_files, output_files, dependency_mapping_files, file_shutil) +def MatchObjectNamesInArchive(xcrunwrapper, archive, object_names): + """Returns object names matching their identity in an archive file. + + The linker that blaze uses appends an md5 hash to object file + names prior to inclusion in the archive file. Thus, object names + such as 'foo.o' need to be matched to their appropriate name in + the archive file, such as 'foo_<hash>.o'. + + Args: + xcrunwrapper: A wrapper script over xcrun. + archive: The location of the archive file. + object_names: The expected basenames of object files to match, + sans extension. For example 'foo' (not 'foo.o'). + Returns: + A list of basenames of matching members of the given archive + """ + ar_contents_cmd = '%s ar -t %s' % (xcrunwrapper, archive) + real_object_names = subprocess.check_output(ar_contents_cmd, shell=True) + expected_object_name_regex = '^(?:%s)_[0-9a-f]{32}.o' % ( + '|'.join([re.escape(name) for name in object_names])) + return re.findall(expected_object_name_regex, real_object_names, + flags=re.MULTILINE) + + def PruneArchiveFile(input_archive, output_archive, dummy_archive, dependency_mapping_files, header_mapping_files, archive_source_mapping_files, entry_classes, xcrunwrapper, - file_open=open, proc_exe=subprocess.check_call): + file_open=open): """Remove unreachable objects from archive file. Args: @@ -315,7 +340,6 @@ def PruneArchiveFile(input_archive, output_archive, dummy_archive, xcrunwrapper: A wrapper script over xcrun. file_open: Reference to the builtin open function so it may be overridden for testing. - proc_exe: Object that can execute a command line process. """ reachability_file_mapping = BuildReachabilityTree( dependency_mapping_files, file_open) @@ -335,7 +359,7 @@ def PruneArchiveFile(input_archive, output_archive, dummy_archive, for source_file in source_files: if os.path.splitext(source_file)[0] not in reachable_files_set: unreachable_object_names.append( - os.path.basename(os.path.splitext(source_file)[0]) + '.o') + os.path.basename(os.path.splitext(source_file)[0])) # There are unreachable objects in the archive to prune if unreachable_object_names: @@ -350,6 +374,8 @@ def PruneArchiveFile(input_archive, output_archive, dummy_archive, # Make the output archive editable j2objc_cmd += 'chmod +w %s;' % (output_archive) # Remove the unreachable objects from the archive + unreachable_object_names = MatchObjectNamesInArchive( + xcrunwrapper, input_archive, unreachable_object_names) j2objc_cmd += '%s ar -d -s %s %s;' % ( xcrunwrapper, output_archive, ' '.join(unreachable_object_names)) # Update the table of content of the archive file @@ -362,7 +388,7 @@ def PruneArchiveFile(input_archive, output_archive, dummy_archive, else: j2objc_cmd = 'cp %s %s' % (input_archive, output_archive) - proc_exe(j2objc_cmd, stderr=subprocess.STDOUT, shell=True) + subprocess.check_output(j2objc_cmd, stderr=subprocess.STDOUT, shell=True) if __name__ == '__main__': |