in scripts/merge_libraries.py [0:0]
def main(argv):
global binutils_force_target_format
binutils_force_target_format = FLAGS.force_binutils_target
try:
working_root = None
input_paths = []
for filename in argv[1:]:
input_paths.append([filename, os.path.abspath(filename)])
if not input_paths:
logging.fatal("No input files specified")
output_path = os.path.abspath(FLAGS.output)
additional_input_paths = []
for filename in FLAGS.scan_libs:
additional_input_paths.append([filename, os.path.abspath(filename)])
# Create the working directory.
working_root = tempfile.mkdtemp(suffix="merge")
if not working_root:
raise Error("Couldn't create temp directory")
# Add absolute paths to these commands if they specify any directory.
FLAGS.binutils_ar_cmd = add_abspath(FLAGS.binutils_ar_cmd)
FLAGS.binutils_nm_cmd = add_abspath(FLAGS.binutils_nm_cmd)
FLAGS.binutils_objcopy_cmd = add_abspath(FLAGS.binutils_objcopy_cmd)
FLAGS.demangle_cmds = [add_abspath(c) for c in FLAGS.demangle_cmds]
FLAGS.cache = (os.path.abspath(FLAGS.cache) if FLAGS.cache else None)
init_cache()
# Scan through subset of libs in FLAGS.hide_c_symbols to find C symbols to
# rename.
rename_symbols = {}
for libfile_and_regex in FLAGS.hide_c_symbols:
if ':' not in libfile_and_regex:
libfile_and_regex += ':.'
[libfile, regex] = libfile_and_regex.split(":", 1)
logging.debug("Scanning for C symbols in %s", libfile)
regex_compiled = re.compile(regex)
if os.path.abspath(libfile) in _cache["symbols"]:
(defined_symbols,
all_symbols) = _cache["symbols"][os.path.abspath(libfile)]
else:
(defined_symbols, all_symbols) = read_symbols_from_archive(libfile)
_cache["symbols"][os.path.abspath(libfile)] = (defined_symbols,
all_symbols)
for symbol in defined_symbols:
# For C symbols, only use them if they are defined.
if (not is_cpp_symbol(symbol)) and regex_compiled.match(symbol):
rename_symbols.update(rename_symbol(symbol))
os.chdir(working_root)
if FLAGS.hide_cpp_namespaces or FLAGS.auto_hide_cpp_namespaces:
init_demanglers()
# Scan through all input libraries for C++ symbols matching any of the
# hide_cpp_namespaces.
cpp_symbols = set()
for input_path in input_paths + additional_input_paths:
logging.debug("Scanning for C++ symbols in %s", input_path[1])
if os.path.abspath(input_path[1]) in _cache["symbols"]:
(defined_symbols,
all_symbols) = _cache["symbols"][os.path.abspath(input_path[1])]
else:
(defined_symbols,
all_symbols) = read_symbols_from_archive(input_path[1])
_cache["symbols"][os.path.abspath(input_path[1])] = (defined_symbols,
all_symbols)
cpp_symbols.update(all_symbols
if FLAGS.rename_external_cpp_symbols
else defined_symbols)
# If we are set to scan for namespaces, do that now.
if FLAGS.auto_hide_cpp_namespaces:
add_automatic_namespaces(defined_symbols)
for symbol in cpp_symbols:
if is_cpp_symbol(symbol):
rename_symbols.update(rename_symbol(symbol))
shutdown_demanglers()
logging.debug("Creating symbol redefinition file for %d symbols",
len(rename_symbols))
symbol_redefinition_file = create_symbol_redefinition_file(rename_symbols)
# List of all object files, which will be renamed to have unique names.
all_obj_files = []
for input_path in input_paths:
logging.debug("Checking input archive %s", input_path[1])
# Create a unique directory name from a hash of the input filename.
lib_name_hash = hashlib.md5(
input_path[0].encode(DEFAULT_ENCODING)).hexdigest()
(obj_file_list, errors) = list_objects_in_archive(input_path[1])
if errors:
logging.fatal("Error listing archive %s: %s", input_path[1], errors)
# If any of the filenames in this archive contain a "/" or "\", we need to
# replace them with "_".
obj_file_renames = {}
for obj_file in obj_file_list:
if "/" in obj_file or "\\" in obj_file:
# Extracting this will fail because it contains subdirectories.
obj_file_bin = obj_file.encode(DEFAULT_ENCODING)
new_obj_file_bin = re.sub(b"[^0-9a-zA-Z_.]", b"_", obj_file_bin)
old_obj_regex_bin = re.sub(b"[^0-9a-zA-Z_.]", b".", obj_file_bin)
obj_file_renames[old_obj_regex_bin] = new_obj_file_bin
if obj_file_renames:
# We renamed some object files within the .a file.
input_path[1] = replace_strings_in_archive(input_path[1],
obj_file_renames)
logging.debug("Extracting input archive %s", input_path[1])
(obj_file_list, errors) = extract_archive(input_path[1])
if errors:
logging.fatal("Error extracting archive %s: %s", input_path[1], errors)
if symbol_redefinition_file:
logging.debug("Redefining symbols in %d files", len(obj_file_list))
for obj_file in obj_file_list:
new_obj_file = "%s_%s" % (lib_name_hash, obj_file)
if len(new_obj_file) > 255:
# Filename is above the limit, hash the first N characters to bring
# the length down to 255 or less.
# Hashes are 32 characters plus an underscore.
# If len = 256 hash the first 34 chars.
# If len = 257 hash the first 35 chars.
split = len(new_obj_file) - (255 - 32 - 1)
new_obj_file = "%s_%s" % (hashlib.md5(
new_obj_file[:split].encode(DEFAULT_ENCODING)).hexdigest(),
new_obj_file[split:])
# Move the .o file to its new name, renaming symbols if needed.
move_object_file(obj_file, new_obj_file, symbol_redefinition_file.name
if symbol_redefinition_file else None)
all_obj_files.append(new_obj_file)
symbol_redefinition_file = None
# Remove any existing output lib so we can create a new one from scratch.
if os.path.isfile(output_path):
os.remove(output_path)
if (FLAGS.skip_creating_archives):
output_path_dir = output_path + ".dir"
logging.debug("Copying object files to %s", output_path_dir)
if not os.path.exists(output_path_dir):
os.makedirs(output_path_dir)
for obj_file in all_obj_files:
logging.debug("Copy %s to %s" % (obj_file, os.path.join(output_path_dir, os.path.basename(obj_file))))
shutil.copyfile(obj_file, os.path.join(output_path_dir, os.path.basename(obj_file)))
else:
logging.debug("Creating output archive %s", output_path)
create_archive(output_path, all_obj_files, input_path[1])
shutdown_cache()
except Exception as e:
logging.error("Got error: %s", e)
raise
finally:
if working_root:
shutil.rmtree(working_root)
return 0