From 4c9a50f78abdbbd3c823173ad7c9260aee5e0ff1 Mon Sep 17 00:00:00 2001 From: Daco Harkes Date: Wed, 1 Nov 2023 19:39:49 +0100 Subject: [PATCH] [native_toolchain_c] Add workaround for minSdkVersion 19 and 20 (#181) Closes: https://github.com/dart-lang/native/issues/171 Uses the workaround that the Android Gradle plugin uses: https://github.com/dart-lang/native/issues/171#issuecomment-1789064713. --- .../lib/src/cbuilder/run_cbuilder.dart | 12 +++- .../cbuilder/cbuilder_cross_android_test.dart | 72 +++++++++++-------- 2 files changed, 52 insertions(+), 32 deletions(-) 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 1fa571865..0db3ddab3 100644 --- a/pkgs/native_toolchain_c/lib/src/cbuilder/run_cbuilder.dart +++ b/pkgs/native_toolchain_c/lib/src/cbuilder/run_cbuilder.dart @@ -2,6 +2,8 @@ // 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:math'; + import 'package:logging/logging.dart'; import 'package:native_assets_cli/native_assets_cli.dart'; @@ -126,13 +128,21 @@ class RunCBuilder { targetIosSdk = buildConfig.targetIOSSdk!; } + // The Android Gradle plugin does not honor API level 19 and 20 when + // invoking clang. Mimic that behavior here. + // See https://github.com/dart-lang/native/issues/171. + late final int targetAndroidNdkApi; + if (target.os == OS.android) { + targetAndroidNdkApi = max(buildConfig.targetAndroidNdkApi!, 21); + } + await runProcess( executable: compiler.uri, arguments: [ if (target.os == OS.android) ...[ '--target=' '${androidNdkClangTargetFlags[target]!}' - '${buildConfig.targetAndroidNdkApi!}', + '$targetAndroidNdkApi', '--sysroot=${androidSysroot(compiler).toFilePath()}', ], if (target.os == OS.macOS) diff --git a/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_android_test.dart b/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_android_test.dart index abaec7ea7..0f5081aec 100644 --- a/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_android_test.dart +++ b/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_android_test.dart @@ -33,6 +33,9 @@ void main() { Target.androidX64: 'elf64-x86-64', }; + /// From https://docs.flutter.dev/reference/supported-platforms. + const flutterAndroidNdkVersionLowestBestEffort = 19; + /// From https://docs.flutter.dev/reference/supported-platforms. const flutterAndroidNdkVersionLowestSupported = 21; @@ -41,38 +44,45 @@ void main() { for (final linkMode in LinkMode.values) { for (final target in targets) { - test('CBuilder $linkMode library $target', () async { - final tempUri = await tempDirForTest(); - final libUri = await buildLib( - tempUri, - target, - flutterAndroidNdkVersionLowestSupported, - linkMode, - ); - if (Platform.isLinux) { - final result = await runProcess( - executable: Uri.file('readelf'), - arguments: ['-h', libUri.path], - logger: logger, - ); - expect(result.exitCode, 0); - final machine = result.stdout - .split('\n') - .firstWhere((e) => e.contains('Machine:')); - expect(machine, contains(readElfMachine[target])); - } else if (Platform.isMacOS) { - final result = await runProcess( - executable: Uri.file('objdump'), - arguments: ['-T', libUri.path], - logger: logger, + for (final apiLevel in [ + flutterAndroidNdkVersionLowestBestEffort, + flutterAndroidNdkVersionLowestSupported, + flutterAndroidNdkVersionHighestSupported, + ]) { + test('CBuilder $linkMode library $target minSdkVersion $apiLevel', + () async { + final tempUri = await tempDirForTest(); + final libUri = await buildLib( + tempUri, + target, + apiLevel, + linkMode, ); - expect(result.exitCode, 0); - final machine = result.stdout - .split('\n') - .firstWhere((e) => e.contains('file format')); - expect(machine, contains(objdumpFileFormat[target])); - } - }); + if (Platform.isLinux) { + final result = await runProcess( + executable: Uri.file('readelf'), + arguments: ['-h', libUri.path], + logger: logger, + ); + expect(result.exitCode, 0); + final machine = result.stdout + .split('\n') + .firstWhere((e) => e.contains('Machine:')); + expect(machine, contains(readElfMachine[target])); + } else if (Platform.isMacOS) { + final result = await runProcess( + executable: Uri.file('objdump'), + arguments: ['-T', libUri.path], + logger: logger, + ); + expect(result.exitCode, 0); + final machine = result.stdout + .split('\n') + .firstWhere((e) => e.contains('file format')); + expect(machine, contains(objdumpFileFormat[target])); + } + }); + } } }