Skip to content

Commit 1d32e80

Browse files
authored
Fix Windows packages by forcing --target format in the case where it's ambiguous. (#233)
This also adds a --skip_creating_archive flag to merge_libraries so you can investigate the generated object files directly, without them being placed into a .obj or .a archive.
1 parent 83666db commit 1d32e80

File tree

1 file changed

+46
-16
lines changed

1 file changed

+46
-16
lines changed

scripts/merge_libraries.py

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,20 @@
9595
"two libraries. C++ symbols in the appropriate namespaces will be renamed "
9696
"even if they are external. Otherwise, only symbols defined in the library "
9797
"are renamed.")
98+
flags.DEFINE_bool(
99+
"skip_creating_archives", False,
100+
"Skip creating archive files (.a or .lib) and instead just leave the object "
101+
"files (.o or .obj) in the output directory.")
98102

99103
# Never rename 'std::' by default when --auto_hide_cpp_namespaces is enabled.
100104
IMPLICIT_CPP_NAMESPACES_TO_IGNORE = {"std"}
101105

102106
DEFAULT_ENCODING = "ascii"
103107

108+
# Once a binutils command fails due to an ambiguous target, use this explicit target
109+
# when running all subsequent binutils commands.
110+
binutils_force_target_format = None
111+
104112

