Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
create_macos_framework.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2#
3# Copyright 2013 The Flutter Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7import argparse
8import platform
9import subprocess
10import shutil
11import sys
12import os
13
14from create_xcframework import create_xcframework # pylint: disable=import-error
15
16buildroot_dir = os.path.abspath(os.path.join(os.path.realpath(__file__), '..', '..', '..', '..'))
17
18ARCH_SUBPATH = 'mac-arm64' if platform.processor() == 'arm' else 'mac-x64'
19DSYMUTIL = os.path.join(
20 os.path.dirname(__file__), '..', '..', 'buildtools', ARCH_SUBPATH, 'clang', 'bin', 'dsymutil'
21)
22
23out_dir = os.path.join(buildroot_dir, 'out')
24
25
26def main():
27 parser = argparse.ArgumentParser(
28 description='Creates FlutterMacOS.framework and FlutterMacOS.xcframework for macOS'
29 )
30
31 parser.add_argument('--dst', type=str, required=True)
32 parser.add_argument('--arm64-out-dir', type=str, required=True)
33 parser.add_argument('--x64-out-dir', type=str, required=True)
34 parser.add_argument('--strip', action='store_true', default=False)
35 parser.add_argument('--dsym', action='store_true', default=False)
36 # TODO(godofredoc): Remove after recipes v2 have landed.
37 parser.add_argument('--zip', action='store_true', default=False)
38
39 args = parser.parse_args()
40
41 dst = (args.dst if os.path.isabs(args.dst) else os.path.join(buildroot_dir, args.dst))
42 arm64_out_dir = (
43 args.arm64_out_dir
44 if os.path.isabs(args.arm64_out_dir) else os.path.join(buildroot_dir, args.arm64_out_dir)
45 )
46 x64_out_dir = (
47 args.x64_out_dir
48 if os.path.isabs(args.x64_out_dir) else os.path.join(buildroot_dir, args.x64_out_dir)
49 )
50
51 fat_framework = os.path.join(dst, 'FlutterMacOS.framework')
52 arm64_framework = os.path.join(arm64_out_dir, 'FlutterMacOS.framework')
53 x64_framework = os.path.join(x64_out_dir, 'FlutterMacOS.framework')
54
55 arm64_dylib = os.path.join(arm64_framework, 'FlutterMacOS')
56 x64_dylib = os.path.join(x64_framework, 'FlutterMacOS')
57
58 if not os.path.isdir(arm64_framework):
59 print('Cannot find macOS arm64 Framework at %s' % arm64_framework)
60 return 1
61
62 if not os.path.isdir(x64_framework):
63 print('Cannot find macOS x64 Framework at %s' % x64_framework)
64 return 1
65
66 if not os.path.isfile(arm64_dylib):
67 print('Cannot find macOS arm64 dylib at %s' % arm64_dylib)
68 return 1
69
70 if not os.path.isfile(x64_dylib):
71 print('Cannot find macOS x64 dylib at %s' % x64_dylib)
72 return 1
73
74 if not os.path.isfile(DSYMUTIL):
75 print('Cannot find dsymutil at %s' % DSYMUTIL)
76 return 1
77
78 shutil.rmtree(fat_framework, True)
79 shutil.copytree(arm64_framework, fat_framework, symlinks=True)
80
81 regenerate_symlinks(fat_framework)
82
83 fat_framework_binary = os.path.join(fat_framework, 'Versions', 'A', 'FlutterMacOS')
84
85 # Create the arm64/x64 fat framework.
86 subprocess.check_call([
87 'lipo', arm64_dylib, x64_dylib, '-create', '-output', fat_framework_binary
88 ])
89
90 # Add group and other readability to all files.
91 versions_path = os.path.join(fat_framework, 'Versions')
92 subprocess.check_call(['chmod', '-R', 'og+r', versions_path])
93 # Find all the files below the target dir with owner execute permission
94 find_subprocess = subprocess.Popen(['find', versions_path, '-perm', '-100', '-print0'],
95 stdout=subprocess.PIPE)
96 # Add execute permission for other and group for all files that had it for owner.
97 xargs_subprocess = subprocess.Popen(['xargs', '-0', 'chmod', 'og+x'],
98 stdin=find_subprocess.stdout)
99 find_subprocess.wait()
100 xargs_subprocess.wait()
101
102 process_framework(dst, args, fat_framework, fat_framework_binary)
103
104 # Create XCFramework from the arm64 and x64 fat framework.
105 xcframeworks = [fat_framework]
106 create_xcframework(location=dst, name='FlutterMacOS', frameworks=xcframeworks)
107
108 zip_framework(dst, args)
109
110 return 0
111
112
113def regenerate_symlinks(fat_framework):
114 """Regenerates the symlinks structure.
115
116 Recipes V2 upload artifacts in CAS before integration and CAS follows symlinks.
117 This logic regenerates the symlinks in the expected structure.
118 """
119 if os.path.islink(os.path.join(fat_framework, 'FlutterMacOS')):
120 return
121 os.remove(os.path.join(fat_framework, 'FlutterMacOS'))
122 shutil.rmtree(os.path.join(fat_framework, 'Headers'), True)
123 shutil.rmtree(os.path.join(fat_framework, 'Modules'), True)
124 shutil.rmtree(os.path.join(fat_framework, 'Resources'), True)
125 current_version_path = os.path.join(fat_framework, 'Versions', 'Current')
126 shutil.rmtree(current_version_path, True)
127 os.symlink('A', current_version_path)
128 os.symlink(
129 os.path.join('Versions', 'Current', 'FlutterMacOS'),
130 os.path.join(fat_framework, 'FlutterMacOS')
131 )
132 os.symlink(os.path.join('Versions', 'Current', 'Headers'), os.path.join(fat_framework, 'Headers'))
133 os.symlink(os.path.join('Versions', 'Current', 'Modules'), os.path.join(fat_framework, 'Modules'))
134 os.symlink(
135 os.path.join('Versions', 'Current', 'Resources'), os.path.join(fat_framework, 'Resources')
136 )
137
138
139def embed_codesign_configuration(config_path, content):
140 with open(config_path, 'w') as file:
141 file.write(content)
142
143
144def process_framework(dst, args, fat_framework, fat_framework_binary):
145 if args.dsym:
146 dsym_out = os.path.splitext(fat_framework)[0] + '.dSYM'
147 subprocess.check_call([DSYMUTIL, '-o', dsym_out, fat_framework_binary])
148 if args.zip:
149 dsym_dst = os.path.join(dst, 'FlutterMacOS.dSYM')
150 subprocess.check_call(['zip', '-r', '-y', 'FlutterMacOS.dSYM.zip', '.'], cwd=dsym_dst)
151 # Double zip to make it consistent with legacy artifacts.
152 # TODO(fujino): remove this once https://github.com/flutter/flutter/issues/125067 is resolved
153 subprocess.check_call([
154 'zip',
155 '-y',
156 'FlutterMacOS.dSYM_.zip',
157 'FlutterMacOS.dSYM.zip',
158 ],
159 cwd=dsym_dst)
160 # Use doubled zipped file.
161 dsym_final_src_path = os.path.join(dsym_dst, 'FlutterMacOS.dSYM_.zip')
162 dsym_final_dst_path = os.path.join(dst, 'FlutterMacOS.dSYM.zip')
163 shutil.move(dsym_final_src_path, dsym_final_dst_path)
164
165 if args.strip:
166 # copy unstripped
167 unstripped_out = os.path.join(dst, 'FlutterMacOS.unstripped')
168 shutil.copyfile(fat_framework_binary, unstripped_out)
169
170 subprocess.check_call(['strip', '-x', '-S', fat_framework_binary])
171
172
173def zip_framework(dst, args):
174 # Zip FlutterMacOS.framework.
175 if args.zip:
176 filepath_with_entitlements = ''
177
178 framework_dst = os.path.join(dst, 'FlutterMacOS.framework')
179 # TODO(xilaizhang): Remove the zip file from the path when outer zip is removed.
180 filepath_without_entitlements = 'FlutterMacOS.framework.zip/Versions/A/FlutterMacOS'
181
183 os.path.join(framework_dst, 'entitlements.txt'), filepath_with_entitlements
184 )
185
187 os.path.join(framework_dst, 'without_entitlements.txt'), filepath_without_entitlements
188 )
189 subprocess.check_call([
190 'zip',
191 '-r',
192 '-y',
193 'FlutterMacOS.framework.zip',
194 '.',
195 ],
196 cwd=framework_dst)
197 # Double zip to make it consistent with legacy artifacts.
198 # TODO(fujino): remove this once https://github.com/flutter/flutter/issues/125067 is resolved
199 subprocess.check_call(
200 [
201 'zip',
202 '-y',
203 'FlutterMacOS.framework_.zip',
204 'FlutterMacOS.framework.zip',
205 # TODO(xilaizhang): Move these files to inner zip before removing the outer zip.
206 'entitlements.txt',
207 'without_entitlements.txt',
208 ],
209 cwd=framework_dst
210 )
211 # Use doubled zipped file.
212 final_src_path = os.path.join(framework_dst, 'FlutterMacOS.framework_.zip')
213 final_dst_path = os.path.join(dst, 'FlutterMacOS.framework.zip')
214 shutil.move(final_src_path, final_dst_path)
215
217
218
220 filepath_with_entitlements = ''
221 filepath_without_entitlements = (
222 'FlutterMacOS.xcframework/macos-arm64_x86_64/'
223 'FlutterMacOS.framework/Versions/A/FlutterMacOS'
224 )
225 embed_codesign_configuration(os.path.join(dst, 'entitlements.txt'), filepath_with_entitlements)
226
228 os.path.join(dst, 'without_entitlements.txt'), filepath_without_entitlements
229 )
230
231 subprocess.check_call([
232 'zip',
233 '-r',
234 '-y',
235 'framework.zip',
236 'FlutterMacOS.xcframework',
237 'entitlements.txt',
238 'without_entitlements.txt',
239 ],
240 cwd=dst)
241
242
243if __name__ == '__main__':
244 sys.exit(main())
void print(void *str)
Definition bridge.cpp:126
process_framework(dst, args, fat_framework, fat_framework_binary)
embed_codesign_configuration(config_path, content)
Definition main.py:1