Unverified Commit 4cc0ab2d authored by Hidenori Matsubayashi's avatar Hidenori Matsubayashi Committed by GitHub

[flutter_tools] Add ARM64 Linux host and cross-building option support (#61221)

parent 97a9f2ae
...@@ -73,3 +73,4 @@ Anurag Roy <anuragr9847@gmail.com> ...@@ -73,3 +73,4 @@ Anurag Roy <anuragr9847@gmail.com>
Andrey Kabylin <andrey@kabylin.ru> Andrey Kabylin <andrey@kabylin.ru>
vimerzhao <vimerzhao@gmail.com> vimerzhao <vimerzhao@gmail.com>
Pedro Massango <pedromassango.developer@gmail.com> Pedro Massango <pedromassango.developer@gmail.com>
Hidenori Matsubayashi <Hidenori.Matsubayashi@sony.com>
...@@ -58,13 +58,24 @@ if [ ! -f "$ENGINE_STAMP" ] || [ "$ENGINE_VERSION" != `cat "$ENGINE_STAMP"` ]; t ...@@ -58,13 +58,24 @@ if [ ! -f "$ENGINE_STAMP" ] || [ "$ENGINE_VERSION" != `cat "$ENGINE_STAMP"` ]; t
} }
>&2 echo "Downloading Dart SDK from Flutter engine $ENGINE_VERSION..." >&2 echo "Downloading Dart SDK from Flutter engine $ENGINE_VERSION..."
# On x64 stdout is "uname -m: x86_64"
# On arm64 stdout is "uname -m: aarch64, arm64_v8a"
case "$(uname -m)" in
x86_64)
ARCH="x64"
;;
*)
ARCH="arm64"
;;
esac
case "$(uname -s)" in case "$(uname -s)" in
Darwin) Darwin)
DART_ZIP_NAME="dart-sdk-darwin-x64.zip" DART_ZIP_NAME="dart-sdk-darwin-x64.zip"
IS_USER_EXECUTABLE="-perm +100" IS_USER_EXECUTABLE="-perm +100"
;; ;;
Linux) Linux)
DART_ZIP_NAME="dart-sdk-linux-x64.zip" DART_ZIP_NAME="dart-sdk-linux-${ARCH}.zip"
IS_USER_EXECUTABLE="-perm /u+x" IS_USER_EXECUTABLE="-perm /u+x"
;; ;;
MINGW*) MINGW*)
......
...@@ -113,6 +113,7 @@ Future<void> main(List<String> args) async { ...@@ -113,6 +113,7 @@ Future<void> main(List<String> args) async {
fileSystem: globals.fs, fileSystem: globals.fs,
cache: globals.cache, cache: globals.cache,
platform: globals.platform, platform: globals.platform,
operatingSystemUtils: globals.os,
), ),
frontendServer: frontendServer, frontendServer: frontendServer,
engineDartBinary: dartSdk, engineDartBinary: dartSdk,
......
...@@ -54,7 +54,7 @@ or ...@@ -54,7 +54,7 @@ or
else else
'flutter' 'flutter'
]); ]);
final String bundlePlatform = targetPlatform == 'windows-x64' ? 'windows' : 'linux'; final String bundlePlatform = targetPlatform == 'windows-x64' ? 'windows' : targetPlatform;
final String target = '${buildMode}_bundle_${bundlePlatform}_assets'; final String target = '${buildMode}_bundle_${bundlePlatform}_assets';
final Process assembleProcess = await Process.start( final Process assembleProcess = await Process.start(
flutterExecutable, flutterExecutable,
......
...@@ -16,6 +16,7 @@ import '../base/os.dart'; ...@@ -16,6 +16,7 @@ import '../base/os.dart';
import '../base/platform.dart'; import '../base/platform.dart';
import '../base/user_messages.dart' hide userMessages; import '../base/user_messages.dart' hide userMessages;
import '../base/version.dart'; import '../base/version.dart';
import '../build_info.dart';
import '../convert.dart'; import '../convert.dart';
import '../doctor.dart'; import '../doctor.dart';
import '../features.dart'; import '../features.dart';
...@@ -45,14 +46,19 @@ class AndroidWorkflow implements Workflow { ...@@ -45,14 +46,19 @@ class AndroidWorkflow implements Workflow {
AndroidWorkflow({ AndroidWorkflow({
@required AndroidSdk androidSdk, @required AndroidSdk androidSdk,
@required FeatureFlags featureFlags, @required FeatureFlags featureFlags,
@required OperatingSystemUtils operatingSystemUtils,
}) : _androidSdk = androidSdk, }) : _androidSdk = androidSdk,
_featureFlags = featureFlags; _featureFlags = featureFlags,
_operatingSystemUtils = operatingSystemUtils;
final AndroidSdk _androidSdk; final AndroidSdk _androidSdk;
final FeatureFlags _featureFlags; final FeatureFlags _featureFlags;
final OperatingSystemUtils _operatingSystemUtils;
@override @override
bool get appliesToHostPlatform => _featureFlags.isAndroidEnabled; bool get appliesToHostPlatform => _featureFlags.isAndroidEnabled
// Android Studio is not currently supported on Linux Arm64 Hosts.
&& _operatingSystemUtils.hostPlatform != HostPlatform.linux_arm64;
@override @override
bool get canListDevices => _androidSdk != null bool get canListDevices => _androidSdk != null
......
...@@ -101,6 +101,7 @@ class ApplicationPackageFactory { ...@@ -101,6 +101,7 @@ class ApplicationPackageFactory {
} }
return WebApplicationPackage(FlutterProject.current()); return WebApplicationPackage(FlutterProject.current());
case TargetPlatform.linux_x64: case TargetPlatform.linux_x64:
case TargetPlatform.linux_arm64:
return applicationBinary == null return applicationBinary == null
? LinuxApp.fromLinuxProject(FlutterProject.current().linux) ? LinuxApp.fromLinuxProject(FlutterProject.current().linux)
: LinuxApp.fromPrebuiltApp(applicationBinary); : LinuxApp.fromPrebuiltApp(applicationBinary);
......
...@@ -9,6 +9,7 @@ import 'package:process/process.dart'; ...@@ -9,6 +9,7 @@ import 'package:process/process.dart';
import 'base/common.dart'; import 'base/common.dart';
import 'base/file_system.dart'; import 'base/file_system.dart';
import 'base/os.dart';
import 'base/platform.dart'; import 'base/platform.dart';
import 'base/utils.dart'; import 'base/utils.dart';
import 'build_info.dart'; import 'build_info.dart';
...@@ -219,6 +220,7 @@ abstract class Artifacts { ...@@ -219,6 +220,7 @@ abstract class Artifacts {
fileSystem: globals.fs, fileSystem: globals.fs,
processManager: globals.processManager, processManager: globals.processManager,
platform: globals.platform, platform: globals.platform,
operatingSystemUtils: globals.os,
); );
} }
...@@ -245,13 +247,16 @@ class CachedArtifacts implements Artifacts { ...@@ -245,13 +247,16 @@ class CachedArtifacts implements Artifacts {
@required FileSystem fileSystem, @required FileSystem fileSystem,
@required Platform platform, @required Platform platform,
@required Cache cache, @required Cache cache,
@required OperatingSystemUtils operatingSystemUtils,
}) : _fileSystem = fileSystem, }) : _fileSystem = fileSystem,
_platform = platform, _platform = platform,
_cache = cache; _cache = cache,
_operatingSystemUtils = operatingSystemUtils;
final FileSystem _fileSystem; final FileSystem _fileSystem;
final Platform _platform; final Platform _platform;
final Cache _cache; final Cache _cache;
final OperatingSystemUtils _operatingSystemUtils;
@override @override
String getArtifactPath( String getArtifactPath(
...@@ -270,6 +275,7 @@ class CachedArtifacts implements Artifacts { ...@@ -270,6 +275,7 @@ class CachedArtifacts implements Artifacts {
return _getIosArtifactPath(artifact, platform, mode, environmentType); return _getIosArtifactPath(artifact, platform, mode, environmentType);
case TargetPlatform.darwin_x64: case TargetPlatform.darwin_x64:
case TargetPlatform.linux_x64: case TargetPlatform.linux_x64:
case TargetPlatform.linux_arm64:
case TargetPlatform.windows_x64: case TargetPlatform.windows_x64:
return _getDesktopArtifactPath(artifact, platform, mode); return _getDesktopArtifactPath(artifact, platform, mode);
case TargetPlatform.fuchsia_arm64: case TargetPlatform.fuchsia_arm64:
...@@ -278,7 +284,7 @@ class CachedArtifacts implements Artifacts { ...@@ -278,7 +284,7 @@ class CachedArtifacts implements Artifacts {
case TargetPlatform.tester: case TargetPlatform.tester:
case TargetPlatform.web_javascript: case TargetPlatform.web_javascript:
default: // could be null, but that can't be specified as a case. default: // could be null, but that can't be specified as a case.
return _getHostArtifactPath(artifact, platform ?? _currentHostPlatform(_platform), mode); return _getHostArtifactPath(artifact, platform ?? _currentHostPlatform(_platform, _operatingSystemUtils), mode);
} }
} }
...@@ -294,7 +300,7 @@ class CachedArtifacts implements Artifacts { ...@@ -294,7 +300,7 @@ class CachedArtifacts implements Artifacts {
final String engineDir = _getEngineArtifactsPath(platform, mode); final String engineDir = _getEngineArtifactsPath(platform, mode);
return _fileSystem.path.join(engineDir, _artifactToFileName(artifact)); return _fileSystem.path.join(engineDir, _artifactToFileName(artifact));
} }
return _getHostArtifactPath(artifact, platform ?? _currentHostPlatform(_platform), mode); return _getHostArtifactPath(artifact, platform ?? _currentHostPlatform(_platform, _operatingSystemUtils), mode);
} }
String _getAndroidArtifactPath(Artifact artifact, TargetPlatform platform, BuildMode mode) { String _getAndroidArtifactPath(Artifact artifact, TargetPlatform platform, BuildMode mode) {
...@@ -480,6 +486,7 @@ class CachedArtifacts implements Artifacts { ...@@ -480,6 +486,7 @@ class CachedArtifacts implements Artifacts {
final String platformName = getNameForTargetPlatform(platform); final String platformName = getNameForTargetPlatform(platform);
switch (platform) { switch (platform) {
case TargetPlatform.linux_x64: case TargetPlatform.linux_x64:
case TargetPlatform.linux_arm64:
case TargetPlatform.darwin_x64: case TargetPlatform.darwin_x64:
case TargetPlatform.windows_x64: case TargetPlatform.windows_x64:
// TODO(jonahwilliams): remove once debug desktop artifacts are uploaded // TODO(jonahwilliams): remove once debug desktop artifacts are uploaded
...@@ -516,12 +523,13 @@ class CachedArtifacts implements Artifacts { ...@@ -516,12 +523,13 @@ class CachedArtifacts implements Artifacts {
bool get isLocalEngine => false; bool get isLocalEngine => false;
} }
TargetPlatform _currentHostPlatform(Platform platform) { TargetPlatform _currentHostPlatform(Platform platform, OperatingSystemUtils operatingSystemUtils) {
if (platform.isMacOS) { if (platform.isMacOS) {
return TargetPlatform.darwin_x64; return TargetPlatform.darwin_x64;
} }
if (platform.isLinux) { if (platform.isLinux) {
return TargetPlatform.linux_x64; return operatingSystemUtils.hostPlatform == HostPlatform.linux_x64 ?
TargetPlatform.linux_x64 : TargetPlatform.linux_arm64;
} }
if (platform.isWindows) { if (platform.isWindows) {
return TargetPlatform.windows_x64; return TargetPlatform.windows_x64;
...@@ -529,19 +537,6 @@ TargetPlatform _currentHostPlatform(Platform platform) { ...@@ -529,19 +537,6 @@ TargetPlatform _currentHostPlatform(Platform platform) {
throw UnimplementedError('Host OS not supported.'); throw UnimplementedError('Host OS not supported.');
} }
HostPlatform _currentHostPlatformAsHost(Platform platform) {
if (platform.isMacOS) {
return HostPlatform.darwin_x64;
}
if (platform.isLinux) {
return HostPlatform.linux_x64;
}
if (platform.isWindows) {
return HostPlatform.windows_x64;
}
throw UnimplementedError('Host OS not supported.');
}
String _getIosEngineArtifactPath(String engineDirectory, String _getIosEngineArtifactPath(String engineDirectory,
EnvironmentType environmentType, FileSystem fileSystem) { EnvironmentType environmentType, FileSystem fileSystem) {
final Directory xcframeworkDirectory = fileSystem final Directory xcframeworkDirectory = fileSystem
...@@ -583,10 +578,12 @@ class LocalEngineArtifacts implements Artifacts { ...@@ -583,10 +578,12 @@ class LocalEngineArtifacts implements Artifacts {
@required Cache cache, @required Cache cache,
@required ProcessManager processManager, @required ProcessManager processManager,
@required Platform platform, @required Platform platform,
@required OperatingSystemUtils operatingSystemUtils,
}) : _fileSystem = fileSystem, }) : _fileSystem = fileSystem,
_cache = cache, _cache = cache,
_processManager = processManager, _processManager = processManager,
_platform = platform; _platform = platform,
_operatingSystemUtils = operatingSystemUtils;
final String engineOutPath; // TODO(goderbauer): This should be private. final String engineOutPath; // TODO(goderbauer): This should be private.
final String _hostEngineOutPath; final String _hostEngineOutPath;
...@@ -594,6 +591,7 @@ class LocalEngineArtifacts implements Artifacts { ...@@ -594,6 +591,7 @@ class LocalEngineArtifacts implements Artifacts {
final Cache _cache; final Cache _cache;
final ProcessManager _processManager; final ProcessManager _processManager;
final Platform _platform; final Platform _platform;
final OperatingSystemUtils _operatingSystemUtils;
@override @override
String getArtifactPath( String getArtifactPath(
...@@ -602,7 +600,7 @@ class LocalEngineArtifacts implements Artifacts { ...@@ -602,7 +600,7 @@ class LocalEngineArtifacts implements Artifacts {
BuildMode mode, BuildMode mode,
EnvironmentType environmentType, EnvironmentType environmentType,
}) { }) {
platform ??= _currentHostPlatform(_platform); platform ??= _currentHostPlatform(_platform, _operatingSystemUtils);
final bool isDirectoryArtifact = artifact == Artifact.flutterWebSdk || artifact == Artifact.flutterPatchedSdkPath; final bool isDirectoryArtifact = artifact == Artifact.flutterWebSdk || artifact == Artifact.flutterPatchedSdkPath;
final String artifactFileName = isDirectoryArtifact ? null : _artifactToFileName(artifact, platform, mode); final String artifactFileName = isDirectoryArtifact ? null : _artifactToFileName(artifact, platform, mode);
switch (artifact) { switch (artifact) {
...@@ -745,12 +743,11 @@ class LocalEngineArtifacts implements Artifacts { ...@@ -745,12 +743,11 @@ class LocalEngineArtifacts implements Artifacts {
} }
String _flutterTesterPath(TargetPlatform platform) { String _flutterTesterPath(TargetPlatform platform) {
final HostPlatform hostPlatform = _currentHostPlatformAsHost(_platform); if (_platform.isLinux) {
if (hostPlatform == HostPlatform.linux_x64) {
return _fileSystem.path.join(engineOutPath, _artifactToFileName(Artifact.flutterTester)); return _fileSystem.path.join(engineOutPath, _artifactToFileName(Artifact.flutterTester));
} else if (hostPlatform == HostPlatform.darwin_x64) { } else if (_platform.isMacOS) {
return _fileSystem.path.join(engineOutPath, 'flutter_tester'); return _fileSystem.path.join(engineOutPath, 'flutter_tester');
} else if (hostPlatform == HostPlatform.windows_x64) { } else if (_platform.isWindows) {
return _fileSystem.path.join(engineOutPath, 'flutter_tester.exe'); return _fileSystem.path.join(engineOutPath, 'flutter_tester.exe');
} }
throw Exception('Unsupported platform $platform.'); throw Exception('Unsupported platform $platform.');
......
...@@ -313,6 +313,7 @@ class AOTSnapshotter { ...@@ -313,6 +313,7 @@ class AOTSnapshotter {
TargetPlatform.ios, TargetPlatform.ios,
TargetPlatform.darwin_x64, TargetPlatform.darwin_x64,
TargetPlatform.linux_x64, TargetPlatform.linux_x64,
TargetPlatform.linux_arm64,
TargetPlatform.windows_x64, TargetPlatform.windows_x64,
].contains(platform); ].contains(platform);
} }
......
...@@ -261,8 +261,30 @@ class _PosixUtils extends OperatingSystemUtils { ...@@ -261,8 +261,30 @@ class _PosixUtils extends OperatingSystemUtils {
@override @override
String get pathVarSeparator => ':'; String get pathVarSeparator => ':';
HostPlatform _hostPlatform;
@override @override
HostPlatform hostPlatform = HostPlatform.linux_x64; HostPlatform get hostPlatform {
if (_hostPlatform == null) {
final RunResult hostPlatformCheck =
_processUtils.runSync(<String>['uname', '-m']);
// On x64 stdout is "uname -m: x86_64"
// On arm64 stdout is "uname -m: aarch64, arm64_v8a"
if (hostPlatformCheck.exitCode != 0) {
_logger.printError(
'Error trying to run uname -m'
'\nstdout: ${hostPlatformCheck.stdout}'
'\nstderr: ${hostPlatformCheck.stderr}',
);
_hostPlatform = HostPlatform.linux_x64;
} else if (hostPlatformCheck.stdout.trim().endsWith('x86_64')) {
_hostPlatform = HostPlatform.linux_x64;
} else {
_hostPlatform = HostPlatform.linux_arm64;
}
}
return _hostPlatform;
}
} }
class _MacOSUtils extends _PosixUtils { class _MacOSUtils extends _PosixUtils {
...@@ -297,8 +319,6 @@ class _MacOSUtils extends _PosixUtils { ...@@ -297,8 +319,6 @@ class _MacOSUtils extends _PosixUtils {
return _name; return _name;
} }
HostPlatform _hostPlatform;
// On ARM returns arm64, even when this process is running in Rosetta. // On ARM returns arm64, even when this process is running in Rosetta.
@override @override
HostPlatform get hostPlatform { HostPlatform get hostPlatform {
......
...@@ -456,6 +456,7 @@ enum HostPlatform { ...@@ -456,6 +456,7 @@ enum HostPlatform {
darwin_x64, darwin_x64,
darwin_arm, darwin_arm,
linux_x64, linux_x64,
linux_arm64,
windows_x64, windows_x64,
} }
...@@ -467,6 +468,8 @@ String getNameForHostPlatform(HostPlatform platform) { ...@@ -467,6 +468,8 @@ String getNameForHostPlatform(HostPlatform platform) {
return 'darwin-arm'; return 'darwin-arm';
case HostPlatform.linux_x64: case HostPlatform.linux_x64:
return 'linux-x64'; return 'linux-x64';
case HostPlatform.linux_arm64:
return 'linux-arm64';
case HostPlatform.windows_x64: case HostPlatform.windows_x64:
return 'windows-x64'; return 'windows-x64';
} }
...@@ -480,6 +483,7 @@ enum TargetPlatform { ...@@ -480,6 +483,7 @@ enum TargetPlatform {
// darwin_arm64 not yet supported, macOS desktop targets run in Rosetta as x86. // darwin_arm64 not yet supported, macOS desktop targets run in Rosetta as x86.
darwin_x64, darwin_x64,
linux_x64, linux_x64,
linux_arm64,
windows_x64, windows_x64,
fuchsia_arm64, fuchsia_arm64,
fuchsia_x64, fuchsia_x64,
...@@ -574,6 +578,8 @@ String getNameForTargetPlatform(TargetPlatform platform, {DarwinArch darwinArch} ...@@ -574,6 +578,8 @@ String getNameForTargetPlatform(TargetPlatform platform, {DarwinArch darwinArch}
return 'darwin-x64'; return 'darwin-x64';
case TargetPlatform.linux_x64: case TargetPlatform.linux_x64:
return 'linux-x64'; return 'linux-x64';
case TargetPlatform.linux_arm64:
return 'linux-arm64';
case TargetPlatform.windows_x64: case TargetPlatform.windows_x64:
return 'windows-x64'; return 'windows-x64';
case TargetPlatform.fuchsia_arm64: case TargetPlatform.fuchsia_arm64:
...@@ -613,6 +619,8 @@ TargetPlatform getTargetPlatformForName(String platform) { ...@@ -613,6 +619,8 @@ TargetPlatform getTargetPlatformForName(String platform) {
return TargetPlatform.darwin_x64; return TargetPlatform.darwin_x64;
case 'linux-x64': case 'linux-x64':
return TargetPlatform.linux_x64; return TargetPlatform.linux_x64;
case 'linux-arm64':
return TargetPlatform.linux_arm64;
case 'windows-x64': case 'windows-x64':
return TargetPlatform.windows_x64; return TargetPlatform.windows_x64;
case 'web-javascript': case 'web-javascript':
...@@ -683,7 +691,8 @@ HostPlatform getCurrentHostPlatform() { ...@@ -683,7 +691,8 @@ HostPlatform getCurrentHostPlatform() {
return HostPlatform.darwin_x64; return HostPlatform.darwin_x64;
} }
if (globals.platform.isLinux) { if (globals.platform.isLinux) {
return HostPlatform.linux_x64; // support x64 and arm64 architecture.
return globals.os.hostPlatform;
} }
if (globals.platform.isWindows) { if (globals.platform.isWindows) {
return HostPlatform.windows_x64; return HostPlatform.windows_x64;
...@@ -747,8 +756,12 @@ String getWebBuildDirectory() { ...@@ -747,8 +756,12 @@ String getWebBuildDirectory() {
} }
/// Returns the Linux build output directory. /// Returns the Linux build output directory.
String getLinuxBuildDirectory() { String getLinuxBuildDirectory([TargetPlatform targetPlatform]) {
return globals.fs.path.join(getBuildDirectory(), 'linux'); final String arch = (targetPlatform == null) ?
_getCurrentHostPlatformArchName() :
getNameForTargetPlatformArch(targetPlatform);
final String subDirs = 'linux/' + arch;
return globals.fs.path.join(getBuildDirectory(), subDirs);
} }
/// Returns the Windows build output directory. /// Returns the Windows build output directory.
...@@ -813,3 +826,40 @@ enum NullSafetyMode { ...@@ -813,3 +826,40 @@ enum NullSafetyMode {
/// The null safety mode was not detected. Only supported for 'flutter test'. /// The null safety mode was not detected. Only supported for 'flutter test'.
autodetect, autodetect,
} }
String _getCurrentHostPlatformArchName() {
final HostPlatform hostPlatform = getCurrentHostPlatform();
return getNameForHostPlatformArch(hostPlatform);
}
String getNameForTargetPlatformArch(TargetPlatform platform) {
switch (platform) {
case TargetPlatform.linux_x64:
case TargetPlatform.darwin_x64:
case TargetPlatform.windows_x64:
return 'x64';
case TargetPlatform.linux_arm64:
return 'arm64';
default:
break;
}
assert(false);
return null;
}
String getNameForHostPlatformArch(HostPlatform platform) {
switch (platform) {
case HostPlatform.darwin_x64:
return 'x64';
case HostPlatform.darwin_arm:
return 'arm';
case HostPlatform.linux_x64:
return 'x64';
case HostPlatform.linux_arm64:
return 'arm64';
case HostPlatform.windows_x64:
return 'x64';
}
assert(false);
return null;
}
...@@ -26,7 +26,9 @@ const String _kLinuxDepfile = 'linux_engine_sources.d'; ...@@ -26,7 +26,9 @@ const String _kLinuxDepfile = 'linux_engine_sources.d';
/// Copies the Linux desktop embedding files to the copy directory. /// Copies the Linux desktop embedding files to the copy directory.
class UnpackLinux extends Target { class UnpackLinux extends Target {
const UnpackLinux(); const UnpackLinux(this.targetPlatform);
final TargetPlatform targetPlatform;
@override @override
String get name => 'unpack_linux'; String get name => 'unpack_linux';
...@@ -52,13 +54,13 @@ class UnpackLinux extends Target { ...@@ -52,13 +54,13 @@ class UnpackLinux extends Target {
.getArtifactPath( .getArtifactPath(
Artifact.linuxDesktopPath, Artifact.linuxDesktopPath,
mode: buildMode, mode: buildMode,
platform: TargetPlatform.linux_x64, platform: targetPlatform,
); );
final String headersPath = environment.artifacts final String headersPath = environment.artifacts
.getArtifactPath( .getArtifactPath(
Artifact.linuxHeaders, Artifact.linuxHeaders,
mode: buildMode, mode: buildMode,
platform: TargetPlatform.linux_x64, platform: targetPlatform,
); );
final Directory outputDirectory = environment.fileSystem.directory( final Directory outputDirectory = environment.fileSystem.directory(
environment.fileSystem.path.join( environment.fileSystem.path.join(
...@@ -75,7 +77,7 @@ class UnpackLinux extends Target { ...@@ -75,7 +77,7 @@ class UnpackLinux extends Target {
clientSourcePaths: <String>[headersPath], clientSourcePaths: <String>[headersPath],
icuDataPath: environment.artifacts.getArtifactPath( icuDataPath: environment.artifacts.getArtifactPath(
Artifact.icuData, Artifact.icuData,
platform: TargetPlatform.linux_x64, platform: targetPlatform,
) )
); );
final DepfileService depfileService = DepfileService( final DepfileService depfileService = DepfileService(
...@@ -91,12 +93,14 @@ class UnpackLinux extends Target { ...@@ -91,12 +93,14 @@ class UnpackLinux extends Target {
/// Creates a bundle for the Linux desktop target. /// Creates a bundle for the Linux desktop target.
abstract class BundleLinuxAssets extends Target { abstract class BundleLinuxAssets extends Target {
const BundleLinuxAssets(); const BundleLinuxAssets(this.targetPlatform);
final TargetPlatform targetPlatform;
@override @override
List<Target> get dependencies => const <Target>[ List<Target> get dependencies => <Target>[
KernelSnapshot(), const KernelSnapshot(),
UnpackLinux(), UnpackLinux(targetPlatform),
]; ];
@override @override
...@@ -132,7 +136,7 @@ abstract class BundleLinuxAssets extends Target { ...@@ -132,7 +136,7 @@ abstract class BundleLinuxAssets extends Target {
final Depfile depfile = await copyAssets( final Depfile depfile = await copyAssets(
environment, environment,
outputDirectory, outputDirectory,
targetPlatform: TargetPlatform.linux_x64, targetPlatform: targetPlatform,
additionalContent: <String, DevFSContent>{ additionalContent: <String, DevFSContent>{
'version.json': DevFSStringContent(versionInfo), 'version.json': DevFSStringContent(versionInfo),
} }
...@@ -186,10 +190,10 @@ class LinuxAotBundle extends Target { ...@@ -186,10 +190,10 @@ class LinuxAotBundle extends Target {
} }
class DebugBundleLinuxAssets extends BundleLinuxAssets { class DebugBundleLinuxAssets extends BundleLinuxAssets {
const DebugBundleLinuxAssets(); const DebugBundleLinuxAssets(TargetPlatform targetPlatform) : super(targetPlatform);
@override @override
String get name => 'debug_bundle_linux_assets'; String get name => 'debug_bundle_${getNameForTargetPlatform(targetPlatform)}_assets';
@override @override
List<Source> get inputs => <Source>[ List<Source> get inputs => <Source>[
...@@ -203,10 +207,10 @@ class DebugBundleLinuxAssets extends BundleLinuxAssets { ...@@ -203,10 +207,10 @@ class DebugBundleLinuxAssets extends BundleLinuxAssets {
} }
class ProfileBundleLinuxAssets extends BundleLinuxAssets { class ProfileBundleLinuxAssets extends BundleLinuxAssets {
const ProfileBundleLinuxAssets(); const ProfileBundleLinuxAssets(TargetPlatform targetPlatform) : super(targetPlatform);
@override @override
String get name => 'profile_bundle_linux_assets'; String get name => 'profile_bundle_${getNameForTargetPlatform(targetPlatform)}_assets';
@override @override
List<Source> get outputs => const <Source>[]; List<Source> get outputs => const <Source>[];
...@@ -214,15 +218,15 @@ class ProfileBundleLinuxAssets extends BundleLinuxAssets { ...@@ -214,15 +218,15 @@ class ProfileBundleLinuxAssets extends BundleLinuxAssets {
@override @override
List<Target> get dependencies => <Target>[ List<Target> get dependencies => <Target>[
...super.dependencies, ...super.dependencies,
const LinuxAotBundle(AotElfProfile(TargetPlatform.linux_x64)), LinuxAotBundle(AotElfProfile(targetPlatform)),
]; ];
} }
class ReleaseBundleLinuxAssets extends BundleLinuxAssets { class ReleaseBundleLinuxAssets extends BundleLinuxAssets {
const ReleaseBundleLinuxAssets(); const ReleaseBundleLinuxAssets(TargetPlatform targetPlatform) : super(targetPlatform);
@override @override
String get name => 'release_bundle_linux_assets'; String get name => 'release_bundle_${getNameForTargetPlatform(targetPlatform)}_assets';
@override @override
List<Source> get outputs => const <Source>[]; List<Source> get outputs => const <Source>[];
...@@ -230,6 +234,6 @@ class ReleaseBundleLinuxAssets extends BundleLinuxAssets { ...@@ -230,6 +234,6 @@ class ReleaseBundleLinuxAssets extends BundleLinuxAssets {
@override @override
List<Target> get dependencies => <Target>[ List<Target> get dependencies => <Target>[
...super.dependencies, ...super.dependencies,
const LinuxAotBundle(AotElfRelease(TargetPlatform.linux_x64)), LinuxAotBundle(AotElfRelease(targetPlatform)),
]; ];
} }
...@@ -23,6 +23,7 @@ import 'base/os.dart' show OperatingSystemUtils; ...@@ -23,6 +23,7 @@ import 'base/os.dart' show OperatingSystemUtils;
import 'base/platform.dart'; import 'base/platform.dart';
import 'base/process.dart'; import 'base/process.dart';
import 'base/user_messages.dart'; import 'base/user_messages.dart';
import 'build_info.dart';
import 'convert.dart'; import 'convert.dart';
import 'dart/package_map.dart'; import 'dart/package_map.dart';
import 'dart/pub.dart'; import 'dart/pub.dart';
...@@ -430,6 +431,10 @@ class Cache { ...@@ -430,6 +431,10 @@ class Cache {
} }
} }
String getHostPlatformArchName() {
return getNameForHostPlatformArch(_osUtils.hostPlatform);
}
/// Return a directory in the cache dir. For `pkg`, this will return `bin/cache/pkg`. /// Return a directory in the cache dir. For `pkg`, this will return `bin/cache/pkg`.
Directory getCacheDir(String name) { Directory getCacheDir(String name) {
final Directory dir = _fileSystem.directory(_fileSystem.path.join(getRoot().path, name)); final Directory dir = _fileSystem.directory(_fileSystem.path.join(getRoot().path, name));
...@@ -996,12 +1001,14 @@ class FlutterSdk extends EngineCachedArtifact { ...@@ -996,12 +1001,14 @@ class FlutterSdk extends EngineCachedArtifact {
@override @override
List<List<String>> getBinaryDirs() { List<List<String>> getBinaryDirs() {
// Currently only Linux supports both arm64 and x64.
final String arch = cache.getHostPlatformArchName();
return <List<String>>[ return <List<String>>[
<String>['common', 'flutter_patched_sdk.zip'], <String>['common', 'flutter_patched_sdk.zip'],
<String>['common', 'flutter_patched_sdk_product.zip'], <String>['common', 'flutter_patched_sdk_product.zip'],
if (cache.includeAllPlatforms) ...<List<String>>[ if (cache.includeAllPlatforms) ...<List<String>>[
<String>['windows-x64', 'windows-x64/artifacts.zip'], <String>['windows-x64', 'windows-x64/artifacts.zip'],
<String>['linux-x64', 'linux-x64/artifacts.zip'], <String>['linux-$arch', 'linux-$arch/artifacts.zip'],
<String>['darwin-x64', 'darwin-x64/artifacts.zip'], <String>['darwin-x64', 'darwin-x64/artifacts.zip'],
] ]
else if (_platform.isWindows) else if (_platform.isWindows)
...@@ -1009,7 +1016,7 @@ class FlutterSdk extends EngineCachedArtifact { ...@@ -1009,7 +1016,7 @@ class FlutterSdk extends EngineCachedArtifact {
else if (_platform.isMacOS) else if (_platform.isMacOS)
<String>['darwin-x64', 'darwin-x64/artifacts.zip'] <String>['darwin-x64', 'darwin-x64/artifacts.zip']
else if (_platform.isLinux) else if (_platform.isLinux)
<String>['linux-x64', 'linux-x64/artifacts.zip'], <String>['linux-$arch', 'linux-$arch/artifacts.zip'],
]; ];
} }
...@@ -1091,7 +1098,12 @@ class LinuxEngineArtifacts extends EngineCachedArtifact { ...@@ -1091,7 +1098,12 @@ class LinuxEngineArtifacts extends EngineCachedArtifact {
@override @override
List<List<String>> getBinaryDirs() { List<List<String>> getBinaryDirs() {
if (_platform.isLinux || ignorePlatformFiltering) { if (_platform.isLinux || ignorePlatformFiltering) {
return _linuxDesktopBinaryDirs; final String arch = cache.getHostPlatformArchName();
return <List<String>>[
<String>['linux-$arch', 'linux-$arch/linux-$arch-flutter-gtk.zip'],
<String>['linux-$arch-profile', 'linux-$arch-profile/linux-$arch-flutter-gtk.zip'],
<String>['linux-$arch-release', 'linux-$arch-release/linux-$arch-flutter-gtk.zip'],
];
} }
return const <List<String>>[]; return const <List<String>>[];
} }
...@@ -1480,9 +1492,11 @@ class FontSubsetArtifacts extends EngineCachedArtifact { ...@@ -1480,9 +1492,11 @@ class FontSubsetArtifacts extends EngineCachedArtifact {
@override @override
List<List<String>> getBinaryDirs() { List<List<String>> getBinaryDirs() {
const Map<String, List<String>> artifacts = <String, List<String>> { // Currently only Linux supports both arm64 and x64.
final String arch = cache.getHostPlatformArchName();
final Map<String, List<String>> artifacts = <String, List<String>> {
'macos': <String>['darwin-x64', 'darwin-x64/$artifactName.zip'], 'macos': <String>['darwin-x64', 'darwin-x64/$artifactName.zip'],
'linux': <String>['linux-x64', 'linux-x64/$artifactName.zip'], 'linux': <String>['linux-$arch', 'linux-$arch/$artifactName.zip'],
'windows': <String>['windows-x64', 'windows-x64/$artifactName.zip'], 'windows': <String>['windows-x64', 'windows-x64/$artifactName.zip'],
}; };
if (cache.includeAllPlatforms) { if (cache.includeAllPlatforms) {
...@@ -1613,12 +1627,6 @@ const List<List<String>> _windowsDesktopBinaryDirs = <List<String>>[ ...@@ -1613,12 +1627,6 @@ const List<List<String>> _windowsDesktopBinaryDirs = <List<String>>[
<String>['windows-x64-release', 'windows-x64-release/windows-x64-flutter.zip'], <String>['windows-x64-release', 'windows-x64-release/windows-x64-flutter.zip'],
]; ];
const List<List<String>> _linuxDesktopBinaryDirs = <List<String>>[
<String>['linux-x64', 'linux-x64/linux-x64-flutter-gtk.zip'],
<String>['linux-x64-profile', 'linux-x64-profile/linux-x64-flutter-gtk.zip'],
<String>['linux-x64-release', 'linux-x64-release/linux-x64-flutter-gtk.zip'],
];
const List<List<String>> _macOSDesktopBinaryDirs = <List<String>>[ const List<List<String>> _macOSDesktopBinaryDirs = <List<String>>[
<String>['darwin-x64', 'darwin-x64/FlutterMacOS.framework.zip'], <String>['darwin-x64', 'darwin-x64/FlutterMacOS.framework.zip'],
<String>['darwin-x64-profile', 'darwin-x64-profile/FlutterMacOS.framework.zip'], <String>['darwin-x64-profile', 'darwin-x64-profile/FlutterMacOS.framework.zip'],
......
...@@ -41,9 +41,12 @@ const List<Target> _kDefaultTargets = <Target>[ ...@@ -41,9 +41,12 @@ const List<Target> _kDefaultTargets = <Target>[
ProfileMacOSBundleFlutterAssets(), ProfileMacOSBundleFlutterAssets(),
ReleaseMacOSBundleFlutterAssets(), ReleaseMacOSBundleFlutterAssets(),
// Linux targets // Linux targets
DebugBundleLinuxAssets(), DebugBundleLinuxAssets(TargetPlatform.linux_x64),
ProfileBundleLinuxAssets(), DebugBundleLinuxAssets(TargetPlatform.linux_arm64),
ReleaseBundleLinuxAssets(), ProfileBundleLinuxAssets(TargetPlatform.linux_x64),
ProfileBundleLinuxAssets(TargetPlatform.linux_arm64),
ReleaseBundleLinuxAssets(TargetPlatform.linux_x64),
ReleaseBundleLinuxAssets(TargetPlatform.linux_arm64),
// Web targets // Web targets
WebServiceWorker(), WebServiceWorker(),
ReleaseAndroidApplication(), ReleaseAndroidApplication(),
......
...@@ -35,7 +35,10 @@ class BuildCommand extends FlutterCommand { ...@@ -35,7 +35,10 @@ class BuildCommand extends FlutterCommand {
addSubcommand(BuildBundleCommand(verboseHelp: verboseHelp)); addSubcommand(BuildBundleCommand(verboseHelp: verboseHelp));
addSubcommand(BuildWebCommand(verboseHelp: verboseHelp)); addSubcommand(BuildWebCommand(verboseHelp: verboseHelp));
addSubcommand(BuildMacosCommand(verboseHelp: verboseHelp)); addSubcommand(BuildMacosCommand(verboseHelp: verboseHelp));
addSubcommand(BuildLinuxCommand(verboseHelp: verboseHelp)); addSubcommand(BuildLinuxCommand(
operatingSystemUtils: globals.os,
verboseHelp: verboseHelp
));
addSubcommand(BuildWindowsCommand(verboseHelp: verboseHelp)); addSubcommand(BuildWindowsCommand(verboseHelp: verboseHelp));
addSubcommand(BuildFuchsiaCommand(verboseHelp: verboseHelp)); addSubcommand(BuildFuchsiaCommand(verboseHelp: verboseHelp));
} }
......
...@@ -34,6 +34,7 @@ class BuildBundleCommand extends BuildSubCommand { ...@@ -34,6 +34,7 @@ class BuildBundleCommand extends BuildSubCommand {
'ios', 'ios',
'darwin-x64', 'darwin-x64',
'linux-x64', 'linux-x64',
'linux-arm64',
'windows-x64', 'windows-x64',
], ],
) )
......
...@@ -4,8 +4,11 @@ ...@@ -4,8 +4,11 @@
// @dart = 2.8 // @dart = 2.8
import 'package:meta/meta.dart';
import '../base/analyze_size.dart'; import '../base/analyze_size.dart';
import '../base/common.dart'; import '../base/common.dart';
import '../base/os.dart';
import '../build_info.dart'; import '../build_info.dart';
import '../cache.dart'; import '../cache.dart';
import '../features.dart'; import '../features.dart';
...@@ -17,10 +20,29 @@ import 'build.dart'; ...@@ -17,10 +20,29 @@ import 'build.dart';
/// A command to build a linux desktop target through a build shell script. /// A command to build a linux desktop target through a build shell script.
class BuildLinuxCommand extends BuildSubCommand { class BuildLinuxCommand extends BuildSubCommand {
BuildLinuxCommand({ bool verboseHelp = false }) { BuildLinuxCommand({
@required OperatingSystemUtils operatingSystemUtils,
bool verboseHelp = false,
}) : _operatingSystemUtils = operatingSystemUtils {
addCommonDesktopBuildOptions(verboseHelp: verboseHelp); addCommonDesktopBuildOptions(verboseHelp: verboseHelp);
final String defaultTargetPlatform =
(_operatingSystemUtils.hostPlatform == HostPlatform.linux_arm64) ?
'linux-arm64' : 'linux-x64';
argParser.addOption('target-platform',
defaultsTo: defaultTargetPlatform,
allowed: <String>['linux-arm64', 'linux-x64'],
help: 'The target platform for which the app is compiled.',
);
argParser.addOption('target-sysroot',
defaultsTo: '/',
help: 'The root filesystem path of target platform for which '
'the app is compiled. This option is valid only '
'if the current host and target architectures are different.',
);
} }
final OperatingSystemUtils _operatingSystemUtils;
@override @override
final String name = 'linux'; final String name = 'linux';
...@@ -39,12 +61,29 @@ class BuildLinuxCommand extends BuildSubCommand { ...@@ -39,12 +61,29 @@ class BuildLinuxCommand extends BuildSubCommand {
Future<FlutterCommandResult> runCommand() async { Future<FlutterCommandResult> runCommand() async {
final BuildInfo buildInfo = await getBuildInfo(); final BuildInfo buildInfo = await getBuildInfo();
final FlutterProject flutterProject = FlutterProject.current(); final FlutterProject flutterProject = FlutterProject.current();
final TargetPlatform targetPlatform =
getTargetPlatformForName(stringArg('target-platform'));
final bool needCrossBuild =
getNameForHostPlatformArch(_operatingSystemUtils.hostPlatform)
!= getNameForTargetPlatformArch(targetPlatform);
if (!featureFlags.isLinuxEnabled) { if (!featureFlags.isLinuxEnabled) {
throwToolExit('"build linux" is not currently supported.'); throwToolExit('"build linux" is not currently supported.');
} }
if (!globals.platform.isLinux) { if (!globals.platform.isLinux) {
throwToolExit('"build linux" only supported on Linux hosts.'); throwToolExit('"build linux" only supported on Linux hosts.');
} }
// Cross-building for x64 targets on arm64 hosts is not supported.
if (_operatingSystemUtils.hostPlatform != HostPlatform.linux_x64 &&
targetPlatform != TargetPlatform.linux_arm64) {
throwToolExit('"cross-building" only supported on Linux x64 hosts.');
}
// TODO(fujino): https://github.com/flutter/flutter/issues/74929
if (_operatingSystemUtils.hostPlatform == HostPlatform.linux_x64 &&
targetPlatform == TargetPlatform.linux_arm64) {
throwToolExit(
'Cross-build from Linux x64 host to Linux arm64 target is not currently supported.');
}
displayNullSafetyMode(buildInfo); displayNullSafetyMode(buildInfo);
await buildLinux( await buildLinux(
flutterProject.linux, flutterProject.linux,
...@@ -55,6 +94,9 @@ class BuildLinuxCommand extends BuildSubCommand { ...@@ -55,6 +94,9 @@ class BuildLinuxCommand extends BuildSubCommand {
logger: globals.logger, logger: globals.logger,
flutterUsage: globals.flutterUsage, flutterUsage: globals.flutterUsage,
), ),
needCrossBuild: needCrossBuild,
targetPlatform: targetPlatform,
targetSysroot: stringArg('target-sysroot'),
); );
return FlutterCommandResult.success(); return FlutterCommandResult.success();
} }
......
...@@ -105,6 +105,7 @@ Future<T> runInContext<T>( ...@@ -105,6 +105,7 @@ Future<T> runInContext<T>(
AndroidWorkflow: () => AndroidWorkflow( AndroidWorkflow: () => AndroidWorkflow(
androidSdk: globals.androidSdk, androidSdk: globals.androidSdk,
featureFlags: featureFlags, featureFlags: featureFlags,
operatingSystemUtils: globals.os,
), ),
ApplicationPackageFactory: () => ApplicationPackageFactory( ApplicationPackageFactory: () => ApplicationPackageFactory(
userMessages: globals.userMessages, userMessages: globals.userMessages,
...@@ -117,6 +118,7 @@ Future<T> runInContext<T>( ...@@ -117,6 +118,7 @@ Future<T> runInContext<T>(
fileSystem: globals.fs, fileSystem: globals.fs,
cache: globals.cache, cache: globals.cache,
platform: globals.platform, platform: globals.platform,
operatingSystemUtils: globals.os,
), ),
AssetBundleFactory: () { AssetBundleFactory: () {
return AssetBundleFactory.defaultInstance( return AssetBundleFactory.defaultInstance(
......
...@@ -394,6 +394,7 @@ class FlutterDeviceManager extends DeviceManager { ...@@ -394,6 +394,7 @@ class FlutterDeviceManager extends DeviceManager {
config: config, config: config,
logger: logger, logger: logger,
artifacts: artifacts, artifacts: artifacts,
operatingSystemUtils: operatingSystemUtils,
), ),
MacOSDevices( MacOSDevices(
processManager: processManager, processManager: processManager,
......
...@@ -33,6 +33,9 @@ Future<void> buildLinux( ...@@ -33,6 +33,9 @@ Future<void> buildLinux(
BuildInfo buildInfo, { BuildInfo buildInfo, {
String target = 'lib/main.dart', String target = 'lib/main.dart',
SizeAnalyzer sizeAnalyzer, SizeAnalyzer sizeAnalyzer,
bool needCrossBuild = false,
TargetPlatform targetPlatform = TargetPlatform.linux_x64,
String targetSysroot = '/',
}) async { }) async {
if (!linuxProject.cmakeFile.existsSync()) { if (!linuxProject.cmakeFile.existsSync()) {
throwToolExit('No Linux desktop project configured. See ' throwToolExit('No Linux desktop project configured. See '
...@@ -68,14 +71,16 @@ Future<void> buildLinux( ...@@ -68,14 +71,16 @@ Future<void> buildLinux(
); );
try { try {
final String buildModeName = getNameForBuildMode(buildInfo.mode ?? BuildMode.release); final String buildModeName = getNameForBuildMode(buildInfo.mode ?? BuildMode.release);
final Directory buildDirectory = globals.fs.directory(getLinuxBuildDirectory()).childDirectory(buildModeName); final Directory buildDirectory =
await _runCmake(buildModeName, linuxProject.cmakeFile.parent, buildDirectory); globals.fs.directory(getLinuxBuildDirectory(targetPlatform)).childDirectory(buildModeName);
await _runCmake(buildModeName, linuxProject.cmakeFile.parent, buildDirectory,
needCrossBuild, targetPlatform, targetSysroot);
await _runBuild(buildDirectory); await _runBuild(buildDirectory);
} finally { } finally {
status.cancel(); status.cancel();
} }
if (buildInfo.codeSizeDirectory != null && sizeAnalyzer != null) { if (buildInfo.codeSizeDirectory != null && sizeAnalyzer != null) {
final String arch = getNameForTargetPlatform(TargetPlatform.linux_x64); final String arch = getNameForTargetPlatform(targetPlatform);
final File codeSizeFile = globals.fs.directory(buildInfo.codeSizeDirectory) final File codeSizeFile = globals.fs.directory(buildInfo.codeSizeDirectory)
.childFile('snapshot.$arch.json'); .childFile('snapshot.$arch.json');
final File precompilerTrace = globals.fs.directory(buildInfo.codeSizeDirectory) final File precompilerTrace = globals.fs.directory(buildInfo.codeSizeDirectory)
...@@ -84,7 +89,7 @@ Future<void> buildLinux( ...@@ -84,7 +89,7 @@ Future<void> buildLinux(
aotSnapshot: codeSizeFile, aotSnapshot: codeSizeFile,
// This analysis is only supported for release builds. // This analysis is only supported for release builds.
outputDirectory: globals.fs.directory( outputDirectory: globals.fs.directory(
globals.fs.path.join(getLinuxBuildDirectory(), 'release', 'bundle'), globals.fs.path.join(getLinuxBuildDirectory(targetPlatform), 'release', 'bundle'),
), ),
precompilerTrace: precompilerTrace, precompilerTrace: precompilerTrace,
type: 'linux', type: 'linux',
...@@ -109,12 +114,15 @@ Future<void> buildLinux( ...@@ -109,12 +114,15 @@ Future<void> buildLinux(
} }
} }
Future<void> _runCmake(String buildModeName, Directory sourceDir, Directory buildDir) async { Future<void> _runCmake(String buildModeName, Directory sourceDir, Directory buildDir,
bool needCrossBuild, TargetPlatform targetPlatform, String targetSysroot) async {
final Stopwatch sw = Stopwatch()..start(); final Stopwatch sw = Stopwatch()..start();
await buildDir.create(recursive: true); await buildDir.create(recursive: true);
final String buildFlag = toTitleCase(buildModeName); final String buildFlag = toTitleCase(buildModeName);
final bool needCrossBuildOptionsForArm64 = needCrossBuild
&& targetPlatform == TargetPlatform.linux_arm64;
int result; int result;
try { try {
result = await globals.processUtils.stream( result = await globals.processUtils.stream(
...@@ -123,6 +131,15 @@ Future<void> _runCmake(String buildModeName, Directory sourceDir, Directory buil ...@@ -123,6 +131,15 @@ Future<void> _runCmake(String buildModeName, Directory sourceDir, Directory buil
'-G', '-G',
'Ninja', 'Ninja',
'-DCMAKE_BUILD_TYPE=$buildFlag', '-DCMAKE_BUILD_TYPE=$buildFlag',
'-DFLUTTER_TARGET_PLATFORM=' + getNameForTargetPlatform(targetPlatform),
// Support cross-building for arm64 targets on x64 hosts.
// (Cross-building for x64 on arm64 hosts isn't supported now.)
if (needCrossBuild)
'-DFLUTTER_TARGET_PLATFORM_SYSROOT=$targetSysroot',
if (needCrossBuildOptionsForArm64)
'-DCMAKE_C_COMPILER_TARGET=aarch64-linux-gnu',
if (needCrossBuildOptionsForArm64)
'-DCMAKE_CXX_COMPILER_TARGET=aarch64-linux-gnu',
sourceDir.path, sourceDir.path,
], ],
workingDirectory: buildDir.path, workingDirectory: buildDir.path,
......
...@@ -27,7 +27,8 @@ class LinuxDevice extends DesktopDevice { ...@@ -27,7 +27,8 @@ class LinuxDevice extends DesktopDevice {
@required Logger logger, @required Logger logger,
@required FileSystem fileSystem, @required FileSystem fileSystem,
@required OperatingSystemUtils operatingSystemUtils, @required OperatingSystemUtils operatingSystemUtils,
}) : super( }) : _operatingSystemUtils = operatingSystemUtils,
super(
'linux', 'linux',
platformType: PlatformType.linux, platformType: PlatformType.linux,
ephemeral: false, ephemeral: false,
...@@ -37,6 +38,10 @@ class LinuxDevice extends DesktopDevice { ...@@ -37,6 +38,10 @@ class LinuxDevice extends DesktopDevice {
operatingSystemUtils: operatingSystemUtils, operatingSystemUtils: operatingSystemUtils,
); );
final OperatingSystemUtils _operatingSystemUtils;
TargetPlatform _targetPlatform;
@override @override
bool isSupported() => true; bool isSupported() => true;
...@@ -44,7 +49,17 @@ class LinuxDevice extends DesktopDevice { ...@@ -44,7 +49,17 @@ class LinuxDevice extends DesktopDevice {
String get name => 'Linux'; String get name => 'Linux';
@override @override
Future<TargetPlatform> get targetPlatform async => TargetPlatform.linux_x64; Future<TargetPlatform> get targetPlatform async {
if (_targetPlatform == null) {
if (_operatingSystemUtils.hostPlatform == HostPlatform.linux_x64) {
_targetPlatform = TargetPlatform.linux_x64;
} else {
_targetPlatform = TargetPlatform.linux_arm64;
}
}
return _targetPlatform;
}
@override @override
bool isSupportedForProject(FlutterProject flutterProject) { bool isSupportedForProject(FlutterProject flutterProject) {
...@@ -61,6 +76,7 @@ class LinuxDevice extends DesktopDevice { ...@@ -61,6 +76,7 @@ class LinuxDevice extends DesktopDevice {
FlutterProject.current().linux, FlutterProject.current().linux,
buildInfo, buildInfo,
target: mainPath, target: mainPath,
targetPlatform: _targetPlatform,
); );
} }
......
...@@ -56,9 +56,20 @@ class CmakeCustomCommandMigration extends ProjectMigrator { ...@@ -56,9 +56,20 @@ class CmakeCustomCommandMigration extends ProjectMigrator {
final String addCustomCommandReplacement = '$addCustomCommandOriginal\n VERBATIM'; final String addCustomCommandReplacement = '$addCustomCommandOriginal\n VERBATIM';
newProjectContents = newProjectContents.replaceAll(addCustomCommandOriginal, addCustomCommandReplacement); newProjectContents = newProjectContents.replaceAll(addCustomCommandOriginal, addCustomCommandReplacement);
} }
// CMake's add_custom_command() should add FLUTTER_TARGET_PLATFORM to support multi-architecture.
// However, developers would get the following warning every time if we do nothing.
// ------------------------------
// CMake Warning:
// Manually-specified variables were not used by the project:
// FLUTTER_TARGET_PLATFORM
// ------------------------------
if (addCustomCommandOriginal?.contains('linux-x64') == true) {
newProjectContents = newProjectContents.replaceAll('linux-x64', r'${FLUTTER_TARGET_PLATFORM}');
}
} }
if (originalProjectContents != newProjectContents) { if (originalProjectContents != newProjectContents) {
logger.printStatus('add_custom_command() missing VERBATIM, updating.'); logger.printStatus('add_custom_command() missing VERBATIM or FLUTTER_TARGET_PLATFORM, updating.');
_cmakeFile.writeAsStringSync(newProjectContents.toString()); _cmakeFile.writeAsStringSync(newProjectContents.toString());
} }
return true; return true;
......
...@@ -1410,6 +1410,7 @@ DevelopmentArtifact _artifactFromTargetPlatform(TargetPlatform targetPlatform) { ...@@ -1410,6 +1410,7 @@ DevelopmentArtifact _artifactFromTargetPlatform(TargetPlatform targetPlatform) {
} }
return null; return null;
case TargetPlatform.linux_x64: case TargetPlatform.linux_x64:
case TargetPlatform.linux_arm64:
if (featureFlags.isLinuxEnabled) { if (featureFlags.isLinuxEnabled) {
return DevelopmentArtifact.linux; return DevelopmentArtifact.linux;
} }
......
...@@ -15,6 +15,7 @@ import '../base/config.dart'; ...@@ -15,6 +15,7 @@ import '../base/config.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
import '../base/io.dart'; import '../base/io.dart';
import '../base/logger.dart'; import '../base/logger.dart';
import '../base/os.dart';
import '../build_info.dart'; import '../build_info.dart';
import '../bundle.dart'; import '../bundle.dart';
import '../convert.dart'; import '../convert.dart';
...@@ -55,12 +56,14 @@ class FlutterTesterDevice extends Device { ...@@ -55,12 +56,14 @@ class FlutterTesterDevice extends Device {
@required String buildDirectory, @required String buildDirectory,
@required FileSystem fileSystem, @required FileSystem fileSystem,
@required Artifacts artifacts, @required Artifacts artifacts,
@required OperatingSystemUtils operatingSystemUtils,
}) : _processManager = processManager, }) : _processManager = processManager,
_flutterVersion = flutterVersion, _flutterVersion = flutterVersion,
_logger = logger, _logger = logger,
_buildDirectory = buildDirectory, _buildDirectory = buildDirectory,
_fileSystem = fileSystem, _fileSystem = fileSystem,
_artifacts = artifacts, _artifacts = artifacts,
_operatingSystemUtils = operatingSystemUtils,
super( super(
deviceId, deviceId,
platformType: null, platformType: null,
...@@ -74,6 +77,7 @@ class FlutterTesterDevice extends Device { ...@@ -74,6 +77,7 @@ class FlutterTesterDevice extends Device {
final String _buildDirectory; final String _buildDirectory;
final FileSystem _fileSystem; final FileSystem _fileSystem;
final Artifacts _artifacts; final Artifacts _artifacts;
final OperatingSystemUtils _operatingSystemUtils;
Process _process; Process _process;
final DevicePortForwarder _portForwarder = const NoOpDevicePortForwarder(); final DevicePortForwarder _portForwarder = const NoOpDevicePortForwarder();
...@@ -162,7 +166,7 @@ class FlutterTesterDevice extends Device { ...@@ -162,7 +166,7 @@ class FlutterTesterDevice extends Device {
mainPath: mainPath, mainPath: mainPath,
applicationKernelFilePath: applicationKernelFilePath, applicationKernelFilePath: applicationKernelFilePath,
trackWidgetCreation: buildInfo.trackWidgetCreation, trackWidgetCreation: buildInfo.trackWidgetCreation,
platform: getTargetPlatformForName(getNameForHostPlatform(getCurrentHostPlatform())), platform: getTargetPlatformForName(getNameForHostPlatform(_operatingSystemUtils.hostPlatform)),
treeShakeIcons: buildInfo.treeShakeIcons, treeShakeIcons: buildInfo.treeShakeIcons,
); );
...@@ -270,6 +274,7 @@ class FlutterTesterDevices extends PollingDeviceDiscovery { ...@@ -270,6 +274,7 @@ class FlutterTesterDevices extends PollingDeviceDiscovery {
@required Logger logger, @required Logger logger,
@required FlutterVersion flutterVersion, @required FlutterVersion flutterVersion,
@required Config config, @required Config config,
@required OperatingSystemUtils operatingSystemUtils,
}) : _testerDevice = FlutterTesterDevice( }) : _testerDevice = FlutterTesterDevice(
kTesterDeviceId, kTesterDeviceId,
fileSystem: fileSystem, fileSystem: fileSystem,
...@@ -278,6 +283,7 @@ class FlutterTesterDevices extends PollingDeviceDiscovery { ...@@ -278,6 +283,7 @@ class FlutterTesterDevices extends PollingDeviceDiscovery {
buildDirectory: getBuildDirectory(config, fileSystem), buildDirectory: getBuildDirectory(config, fileSystem),
logger: logger, logger: logger,
flutterVersion: flutterVersion, flutterVersion: flutterVersion,
operatingSystemUtils: operatingSystemUtils,
), ),
super('Flutter tester'); super('Flutter tester');
......
...@@ -8,6 +8,16 @@ cmake_policy(SET CMP0063 NEW) ...@@ -8,6 +8,16 @@ cmake_policy(SET CMP0063 NEW)
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
# Root filesystem for cross-building.
if(FLUTTER_TARGET_PLATFORM_SYSROOT)
set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
endif()
# Configure build options. # Configure build options.
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE "Debug" CACHE set(CMAKE_BUILD_TYPE "Debug" CACHE
......
...@@ -82,7 +82,7 @@ add_custom_command( ...@@ -82,7 +82,7 @@ add_custom_command(
COMMAND ${CMAKE_COMMAND} -E env COMMAND ${CMAKE_COMMAND} -E env
${FLUTTER_TOOL_ENVIRONMENT} ${FLUTTER_TOOL_ENVIRONMENT}
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
linux-x64 ${CMAKE_BUILD_TYPE} ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
VERBATIM VERBATIM
) )
add_custom_target(flutter_assemble DEPENDS add_custom_target(flutter_assemble DEPENDS
......
...@@ -118,6 +118,7 @@ void main() { ...@@ -118,6 +118,7 @@ void main() {
cache: globals.cache, cache: globals.cache,
fileSystem: fileSystem, fileSystem: fileSystem,
platform: platform, platform: platform,
operatingSystemUtils: FakeOperatingSystemUtils(),
); );
Cache.flutterRoot = Cache.defaultFlutterRoot( Cache.flutterRoot = Cache.defaultFlutterRoot(
fileSystem: fileSystem, fileSystem: fileSystem,
......
...@@ -15,6 +15,7 @@ import 'package:flutter_tools/src/device.dart'; ...@@ -15,6 +15,7 @@ import 'package:flutter_tools/src/device.dart';
import 'package:test/fake.dart'; import 'package:test/fake.dart';
import '../../src/common.dart'; import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/fake_process_manager.dart'; import '../../src/fake_process_manager.dart';
import '../../src/testbed.dart'; import '../../src/testbed.dart';
...@@ -25,6 +26,7 @@ void main() { ...@@ -25,6 +26,7 @@ void main() {
androidWorkflow = AndroidWorkflow( androidWorkflow = AndroidWorkflow(
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
featureFlags: TestFeatureFlags(), featureFlags: TestFeatureFlags(),
operatingSystemUtils: FakeOperatingSystemUtils(),
); );
}); });
...@@ -35,6 +37,7 @@ void main() { ...@@ -35,6 +37,7 @@ void main() {
androidWorkflow: AndroidWorkflow( androidWorkflow: AndroidWorkflow(
androidSdk: FakeAndroidSdk(null), androidSdk: FakeAndroidSdk(null),
featureFlags: TestFeatureFlags(), featureFlags: TestFeatureFlags(),
operatingSystemUtils: FakeOperatingSystemUtils(),
), ),
processManager: FakeProcessManager.list(<FakeCommand>[]), processManager: FakeProcessManager.list(<FakeCommand>[]),
fileSystem: MemoryFileSystem.test(), fileSystem: MemoryFileSystem.test(),
...@@ -55,6 +58,7 @@ void main() { ...@@ -55,6 +58,7 @@ void main() {
androidWorkflow: AndroidWorkflow( androidWorkflow: AndroidWorkflow(
androidSdk: FakeAndroidSdk('adb'), androidSdk: FakeAndroidSdk('adb'),
featureFlags: TestFeatureFlags(), featureFlags: TestFeatureFlags(),
operatingSystemUtils: FakeOperatingSystemUtils(),
), ),
processManager: fakeProcessManager, processManager: fakeProcessManager,
fileSystem: MemoryFileSystem.test(), fileSystem: MemoryFileSystem.test(),
...@@ -74,6 +78,7 @@ void main() { ...@@ -74,6 +78,7 @@ void main() {
androidWorkflow: AndroidWorkflow( androidWorkflow: AndroidWorkflow(
androidSdk: FakeAndroidSdk(null), androidSdk: FakeAndroidSdk(null),
featureFlags: TestFeatureFlags(), featureFlags: TestFeatureFlags(),
operatingSystemUtils: FakeOperatingSystemUtils(),
), ),
processManager: FakeProcessManager.list(<FakeCommand>[]), processManager: FakeProcessManager.list(<FakeCommand>[]),
fileSystem: MemoryFileSystem.test(), fileSystem: MemoryFileSystem.test(),
...@@ -115,6 +120,7 @@ void main() { ...@@ -115,6 +120,7 @@ void main() {
featureFlags: TestFeatureFlags( featureFlags: TestFeatureFlags(
isAndroidEnabled: false, isAndroidEnabled: false,
), ),
operatingSystemUtils: FakeOperatingSystemUtils(),
), ),
processManager: FakeProcessManager.any(), processManager: FakeProcessManager.any(),
fileSystem: MemoryFileSystem.test(), fileSystem: MemoryFileSystem.test(),
......
...@@ -9,9 +9,11 @@ import 'package:flutter_tools/src/android/android_sdk.dart'; ...@@ -9,9 +9,11 @@ import 'package:flutter_tools/src/android/android_sdk.dart';
import 'package:flutter_tools/src/android/android_workflow.dart'; import 'package:flutter_tools/src/android/android_workflow.dart';
import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/user_messages.dart'; import 'package:flutter_tools/src/base/user_messages.dart';
import 'package:flutter_tools/src/base/version.dart'; import 'package:flutter_tools/src/base/version.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/doctor.dart'; import 'package:flutter_tools/src/doctor.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
...@@ -49,6 +51,7 @@ void main() { ...@@ -49,6 +51,7 @@ void main() {
final AndroidWorkflow androidWorkflow = AndroidWorkflow( final AndroidWorkflow androidWorkflow = AndroidWorkflow(
featureFlags: TestFeatureFlags(), featureFlags: TestFeatureFlags(),
androidSdk: null, androidSdk: null,
operatingSystemUtils: FakeOperatingSystemUtils(),
); );
expect(androidWorkflow.canLaunchDevices, false); expect(androidWorkflow.canLaunchDevices, false);
...@@ -62,6 +65,7 @@ void main() { ...@@ -62,6 +65,7 @@ void main() {
final AndroidWorkflow androidWorkflow = AndroidWorkflow( final AndroidWorkflow androidWorkflow = AndroidWorkflow(
featureFlags: TestFeatureFlags(), featureFlags: TestFeatureFlags(),
androidSdk: androidSdk, androidSdk: androidSdk,
operatingSystemUtils: FakeOperatingSystemUtils(),
); );
expect(androidWorkflow.canLaunchDevices, false); expect(androidWorkflow.canLaunchDevices, false);
...@@ -69,6 +73,18 @@ void main() { ...@@ -69,6 +73,18 @@ void main() {
expect(androidWorkflow.canListEmulators, false); expect(androidWorkflow.canListEmulators, false);
}); });
// Android Studio is not currently supported on Linux Arm64 hosts.
testWithoutContext('Not supported AndroidStudio on Linux Arm Hosts', () {
final MockAndroidSdk androidSdk = MockAndroidSdk();
when(androidSdk.adbPath).thenReturn(null);
final AndroidWorkflow androidWorkflow = AndroidWorkflow(
featureFlags: TestFeatureFlags(),
androidSdk: androidSdk,
operatingSystemUtils: CustomFakeOperatingSystemUtils(hostPlatform: HostPlatform.linux_arm64),
);
expect(androidWorkflow.appliesToHostPlatform, false);
});
testWithoutContext('licensesAccepted returns LicensesAccepted.unknown if cannot find sdkmanager', () async { testWithoutContext('licensesAccepted returns LicensesAccepted.unknown if cannot find sdkmanager', () async {
processManager.canRunSucceeds = false; processManager.canRunSucceeds = false;
...@@ -394,3 +410,17 @@ void main() { ...@@ -394,3 +410,17 @@ void main() {
); );
}); });
} }
class CustomFakeOperatingSystemUtils extends Fake implements OperatingSystemUtils {
CustomFakeOperatingSystemUtils({
HostPlatform hostPlatform = HostPlatform.linux_x64
}) : _hostPlatform = hostPlatform;
final HostPlatform _hostPlatform;
@override
String get name => 'Linux';
@override
HostPlatform get hostPlatform => _hostPlatform;
}
...@@ -8,11 +8,9 @@ import 'package:file/memory.dart'; ...@@ -8,11 +8,9 @@ import 'package:file/memory.dart';
import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
import 'package:mockito/mockito.dart';
import '../src/common.dart'; import '../src/common.dart';
import '../src/context.dart'; import '../src/context.dart';
...@@ -34,12 +32,13 @@ void main() { ...@@ -34,12 +32,13 @@ void main() {
fileSystem: fileSystem, fileSystem: fileSystem,
platform: platform, platform: platform,
logger: BufferLogger.test(), logger: BufferLogger.test(),
osUtils: MockOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
artifacts = CachedArtifacts( artifacts = CachedArtifacts(
fileSystem: fileSystem, fileSystem: fileSystem,
cache: cache, cache: cache,
platform: platform, platform: platform,
operatingSystemUtils: FakeOperatingSystemUtils(),
); );
}); });
...@@ -114,6 +113,10 @@ void main() { ...@@ -114,6 +113,10 @@ void main() {
artifacts.getArtifactPath(Artifact.flutterTester), artifacts.getArtifactPath(Artifact.flutterTester),
fileSystem.path.join('root', 'bin', 'cache', 'artifacts', 'engine', 'linux-x64', 'flutter_tester'), fileSystem.path.join('root', 'bin', 'cache', 'artifacts', 'engine', 'linux-x64', 'flutter_tester'),
); );
expect(
artifacts.getArtifactPath(Artifact.flutterTester, platform: TargetPlatform.linux_arm64),
fileSystem.path.join('root', 'bin', 'cache', 'artifacts', 'engine', 'linux-arm64', 'flutter_tester'),
);
}); });
testWithoutContext('precompiled web artifact paths are correct', () { testWithoutContext('precompiled web artifact paths are correct', () {
...@@ -183,7 +186,7 @@ void main() { ...@@ -183,7 +186,7 @@ void main() {
fileSystem: fileSystem, fileSystem: fileSystem,
platform: platform, platform: platform,
logger: BufferLogger.test(), logger: BufferLogger.test(),
osUtils: MockOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
artifacts = LocalEngineArtifacts( artifacts = LocalEngineArtifacts(
fileSystem.path.join(fileSystem.currentDirectory.path, 'out', 'android_debug_unopt'), fileSystem.path.join(fileSystem.currentDirectory.path, 'out', 'android_debug_unopt'),
...@@ -192,6 +195,7 @@ void main() { ...@@ -192,6 +195,7 @@ void main() {
fileSystem: fileSystem, fileSystem: fileSystem,
platform: platform, platform: platform,
processManager: FakeProcessManager.any(), processManager: FakeProcessManager.any(),
operatingSystemUtils: FakeOperatingSystemUtils(),
); );
}); });
...@@ -302,6 +306,7 @@ void main() { ...@@ -302,6 +306,7 @@ void main() {
fileSystem: fileSystem, fileSystem: fileSystem,
platform: FakePlatform(operatingSystem: 'windows'), platform: FakePlatform(operatingSystem: 'windows'),
processManager: FakeProcessManager.any(), processManager: FakeProcessManager.any(),
operatingSystemUtils: FakeOperatingSystemUtils(),
); );
expect(artifacts.getArtifactPath(Artifact.engineDartBinary), contains('.exe')); expect(artifacts.getArtifactPath(Artifact.engineDartBinary), contains('.exe'));
...@@ -312,5 +317,3 @@ void main() { ...@@ -312,5 +317,3 @@ void main() {
}); });
}); });
} }
class MockOperatingSystemUtils extends Mock implements OperatingSystemUtils {}
...@@ -151,6 +151,16 @@ void main() { ...@@ -151,6 +151,16 @@ void main() {
group('host platform', () { group('host platform', () {
testWithoutContext('unknown defaults to Linux', () async { testWithoutContext('unknown defaults to Linux', () async {
fakeProcessManager.addCommand(
const FakeCommand(
command: <String>[
'uname',
'-m',
],
stdout: 'x86_64',
),
);
final OperatingSystemUtils utils = final OperatingSystemUtils utils =
createOSUtils(FakePlatform(operatingSystem: 'fuchsia')); createOSUtils(FakePlatform(operatingSystem: 'fuchsia'));
expect(utils.hostPlatform, HostPlatform.linux_x64); expect(utils.hostPlatform, HostPlatform.linux_x64);
...@@ -162,12 +172,38 @@ void main() { ...@@ -162,12 +172,38 @@ void main() {
expect(utils.hostPlatform, HostPlatform.windows_x64); expect(utils.hostPlatform, HostPlatform.windows_x64);
}); });
testWithoutContext('Linux', () async { testWithoutContext('Linux x64', () async {
fakeProcessManager.addCommand(
const FakeCommand(
command: <String>[
'uname',
'-m',
],
stdout: 'x86_64',
),
);
final OperatingSystemUtils utils = final OperatingSystemUtils utils =
createOSUtils(FakePlatform(operatingSystem: 'linux')); createOSUtils(FakePlatform(operatingSystem: 'linux'));
expect(utils.hostPlatform, HostPlatform.linux_x64); expect(utils.hostPlatform, HostPlatform.linux_x64);
}); });
testWithoutContext('Linux ARM', () async {
fakeProcessManager.addCommand(
const FakeCommand(
command: <String>[
'uname',
'-m',
],
stdout: 'aarch64',
),
);
final OperatingSystemUtils utils =
createOSUtils(FakePlatform(operatingSystem: 'linux'));
expect(utils.hostPlatform, HostPlatform.linux_arm64);
});
testWithoutContext('macOS ARM', () async { testWithoutContext('macOS ARM', () async {
fakeProcessManager.addCommands( fakeProcessManager.addCommands(
<FakeCommand>[ <FakeCommand>[
......
...@@ -20,7 +20,7 @@ import '../../../src/common.dart'; ...@@ -20,7 +20,7 @@ import '../../../src/common.dart';
import '../../../src/context.dart'; import '../../../src/context.dart';
void main() { void main() {
testWithoutContext('Copies files to correct cache directory, excluding unrelated code', () async { testWithoutContext('Copies files to correct cache directory, excluding unrelated code on a x64 host', () async {
final FileSystem fileSystem = MemoryFileSystem.test(); final FileSystem fileSystem = MemoryFileSystem.test();
final Artifacts artifacts = Artifacts.test(); final Artifacts artifacts = Artifacts.test();
setUpCacheDirectory(fileSystem, artifacts); setUpCacheDirectory(fileSystem, artifacts);
...@@ -37,16 +37,57 @@ void main() { ...@@ -37,16 +37,57 @@ void main() {
); );
testEnvironment.buildDir.createSync(recursive: true); testEnvironment.buildDir.createSync(recursive: true);
await const UnpackLinux().build(testEnvironment); await const UnpackLinux(TargetPlatform.linux_x64).build(testEnvironment);
expect(fileSystem.file('linux/flutter/ephemeral/libflutter_linux_gtk.so'), exists); expect(fileSystem.file('linux/flutter/ephemeral/libflutter_linux_gtk.so'), exists);
expect(fileSystem.file('linux/flutter/ephemeral/unrelated-stuff'), isNot(exists));
// Check if the target files are copied correctly.
final String headersPathForX64 = artifacts.getArtifactPath(Artifact.linuxHeaders, platform: TargetPlatform.linux_x64, mode: BuildMode.debug);
final String headersPathForArm64 = artifacts.getArtifactPath(Artifact.linuxHeaders, platform: TargetPlatform.linux_arm64, mode: BuildMode.debug);
expect(fileSystem.file('linux/flutter/ephemeral/$headersPathForX64/foo.h'), exists);
expect(fileSystem.file('linux/flutter/ephemeral/$headersPathForArm64/foo.h'), isNot(exists));
final String icuDataPathForX64 = artifacts.getArtifactPath(Artifact.icuData, platform: TargetPlatform.linux_x64);
final String icuDataPathForArm64 = artifacts.getArtifactPath(Artifact.icuData, platform: TargetPlatform.linux_arm64);
expect(fileSystem.file('linux/flutter/ephemeral/$icuDataPathForX64'), exists);
expect(fileSystem.file('linux/flutter/ephemeral/$icuDataPathForArm64'), isNot(exists));
});
// This test is basically the same logic as the above test.
// The difference is the target CPU architecture.
testWithoutContext('Copies files to correct cache directory, excluding unrelated code on a arm64 host', () async {
final FileSystem fileSystem = MemoryFileSystem.test();
final Artifacts artifacts = Artifacts.test();
setUpCacheDirectory(fileSystem, artifacts);
final Environment testEnvironment = Environment.test(
fileSystem.currentDirectory,
defines: <String, String>{
kBuildMode: 'debug',
},
artifacts: artifacts,
processManager: FakeProcessManager.any(),
fileSystem: fileSystem,
logger: BufferLogger.test(),
);
testEnvironment.buildDir.createSync(recursive: true);
final String headersPath = artifacts.getArtifactPath(Artifact.linuxHeaders, platform: TargetPlatform.linux_x64, mode: BuildMode.debug); await const UnpackLinux(TargetPlatform.linux_arm64).build(testEnvironment);
expect(fileSystem.file('linux/flutter/ephemeral/$headersPath/foo.h'), exists);
final String icuDataPath = artifacts.getArtifactPath(Artifact.icuData, platform: TargetPlatform.linux_x64); expect(fileSystem.file('linux/flutter/ephemeral/libflutter_linux_gtk.so'), exists);
expect(fileSystem.file('linux/flutter/ephemeral/$icuDataPath'), exists);
expect(fileSystem.file('linux/flutter/ephemeral/unrelated-stuff'), isNot(exists)); expect(fileSystem.file('linux/flutter/ephemeral/unrelated-stuff'), isNot(exists));
// Check if the target files are copied correctly.
final String headersPathForX64 = artifacts.getArtifactPath(Artifact.linuxHeaders, platform: TargetPlatform.linux_x64, mode: BuildMode.debug);
final String headersPathForArm64 = artifacts.getArtifactPath(Artifact.linuxHeaders, platform: TargetPlatform.linux_arm64, mode: BuildMode.debug);
expect(fileSystem.file('linux/flutter/ephemeral/$headersPathForX64/foo.h'), isNot(exists));
expect(fileSystem.file('linux/flutter/ephemeral/$headersPathForArm64/foo.h'), exists);
final String icuDataPathForX64 = artifacts.getArtifactPath(Artifact.icuData, platform: TargetPlatform.linux_x64);
final String icuDataPathForArm64 = artifacts.getArtifactPath(Artifact.icuData, platform: TargetPlatform.linux_arm64);
expect(fileSystem.file('linux/flutter/ephemeral/$icuDataPathForX64'), isNot(exists));
expect(fileSystem.file('linux/flutter/ephemeral/$icuDataPathForArm64'), exists);
}); });
// Only required for the test below that still depends on the context. // Only required for the test below that still depends on the context.
...@@ -85,7 +126,8 @@ void main() { ...@@ -85,7 +126,8 @@ void main() {
} }
)); ));
await const DebugBundleLinuxAssets().build(testEnvironment); await const DebugBundleLinuxAssets(TargetPlatform.linux_x64).build(testEnvironment);
final Directory output = testEnvironment.outputDir final Directory output = testEnvironment.outputDir
.childDirectory('flutter_assets'); .childDirectory('flutter_assets');
...@@ -103,6 +145,11 @@ void main() { ...@@ -103,6 +145,11 @@ void main() {
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
}); });
testWithoutContext('DebugBundleLinuxAssets\'s name depends on target platforms', () async {
expect(const DebugBundleLinuxAssets(TargetPlatform.linux_x64).name, 'debug_bundle_linux-x64_assets');
expect(const DebugBundleLinuxAssets(TargetPlatform.linux_arm64).name, 'debug_bundle_linux-arm64_assets');
});
testUsingContext('ProfileBundleLinuxAssets copies artifacts to out directory', () async { testUsingContext('ProfileBundleLinuxAssets copies artifacts to out directory', () async {
final Environment testEnvironment = Environment.test( final Environment testEnvironment = Environment.test(
fileSystem.currentDirectory, fileSystem.currentDirectory,
...@@ -121,7 +168,7 @@ void main() { ...@@ -121,7 +168,7 @@ void main() {
testEnvironment.buildDir.childFile('app.so').createSync(); testEnvironment.buildDir.childFile('app.so').createSync();
await const LinuxAotBundle(AotElfProfile(TargetPlatform.linux_x64)).build(testEnvironment); await const LinuxAotBundle(AotElfProfile(TargetPlatform.linux_x64)).build(testEnvironment);
await const ProfileBundleLinuxAssets().build(testEnvironment); await const ProfileBundleLinuxAssets(TargetPlatform.linux_x64).build(testEnvironment);
final Directory libDir = testEnvironment.outputDir final Directory libDir = testEnvironment.outputDir
.childDirectory('lib'); .childDirectory('lib');
final Directory assetsDir = testEnvironment.outputDir final Directory assetsDir = testEnvironment.outputDir
...@@ -137,6 +184,11 @@ void main() { ...@@ -137,6 +184,11 @@ void main() {
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
}); });
testWithoutContext('ProfileBundleLinuxAssets\'s name depends on target platforms', () async {
expect(const ProfileBundleLinuxAssets(TargetPlatform.linux_x64).name, 'profile_bundle_linux-x64_assets');
expect(const ProfileBundleLinuxAssets(TargetPlatform.linux_arm64).name, 'profile_bundle_linux-arm64_assets');
});
testUsingContext('ReleaseBundleLinuxAssets copies artifacts to out directory', () async { testUsingContext('ReleaseBundleLinuxAssets copies artifacts to out directory', () async {
final Environment testEnvironment = Environment.test( final Environment testEnvironment = Environment.test(
fileSystem.currentDirectory, fileSystem.currentDirectory,
...@@ -155,7 +207,7 @@ void main() { ...@@ -155,7 +207,7 @@ void main() {
testEnvironment.buildDir.childFile('app.so').createSync(); testEnvironment.buildDir.childFile('app.so').createSync();
await const LinuxAotBundle(AotElfRelease(TargetPlatform.linux_x64)).build(testEnvironment); await const LinuxAotBundle(AotElfRelease(TargetPlatform.linux_x64)).build(testEnvironment);
await const ReleaseBundleLinuxAssets().build(testEnvironment); await const ReleaseBundleLinuxAssets(TargetPlatform.linux_x64).build(testEnvironment);
final Directory libDir = testEnvironment.outputDir final Directory libDir = testEnvironment.outputDir
.childDirectory('lib'); .childDirectory('lib');
final Directory assetsDir = testEnvironment.outputDir final Directory assetsDir = testEnvironment.outputDir
...@@ -170,16 +222,28 @@ void main() { ...@@ -170,16 +222,28 @@ void main() {
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
}); });
testWithoutContext('ReleaseBundleLinuxAssets\'s name depends on target platforms', () async {
expect(const ReleaseBundleLinuxAssets(TargetPlatform.linux_x64).name, 'release_bundle_linux-x64_assets');
expect(const ReleaseBundleLinuxAssets(TargetPlatform.linux_arm64).name, 'release_bundle_linux-arm64_assets');
});
} }
void setUpCacheDirectory(FileSystem fileSystem, Artifacts artifacts) { void setUpCacheDirectory(FileSystem fileSystem, Artifacts artifacts) {
final String desktopPath = artifacts.getArtifactPath(Artifact.linuxDesktopPath, platform: TargetPlatform.linux_x64, mode: BuildMode.debug); final String desktopPathForX64 = artifacts.getArtifactPath(Artifact.linuxDesktopPath, platform: TargetPlatform.linux_x64, mode: BuildMode.debug);
fileSystem.file('$desktopPath/unrelated-stuff').createSync(recursive: true); final String desktopPathForArm64 = artifacts.getArtifactPath(Artifact.linuxDesktopPath, platform: TargetPlatform.linux_arm64, mode: BuildMode.debug);
fileSystem.file('$desktopPath/libflutter_linux_gtk.so').createSync(recursive: true); fileSystem.file('$desktopPathForX64/unrelated-stuff').createSync(recursive: true);
fileSystem.file('$desktopPathForX64/libflutter_linux_gtk.so').createSync(recursive: true);
final String headersPath = artifacts.getArtifactPath(Artifact.linuxHeaders, platform: TargetPlatform.linux_x64, mode: BuildMode.debug); fileSystem.file('$desktopPathForArm64/unrelated-stuff').createSync(recursive: true);
fileSystem.file('$headersPath/foo.h').createSync(recursive: true); fileSystem.file('$desktopPathForArm64/libflutter_linux_gtk.so').createSync(recursive: true);
final String headersPathForX64 = artifacts.getArtifactPath(Artifact.linuxHeaders, platform: TargetPlatform.linux_x64, mode: BuildMode.debug);
final String headersPathForArm64 = artifacts.getArtifactPath(Artifact.linuxHeaders, platform: TargetPlatform.linux_arm64, mode: BuildMode.debug);
fileSystem.file('$headersPathForX64/foo.h').createSync(recursive: true);
fileSystem.file('$headersPathForArm64/foo.h').createSync(recursive: true);
fileSystem.file(artifacts.getArtifactPath(Artifact.icuData, platform: TargetPlatform.linux_x64)).createSync(); fileSystem.file(artifacts.getArtifactPath(Artifact.icuData, platform: TargetPlatform.linux_x64)).createSync();
fileSystem.file(artifacts.getArtifactPath(Artifact.icuData, platform: TargetPlatform.linux_arm64)).createSync();
fileSystem.file('packages/flutter_tools/lib/src/build_system/targets/linux.dart').createSync(recursive: true); fileSystem.file('packages/flutter_tools/lib/src/build_system/targets/linux.dart').createSync(recursive: true);
} }
...@@ -23,7 +23,36 @@ import 'package:process/process.dart'; ...@@ -23,7 +23,36 @@ import 'package:process/process.dart';
import '../src/common.dart'; import '../src/common.dart';
import '../src/context.dart'; import '../src/context.dart';
const FakeCommand unameCommandForX64 = FakeCommand(
command: <String>[
'uname',
'-m',
],
stdout: 'x86_64',
);
const FakeCommand unameCommandForArm64 = FakeCommand(
command: <String>[
'uname',
'-m',
],
stdout: 'aarch64',
);
void main() { void main() {
FakeProcessManager fakeProcessManager;
setUp(() {
fakeProcessManager = FakeProcessManager.list(<FakeCommand>[]);
});
Cache createCache(Platform platform) {
return Cache.test(
platform: platform,
processManager: fakeProcessManager
);
}
group('Cache.checkLockAcquired', () { group('Cache.checkLockAcquired', () {
setUp(() { setUp(() {
Cache.enableLocking(); Cache.enableLocking();
...@@ -365,16 +394,28 @@ void main() { ...@@ -365,16 +394,28 @@ void main() {
expect(artifacts.developmentArtifact, DevelopmentArtifact.universal); expect(artifacts.developmentArtifact, DevelopmentArtifact.universal);
}); });
testWithoutContext('FontSubset artifacts on linux', () { testWithoutContext('FontSubset artifacts on x64 linux', () {
final Cache cache = Cache.test(); fakeProcessManager.addCommand(unameCommandForX64);
final Cache cache = createCache(FakePlatform(operatingSystem: 'linux'));
final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache, platform: FakePlatform(operatingSystem: 'linux')); final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache, platform: FakePlatform(operatingSystem: 'linux'));
cache.includeAllPlatforms = false; cache.includeAllPlatforms = false;
expect(artifacts.getBinaryDirs(), <List<String>>[<String>['linux-x64', 'linux-x64/font-subset.zip']]); expect(artifacts.getBinaryDirs(), <List<String>>[<String>['linux-x64', 'linux-x64/font-subset.zip']]);
}); });
testWithoutContext('FontSubset artifacts on arm64 linux', () {
fakeProcessManager.addCommand(unameCommandForArm64);
final Cache cache = createCache(FakePlatform(operatingSystem: 'linux'));
final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache, platform: FakePlatform(operatingSystem: 'linux'));
cache.includeAllPlatforms = false;
expect(artifacts.getBinaryDirs(), <List<String>>[<String>['linux-arm64', 'linux-arm64/font-subset.zip']]);
});
testWithoutContext('FontSubset artifacts on windows', () { testWithoutContext('FontSubset artifacts on windows', () {
final Cache cache = Cache.test(); final Cache cache = createCache(FakePlatform(operatingSystem: 'windows'));
final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache, platform: FakePlatform(operatingSystem: 'windows')); final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache, platform: FakePlatform(operatingSystem: 'windows'));
cache.includeAllPlatforms = false; cache.includeAllPlatforms = false;
...@@ -382,7 +423,24 @@ void main() { ...@@ -382,7 +423,24 @@ void main() {
}); });
testWithoutContext('FontSubset artifacts on macos', () { testWithoutContext('FontSubset artifacts on macos', () {
final Cache cache = Cache.test(); fakeProcessManager.addCommands(<FakeCommand>[
const FakeCommand(
command: <String>[
'which',
'sysctl'
],
stdout: '/sbin/sysctl',
),
const FakeCommand(
command: <String>[
'sysctl',
'hw.optional.arm64',
],
stdout: 'hw.optional.arm64: 0',
),
]);
final Cache cache = createCache(FakePlatform(operatingSystem: 'macos'));
final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache, platform: FakePlatform(operatingSystem: 'macos')); final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache, platform: FakePlatform(operatingSystem: 'macos'));
cache.includeAllPlatforms = false; cache.includeAllPlatforms = false;
...@@ -390,15 +448,19 @@ void main() { ...@@ -390,15 +448,19 @@ void main() {
}); });
testWithoutContext('FontSubset artifacts on fuchsia', () { testWithoutContext('FontSubset artifacts on fuchsia', () {
final Cache cache = Cache.test(); fakeProcessManager.addCommand(unameCommandForX64);
final Cache cache = createCache(FakePlatform(operatingSystem: 'fuchsia'));
final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache, platform: FakePlatform(operatingSystem: 'fuchsia')); final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache, platform: FakePlatform(operatingSystem: 'fuchsia'));
cache.includeAllPlatforms = false; cache.includeAllPlatforms = false;
expect(artifacts.getBinaryDirs, throwsToolExit(message: 'Unsupported operating system: fuchsia')); expect(artifacts.getBinaryDirs, throwsToolExit(message: 'Unsupported operating system: fuchsia'));
}); });
testWithoutContext('FontSubset artifacts for all platforms', () { testWithoutContext('FontSubset artifacts for all platforms on x64 hosts', () {
final Cache cache = Cache.test(); fakeProcessManager.addCommand(unameCommandForX64);
final Cache cache = createCache(FakePlatform(operatingSystem: 'fuchsia'));
final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache, platform: FakePlatform(operatingSystem: 'fuchsia')); final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache, platform: FakePlatform(operatingSystem: 'fuchsia'));
cache.includeAllPlatforms = true; cache.includeAllPlatforms = true;
...@@ -409,6 +471,20 @@ void main() { ...@@ -409,6 +471,20 @@ void main() {
]); ]);
}); });
testWithoutContext('FontSubset artifacts for all platforms on arm64 hosts', () {
fakeProcessManager.addCommand(unameCommandForArm64);
final Cache cache = createCache(FakePlatform(operatingSystem: 'fuchsia'));
final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache, platform: FakePlatform(operatingSystem: 'fuchsia'));
cache.includeAllPlatforms = true;
expect(artifacts.getBinaryDirs(), <List<String>>[
<String>['darwin-x64', 'darwin-x64/font-subset.zip'], // arm64 macOS hosts are not supported now
<String>['linux-arm64', 'linux-arm64/font-subset.zip'],
<String>['windows-x64', 'windows-x64/font-subset.zip'], // arm64 macOS hosts are not supported now
]);
});
testWithoutContext('macOS desktop artifacts ignore filtering when requested', () { testWithoutContext('macOS desktop artifacts ignore filtering when requested', () {
final Cache cache = Cache.test(); final Cache cache = Cache.test();
final MacOSEngineArtifacts artifacts = MacOSEngineArtifacts(cache, platform: FakePlatform(operatingSystem: 'linux')); final MacOSEngineArtifacts artifacts = MacOSEngineArtifacts(cache, platform: FakePlatform(operatingSystem: 'linux'));
...@@ -444,7 +520,9 @@ void main() { ...@@ -444,7 +520,9 @@ void main() {
}); });
testWithoutContext('Linux desktop artifacts ignore filtering when requested', () { testWithoutContext('Linux desktop artifacts ignore filtering when requested', () {
final Cache cache = Cache.test(); fakeProcessManager.addCommand(unameCommandForX64);
final Cache cache = createCache(FakePlatform(operatingSystem: 'linux'));
final LinuxEngineArtifacts artifacts = LinuxEngineArtifacts( final LinuxEngineArtifacts artifacts = LinuxEngineArtifacts(
cache, cache,
platform: FakePlatform(operatingSystem: 'macos'), platform: FakePlatform(operatingSystem: 'macos'),
...@@ -455,17 +533,36 @@ void main() { ...@@ -455,17 +533,36 @@ void main() {
expect(artifacts.getBinaryDirs(), isNotEmpty); expect(artifacts.getBinaryDirs(), isNotEmpty);
}); });
testWithoutContext('Linux desktop artifacts include profile and release artifacts', () { testWithoutContext('Linux desktop artifacts for x64 include profile and release artifacts', () {
final Cache cache = Cache.test(); fakeProcessManager.addCommand(unameCommandForX64);
final Cache cache = createCache(FakePlatform(operatingSystem: 'linux'));
final LinuxEngineArtifacts artifacts = LinuxEngineArtifacts( final LinuxEngineArtifacts artifacts = LinuxEngineArtifacts(
cache, cache,
platform: FakePlatform(operatingSystem: 'linux'), platform: FakePlatform(operatingSystem: 'linux'),
); );
expect(artifacts.getBinaryDirs(), containsAll(<Matcher>[ expect(artifacts.getBinaryDirs(), <List<String>>[
contains(contains('profile')), <String>['linux-x64', 'linux-x64/linux-x64-flutter-gtk.zip'],
contains(contains('release')), <String>['linux-x64-profile', 'linux-x64-profile/linux-x64-flutter-gtk.zip'],
])); <String>['linux-x64-release', 'linux-x64-release/linux-x64-flutter-gtk.zip'],
]);
});
testWithoutContext('Linux desktop artifacts for arm64 include profile and release artifacts', () {
fakeProcessManager.addCommand(unameCommandForArm64);
final Cache cache = createCache(FakePlatform(operatingSystem: 'linux'));
final LinuxEngineArtifacts artifacts = LinuxEngineArtifacts(
cache,
platform: FakePlatform(operatingSystem: 'linux'),
);
expect(artifacts.getBinaryDirs(), <List<String>>[
<String>['linux-arm64', 'linux-arm64/linux-arm64-flutter-gtk.zip'],
<String>['linux-arm64-profile', 'linux-arm64-profile/linux-arm64-flutter-gtk.zip'],
<String>['linux-arm64-release', 'linux-arm64-release/linux-arm64-flutter-gtk.zip'],
]);
}); });
testWithoutContext('Cache can delete stampfiles of artifacts', () { testWithoutContext('Cache can delete stampfiles of artifacts', () {
......
...@@ -28,7 +28,7 @@ void main() { ...@@ -28,7 +28,7 @@ void main() {
testUsingContext('All build commands support null safety options', () { testUsingContext('All build commands support null safety options', () {
final List<FlutterCommand> commands = <FlutterCommand>[ final List<FlutterCommand> commands = <FlutterCommand>[
BuildWindowsCommand(verboseHelp: false), BuildWindowsCommand(verboseHelp: false),
BuildLinuxCommand(verboseHelp: false), BuildLinuxCommand(verboseHelp: false, operatingSystemUtils: globals.os),
BuildMacosCommand(verboseHelp: false), BuildMacosCommand(verboseHelp: false),
BuildWebCommand(verboseHelp: false), BuildWebCommand(verboseHelp: false),
BuildApkCommand(verboseHelp: false), BuildApkCommand(verboseHelp: false),
......
...@@ -79,6 +79,7 @@ void main() { ...@@ -79,6 +79,7 @@ void main() {
androidWorkflow: AndroidWorkflow( androidWorkflow: AndroidWorkflow(
androidSdk: mockSdk, androidSdk: mockSdk,
featureFlags: TestFeatureFlags(), featureFlags: TestFeatureFlags(),
operatingSystemUtils: FakeOperatingSystemUtils(),
), ),
); );
...@@ -101,6 +102,7 @@ void main() { ...@@ -101,6 +102,7 @@ void main() {
androidWorkflow: AndroidWorkflow( androidWorkflow: AndroidWorkflow(
androidSdk: null, androidSdk: null,
featureFlags: TestFeatureFlags(), featureFlags: TestFeatureFlags(),
operatingSystemUtils: FakeOperatingSystemUtils(),
), ),
); );
...@@ -135,6 +137,7 @@ void main() { ...@@ -135,6 +137,7 @@ void main() {
androidWorkflow: AndroidWorkflow( androidWorkflow: AndroidWorkflow(
androidSdk: mockSdk, androidSdk: mockSdk,
featureFlags: TestFeatureFlags(), featureFlags: TestFeatureFlags(),
operatingSystemUtils: FakeOperatingSystemUtils(),
), ),
); );
final CreateEmulatorResult result = await emulatorManager.createEmulator(); final CreateEmulatorResult result = await emulatorManager.createEmulator();
...@@ -176,6 +179,7 @@ void main() { ...@@ -176,6 +179,7 @@ void main() {
androidWorkflow: AndroidWorkflow( androidWorkflow: AndroidWorkflow(
androidSdk: mockSdk, androidSdk: mockSdk,
featureFlags: TestFeatureFlags(), featureFlags: TestFeatureFlags(),
operatingSystemUtils: FakeOperatingSystemUtils(),
), ),
); );
final CreateEmulatorResult result = await emulatorManager.createEmulator(); final CreateEmulatorResult result = await emulatorManager.createEmulator();
...@@ -212,6 +216,7 @@ void main() { ...@@ -212,6 +216,7 @@ void main() {
androidWorkflow: AndroidWorkflow( androidWorkflow: AndroidWorkflow(
androidSdk: mockSdk, androidSdk: mockSdk,
featureFlags: TestFeatureFlags(), featureFlags: TestFeatureFlags(),
operatingSystemUtils: FakeOperatingSystemUtils(),
), ),
); );
final CreateEmulatorResult result = await emulatorManager.createEmulator(name: 'test'); final CreateEmulatorResult result = await emulatorManager.createEmulator(name: 'test');
...@@ -250,6 +255,7 @@ void main() { ...@@ -250,6 +255,7 @@ void main() {
androidWorkflow: AndroidWorkflow( androidWorkflow: AndroidWorkflow(
androidSdk: mockSdk, androidSdk: mockSdk,
featureFlags: TestFeatureFlags(), featureFlags: TestFeatureFlags(),
operatingSystemUtils: FakeOperatingSystemUtils(),
), ),
); );
final CreateEmulatorResult result = await emulatorManager.createEmulator(name: 'existing-avd-1'); final CreateEmulatorResult result = await emulatorManager.createEmulator(name: 'existing-avd-1');
...@@ -291,6 +297,7 @@ void main() { ...@@ -291,6 +297,7 @@ void main() {
androidWorkflow: AndroidWorkflow( androidWorkflow: AndroidWorkflow(
androidSdk: mockSdk, androidSdk: mockSdk,
featureFlags: TestFeatureFlags(), featureFlags: TestFeatureFlags(),
operatingSystemUtils: FakeOperatingSystemUtils(),
), ),
); );
final CreateEmulatorResult result = await emulatorManager.createEmulator(); final CreateEmulatorResult result = await emulatorManager.createEmulator();
......
...@@ -839,6 +839,7 @@ void main() { ...@@ -839,6 +839,7 @@ void main() {
cache: cache, cache: cache,
fileSystem: fileSystem, fileSystem: fileSystem,
platform: FakePlatform(operatingSystem: 'linux'), platform: FakePlatform(operatingSystem: 'linux'),
operatingSystemUtils: globals.os,
); );
expect(artifacts.getArtifactPath( expect(artifacts.getArtifactPath(
Artifact.fuchsiaFlutterRunner, Artifact.fuchsiaFlutterRunner,
......
...@@ -53,6 +53,16 @@ void main() { ...@@ -53,6 +53,16 @@ void main() {
expect(device.supportsRuntimeMode(BuildMode.jitRelease), false); expect(device.supportsRuntimeMode(BuildMode.jitRelease), false);
}); });
testWithoutContext('LinuxDevice on arm64 hosts is arm64', () async {
final LinuxDevice deviceArm64Host = LinuxDevice(
processManager: FakeProcessManager.any(),
logger: BufferLogger.test(),
fileSystem: MemoryFileSystem.test(),
operatingSystemUtils: FakeOperatingSystemUtils(hostPlatform: HostPlatform.linux_arm64),
);
expect(await deviceArm64Host.targetPlatform, TargetPlatform.linux_arm64);
});
testWithoutContext('LinuxDevice: no devices listed if platform unsupported', () async { testWithoutContext('LinuxDevice: no devices listed if platform unsupported', () async {
expect(await LinuxDevices( expect(await LinuxDevices(
fileSystem: MemoryFileSystem.test(), fileSystem: MemoryFileSystem.test(),
...@@ -159,6 +169,15 @@ FlutterProject setUpFlutterProject(Directory directory) { ...@@ -159,6 +169,15 @@ FlutterProject setUpFlutterProject(Directory directory) {
class MockLinuxApp extends Mock implements LinuxApp {} class MockLinuxApp extends Mock implements LinuxApp {}
class FakeOperatingSystemUtils extends Fake implements OperatingSystemUtils { class FakeOperatingSystemUtils extends Fake implements OperatingSystemUtils {
FakeOperatingSystemUtils({
HostPlatform hostPlatform = HostPlatform.linux_x64
}) : _hostPlatform = hostPlatform;
final HostPlatform _hostPlatform;
@override @override
String get name => 'Linux'; String get name => 'Linux';
@override
HostPlatform get hostPlatform => _hostPlatform;
} }
...@@ -90,7 +90,7 @@ add_custom_command( ...@@ -90,7 +90,7 @@ add_custom_command(
COMMAND ${CMAKE_COMMAND} -E env COMMAND ${CMAKE_COMMAND} -E env
${FLUTTER_TOOL_ENVIRONMENT} ${FLUTTER_TOOL_ENVIRONMENT}
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
linux-x64 ${CMAKE_BUILD_TYPE} ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
VERBATIM VERBATIM
) )
'''; ''';
...@@ -117,7 +117,7 @@ add_custom_command( ...@@ -117,7 +117,7 @@ add_custom_command(
COMMAND ${CMAKE_COMMAND} -E env COMMAND ${CMAKE_COMMAND} -E env
${FLUTTER_TOOL_ENVIRONMENT} ${FLUTTER_TOOL_ENVIRONMENT}
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
linux-x64 ${CMAKE_BUILD_TYPE} ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
) )
'''); ''');
...@@ -128,6 +128,22 @@ add_custom_command( ...@@ -128,6 +128,22 @@ add_custom_command(
expect(cmakeProjectMigration.migrate(), isTrue); expect(cmakeProjectMigration.migrate(), isTrue);
expect(managedCmakeFile.readAsStringSync(), r''' expect(managedCmakeFile.readAsStringSync(), r'''
add_custom_command(
OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
${CMAKE_CURRENT_BINARY_DIR}/_phony_
COMMAND ${CMAKE_COMMAND} -E env
${FLUTTER_TOOL_ENVIRONMENT}
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
VERBATIM
)
''');
expect(testLogger.statusText, contains('add_custom_command() missing VERBATIM or FLUTTER_TARGET_PLATFORM, updating.'));
});
testWithoutContext('is migrated to use FLUTTER_TARGET_PLATFORM', () {
managedCmakeFile.writeAsStringSync(r'''
add_custom_command( add_custom_command(
OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
${CMAKE_CURRENT_BINARY_DIR}/_phony_ ${CMAKE_CURRENT_BINARY_DIR}/_phony_
...@@ -139,7 +155,25 @@ add_custom_command( ...@@ -139,7 +155,25 @@ add_custom_command(
) )
'''); ''');
expect(testLogger.statusText, contains('add_custom_command() missing VERBATIM, updating.')); final CmakeCustomCommandMigration cmakeProjectMigration = CmakeCustomCommandMigration(
mockCmakeProject,
testLogger,
);
expect(cmakeProjectMigration.migrate(), isTrue);
expect(managedCmakeFile.readAsStringSync(), r'''
add_custom_command(
OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
${CMAKE_CURRENT_BINARY_DIR}/_phony_
COMMAND ${CMAKE_COMMAND} -E env
${FLUTTER_TOOL_ENVIRONMENT}
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
VERBATIM
)
''');
expect(testLogger.statusText, contains('add_custom_command() missing VERBATIM or FLUTTER_TARGET_PLATFORM, updating.'));
}); });
}); });
}); });
......
...@@ -71,8 +71,8 @@ void main() { ...@@ -71,8 +71,8 @@ void main() {
final List<Device> devices = await discoverer.discoverDevices(timeout: const Duration(seconds: 10)); final List<Device> devices = await discoverer.discoverDevices(timeout: const Duration(seconds: 10));
expect(devices, hasLength(1)); expect(devices, hasLength(1));
}); });
}); });
group('startApp', () { group('startApp', () {
FlutterTesterDevice device; FlutterTesterDevice device;
List<String> logLines; List<String> logLines;
...@@ -106,6 +106,7 @@ void main() { ...@@ -106,6 +106,7 @@ void main() {
buildDirectory: 'build', buildDirectory: 'build',
logger: BufferLogger.test(), logger: BufferLogger.test(),
flutterVersion: MockFlutterVersion(), flutterVersion: MockFlutterVersion(),
operatingSystemUtils: FakeOperatingSystemUtils(),
); );
logLines = <String>[]; logLines = <String>[];
device.getLogReader().logLines.listen(logLines.add); device.getLogReader().logLines.listen(logLines.add);
...@@ -169,7 +170,7 @@ Hello! ...@@ -169,7 +170,7 @@ Hello!
final LaunchResult result = await device.startApp(app, final LaunchResult result = await device.startApp(app,
mainPath: mainPath, mainPath: mainPath,
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug) debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
); );
expect(result.started, isTrue); expect(result.started, isTrue);
...@@ -188,6 +189,7 @@ FlutterTesterDevices setUpFlutterTesterDevices() { ...@@ -188,6 +189,7 @@ FlutterTesterDevices setUpFlutterTesterDevices() {
fileSystem: MemoryFileSystem.test(), fileSystem: MemoryFileSystem.test(),
config: Config.test(), config: Config.test(),
flutterVersion: MockFlutterVersion(), flutterVersion: MockFlutterVersion(),
operatingSystemUtils: FakeOperatingSystemUtils(),
); );
} }
......
...@@ -396,6 +396,9 @@ class FakeCache implements Cache { ...@@ -396,6 +396,9 @@ class FakeCache implements Cache {
return globals.fs.currentDirectory; return globals.fs.currentDirectory;
} }
@override
String getHostPlatformArchName() => 'x64';
@override @override
File getLicenseFile() { File getLicenseFile() {
return globals.fs.currentDirectory.childFile('LICENSE'); return globals.fs.currentDirectory.childFile('LICENSE');
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment