diff --git a/pkgs/native_toolchain_c/CHANGELOG.md b/pkgs/native_toolchain_c/CHANGELOG.md index 03addb4bd8..1ee6f3cb31 100644 --- a/pkgs/native_toolchain_c/CHANGELOG.md +++ b/pkgs/native_toolchain_c/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.17.3-wip + +- Search for NDK in `ANDROID_HOME` and `ANDROID_NDK` environment variables. + ## 0.17.2 - Made `CBuilder.run` `Logger` argument optional. It now defaults to a logger diff --git a/pkgs/native_toolchain_c/lib/src/cbuilder/compiler_resolver.dart b/pkgs/native_toolchain_c/lib/src/cbuilder/compiler_resolver.dart index c1e44e47c1..a3e1e2d48b 100644 --- a/pkgs/native_toolchain_c/lib/src/cbuilder/compiler_resolver.dart +++ b/pkgs/native_toolchain_c/lib/src/cbuilder/compiler_resolver.dart @@ -16,6 +16,7 @@ import '../native_toolchain/recognizer.dart'; import '../tool/tool.dart'; import '../tool/tool_error.dart'; import '../tool/tool_instance.dart'; +import '../tool/tool_resolver.dart'; import '../utils/env_from_bat.dart'; // TODO(dacoharkes): This should support alternatives. @@ -25,6 +26,7 @@ class CompilerResolver { final Logger? logger; final OS hostOS; final Architecture hostArchitecture; + final ToolResolvingContext context; CompilerResolver({ required this.codeConfig, @@ -32,7 +34,8 @@ class CompilerResolver { OS? hostOS, // Only visible for testing. Architecture? hostArchitecture, // Only visible for testing. }) : hostOS = hostOS ?? OS.current, - hostArchitecture = hostArchitecture ?? Architecture.current; + hostArchitecture = hostArchitecture ?? Architecture.current, + context = ToolResolvingContext(logger: logger); Future resolveCompiler() async { // First, check if the launcher provided a direct path to the compiler. @@ -96,9 +99,7 @@ class CompilerResolver { 'Using compiler ${inputCcUri.toFilePath()} ' 'from BuildInput.cCompiler.cc.', ); - return (await CompilerRecognizer( - inputCcUri, - ).resolve(logger: logger)).first; + return (await CompilerRecognizer(inputCcUri).resolve(context)).first; } logger?.finer('No compiler set in BuildInput.cCompiler.cc.'); return null; @@ -106,7 +107,7 @@ class CompilerResolver { Future _tryLoadToolFromNativeToolchain(Tool tool) async { final resolved = (await tool.defaultResolver!.resolve( - logger: logger, + context, )).where((i) => i.tool == tool).toList()..sort(); return resolved.isEmpty ? null : resolved.first; } @@ -183,9 +184,7 @@ class CompilerResolver { 'Using archiver ${inputArUri.toFilePath()} ' 'from BuildInput.cCompiler.ar.', ); - return (await ArchiverRecognizer( - inputArUri, - ).resolve(logger: logger)).first; + return (await ArchiverRecognizer(inputArUri).resolve(context)).first; } logger?.finer('No archiver set in BuildInput.cCompiler.ar.'); return null; @@ -221,7 +220,7 @@ class CompilerResolver { } final vcvarsScript = (await vcvars( compiler, - ).defaultResolver!.resolve(logger: logger)).first; + ).defaultResolver!.resolve(context)).first; return await environmentFromBatchFile( vcvarsScript.uri, arguments: [ diff --git a/pkgs/native_toolchain_c/lib/src/cbuilder/run_cbuilder.dart b/pkgs/native_toolchain_c/lib/src/cbuilder/run_cbuilder.dart index 394a4ef1bc..06c29b187c 100644 --- a/pkgs/native_toolchain_c/lib/src/cbuilder/run_cbuilder.dart +++ b/pkgs/native_toolchain_c/lib/src/cbuilder/run_cbuilder.dart @@ -12,6 +12,7 @@ import '../native_toolchain/msvc.dart'; import '../native_toolchain/tool_likeness.dart'; import '../native_toolchain/xcode.dart'; import '../tool/tool_instance.dart'; +import '../tool/tool_resolver.dart'; import '../utils/run_process.dart'; import 'compiler_resolver.dart'; import 'language.dart'; @@ -96,21 +97,21 @@ class RunCBuilder { Future archiver() async => (await _resolver.resolveArchiver()).uri; - Future iosSdk(IOSSdk iosSdk, {required Logger? logger}) async { + Future iosSdk(IOSSdk iosSdk, ToolResolvingContext context) async { if (iosSdk == IOSSdk.iPhoneOS) { return (await iPhoneOSSdk.defaultResolver!.resolve( - logger: logger, + context, )).where((i) => i.tool == iPhoneOSSdk).first.uri; } assert(iosSdk == IOSSdk.iPhoneSimulator); return (await iPhoneSimulatorSdk.defaultResolver!.resolve( - logger: logger, + context, )).where((i) => i.tool == iPhoneSimulatorSdk).first.uri; } - Future macosSdk({required Logger? logger}) async => + Future macosSdk(ToolResolvingContext context) async => (await macosxSdk.defaultResolver!.resolve( - logger: logger, + context, )).where((i) => i.tool == macosxSdk).first.uri; Uri androidSysroot(ToolInstance compiler) => @@ -224,6 +225,8 @@ class RunCBuilder { Uri? outFile, Map environment, ) async { + final context = ToolResolvingContext(logger: logger); + await runProcess( executable: toolInstance.uri, environment: environment, @@ -245,11 +248,11 @@ class RunCBuilder { '-mmacos-version-min=$targetMacOSVersion', if (codeConfig.targetOS == OS.iOS) ...[ '-isysroot', - (await iosSdk(targetIosSdk!, logger: logger)).toFilePath(), + (await iosSdk(targetIosSdk!, context)).toFilePath(), ], if (codeConfig.targetOS == OS.macOS) ...[ '-isysroot', - (await macosSdk(logger: logger)).toFilePath(), + (await macosSdk(context)).toFilePath(), ], if (installName != null) ...[ '-install_name', diff --git a/pkgs/native_toolchain_c/lib/src/native_toolchain/android_ndk.dart b/pkgs/native_toolchain_c/lib/src/native_toolchain/android_ndk.dart index 44a73ddf77..765fde3053 100644 --- a/pkgs/native_toolchain_c/lib/src/native_toolchain/android_ndk.dart +++ b/pkgs/native_toolchain_c/lib/src/native_toolchain/android_ndk.dart @@ -6,6 +6,7 @@ import 'dart:io'; import 'package:code_assets/code_assets.dart'; import 'package:logging/logging.dart'; +import 'package:path/path.dart' as p; import '../tool/tool.dart'; import '../tool/tool_instance.dart'; @@ -36,41 +37,51 @@ final androidNdkLld = Tool( ); class _AndroidNdkResolver implements ToolResolver { - final installLocationResolver = PathVersionResolver( - wrappedResolver: ToolResolvers([ - RelativeToolResolver( - toolName: 'Android NDK', - wrappedResolver: PathToolResolver( - toolName: 'ndk-build', - executableName: Platform.isWindows ? 'ndk-build.cmd' : 'ndk-build', - ), - relativePath: Uri(path: ''), - ), - InstallLocationResolver( - toolName: 'Android NDK', - paths: [ - if (Platform.isLinux) ...[ - '\$HOME/.androidsdkroot/ndk/*/', // Firebase Studio - '\$HOME/Android/Sdk/ndk/*/', - '\$HOME/Android/Sdk/ndk-bundle/', - ], - if (Platform.isMacOS) ...['\$HOME/Library/Android/sdk/ndk/*/'], - if (Platform.isWindows) ...[ - '\$HOME/AppData/Local/Android/Sdk/ndk/*/', - ], - ], - ), - ]), - ); + ToolResolver installLocationResolver(ToolResolvingContext context) => + PathVersionResolver( + wrappedResolver: ToolResolvers([ + RelativeToolResolver( + toolName: 'Android NDK', + wrappedResolver: PathToolResolver( + toolName: 'ndk-build', + executableName: Platform.isWindows + ? 'ndk-build.cmd' + : 'ndk-build', + ), + relativePath: Uri(path: ''), + ), + InstallLocationResolver( + toolName: 'Android NDK', + paths: [ + if (context.environment['ANDROID_HOME'] case final androidHome?) + p.join(androidHome, 'ndk/*/'), + for (final ndkHomeKey in _ndkHomeEnvironmentVariables) + if (context.environment[ndkHomeKey] case final home?) home, + + if (Platform.isLinux) ...[ + '\$HOME/.androidsdkroot/ndk/*/', // Firebase Studio + '\$HOME/Android/Sdk/ndk/*/', + '\$HOME/Android/Sdk/ndk-bundle/', + ], + if (Platform.isMacOS) ...['\$HOME/Library/Android/sdk/ndk/*/'], + if (Platform.isWindows) ...[ + '\$HOME/AppData/Local/Android/Sdk/ndk/*/', + ], + ], + ), + ]), + ); @override - Future> resolve({required Logger? logger}) async { - final ndkInstances = await installLocationResolver.resolve(logger: logger); + Future> resolve(ToolResolvingContext context) async { + final ndkInstances = await installLocationResolver( + context, + ).resolve(context); return [ for (final ndkInstance in ndkInstances) ...[ ndkInstance, - ...await tryResolveClang(ndkInstance, logger: logger), + ...await tryResolveClang(ndkInstance, logger: context.logger), ], ]; } @@ -127,4 +138,12 @@ class _AndroidNdkResolver implements ToolResolver { } return result; } + + static const _ndkHomeEnvironmentVariables = [ + // https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2404-Readme.md#environment-variables-2 + 'ANDROID_NDK', + 'ANDROID_NDK_HOME', + 'ANDROID_NDK_LATEST_HOME', + 'ANDROID_NDK_ROOT', + ]; } diff --git a/pkgs/native_toolchain_c/lib/src/native_toolchain/msvc.dart b/pkgs/native_toolchain_c/lib/src/native_toolchain/msvc.dart index d4a8e48bd0..4287f5f3dd 100644 --- a/pkgs/native_toolchain_c/lib/src/native_toolchain/msvc.dart +++ b/pkgs/native_toolchain_c/lib/src/native_toolchain/msvc.dart @@ -258,10 +258,9 @@ Tool _msvcTool({ class VisualStudioResolver implements ToolResolver { @override - Future> resolve({required Logger? logger}) async { - final vswhereInstances = await vswhere.defaultResolver!.resolve( - logger: logger, - ); + Future> resolve(ToolResolvingContext context) async { + final vswhereInstances = await vswhere.defaultResolver!.resolve(context); + final logger = context.logger; final result = []; for (final vswhereInstance in vswhereInstances.take(1)) { diff --git a/pkgs/native_toolchain_c/lib/src/native_toolchain/recognizer.dart b/pkgs/native_toolchain_c/lib/src/native_toolchain/recognizer.dart index f873a12299..73a0fb689a 100644 --- a/pkgs/native_toolchain_c/lib/src/native_toolchain/recognizer.dart +++ b/pkgs/native_toolchain_c/lib/src/native_toolchain/recognizer.dart @@ -3,7 +3,6 @@ // BSD-style license that can be found in the LICENSE file. import 'package:code_assets/code_assets.dart'; -import 'package:logging/logging.dart'; import '../tool/tool.dart'; import '../tool/tool_instance.dart'; @@ -19,7 +18,8 @@ class CompilerRecognizer implements ToolResolver { CompilerRecognizer(this.uri); @override - Future> resolve({required Logger? logger}) async { + Future> resolve(ToolResolvingContext context) async { + final logger = context.logger; final os = OS.current; logger?.finer('Trying to recognize $uri.'); final filePath = uri.toFilePath(); @@ -64,7 +64,8 @@ class LinkerRecognizer implements ToolResolver { LinkerRecognizer(this.uri); @override - Future> resolve({required Logger? logger}) async { + Future> resolve(ToolResolvingContext context) async { + final logger = context.logger; final os = OS.current; logger?.finer('Trying to recognize $uri.'); final filePath = uri.toFilePath(); @@ -111,7 +112,8 @@ class ArchiverRecognizer implements ToolResolver { ArchiverRecognizer(this.uri); @override - Future> resolve({required Logger? logger}) async { + Future> resolve(ToolResolvingContext context) async { + final logger = context.logger; logger?.finer('Trying to recognize $uri.'); final os = OS.current; final filePath = uri.toFilePath(); diff --git a/pkgs/native_toolchain_c/lib/src/native_toolchain/xcode.dart b/pkgs/native_toolchain_c/lib/src/native_toolchain/xcode.dart index dbefb7683e..392968a9e4 100644 --- a/pkgs/native_toolchain_c/lib/src/native_toolchain/xcode.dart +++ b/pkgs/native_toolchain_c/lib/src/native_toolchain/xcode.dart @@ -44,8 +44,8 @@ final Tool iPhoneSimulatorSdk = Tool( class XCodeSdkResolver implements ToolResolver { @override - Future> resolve({required Logger? logger}) async { - final xcrunInstances = await xcrun.defaultResolver!.resolve(logger: logger); + Future> resolve(ToolResolvingContext context) async { + final xcrunInstances = await xcrun.defaultResolver!.resolve(context); return [ for (final xcrunInstance in xcrunInstances) ...[ @@ -53,19 +53,19 @@ class XCodeSdkResolver implements ToolResolver { xcrunInstance: xcrunInstance, sdk: 'macosx', tool: macosxSdk, - logger: logger, + logger: context.logger, ), ...await tryResolveSdk( xcrunInstance: xcrunInstance, sdk: 'iphoneos', tool: iPhoneOSSdk, - logger: logger, + logger: context.logger, ), ...await tryResolveSdk( xcrunInstance: xcrunInstance, sdk: 'iphonesimulator', tool: iPhoneSimulatorSdk, - logger: logger, + logger: context.logger, ), ], // xcrun --sdk macosx --show-sdk-path) diff --git a/pkgs/native_toolchain_c/lib/src/tool/tool_resolver.dart b/pkgs/native_toolchain_c/lib/src/tool/tool_resolver.dart index 0603703181..247e16a6f7 100644 --- a/pkgs/native_toolchain_c/lib/src/tool/tool_resolver.dart +++ b/pkgs/native_toolchain_c/lib/src/tool/tool_resolver.dart @@ -19,7 +19,20 @@ import 'tool_instance.dart'; abstract class ToolResolver { /// Resolves tools on the host system. - Future> resolve({required Logger? logger}); + Future> resolve(ToolResolvingContext context); +} + +/// A context passed to [ToolResolver.resolve]. +/// +/// To keep resolvers testable, [ToolResolver.resolve] should ideally not access +/// global state not available in this context. Not all resolvers adhere to that +/// though, since some need to run subprocesses to resolve tools. +final class ToolResolvingContext { + final Logger? logger; + final Map environment; + + ToolResolvingContext({required this.logger, Map? environment}) + : environment = environment ?? Platform.environment; } /// Tries to resolve a tool on the `PATH`. @@ -37,9 +50,10 @@ class PathToolResolver extends ToolResolver { OS.current.executableFileName(toolName.toLowerCase()); @override - Future> resolve({required Logger? logger}) async { + Future> resolve(ToolResolvingContext context) async { + final logger = context.logger; logger?.finer('Looking for $toolName on PATH.'); - final uri = await runWhich(logger: logger); + final uri = await runWhich(context); if (uri == null) { logger?.fine('Did not find $toolName on PATH.'); return []; @@ -56,11 +70,11 @@ class PathToolResolver extends ToolResolver { static Uri get which => Uri.file(Platform.isWindows ? 'where' : 'which'); - Future runWhich({required Logger? logger}) async { + Future runWhich(ToolResolvingContext context) async { final process = await runProcess( executable: which, arguments: [executableName], - logger: logger, + logger: context.logger, ); if (process.exitCode == 0) { final file = File(LineSplitter.split(process.stdout).first); @@ -89,15 +103,15 @@ class CliVersionResolver implements ToolResolver { }); @override - Future> resolve({required Logger? logger}) async { - final toolInstances = await wrappedResolver.resolve(logger: logger); + Future> resolve(ToolResolvingContext context) async { + final toolInstances = await wrappedResolver.resolve(context); return [ for (final toolInstance in toolInstances) await lookupVersion( toolInstance, arguments: arguments, expectedExitCode: expectedExitCode, - logger: logger, + logger: context.logger, ), ]; } @@ -144,14 +158,16 @@ class CliVersionResolver implements ToolResolver { } } +/// Wraps a [ToolResolver] to attach the version number of found tools if they +/// have not been found by [wrappedResolver] directly. class PathVersionResolver implements ToolResolver { ToolResolver wrappedResolver; PathVersionResolver({required this.wrappedResolver}); @override - Future> resolve({required Logger? logger}) async { - final toolInstances = await wrappedResolver.resolve(logger: logger); + Future> resolve(ToolResolvingContext context) async { + final toolInstances = await wrappedResolver.resolve(context); return [ for (final toolInstance in toolInstances) lookupVersion(toolInstance), @@ -179,8 +195,8 @@ class ToolResolvers implements ToolResolver { ToolResolvers(this.resolvers); @override - Future> resolve({required Logger? logger}) async => [ - for (final resolver in resolvers) ...await resolver.resolve(logger: logger), + Future> resolve(ToolResolvingContext context) async => [ + for (final resolver in resolvers) ...await resolver.resolve(context), ]; } @@ -193,7 +209,8 @@ class InstallLocationResolver implements ToolResolver { static const home = '\$HOME'; @override - Future> resolve({required Logger? logger}) async { + Future> resolve(ToolResolvingContext context) async { + final logger = context.logger; logger?.finer('Looking for $toolName in $paths.'); final resolvedPaths = [ for (final path in paths) ...await tryResolvePath(path), @@ -257,8 +274,9 @@ class RelativeToolResolver implements ToolResolver { }); @override - Future> resolve({required Logger? logger}) async { - final otherToolInstances = await wrappedResolver.resolve(logger: logger); + Future> resolve(ToolResolvingContext context) async { + final logger = context.logger; + final otherToolInstances = await wrappedResolver.resolve(context); logger?.finer( 'Looking for $toolName relative to $otherToolInstances ' @@ -308,11 +326,11 @@ class CliFilter implements ToolResolver { }); @override - Future> resolve({required Logger? logger}) async { - final toolInstances = await wrappedResolver.resolve(logger: logger); + Future> resolve(ToolResolvingContext context) async { + final toolInstances = await wrappedResolver.resolve(context); return [ for (final toolInstance in toolInstances) - await filter(toolInstance, logger: logger), + await filter(toolInstance, logger: context.logger), ].whereType().toList(); } diff --git a/pkgs/native_toolchain_c/pubspec.yaml b/pkgs/native_toolchain_c/pubspec.yaml index dc271e0803..bb0e2bc0d7 100644 --- a/pkgs/native_toolchain_c/pubspec.yaml +++ b/pkgs/native_toolchain_c/pubspec.yaml @@ -1,7 +1,7 @@ name: native_toolchain_c description: >- A library to invoke the native C compiler installed on the host machine. -version: 0.17.2 +version: 0.17.3-wip repository: https://github.com/dart-lang/native/tree/main/pkgs/native_toolchain_c topics: @@ -33,3 +33,4 @@ dev_dependencies: repo_lint_rules: path: ../repo_lint_rules/ test: ^1.25.15 + test_descriptor: ^2.0.2 diff --git a/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_windows_host_test.dart b/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_windows_host_test.dart index 83e75d494d..6f644ed733 100644 --- a/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_windows_host_test.dart +++ b/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_windows_host_test.dart @@ -30,12 +30,10 @@ void main() async { // Clang on Windows. clang: () async => CCompilerConfig( archiver: (await llvmAr.defaultResolver!.resolve( - logger: logger, + systemContext, )).first.uri, - compiler: (await clang.defaultResolver!.resolve( - logger: logger, - )).first.uri, - linker: (await lld.defaultResolver!.resolve(logger: logger)).first.uri, + compiler: (await clang.defaultResolver!.resolve(systemContext)).first.uri, + linker: (await lld.defaultResolver!.resolve(systemContext)).first.uri, windows: WindowsCCompilerConfig(), ), }; @@ -51,7 +49,7 @@ void main() async { setUp(() async { dumpbinUri = (await dumpbin.defaultResolver!.resolve( - logger: logger, + systemContext, )).first.uri; }); diff --git a/pkgs/native_toolchain_c/test/cbuilder/compiler_resolver_test.dart b/pkgs/native_toolchain_c/test/cbuilder/compiler_resolver_test.dart index d0ef005355..1b71a0fa4b 100644 --- a/pkgs/native_toolchain_c/test/cbuilder/compiler_resolver_test.dart +++ b/pkgs/native_toolchain_c/test/cbuilder/compiler_resolver_test.dart @@ -22,22 +22,22 @@ void main() { final tempUri = await tempDirForTest(); final tempUri2 = await tempDirForTest(); final ar = [ - ...await appleAr.defaultResolver!.resolve(logger: logger), - ...await msvc.lib.defaultResolver!.resolve(logger: logger), - ...await llvmAr.defaultResolver!.resolve(logger: logger), + ...await appleAr.defaultResolver!.resolve(systemContext), + ...await msvc.lib.defaultResolver!.resolve(systemContext), + ...await llvmAr.defaultResolver!.resolve(systemContext), ].first.uri; final cc = [ - ...await appleClang.defaultResolver!.resolve(logger: logger), - ...await msvc.cl.defaultResolver!.resolve(logger: logger), - ...await clang.defaultResolver!.resolve(logger: logger), + ...await appleClang.defaultResolver!.resolve(systemContext), + ...await msvc.cl.defaultResolver!.resolve(systemContext), + ...await clang.defaultResolver!.resolve(systemContext), ].first.uri; final ld = [ - ...await appleLd.defaultResolver!.resolve(logger: logger), - ...await msvc.msvcLink.defaultResolver!.resolve(logger: logger), - ...await lld.defaultResolver!.resolve(logger: logger), + ...await appleLd.defaultResolver!.resolve(systemContext), + ...await msvc.msvcLink.defaultResolver!.resolve(systemContext), + ...await lld.defaultResolver!.resolve(systemContext), ].first.uri; final envScript = [ - ...await msvc.vcvars64.defaultResolver!.resolve(logger: logger), + ...await msvc.vcvars64.defaultResolver!.resolve(systemContext), ].firstOrNull?.uri; final targetOS = OS.current; diff --git a/pkgs/native_toolchain_c/test/helpers.dart b/pkgs/native_toolchain_c/test/helpers.dart index 798cf4ac2d..a770b4501d 100644 --- a/pkgs/native_toolchain_c/test/helpers.dart +++ b/pkgs/native_toolchain_c/test/helpers.dart @@ -11,6 +11,7 @@ import 'package:logging/logging.dart'; import 'package:native_test_helpers/native_test_helpers.dart'; import 'package:native_toolchain_c/src/native_toolchain/apple_clang.dart'; import 'package:native_toolchain_c/src/native_toolchain/msvc.dart'; +import 'package:native_toolchain_c/src/tool/tool_resolver.dart'; import 'package:native_toolchain_c/src/utils/run_process.dart'; import 'package:test/test.dart'; @@ -66,6 +67,8 @@ Logger get logger => _logger ??= () { return _createTestLogger(); }(); +ToolResolvingContext get systemContext => ToolResolvingContext(logger: logger); + Logger? _logger; Logger createCapturingLogger(List capturedMessages) => @@ -143,7 +146,7 @@ extension on String { /// Because `otool` output multiple names, [libraryName] as search parameter. Future runOtoolInstallName(Uri libraryUri, String libraryName) async { final otoolUri = (await otool.defaultResolver!.resolve( - logger: logger, + systemContext, )).first.uri; final otoolResult = await runProcess( executable: otoolUri, @@ -229,7 +232,7 @@ Future _runDumpbin( List arguments, Uri libUri, ) async { - final dumpbinTools = await dumpbin.defaultResolver!.resolve(logger: logger); + final dumpbinTools = await dumpbin.defaultResolver!.resolve(systemContext); if (dumpbinTools.isEmpty) { logger.info('Unable to locate dumpbin tool. Some expects may be skipped.'); return null; diff --git a/pkgs/native_toolchain_c/test/native_toolchain/apple_clang_test.dart b/pkgs/native_toolchain_c/test/native_toolchain/apple_clang_test.dart index 65aa0789a9..cc1ce44cc1 100644 --- a/pkgs/native_toolchain_c/test/native_toolchain/apple_clang_test.dart +++ b/pkgs/native_toolchain_c/test/native_toolchain/apple_clang_test.dart @@ -26,7 +26,7 @@ void main() { appleClang, minimumVersion: Version(12, 0, 0, pre: '0'), ); - final resolved = await appleClang.defaultResolver!.resolve(logger: logger); + final resolved = await appleClang.defaultResolver!.resolve(systemContext); expect(resolved.isNotEmpty, true); final satisfied = requirement.satisfy(resolved); expect(satisfied?.length, 1); @@ -34,7 +34,7 @@ void main() { test('ar test', () async { final requirement = ToolRequirement(appleAr); - final resolved = await appleAr.defaultResolver!.resolve(logger: logger); + final resolved = await appleAr.defaultResolver!.resolve(systemContext); expect(resolved.isNotEmpty, true); final satisfied = requirement.satisfy(resolved); expect(satisfied?.length, 1); @@ -42,7 +42,7 @@ void main() { test('ld test', () async { final requirement = ToolRequirement(appleLd); - final resolved = await appleLd.defaultResolver!.resolve(logger: logger); + final resolved = await appleLd.defaultResolver!.resolve(systemContext); expect(resolved.isNotEmpty, true); final satisfied = requirement.satisfy(resolved); expect(satisfied?.length, 1); @@ -50,7 +50,7 @@ void main() { test('otool test', () async { final requirement = ToolRequirement(otool); - final resolved = await otool.defaultResolver!.resolve(logger: logger); + final resolved = await otool.defaultResolver!.resolve(systemContext); expect(resolved.isNotEmpty, true); final satisfied = requirement.satisfy(resolved); expect(satisfied?.length, 1); diff --git a/pkgs/native_toolchain_c/test/native_toolchain/clang_test.dart b/pkgs/native_toolchain_c/test/native_toolchain/clang_test.dart index 9048eec571..cfa9c5f88c 100644 --- a/pkgs/native_toolchain_c/test/native_toolchain/clang_test.dart +++ b/pkgs/native_toolchain_c/test/native_toolchain/clang_test.dart @@ -31,7 +31,7 @@ void main() { clang, minimumVersion: Version(14, 0, 0, pre: '0'), ); - final resolved = await clang.defaultResolver!.resolve(logger: logger); + final resolved = await clang.defaultResolver!.resolve(systemContext); expect(resolved.isNotEmpty, true); final satisfied = requirement.satisfy(resolved); expect(satisfied?.length, 1); @@ -53,7 +53,7 @@ void main() { test('llvm-ar smoke test', () async { final requirement = ToolRequirement(llvmAr); - final resolved = await llvmAr.defaultResolver!.resolve(logger: logger); + final resolved = await llvmAr.defaultResolver!.resolve(systemContext); expect(resolved.isNotEmpty, true); final satisfied = requirement.satisfy(resolved); expect(satisfied?.length, 1); @@ -61,7 +61,7 @@ void main() { test('ld test', () async { final requirement = ToolRequirement(lld); - final resolved = await lld.defaultResolver!.resolve(logger: logger); + final resolved = await lld.defaultResolver!.resolve(systemContext); expect(resolved.isNotEmpty, true); final satisfied = requirement.satisfy(resolved); expect(satisfied?.length, 1); diff --git a/pkgs/native_toolchain_c/test/native_toolchain/gcc_test.dart b/pkgs/native_toolchain_c/test/native_toolchain/gcc_test.dart index c87f53e077..3336747d2b 100644 --- a/pkgs/native_toolchain_c/test/native_toolchain/gcc_test.dart +++ b/pkgs/native_toolchain_c/test/native_toolchain/gcc_test.dart @@ -27,7 +27,7 @@ void main() { for (final tool in tools) tool.defaultResolver!, ]); - final resolved = await resolver.resolve(logger: logger); + final resolved = await resolver.resolve(systemContext); printOnFailure(resolved.toString()); expect(resolved.isNotEmpty, true); diff --git a/pkgs/native_toolchain_c/test/native_toolchain/msvc_test.dart b/pkgs/native_toolchain_c/test/native_toolchain/msvc_test.dart index 751fb588c6..ce959ed606 100644 --- a/pkgs/native_toolchain_c/test/native_toolchain/msvc_test.dart +++ b/pkgs/native_toolchain_c/test/native_toolchain/msvc_test.dart @@ -21,79 +21,79 @@ void main() { } test('vswhere', () async { - final instances = await vswhere.defaultResolver!.resolve(logger: logger); + final instances = await vswhere.defaultResolver!.resolve(systemContext); expect(instances.isNotEmpty, true); }); test('visualStudio', () async { final instances = await visualStudio.defaultResolver!.resolve( - logger: logger, + systemContext, ); expect(instances.isNotEmpty, true); }); test('msvc', () async { - final instances = await msvc.defaultResolver!.resolve(logger: logger); + final instances = await msvc.defaultResolver!.resolve(systemContext); expect(instances.isNotEmpty, true); }); test('cl', () async { - final instances = await cl.defaultResolver!.resolve(logger: logger); + final instances = await cl.defaultResolver!.resolve(systemContext); expect(instances.isNotEmpty, true); }); test('clIA32', () async { - final instances = await clIA32.defaultResolver!.resolve(logger: logger); + final instances = await clIA32.defaultResolver!.resolve(systemContext); expect(instances.isNotEmpty, true); }); test('clArm64', () async { - final instances = await clArm64.defaultResolver!.resolve(logger: logger); + final instances = await clArm64.defaultResolver!.resolve(systemContext); expect(instances.isNotEmpty, true); }); test('lib', () async { - final instances = await lib.defaultResolver!.resolve(logger: logger); + final instances = await lib.defaultResolver!.resolve(systemContext); expect(instances.isNotEmpty, true); }); test('libIA32', () async { - final instances = await libIA32.defaultResolver!.resolve(logger: logger); + final instances = await libIA32.defaultResolver!.resolve(systemContext); expect(instances.isNotEmpty, true); }); test('libArm64', () async { - final instances = await libArm64.defaultResolver!.resolve(logger: logger); + final instances = await libArm64.defaultResolver!.resolve(systemContext); expect(instances.isNotEmpty, true); }); test('link', () async { - final instances = await msvcLink.defaultResolver!.resolve(logger: logger); + final instances = await msvcLink.defaultResolver!.resolve(systemContext); expect(instances.isNotEmpty, true); }); test('linkIA32', () async { - final instances = await linkIA32.defaultResolver!.resolve(logger: logger); + final instances = await linkIA32.defaultResolver!.resolve(systemContext); expect(instances.isNotEmpty, true); }); test('linkArm64', () async { - final instances = await linkArm64.defaultResolver!.resolve(logger: logger); + final instances = await linkArm64.defaultResolver!.resolve(systemContext); expect(instances.isNotEmpty, true); }); test('dumpbin', () async { - final instances = await dumpbin.defaultResolver!.resolve(logger: logger); + final instances = await dumpbin.defaultResolver!.resolve(systemContext); expect(instances.isNotEmpty, true); }); test('vcvars32 from cl.exe', () async { - final clInstances = await clIA32.defaultResolver!.resolve(logger: logger); + final clInstances = await clIA32.defaultResolver!.resolve(systemContext); expect(clInstances.isNotEmpty, true); final instances = await vcvars( clInstances.first, - ).defaultResolver!.resolve(logger: logger); + ).defaultResolver!.resolve(systemContext); expect(instances.isNotEmpty, true); final instance = instances.first; expect(instance.tool, vcvars32); @@ -103,12 +103,12 @@ void main() { }); test('vcvars64 from cl.exe', () async { - final clInstances = await cl.defaultResolver!.resolve(logger: logger); + final clInstances = await cl.defaultResolver!.resolve(systemContext); expect(clInstances.isNotEmpty, true); final instances = await vcvars( clInstances.first, - ).defaultResolver!.resolve(logger: logger); + ).defaultResolver!.resolve(systemContext); expect(instances.isNotEmpty, true); final instance = instances.first; expect(instance.tool, vcvars64); @@ -118,12 +118,12 @@ void main() { }); test('vcvarsarm64 from cl.exe', () async { - final clInstances = await clArm64.defaultResolver!.resolve(logger: logger); + final clInstances = await clArm64.defaultResolver!.resolve(systemContext); expect(clInstances.isNotEmpty, true); final instances = await vcvars( clInstances.first, - ).defaultResolver!.resolve(logger: logger); + ).defaultResolver!.resolve(systemContext); expect(instances.isNotEmpty, true); final instance = instances.first; expect(instance.tool, vcvarsarm64); @@ -133,7 +133,7 @@ void main() { }); test('vcvars32', () async { - final instances = await vcvars32.defaultResolver!.resolve(logger: logger); + final instances = await vcvars32.defaultResolver!.resolve(systemContext); expect(instances.isNotEmpty, true); final instance = instances.first; final env = await environmentFromBatchFile(instance.uri); @@ -142,7 +142,7 @@ void main() { }); test('vcvars64', () async { - final instances = await vcvars64.defaultResolver!.resolve(logger: logger); + final instances = await vcvars64.defaultResolver!.resolve(systemContext); expect(instances.isNotEmpty, true); final instance = instances.first; final env = await environmentFromBatchFile(instance.uri); @@ -151,9 +151,7 @@ void main() { }); test('vcvarsarm64', () async { - final instances = await vcvarsarm64.defaultResolver!.resolve( - logger: logger, - ); + final instances = await vcvarsarm64.defaultResolver!.resolve(systemContext); expect(instances.isNotEmpty, true); final instance = instances.first; final env = await environmentFromBatchFile(instance.uri); @@ -162,7 +160,7 @@ void main() { }); test('vcvarsall', () async { - final instances = await vcvarsall.defaultResolver!.resolve(logger: logger); + final instances = await vcvarsall.defaultResolver!.resolve(systemContext); expect(instances.isNotEmpty, true); final instance = instances.first; final env = await environmentFromBatchFile( @@ -174,7 +172,7 @@ void main() { }); test('vsDevCmd', () async { - final instances = await vsDevCmd.defaultResolver!.resolve(logger: logger); + final instances = await vsDevCmd.defaultResolver!.resolve(systemContext); expect(instances.isNotEmpty, true); final instance = instances.first; final env = await environmentFromBatchFile(instance.uri); diff --git a/pkgs/native_toolchain_c/test/native_toolchain/ndk_test.dart b/pkgs/native_toolchain_c/test/native_toolchain/ndk_test.dart index b21b0aa976..445d587e7c 100644 --- a/pkgs/native_toolchain_c/test/native_toolchain/ndk_test.dart +++ b/pkgs/native_toolchain_c/test/native_toolchain/ndk_test.dart @@ -2,9 +2,13 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +import 'dart:io'; + import 'package:native_toolchain_c/src/native_toolchain/android_ndk.dart'; import 'package:native_toolchain_c/src/tool/tool_requirement.dart'; +import 'package:native_toolchain_c/src/tool/tool_resolver.dart'; import 'package:test/test.dart'; +import 'package:test_descriptor/test_descriptor.dart' as d; import '../helpers.dart'; @@ -16,9 +20,47 @@ void main() { ToolRequirement(androidNdkLlvmAr), ToolRequirement(androidNdkLld), ]); - final resolved = await androidNdk.defaultResolver!.resolve(logger: logger); + final resolved = await androidNdk.defaultResolver!.resolve(systemContext); printOnFailure(resolved.toString()); final satisfied = requirement.satisfy(resolved); expect(satisfied?.length, 4); }); + + test('discovers NDK in ANDROID_HOME', () async { + await d.dir('fake_android', [ + d.dir('ndk', [d.dir('1.3.37')]), + ]).create(); + + final resolved = await androidNdk.defaultResolver!.resolve( + ToolResolvingContext( + logger: logger, + environment: {'ANDROID_HOME': d.path('fake_android')}, + ), + ); + resolved.retainWhere((e) => e.tool.name == androidNdk.name); + + expect( + resolved.map((e) => e.uri.toFilePath()), + contains(d.path('fake_android/ndk/1.3.37${Platform.pathSeparator}')), + ); + }); + + test('discovers NDK in ANDROID_NDK_HOME', () async { + await d.dir('weird', [ + d.dir('ndk', [d.dir('directory')]), + ]).create(); + + final resolved = await androidNdk.defaultResolver!.resolve( + ToolResolvingContext( + logger: logger, + environment: {'ANDROID_NDK_HOME': d.path('weird/ndk/directory')}, + ), + ); + resolved.retainWhere((e) => e.tool.name == androidNdk.name); + + expect( + resolved.map((e) => e.uri.toFilePath()), + contains(d.path('weird/ndk/directory${Platform.pathSeparator}')), + ); + }); } diff --git a/pkgs/native_toolchain_c/test/native_toolchain/recognizer_test.dart b/pkgs/native_toolchain_c/test/native_toolchain/recognizer_test.dart index 0b622be0be..d78470efe2 100644 --- a/pkgs/native_toolchain_c/test/native_toolchain/recognizer_test.dart +++ b/pkgs/native_toolchain_c/test/native_toolchain/recognizer_test.dart @@ -58,21 +58,21 @@ void main() async { test('compiler does not exist', () async { final tempUri = await tempDirForTest(); final recognizer = CompilerRecognizer(tempUri.resolve('asdf')); - final result = await recognizer.resolve(logger: logger); + final result = await recognizer.resolve(systemContext); expect(result, []); }); test('linker does not exist', () async { final tempUri = await tempDirForTest(); final recognizer = LinkerRecognizer(tempUri.resolve('asdf')); - final result = await recognizer.resolve(logger: logger); + final result = await recognizer.resolve(systemContext); expect(result, []); }); test('archiver does not exist', () async { final tempUri = await tempDirForTest(); final recognizer = ArchiverRecognizer(tempUri.resolve('asdf')); - final result = await recognizer.resolve(logger: logger); + final result = await recognizer.resolve(systemContext); expect(result, []); }); } @@ -86,7 +86,9 @@ class RecognizerTest { Future setUp() async { toolInstance = (await tool.defaultResolver!.resolve( - logger: null /* no printOnFailure support in setup. */, + ToolResolvingContext( + logger: null, + ) /* no printOnFailure support in setup. */, )).where((element) => element.tool == tool).firstOrNull; } @@ -101,7 +103,7 @@ class RecognizerTest { test('recognize ${tool.name}', () async { final recognizer_ = recognizer(toolInstance!.uri); final toolInstanceAgain = (await recognizer_.resolve( - logger: logger, + systemContext, )).first; expect(toolInstanceAgain, toolInstance); }); diff --git a/pkgs/native_toolchain_c/test/native_toolchain/xcode_test.dart b/pkgs/native_toolchain_c/test/native_toolchain/xcode_test.dart index 53fd039aa7..8aa53e30fe 100644 --- a/pkgs/native_toolchain_c/test/native_toolchain/xcode_test.dart +++ b/pkgs/native_toolchain_c/test/native_toolchain/xcode_test.dart @@ -23,35 +23,35 @@ void main() { test('xcrun', () async { final resolved = (await xcrun.defaultResolver!.resolve( - logger: logger, + systemContext, )).where((i) => i.tool == xcrun); expect(resolved.isNotEmpty, true); }); test('macosxSdk', () async { final resolved = (await macosxSdk.defaultResolver!.resolve( - logger: logger, + systemContext, )).where((i) => i.tool == macosxSdk); expect(resolved.isNotEmpty, true); }); test('iPhoneOSSdk', () async { final resolved = (await iPhoneOSSdk.defaultResolver!.resolve( - logger: logger, + systemContext, )).where((i) => i.tool == iPhoneOSSdk); expect(resolved.isNotEmpty, true); }); test('iPhoneSimulatorSdk', () async { final resolved = (await iPhoneSimulatorSdk.defaultResolver!.resolve( - logger: logger, + systemContext, )).where((i) => i.tool == iPhoneSimulatorSdk); expect(resolved.isNotEmpty, true); }); test('non-existing SDK', () async { final xcrunInstance = (await xcrun.defaultResolver!.resolve( - logger: logger, + systemContext, )).first; final tool = Tool(name: 'non-tool'); final result = await XCodeSdkResolver.tryResolveSdk( diff --git a/pkgs/native_toolchain_c/test/tool/tool_resolver_test.dart b/pkgs/native_toolchain_c/test/tool/tool_resolver_test.dart index 71ffe38962..e48ee676a4 100644 --- a/pkgs/native_toolchain_c/test/tool/tool_resolver_test.dart +++ b/pkgs/native_toolchain_c/test/tool/tool_resolver_test.dart @@ -19,9 +19,9 @@ import '../helpers.dart'; void main() { test('CliVersionResolver.executableVersion', () async { final toolInstances = [ - ...await appleClang.defaultResolver!.resolve(logger: logger), - ...await clang.defaultResolver!.resolve(logger: logger), - ...await cl.defaultResolver!.resolve(logger: logger), + ...await appleClang.defaultResolver!.resolve(systemContext), + ...await clang.defaultResolver!.resolve(systemContext), + ...await cl.defaultResolver!.resolve(systemContext), ]; expect(toolInstances.isNotEmpty, true); final toolInstance = toolInstances.first; @@ -73,14 +73,14 @@ void main() { wrappedResolver: barResolver, relativePath: Uri.file(bazExeName), ); - final resolvedBarInstances = await barResolver.resolve(logger: logger); + final resolvedBarInstances = await barResolver.resolve(systemContext); expect(resolvedBarInstances, [ ToolInstance( tool: Tool(name: 'bar'), uri: barExeUri, ), ]); - final resolvedBazInstances = await bazResolver.resolve(logger: logger); + final resolvedBazInstances = await bazResolver.resolve(systemContext); expect(resolvedBazInstances, [ ToolInstance( tool: Tool(name: 'baz'), @@ -105,8 +105,12 @@ void main() { ); final barLogs = []; final bazLogs = []; - await barResolver.resolve(logger: createCapturingLogger(barLogs)); - await bazResolver.resolve(logger: createCapturingLogger(bazLogs)); + await barResolver.resolve( + ToolResolvingContext(logger: createCapturingLogger(barLogs)), + ); + await bazResolver.resolve( + ToolResolvingContext(logger: createCapturingLogger(bazLogs)), + ); expect(barLogs.join('\n'), contains('Found [ToolInstance(bar')); expect(bazLogs.join('\n'), contains('Found no baz')); });