diff --git a/.pylintrc b/.pylintrc index 431b9e51c99f2..0803a4f4e3ef5 100644 --- a/.pylintrc +++ b/.pylintrc @@ -38,6 +38,7 @@ docstring-quote = double # multiple time (only on the command line, not in the configuration file where # it should appear only once). disable= + duplicate-code, exec-used, fixme, missing-class-docstring, diff --git a/ci/builders/mac_host_engine.json b/ci/builders/mac_host_engine.json index 368b3fefc0cfe..6b9c9c5e7ea4b 100644 --- a/ci/builders/mac_host_engine.json +++ b/ci/builders/mac_host_engine.json @@ -7,7 +7,6 @@ "type": "gcs", "include_paths": [ "out/host_debug/zip_archives/darwin-x64/artifacts.zip", - "out/host_debug/zip_archives/darwin-x64/FlutterEmbedder.framework.zip", "out/host_debug/zip_archives/dart-sdk-darwin-x64.zip" ], "name": "host_debug", @@ -214,6 +213,7 @@ "flutter/build/archives:archive_gen_snapshot", "flutter/build/archives:artifacts", "flutter/build/archives:dart_sdk_archive", + "flutter/build/archives:flutter_embedder_framework", "flutter/shell/platform/darwin/macos:zip_macos_flutter_framework" ] } @@ -299,6 +299,19 @@ ], "generators": { "tasks": [ + { + "name": "Debug-FlutterEmbedder.framework", + "parameters": [ + "--dst", + "out/debug/framework", + "--arm64-out-dir", + "out/mac_debug_arm64", + "--x64-out-dir", + "out/host_debug", + "--zip" + ], + "script": "flutter/sky/tools/create_embedder_framework.py" + }, { "name": "Release-FlutterMacOS.framework", "parameters": [ @@ -390,6 +403,11 @@ ] }, "archives": [ + { + "source": "out/debug/framework/FlutterEmbedder.framework.zip", + "destination": "darwin-x64/FlutterEmbedder.framework.zip", + "realm": "production" + }, { "source": "out/release/framework/FlutterMacOS.dSYM.zip", "destination": "darwin-x64-release/FlutterMacOS.dSYM.zip", diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files index 3127bada87d05..65012422421e5 100644 --- a/ci/licenses_golden/excluded_files +++ b/ci/licenses_golden/excluded_files @@ -356,6 +356,7 @@ ../../../flutter/sky/packages/sky_engine/README.md ../../../flutter/sky/packages/sky_engine/lib/_embedder.yaml ../../../flutter/sky/packages/sky_engine/pubspec.yaml +../../../flutter/sky/tools/create_embedder_framework.py ../../../flutter/sky/tools/create_full_ios_framework.py ../../../flutter/sky/tools/create_ios_framework.py ../../../flutter/sky/tools/create_macos_framework.py diff --git a/sky/tools/create_embedder_framework.py b/sky/tools/create_embedder_framework.py new file mode 100755 index 0000000000000..357095785272e --- /dev/null +++ b/sky/tools/create_embedder_framework.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python3 +# +# Copyright 2013 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import argparse +import subprocess +import shutil +import sys +import os + +buildroot_dir = os.path.abspath( + os.path.join(os.path.realpath(__file__), '..', '..', '..', '..') +) + +DSYMUTIL = os.path.join( + os.path.dirname(__file__), '..', '..', '..', 'buildtools', 'mac-x64', + 'clang', 'bin', 'dsymutil' +) + +out_dir = os.path.join(buildroot_dir, 'out') + + +def main(): + parser = argparse.ArgumentParser( + description='Creates FlutterEmbedder.framework for macOS' + ) + + parser.add_argument('--dst', type=str, required=True) + parser.add_argument('--arm64-out-dir', type=str, required=True) + parser.add_argument('--x64-out-dir', type=str, required=True) + parser.add_argument('--strip', action='store_true', default=False) + parser.add_argument('--dsym', action='store_true', default=False) + # TODO(godofredoc): Remove after recipes v2 have landed. + parser.add_argument('--zip', action='store_true', default=False) + + args = parser.parse_args() + + dst = ( + args.dst + if os.path.isabs(args.dst) else os.path.join(buildroot_dir, args.dst) + ) + arm64_out_dir = ( + args.arm64_out_dir if os.path.isabs(args.arm64_out_dir) else + os.path.join(buildroot_dir, args.arm64_out_dir) + ) + x64_out_dir = ( + args.x64_out_dir if os.path.isabs(args.x64_out_dir) else + os.path.join(buildroot_dir, args.x64_out_dir) + ) + + fat_framework = os.path.join(dst, 'FlutterEmbedder.framework') + arm64_framework = os.path.join(arm64_out_dir, 'FlutterEmbedder.framework') + x64_framework = os.path.join(x64_out_dir, 'FlutterEmbedder.framework') + + arm64_dylib = os.path.join(arm64_framework, 'FlutterEmbedder') + x64_dylib = os.path.join(x64_framework, 'FlutterEmbedder') + + if not os.path.isdir(arm64_framework): + print('Cannot find macOS arm64 Framework at %s' % arm64_framework) + return 1 + + if not os.path.isdir(x64_framework): + print('Cannot find macOS x64 Framework at %s' % x64_framework) + return 1 + + if not os.path.isfile(arm64_dylib): + print('Cannot find macOS arm64 dylib at %s' % arm64_dylib) + return 1 + + if not os.path.isfile(x64_dylib): + print('Cannot find macOS x64 dylib at %s' % x64_dylib) + return 1 + + if not os.path.isfile(DSYMUTIL): + print('Cannot find dsymutil at %s' % DSYMUTIL) + return 1 + + shutil.rmtree(fat_framework, True) + shutil.copytree(arm64_framework, fat_framework, symlinks=True) + regenerate_symlinks(fat_framework) + + fat_framework_binary = os.path.join( + fat_framework, 'Versions', 'A', 'FlutterEmbedder' + ) + + # Create the arm64/x64 fat framework. + subprocess.check_call([ + 'lipo', arm64_dylib, x64_dylib, '-create', '-output', fat_framework_binary + ]) + process_framework(dst, args, fat_framework, fat_framework_binary) + + return 0 + + +def regenerate_symlinks(fat_framework): + """Regenerates the symlinks structure. + + Recipes V2 upload artifacts in CAS before integration and CAS follows symlinks. + This logic regenerates the symlinks in the expected structure. + """ + if os.path.islink(os.path.join(fat_framework, 'FlutterEmbedder')): + return + os.remove(os.path.join(fat_framework, 'FlutterEmbedder')) + shutil.rmtree(os.path.join(fat_framework, 'Headers'), True) + shutil.rmtree(os.path.join(fat_framework, 'Modules'), True) + shutil.rmtree(os.path.join(fat_framework, 'Resources'), True) + current_version_path = os.path.join(fat_framework, 'Versions', 'Current') + shutil.rmtree(current_version_path, True) + os.symlink('A', current_version_path) + os.symlink( + os.path.join('Versions', 'Current', 'FlutterEmbedder'), + os.path.join(fat_framework, 'FlutterEmbedder') + ) + os.symlink( + os.path.join('Versions', 'Current', 'Headers'), + os.path.join(fat_framework, 'Headers') + ) + os.symlink( + os.path.join('Versions', 'Current', 'Modules'), + os.path.join(fat_framework, 'Modules') + ) + os.symlink( + os.path.join('Versions', 'Current', 'Resources'), + os.path.join(fat_framework, 'Resources') + ) + + +def process_framework(dst, args, fat_framework, fat_framework_binary): + if args.dsym: + dsym_out = os.path.splitext(fat_framework)[0] + '.dSYM' + subprocess.check_call([DSYMUTIL, '-o', dsym_out, fat_framework_binary]) + if args.zip: + dsym_dst = os.path.join(dst, 'FlutterEmbedder.dSYM') + subprocess.check_call([ + 'zip', '-r', '-y', 'FlutterEmbedder.dSYM.zip', '.' + ], + cwd=dsym_dst) + dsym_final_src_path = os.path.join(dsym_dst, 'FlutterEmbedder.dSYM.zip') + dsym_final_dst_path = os.path.join(dst, 'FlutterEmbedder.dSYM.zip') + shutil.move(dsym_final_src_path, dsym_final_dst_path) + + if args.strip: + # copy unstripped + unstripped_out = os.path.join(dst, 'FlutterEmbedder.unstripped') + shutil.copyfile(fat_framework_binary, unstripped_out) + subprocess.check_call(['strip', '-x', '-S', fat_framework_binary]) + + # Zip FlutterEmbedder.framework. + if args.zip: + framework_dst = os.path.join(dst, 'FlutterEmbedder.framework') + subprocess.check_call([ + 'zip', + '-r', + '-y', + 'FlutterEmbedder.framework.zip', + '.', + ], + cwd=framework_dst) + final_src_path = os.path.join( + framework_dst, 'FlutterEmbedder.framework.zip' + ) + final_dst_path = os.path.join(dst, 'FlutterEmbedder.framework.zip') + shutil.move(final_src_path, final_dst_path) + + +if __name__ == '__main__': + sys.exit(main())