blob: 651024eb6aca22317ad34bf7fb29ebc0d3024544 [file] [log] [blame]
tkchin@webrtc.org64eb2ff2015-03-23 19:07:37 +00001#!/usr/bin/python
hjonbc73fe12016-03-21 11:38:26 -07002
3# Copyright 2016 The WebRTC project authors. All Rights Reserved.
tkchin@webrtc.org64eb2ff2015-03-23 19:07:37 +00004#
hjonbc73fe12016-03-21 11:38:26 -07005# Use of this source code is governed by a BSD-style license
6# that can be found in the LICENSE file in the root of the source
7# tree. An additional intellectual property rights grant can be found
8# in the file PATENTS. All contributing project authors may
9# be found in the AUTHORS file in the root of the source tree.
tkchin@webrtc.org64eb2ff2015-03-23 19:07:37 +000010
11"""Script for merging generated iOS libraries."""
12
tkchin5209d672016-04-16 12:06:33 -070013import sys
14
15import argparse
tkchin@webrtc.org64eb2ff2015-03-23 19:07:37 +000016import os
17import re
18import subprocess
tkchin5209d672016-04-16 12:06:33 -070019
20# Valid arch subdir names.
21VALID_ARCHS = ['arm_libs', 'arm64_libs', 'ia32_libs', 'x64_libs']
tkchin@webrtc.org64eb2ff2015-03-23 19:07:37 +000022
23
24def MergeLibs(lib_base_dir):
25 """Merges generated iOS libraries for different archs.
26
27 Uses libtool to generate FAT archive files for each generated library.
28
29 Args:
30 lib_base_dir: directory whose subdirectories are named by architecture and
31 contain the built libraries for that architecture
32
33 Returns:
34 Exit code of libtool.
35 """
tkchin5209d672016-04-16 12:06:33 -070036 output_dir_name = 'fat_libs'
tkchin@webrtc.org64eb2ff2015-03-23 19:07:37 +000037 archs = [arch for arch in os.listdir(lib_base_dir)
tkchin5209d672016-04-16 12:06:33 -070038 if arch in VALID_ARCHS]
tkchin@webrtc.org64eb2ff2015-03-23 19:07:37 +000039 # For each arch, find (library name, libary path) for arch. We will merge
40 # all libraries with the same name.
41 libs = {}
tkchin5209d672016-04-16 12:06:33 -070042 for lib_dir in [os.path.join(lib_base_dir, arch) for arch in VALID_ARCHS]:
43 if not os.path.exists(lib_dir):
tkchin@webrtc.org64eb2ff2015-03-23 19:07:37 +000044 continue
tkchin5209d672016-04-16 12:06:33 -070045 for dirpath, _, filenames in os.walk(lib_dir):
46 for filename in filenames:
47 if not filename.endswith('.a'):
48 continue
49 entry = libs.get(filename, [])
50 entry.append(os.path.join(dirpath, filename))
51 libs[filename] = entry
tkchindd2bd262015-10-19 12:53:53 -070052 orphaned_libs = {}
53 valid_libs = {}
tkchin@webrtc.org64eb2ff2015-03-23 19:07:37 +000054 for library, paths in libs.items():
55 if len(paths) < len(archs):
tkchindd2bd262015-10-19 12:53:53 -070056 orphaned_libs[library] = paths
57 else:
58 valid_libs[library] = paths
59 for library, paths in orphaned_libs.items():
60 components = library[:-2].split('_')[:-1]
61 found = False
62 # Find directly matching parent libs by stripping suffix.
63 while components and not found:
64 parent_library = '_'.join(components) + '.a'
65 if parent_library in valid_libs:
66 valid_libs[parent_library].extend(paths)
67 found = True
68 break
69 components = components[:-1]
70 # Find next best match by finding parent libs with the same prefix.
71 if not found:
72 base_prefix = library[:-2].split('_')[0]
73 for valid_lib, valid_paths in valid_libs.items():
tkchindd2bd262015-10-19 12:53:53 -070074 if valid_lib[:len(base_prefix)] == base_prefix:
75 valid_paths.extend(paths)
tkchin@webrtc.org64eb2ff2015-03-23 19:07:37 +000076 found = True
77 break
tkchindd2bd262015-10-19 12:53:53 -070078 assert found
tkchin@webrtc.org64eb2ff2015-03-23 19:07:37 +000079
80 # Create output directory.
81 output_dir_path = os.path.join(lib_base_dir, output_dir_name)
82 if not os.path.exists(output_dir_path):
83 os.mkdir(output_dir_path)
84
85 # Use this so libtool merged binaries are always the same.
86 env = os.environ.copy()
87 env['ZERO_AR_DATE'] = '1'
88
89 # Ignore certain errors.
90 libtool_re = re.compile(r'^.*libtool:.*file: .* has no symbols$')
91
92 # Merge libraries using libtool.
tkchin5209d672016-04-16 12:06:33 -070093 libtool_returncode = 0
tkchindd2bd262015-10-19 12:53:53 -070094 for library, paths in valid_libs.items():
tkchin@webrtc.org64eb2ff2015-03-23 19:07:37 +000095 cmd_list = ['libtool', '-static', '-v', '-o',
96 os.path.join(output_dir_path, library)] + paths
97 libtoolout = subprocess.Popen(cmd_list, stderr=subprocess.PIPE, env=env)
98 _, err = libtoolout.communicate()
99 for line in err.splitlines():
100 if not libtool_re.match(line):
101 print >>sys.stderr, line
102 # Unconditionally touch the output .a file on the command line if present
103 # and the command succeeded. A bit hacky.
tkchin5209d672016-04-16 12:06:33 -0700104 libtool_returncode = libtoolout.returncode
105 if not libtool_returncode:
tkchin@webrtc.org64eb2ff2015-03-23 19:07:37 +0000106 for i in range(len(cmd_list) - 1):
107 if cmd_list[i] == '-o' and cmd_list[i+1].endswith('.a'):
108 os.utime(cmd_list[i+1], None)
109 break
tkchin5209d672016-04-16 12:06:33 -0700110 return libtool_returncode
tkchin@webrtc.org64eb2ff2015-03-23 19:07:37 +0000111
112
113def Main():
tkchin5209d672016-04-16 12:06:33 -0700114 parser_description = 'Merge WebRTC libraries.'
115 parser = argparse.ArgumentParser(description=parser_description)
116 parser.add_argument('lib_base_dir',
117 help='Directory with built libraries. ',
118 type=str)
119 args = parser.parse_args()
120 lib_base_dir = args.lib_base_dir
tkchin@webrtc.org64eb2ff2015-03-23 19:07:37 +0000121 MergeLibs(lib_base_dir)
122
123if __name__ == '__main__':
124 sys.exit(Main())