105113
class Demangler(object):
106114
"""Spins up a C++ demangler and pipes symboles to/from it to demangle them.
@@ -258,19 +266,20 @@ def create_archive(output_archive_file, object_files, old_archive=None):
258266
Empty list if there are no errors, or error text if there was an error.
259267
"""
260268
errors = []
261-
if old_archive:
269+
if old_archive and FLAGS.platform != "windows":
262270
# Copy the old archive to the new archive, then clear the files from it.
263271
# This preserves the file format of the old archive file.
272+
# On Windows, we'll always create a new archive.
264273
shutil.copy(old_archive, output_archive_file)
265274
(old_contents, errors) = list_objects_in_archive(output_archive_file)
266-
run_command(
275+
run_binutils_command(
267276
[FLAGS.binutils_ar_cmd, "d", output_archive_file] + old_contents,
268277
errors)
269-
run_command(
278+
run_binutils_command(
270279
[FLAGS.binutils_ar_cmd, "rs", output_archive_file] + object_files,
271280
errors)
272281
else:
273-
run_command(
282+
run_binutils_command(
274283
[FLAGS.binutils_ar_cmd, "rcs", output_archive_file] + object_files,
275284
errors)
276285

@@ -738,7 +747,17 @@ def run_binutils_command(cmdline, error_output=None, ignore_errors=False):
738747
Returns:
739748
A list of lines of text of the command's stdout.
740749
"""
741-
output = run_command(cmdline, error_output, True)
750+
global binutils_force_target_format
751+
if binutils_force_target_format:
752+
# Once we've had to force the format once, assume all subsequent
753+
# files use the same format. Also we will need to explicitly specify this
754+
# format when creating an archive with "ar".
755+
# If we've never had to force a format, let binutils autodetect.
756+
output = run_command([cmdline[0]] + ["--target=%s" % binutils_force_target_format] + cmdline[1:],
757+
error_output, ignore_errors)
758+
else:
759+
# Otherwise, if we've never had to force a format, use the default.
760+
output = run_command(cmdline, error_output, True)
742761
if error_output and not output:
743762
# There are some expected errors: "Bad value" or "File format is ambiguous".
744763
#
@@ -748,20 +767,22 @@ def run_binutils_command(cmdline, error_output=None, ignore_errors=False):
748767
# depending on whether the file is 32-bit or 64-bit.
749768
#
750769
# Line 0: filename.o: Bad value
751-
if error_output and "Bad value" in error_output[0]:
770+
if not binutils_force_target_format and error_output and "Bad value" in error_output[0]:
752771
# Workaround for MIPS, force elf32-little and/or elf64-little.
753772
error_output = []
754773
logging.debug("Bad value when running %s %s",
755774
os.path.basename(cmdline[0]), " ".join(cmdline[1:]))
756775
logging.debug("Retrying with --target=elf32-little")
757776
output = run_command([cmdline[0]] + ["--target=elf32-little"] +
758777
cmdline[1:], error_output, True)
778+
binutils_force_target_format='elf32-little'
759779
if error_output:
760780
# Oops, it wasn't 32-bit, try 64-bit instead.
761781
error_output = []
762782
logging.debug("Retrying with --target=elf64-little")
763783
output = run_command([cmdline[0]] + ["--target=elf64-little"] +
764784
cmdline[1:], error_output, ignore_errors)
785+
binutils_force_target_format='elf64-little'
765786
# In other cases, we sometimes get an expected error about ambiguous file
766787
# format, which also includes a list of matching formats:
767788
#
@@ -770,7 +791,7 @@ def run_binutils_command(cmdline, error_output=None, ignore_errors=False):
770791
#
771792
# If this occurs, we will run the command again, passing in the
772793
# target format that we believe we should use instead.
773-
elif (len(error_output) >= 2 and
794+
elif not binutils_force_target_format and (len(error_output) >= 2 and
774795
"ile format is ambiguous" in error_output[0]):
775796
m = re.search("Matching formats: (.+)", error_output[1])
776797
if m:
@@ -783,14 +804,14 @@ def run_binutils_command(cmdline, error_output=None, ignore_errors=False):
783804
BINUTILS_PREFERRED_FORMAT_PREFIX_IF_AMBIGUOUS[FLAGS.platform])
784805
]
785806
# Or if for some reason none was found, just take the default (first).
786-
retry_format = (preferred_formats[0]
787-
if len(preferred_formats) > 0
788-
else all_formats[0])
807+
binutils_force_target_format=(preferred_formats[0]
808+
if len(preferred_formats) > 0
809+
else all_formats[0])
789810
error_output = []
790-
logging.debug("Ambiguous file format when running %s %s",
791-
os.path.basename(cmdline[0]), " ".join(cmdline[1:]))
792-
logging.debug("Retrying with --target=%s", retry_format)
793-
output = run_command([cmdline[0]] + ["--target=%s" % retry_format] + cmdline[1:],
811+
logging.debug("Ambiguous file format when running %s %s (%s)",
812+
os.path.basename(cmdline[0]), " ".join(cmdline[1:]), ", ".join(all_formats))
813+
logging.debug("Retrying with --target=%s", binutils_force_target_format)
814+
output = run_command([cmdline[0]] + ["--target=%s" % binutils_force_target_format] + cmdline[1:],
794815
error_output, ignore_errors)
795816
if error_output and not ignore_errors:
796817
# If we failed any other way, or if the second run failed, bail.
@@ -1014,8 +1035,17 @@ def main(argv):
10141035
if os.path.isfile(output_path):
10151036
os.remove(output_path)
10161037

1017-
logging.debug("Creating output archive %s", output_path)
1018-
create_archive(output_path, all_obj_files, input_path[1])
1038+
if (FLAGS.skip_creating_archives):
1039+
output_path_dir = output_path + ".dir"
1040+
logging.debug("Copying object files to %s", output_path_dir)
1041+
if not os.path.exists(output_path_dir):
1042+
os.makedirs(output_path_dir)
1043+
for obj_file in all_obj_files:
1044+
logging.debug("Copy %s to %s" % (obj_file, os.path.join(output_path_dir, os.path.basename(obj_file))))
1045+
shutil.copyfile(obj_file, os.path.join(output_path_dir, os.path.basename(obj_file)))
1046+
else:
1047+
logging.debug("Creating output archive %s", output_path)
1048+
create_archive(output_path, all_obj_files, input_path[1])
10191049

10201050
shutdown_cache()
10211051

0 commit comments

Comments
 (0)