flutter/packages/flutter_tools/lib/src/macos/native_assets_host.dart
auto-submit[bot] ceca606662
Reverts "Move native assets to isolated/ directory" (#143027)
Reverts flutter/flutter#142709

Initiated by: vashworth

Reason for reverting: `Mac tool_tests_general` started failing on this commit: https://ci.chromium.org/ui/p/flutter/builders/prod/Mac%20tool_tests_general/15552/overview

Original PR Author: dcharkes

Reviewed By: {christopherfujino, chingjun, reidbaker}

This change reverts the following previous change:
Original Description:
Native assets in other build systems are not built with `package:native_assets_builder` invoking `build.dart` scripts. Instead all packages have their own blaze rules. Therefore we'd like to not depend on `package:native_assets_builder` from flutter tools in g3 at all.

This PR aims to move the imports of `native_assets_builder` and `native_assets_cli` into the `isolated/` directory and into the files with a `main` function that are not used in with other build systems.

In order to be able to remove all imports in files used by other build systems, two new interfaces are added `HotRunnerNativeAssetsBuilder` and `TestCompilerNativeAssetsBuilder`. New parameters are then piped all the way through from the entry points:

* bin/fuchsia_tester.dart
* lib/executable.dart

The build_system/targets dir is already excluded in other build systems.

So, after this PR only the two above files and build_system/targets import from `isolated/native_assets/` and only `isolated/native_assets/` import `package:native_assets_cli` and `package:native_assets_builder`.

Context:

* https://github.com/flutter/flutter/issues/142041
2024-02-07 00:01:18 +00:00

209 lines
6.9 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright 2014 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.
// Shared logic between iOS and macOS implementations of native assets.
import 'package:native_assets_cli/native_assets_cli_internal.dart'
hide BuildMode;
import '../base/common.dart';
import '../base/file_system.dart';
import '../base/io.dart';
import '../build_info.dart';
import '../convert.dart';
import '../globals.dart' as globals;
/// Create an `Info.plist` in [target] for a framework with a single dylib.
///
/// The framework must be named [name].framework and the dylib [name].
Future<void> createInfoPlist(
String name,
Directory target,
) async {
final File infoPlistFile = target.childFile('Info.plist');
await infoPlistFile.writeAsString('''
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$name</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.native_assets.$name</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$name</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
</dict>
</plist>
''');
}
/// Combines dylibs from [sources] into a fat binary at [targetFullPath].
///
/// The dylibs must have different architectures. E.g. a dylib targeting
/// arm64 ios simulator cannot be combined with a dylib targeting arm64
/// ios device or macos arm64.
Future<void> lipoDylibs(File target, List<Uri> sources) async {
final ProcessResult lipoResult = await globals.processManager.run(
<String>[
'lipo',
'-create',
'-output',
target.path,
for (final Uri source in sources) source.toFilePath(),
],
);
if (lipoResult.exitCode != 0) {
throwToolExit('Failed to create universal binary:\n${lipoResult.stderr}');
}
globals.logger.printTrace(lipoResult.stdout as String);
globals.logger.printTrace(lipoResult.stderr as String);
}
/// Sets the install name in a dylib with a Mach-O format.
///
/// On macOS and iOS, opening a dylib at runtime fails if the path inside the
/// dylib itself does not correspond to the path that the file is at. Therefore,
/// native assets copied into their final location also need their install name
/// updated with the `install_name_tool`.
Future<void> setInstallNameDylib(File dylibFile) async {
final String fileName = dylibFile.basename;
final ProcessResult installNameResult = await globals.processManager.run(
<String>[
'install_name_tool',
'-id',
'@rpath/$fileName.framework/$fileName',
dylibFile.path,
],
);
if (installNameResult.exitCode != 0) {
throwToolExit(
'Failed to change the install name of $dylibFile:\n${installNameResult.stderr}',
);
}
}
Future<void> codesignDylib(
String? codesignIdentity,
BuildMode buildMode,
FileSystemEntity target,
) async {
if (codesignIdentity == null || codesignIdentity.isEmpty) {
codesignIdentity = '-';
}
final List<String> codesignCommand = <String>[
'codesign',
'--force',
'--sign',
codesignIdentity,
if (buildMode != BuildMode.release) ...<String>[
// Mimic Xcode's timestamp codesigning behavior on non-release binaries.
'--timestamp=none',
],
target.path,
];
globals.logger.printTrace(codesignCommand.join(' '));
final ProcessResult codesignResult = await globals.processManager.run(
codesignCommand,
);
if (codesignResult.exitCode != 0) {
throwToolExit(
'Failed to code sign binary: exit code: ${codesignResult.exitCode} '
'${codesignResult.stdout} ${codesignResult.stderr}',
);
}
globals.logger.printTrace(codesignResult.stdout as String);
globals.logger.printTrace(codesignResult.stderr as String);
}
/// Flutter expects `xcrun` to be on the path on macOS hosts.
///
/// Use the `clang`, `ar`, and `ld` that would be used if run with `xcrun`.
Future<CCompilerConfig> cCompilerConfigMacOS() async {
final ProcessResult xcrunResult = await globals.processManager.run(
<String>['xcrun', 'clang', '--version'],
);
if (xcrunResult.exitCode != 0) {
throwToolExit('Failed to find clang with xcrun:\n${xcrunResult.stderr}');
}
final String installPath = LineSplitter.split(xcrunResult.stdout as String)
.firstWhere((String s) => s.startsWith('InstalledDir: '))
.split(' ')
.last;
return CCompilerConfig(
cc: Uri.file('$installPath/clang'),
ar: Uri.file('$installPath/ar'),
ld: Uri.file('$installPath/ld'),
);
}
/// Converts [fileName] into a suitable framework name.
///
/// On MacOS and iOS, dylibs need to be packaged in a framework.
///
/// In order for resolution to work, the file name inside the framework must be
/// equal to the framework name.
///
/// Dylib names on MacOS/iOS usually have a dylib extension. If so, remove it.
///
/// Dylib names on MacOS/iOS are usually prefixed with 'lib'. So, if the file is
/// a dylib, try to remove the prefix.
///
/// The bundle ID string must contain only alphanumeric characters
/// (AZ, az, and 09), hyphens (-), and periods (.).
/// https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleidentifier
///
/// This name can contain up to 15 characters.
/// https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundlename
///
/// The [alreadyTakenNames] are used to ensure that the framework name does not
/// conflict with previously chosen names.
Uri frameworkUri(String fileName, Set<String> alreadyTakenNames) {
final List<String> splitFileName = fileName.split('.');
final bool isDylib;
if (splitFileName.length >= 2) {
isDylib = splitFileName.last == 'dylib';
if (isDylib) {
fileName = splitFileName.sublist(0, splitFileName.length - 1).join('.');
}
} else {
isDylib = false;
}
if (isDylib && fileName.startsWith('lib')) {
fileName = fileName.replaceFirst('lib', '');
}
fileName = fileName.replaceAll(RegExp(r'[^A-Za-z0-9_-]'), '');
if (fileName.length > 15) {
fileName = fileName.substring(0, 15);
}
if (alreadyTakenNames.contains(fileName)) {
if (fileName.length > 12) {
fileName = fileName.substring(0, 12);
}
final String prefixName = fileName;
for (int i = 1; i < 1000; i++) {
fileName = '$prefixName$i';
if (!alreadyTakenNames.contains(fileName)) {
break;
}
}
if (alreadyTakenNames.contains(fileName)) {
throwToolExit('Failed to rename $fileName in native assets packaging.');
}
}
alreadyTakenNames.add(fileName);
return Uri(path: '$fileName.framework/$fileName');
}