def _lipo_exec_files(exec_files, target_archs, strip_bitcode, source_path, destination_path): """Strips executable files if needed and copies them to the destination.""" # Find all architectures from the set of files we might have to lipo. exec_archs = lipo.find_archs_for_binaries( [os.path.join(source_path, f) for f in exec_files]) # Ensure directory for remote execution if not os.path.exists(destination_path): os.makedirs(destination_path) # Copy or lipo each file as needed, from source to destination. for exec_file in exec_files: exec_file_source_path = os.path.join(source_path, exec_file) exec_file_destination_path = os.path.join(destination_path, exec_file) if len(exec_archs) == 1 or target_archs == exec_archs: # If there is no need to lipo, copy and mark as executable. shutil.copy(exec_file_source_path, exec_file_destination_path) os.chmod(exec_file_destination_path, 0o755) else: lipo.invoke_lipo(exec_file_source_path, target_archs, exec_file_destination_path) if strip_bitcode: bitcode_strip.invoke(exec_file_destination_path, exec_file_destination_path)
def _lipo_exec_files(exec_files, target_archs, strip_bitcode, source_path, destination_path): """Strips executable files if needed and copies them to the destination.""" # Find all architectures from the set of files we might have to lipo. _, exec_archs = lipo.find_archs_for_binaries( [os.path.join(source_path, f) for f in exec_files]) # Copy or lipo each file as needed, from source to destination. for exec_file in exec_files: exec_file_source_path = os.path.join(source_path, exec_file) exec_file_destination_path = os.path.join(destination_path, exec_file) file_archs = exec_archs[exec_file_source_path] archs_to_keep = target_archs & file_archs # On M1 hardware, thin x86_64 libraries do not need lipo when archs_to_keep # is empty. if len(file_archs ) == 1 or archs_to_keep == file_archs or not archs_to_keep: # If there is no need to lipo, copy and mark as executable. shutil.copy(exec_file_source_path, exec_file_destination_path) os.chmod(exec_file_destination_path, 0o755) else: lipo.invoke_lipo(exec_file_source_path, archs_to_keep, exec_file_destination_path) if strip_bitcode: bitcode_strip.invoke(exec_file_destination_path, exec_file_destination_path)
def main(): parser = argparse.ArgumentParser(description="swift stdlib tool") parser.add_argument( "--binary", type=str, required=True, action="append", help= "path to a binary file which will be the basis for Swift stdlib tool" " operations") parser.add_argument("--platform", type=str, required=True, help="the target platform, e.g. " "'iphoneos'") parser.add_argument( "--swift_dylibs_path", action="append", type=str, required=True, help="path relative from the developer directory to find the Swift " "standard libraries, independent of platform") parser.add_argument("--strip_bitcode", action="store_true", default=False, help="strip " "bitcode from the Swift support libraries") parser.add_argument("--output_path", type=str, required=True, help="path to save the Swift " "support libraries to") args = parser.parse_args() # Create a temporary location for the unstripped Swift stdlibs. temp_path = tempfile.mkdtemp(prefix="swift_stdlib_tool.XXXXXX") # Use the binaries to copy only the Swift stdlibs we need for this app. _copy_swift_stdlibs(args.binary, args.swift_dylibs_path, args.platform, temp_path) # Determine the binary slices we need to strip with lipo. target_archs, _ = lipo.find_archs_for_binaries(args.binary) # Select all of the files in this temp directory, which are our Swift stdlibs. stdlib_files = [ f for f in os.listdir(temp_path) if os.path.isfile(os.path.join(temp_path, f)) ] destination_path = args.output_path # Ensure directory exists for remote execution. os.makedirs(destination_path, exist_ok=True) # Copy or use lipo to strip the executable Swift stdlibs to their destination. _lipo_exec_files(stdlib_files, target_archs, args.strip_bitcode, temp_path, destination_path) shutil.rmtree(temp_path)
def main(): parser = codesigningtool.generate_arg_parser() parser.add_argument( "--framework_binary", type=str, required=True, action="append", help="path to a binary file scoped to one of the imported frameworks") parser.add_argument("--slice", type=str, required=True, action="append", help="binary slice " "expected to represent the target architectures") parser.add_argument("--strip_bitcode", action="store_true", default=False, help="strip " "bitcode from the imported frameworks.") parser.add_argument( "--framework_file", type=str, action="append", help="path to a file " "scoped to one of the imported frameworks, distinct from the binary files" ) parser.add_argument("--temp_path", type=str, required=True, help="temporary path to copy " "all framework files to") parser.add_argument( "--output_zip", type=str, required=True, help="path to save the zip file " "containing a codesigned, lipoed version of the imported framework") args = parser.parse_args() all_binary_archs = args.slice framework_archs = lipo.find_archs_for_binaries(args.framework_binary) if not framework_archs: return 1 # Delete any existing stale framework files, if any exist. if os.path.exists(args.temp_path): shutil.rmtree(args.temp_path) if os.path.exists(args.output_zip): os.remove(args.output_zip) os.makedirs(args.temp_path) for framework_binary in args.framework_binary: # If the imported framework is single architecture, and therefore assumed # that it doesn't need to be lipoed, or if the binary architectures match # the framework architectures perfectly, treat as a copy instead of a lipo # operation. if len(framework_archs) == 1 or all_binary_archs == framework_archs: status_code = _copy_framework_file(framework_binary, executable=True, output_path=args.temp_path) else: slices_needed = framework_archs.intersection(all_binary_archs) if not slices_needed: print("Error: Precompiled framework does not share any binary " "architectures with the binaries that were built.") return 1 status_code = _strip_framework_binary(framework_binary, args.temp_path, slices_needed) if status_code: return 1 # Strip bitcode from the output framework binary if args.strip_bitcode: output_binary = os.path.join(args.temp_path, os.path.basename(framework_binary)) bitcode_strip.invoke(output_binary, output_binary) if args.framework_file: for framework_file in args.framework_file: status_code = _copy_framework_file(framework_file, executable=False, output_path=args.temp_path) if status_code: return 1 # Attempt to sign the framework, check for an error when signing. status_code = codesigningtool.main(args) if status_code: return status_code _zip_framework(args.temp_path, args.output_zip)