diff --git a/tools/pkg/engine_build_configs/bin/run.dart b/tools/pkg/engine_build_configs/bin/run.dart index 91e43a15ea0da..be5874b9ca55b 100644 --- a/tools/pkg/engine_build_configs/bin/run.dart +++ b/tools/pkg/engine_build_configs/bin/run.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:ffi' as ffi; import 'dart:io' as io; import 'package:engine_build_configs/engine_build_configs.dart'; @@ -119,6 +120,7 @@ The build names are the "name" fields of the maps in the list of "builds". final GlobalBuildRunner buildRunner = GlobalBuildRunner( platform: const LocalPlatform(), processRunner: ProcessRunner(), + abi: ffi.Abi.current(), engineSrcDir: engine.srcDir, build: targetBuild, extraGnArgs: extraGnArgs, diff --git a/tools/pkg/engine_build_configs/lib/src/build_config_runner.dart b/tools/pkg/engine_build_configs/lib/src/build_config_runner.dart index 191993545c293..1bcf80c4424a9 100644 --- a/tools/pkg/engine_build_configs/lib/src/build_config_runner.dart +++ b/tools/pkg/engine_build_configs/lib/src/build_config_runner.dart @@ -4,7 +4,8 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:io' as io show Directory, Process, ProcessResult; +import 'dart:ffi' as ffi; +import 'dart:io' as io show Directory, Process; import 'package:path/path.dart' as p; import 'package:platform/platform.dart'; @@ -111,7 +112,13 @@ typedef RunnerEventHandler = void Function(RunnerEvent); /// An abstract base clase for running the various tasks that a build config /// specifies. Derived classes implement the `run()` method. sealed class Runner { - Runner(this.platform, this.processRunner, this.engineSrcDir, this.dryRun); + Runner( + this.platform, + this.processRunner, + this.abi, + this.engineSrcDir, + this.dryRun, + ); /// Information about the platform that hosts the runner. final Platform platform; @@ -119,6 +126,9 @@ sealed class Runner { /// Runs the subprocesses required to run the element of the build config. final ProcessRunner processRunner; + /// The [Abi] of the host platform. + final ffi.Abi abi; + /// The src/ directory of the engine checkout. final io.Directory engineSrcDir; @@ -162,6 +172,7 @@ final class GlobalBuildRunner extends Runner { GlobalBuildRunner({ Platform? platform, ProcessRunner? processRunner, + ffi.Abi? abi, required io.Directory engineSrcDir, required this.build, this.extraGnArgs = const [], @@ -175,6 +186,7 @@ final class GlobalBuildRunner extends Runner { }) : super( platform ?? const LocalPlatform(), processRunner ?? ProcessRunner(), + abi ?? ffi.Abi.current(), engineSrcDir, dryRun, ); @@ -289,22 +301,20 @@ final class GlobalBuildRunner extends Runner { } late final String _hostCpu = (){ - if (platform.isWindows) { - return platform.environment['PROCESSOR_ARCHITECTURE'] ?? 'x64'; - } - final List unameCommand = ['uname', '-m']; - final io.ProcessResult unameResult = processRunner.processManager.runSync( - unameCommand, - ); - return unameResult.exitCode == 0 ? (unameResult.stdout as String).trim() : 'x64'; + return switch (abi) { + ffi.Abi.linuxArm64 || ffi.Abi.macosArm64 || ffi.Abi.windowsArm64 => 'arm64', + ffi.Abi.linuxX64 || ffi.Abi.macosX64 || ffi.Abi.windowsX64 => 'x64', + _ => throw StateError('This host platform "$abi" is not supported.'), + }; }(); late final String _buildtoolsPath = (){ - final String platformDir = switch (platform.operatingSystem) { + final String os = platform.operatingSystem; + final String platformDir = switch (os) { Platform.linux => 'linux-$_hostCpu', Platform.macOS => 'mac-$_hostCpu', Platform.windows => 'windows-$_hostCpu', - _ => '', + _ => throw StateError('This host OS "$os" is not supported.'), }; return p.join(engineSrcDir.path, 'buildtools', platformDir); }(); @@ -317,11 +327,12 @@ final class GlobalBuildRunner extends Runner { final String exe = platform.isWindows ? '.exe' : ''; final String bootstrapPath = p.join(reclientPath, 'bootstrap$exe'); final String reproxyPath = p.join(reclientPath, 'reproxy$exe'); - final String reclientConfigFile = switch (platform.operatingSystem) { + final String os = platform.operatingSystem; + final String reclientConfigFile = switch (os) { Platform.linux => 'reclient-linux.cfg', Platform.macOS => 'reclient-mac.cfg', Platform.windows => 'reclient-win.cfg', - _ => '', + _ => throw StateError('This host OS "$os" is not supported.'), }; final String reclientConfigPath = p.join( engineSrcDir.path, 'flutter', 'build', 'rbe', reclientConfigFile, @@ -487,6 +498,7 @@ final class GlobalBuildRunner extends Runner { final BuildTaskRunner runner = BuildTaskRunner( processRunner: processRunner, platform: platform, + abi: abi, engineSrcDir: engineSrcDir, task: task, dryRun: dryRun, @@ -503,6 +515,7 @@ final class GlobalBuildRunner extends Runner { final BuildTestRunner runner = BuildTestRunner( processRunner: processRunner, platform: platform, + abi: abi, engineSrcDir: engineSrcDir, test: test, extraTestArgs: extraTestArgs, @@ -521,12 +534,14 @@ final class BuildTaskRunner extends Runner { BuildTaskRunner({ Platform? platform, ProcessRunner? processRunner, + ffi.Abi? abi, required io.Directory engineSrcDir, required this.task, bool dryRun = false, }) : super( platform ?? const LocalPlatform(), processRunner ?? ProcessRunner(), + abi ?? ffi.Abi.current(), engineSrcDir, dryRun, ); @@ -571,6 +586,7 @@ final class BuildTestRunner extends Runner { BuildTestRunner({ Platform? platform, ProcessRunner? processRunner, + ffi.Abi? abi, required io.Directory engineSrcDir, required this.test, this.extraTestArgs = const [], @@ -578,6 +594,7 @@ final class BuildTestRunner extends Runner { }) : super( platform ?? const LocalPlatform(), processRunner ?? ProcessRunner(), + abi ?? ffi.Abi.current(), engineSrcDir, dryRun, ); diff --git a/tools/pkg/engine_build_configs/test/build_config_runner_test.dart b/tools/pkg/engine_build_configs/test/build_config_runner_test.dart index fa49ba23a9f51..86bc5b2cef0b9 100644 --- a/tools/pkg/engine_build_configs/test/build_config_runner_test.dart +++ b/tools/pkg/engine_build_configs/test/build_config_runner_test.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'dart:convert' as convert; +import 'dart:ffi' as ffi; import 'dart:io' as io; import 'package:engine_build_configs/src/build_config.dart'; @@ -39,6 +40,7 @@ void main() { // dryRun should not try to spawn any processes. processManager: _fakeProcessManager(), ), + abi: ffi.Abi.linuxX64, engineSrcDir: engine.srcDir, task: generator, dryRun: true, @@ -65,6 +67,7 @@ void main() { // dryRun should not try to spawn any processes. processManager: _fakeProcessManager(), ), + abi: ffi.Abi.linuxX64, engineSrcDir: engine.srcDir, test: test, dryRun: true, @@ -93,6 +96,7 @@ void main() { // dryRun should not try to spawn any processes. processManager: _fakeProcessManager(), ), + abi: ffi.Abi.linuxX64, engineSrcDir: engine.srcDir, build: targetBuild, dryRun: true, @@ -154,6 +158,7 @@ void main() { // dryRun should not try to spawn any processes. processManager: _fakeProcessManager(), ), + abi: ffi.Abi.linuxX64, engineSrcDir: engine.srcDir, build: targetBuild, extraGnArgs: ['--extra-gn-arg'], @@ -193,6 +198,7 @@ void main() { // dryRun should not try to spawn any processes. processManager: _fakeProcessManager(), ), + abi: ffi.Abi.linuxX64, engineSrcDir: engine.srcDir, build: targetBuild, extraGnArgs: ['--goma'], @@ -218,10 +224,9 @@ void main() { final GlobalBuildRunner buildRunner = GlobalBuildRunner( platform: FakePlatform(operatingSystem: Platform.linux), processRunner: ProcessRunner( - processManager: _fakeProcessManager( - unameResult: io.ProcessResult(1, 0, 'arm64', ''), - ), + processManager: _fakeProcessManager(), ), + abi: ffi.Abi.linuxX64, engineSrcDir: engine.srcDir, build: targetBuild, extraGnArgs: ['--rbe'], @@ -263,6 +268,7 @@ void main() { // dryRun should not try to spawn any processes. processManager: _fakeProcessManager(), ), + abi: ffi.Abi.linuxX64, engineSrcDir: engine.srcDir, build: targetBuild, runGn: false, @@ -297,6 +303,7 @@ void main() { // dryRun should not try to spawn any processes. processManager: _fakeProcessManager(), ), + abi: ffi.Abi.linuxX64, engineSrcDir: engine.srcDir, build: targetBuild, runNinja: false, @@ -338,6 +345,7 @@ void main() { // dryRun should not try to spawn any processes. processManager: _fakeProcessManager(), ), + abi: ffi.Abi.linuxX64, engineSrcDir: engine.srcDir, build: targetBuild, runGenerators: false, @@ -381,6 +389,7 @@ void main() { // dryRun should not try to spawn any processes. processManager: _fakeProcessManager(), ), + abi: ffi.Abi.linuxX64, engineSrcDir: engine.srcDir, build: targetBuild, runTests: false, @@ -409,10 +418,9 @@ void main() { final GlobalBuildRunner buildRunner = GlobalBuildRunner( platform: FakePlatform(operatingSystem: Platform.linux), processRunner: ProcessRunner( - processManager: _fakeProcessManager( - unameResult: io.ProcessResult(1, 0, 'arm64', ''), - ), + processManager: _fakeProcessManager(), ), + abi: ffi.Abi.linuxX64, engineSrcDir: engine.srcDir, build: targetBuild, extraGnArgs: ['--no-lto', '--no-goma', '--rbe'], @@ -448,6 +456,7 @@ void main() { // dryRun should not try to spawn any processes. processManager: _fakeProcessManager(), ), + abi: ffi.Abi.linuxX64, engineSrcDir: engine.srcDir, build: targetBuild, dryRun: true, @@ -469,6 +478,7 @@ void main() { gnResult: io.ProcessResult(1, 1, '', ''), ), ), + abi: ffi.Abi.linuxX64, engineSrcDir: engine.srcDir, build: targetBuild, ); @@ -495,6 +505,7 @@ void main() { ninjaResult: io.ProcessResult(1, 1, '', ''), ), ), + abi: ffi.Abi.linuxX64, engineSrcDir: engine.srcDir, build: targetBuild, ); @@ -518,10 +529,10 @@ void main() { platform: FakePlatform(operatingSystem: Platform.linux), processRunner: ProcessRunner( processManager: _fakeProcessManager( - unameResult: io.ProcessResult(1, 0, 'arm64', ''), bootstrapResult: io.ProcessResult(1, 1, '', ''), ), ), + abi: ffi.Abi.linuxX64, engineSrcDir: engine.srcDir, build: targetBuild, extraGnArgs: ['--rbe'], @@ -547,7 +558,6 @@ void main() { platform: FakePlatform(operatingSystem: Platform.linux), processRunner: ProcessRunner( processManager: _fakeProcessManager( - unameResult: io.ProcessResult(1, 0, 'arm64', ''), canRun: (Object? exe, {String? workingDirectory}) { if (exe is String? && exe != null && exe.endsWith('bootstrap')) { return false; @@ -556,6 +566,7 @@ void main() { }, ), ), + abi: ffi.Abi.linuxX64, engineSrcDir: engine.srcDir, build: targetBuild, extraGnArgs: ['--rbe'], @@ -568,10 +579,31 @@ void main() { expect(events[2] is RunnerError, isTrue); }); + + test('GlobalBuildRunner throws a StateError on an unsupported host cpu', () async { + final GlobalBuild targetBuild = buildConfig.builds[0]; + final GlobalBuildRunner buildRunner = GlobalBuildRunner( + platform: FakePlatform(operatingSystem: Platform.linux), + processRunner: ProcessRunner( + processManager: _fakeProcessManager(), + ), + abi: ffi.Abi.linuxRiscv32, + engineSrcDir: engine.srcDir, + build: targetBuild, + extraGnArgs: ['--rbe'], + ); + + bool caughtError = false; + try { + await buildRunner.run((RunnerEvent event) {}); + } on StateError catch (_) { + caughtError = true; + } + expect(caughtError, isTrue); + }); } FakeProcessManager _fakeProcessManager({ - io.ProcessResult? unameResult, io.ProcessResult? bootstrapResult, io.ProcessResult? gnResult, io.ProcessResult? ninjaResult, @@ -587,7 +619,6 @@ FakeProcessManager _fakeProcessManager({ return FakeProcessManager( canRun: canRun ?? (Object? exe, {String? workingDirectory}) => true, onRun: (List cmd) => switch (cmd) { - ['uname', ...] => unameResult ?? success, _ => failUnknown ? io.ProcessResult(1, 1, '', '') : success, }, onStart: (List cmd) => switch (cmd) {