Skip to content

Commit

Permalink
Add Android NDK API version (#49)
Browse files Browse the repository at this point in the history
  • Loading branch information
dcharkes authored May 23, 2023
1 parent 0c9079f commit 3e1cf18
Show file tree
Hide file tree
Showing 11 changed files with 190 additions and 46 deletions.
4 changes: 3 additions & 1 deletion pkgs/c_compiler/lib/src/cbuilder/run_cbuilder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@ class RunCBuilder {
// The sysroot should be discovered automatically after NDK 22.
// Workaround:
if (dynamicLibrary != null) '-nostartfiles',
'--target=${androidNdkClangTargetFlags[target]!}',
'--target='
'${androidNdkClangTargetFlags[target]!}'
'${buildConfig.targetAndroidNdkApi!}',
],
if (target.os == OS.macOS || target.os == OS.iOS)
'--target=${appleClangTargetFlags[target]!}',
Expand Down
97 changes: 71 additions & 26 deletions pkgs/c_compiler/test/cbuilder/cbuilder_cross_android_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,37 +33,22 @@ void main() {
Target.androidX64: 'elf64-x86-64',
};

/// From https://docs.flutter.dev/reference/supported-platforms.
const flutterAndroidNdkVersionLowestSupported = 21;

/// From https://docs.flutter.dev/reference/supported-platforms.
const flutterAndroidNdkVersionHighestSupported = 30;

for (final linkMode in LinkMode.values) {
for (final target in targets) {
test('Cbuilder $linkMode library $target', () async {
await inTempDir((tempUri) async {
final addCUri =
packageUri.resolve('test/cbuilder/testfiles/add/src/add.c');
const name = 'add';

final buildConfig = BuildConfig(
outDir: tempUri,
packageRoot: tempUri,
target: target,
linkModePreference: linkMode == LinkMode.dynamic
? LinkModePreference.dynamic
: LinkModePreference.static,
final libUri = await buildLib(
tempUri,
target,
flutterAndroidNdkVersionLowestSupported,
linkMode,
);
final buildOutput = BuildOutput();

final cbuilder = CBuilder.library(
name: 'add',
assetName: 'add',
sources: [addCUri.toFilePath()],
);
await cbuilder.run(
buildConfig: buildConfig,
buildOutput: buildOutput,
logger: logger,
);

final libUri =
tempUri.resolve(target.os.libraryFileName(name, linkMode));
if (Platform.isLinux) {
final result = await runProcess(
executable: Uri.file('readelf'),
Expand Down Expand Up @@ -91,4 +76,64 @@ void main() {
});
}
}

test('Cbuilder API levels binary difference', () async {
const target = Target.androidArm64;
const linkMode = LinkMode.dynamic;
const apiLevel1 = flutterAndroidNdkVersionLowestSupported;
const apiLevel2 = flutterAndroidNdkVersionHighestSupported;
await inTempDir((tempUri) async {
final out1Uri = tempUri.resolve('out1/');
final out2Uri = tempUri.resolve('out2/');
final out3Uri = tempUri.resolve('out3/');
await Directory.fromUri(out1Uri).create();
await Directory.fromUri(out2Uri).create();
await Directory.fromUri(out3Uri).create();
final lib1Uri = await buildLib(out1Uri, target, apiLevel1, linkMode);
final lib2Uri = await buildLib(out2Uri, target, apiLevel2, linkMode);
final lib3Uri = await buildLib(out3Uri, target, apiLevel2, linkMode);
final bytes1 = await File.fromUri(lib1Uri).readAsBytes();
final bytes2 = await File.fromUri(lib2Uri).readAsBytes();
final bytes3 = await File.fromUri(lib3Uri).readAsBytes();
// Different API levels should lead to a different binary.
expect(bytes1, isNot(bytes2));
// Identical API levels should lead to an identical binary.
expect(bytes2, bytes3);
});
});
}

Future<Uri> buildLib(
Uri tempUri,
Target target,
int androidNdkApi,
LinkMode linkMode,
) async {
final addCUri = packageUri.resolve('test/cbuilder/testfiles/add/src/add.c');
const name = 'add';

final buildConfig = BuildConfig(
outDir: tempUri,
packageRoot: tempUri,
target: target,
targetAndroidNdkApi: androidNdkApi,
linkModePreference: linkMode == LinkMode.dynamic
? LinkModePreference.dynamic
: LinkModePreference.static,
);
final buildOutput = BuildOutput();

final cbuilder = CBuilder.library(
name: name,
assetName: name,
sources: [addCUri.toFilePath()],
);
await cbuilder.run(
buildConfig: buildConfig,
buildOutput: buildOutput,
logger: logger,
);

final libUri = tempUri.resolve(target.os.libraryFileName(name, linkMode));
return libUri;
}
4 changes: 2 additions & 2 deletions pkgs/c_compiler/test/cbuilder/cbuilder_cross_ios_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ void main() {
final buildOutput = BuildOutput();

final cbuilder = CBuilder.library(
name: 'add',
assetName: 'add',
name: name,
assetName: name,
sources: [addCUri.toFilePath()],
);
await cbuilder.run(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ void main() {
final buildOutput = BuildOutput();

final cbuilder = CBuilder.library(
name: 'add',
assetName: 'add',
name: name,
assetName: name,
sources: [addCUri.toFilePath()],
);
await cbuilder.run(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ void main() {
final buildOutput = BuildOutput();

final cbuilder = CBuilder.library(
name: 'add',
assetName: 'add',
name: name,
assetName: name,
sources: [addCUri.toFilePath()],
);
await cbuilder.run(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ void main() {
final buildOutput = BuildOutput();

final cbuilder = CBuilder.library(
name: 'add',
assetName: 'add',
name: name,
assetName: name,
sources: [addCUri.toFilePath()],
);
await cbuilder.run(
Expand Down
18 changes: 18 additions & 0 deletions pkgs/native_assets_cli/lib/src/model/build_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ class BuildConfig {
IOSSdk? get targetIOSSdk => _targetIOSSdk;
late final IOSSdk? _targetIOSSdk;

/// When compiling for Android, the API version to target.
///
/// Required when [target.os] equals [OS.android].
int? get targetAndroidNdkApi => _targetAndroidNdkApi;
late final int? _targetAndroidNdkApi;

/// Preferred linkMode method for library.
LinkModePreference get linkModePreference => _linkModePreference;
late final LinkModePreference _linkModePreference;
Expand Down Expand Up @@ -66,6 +72,7 @@ class BuildConfig {
required Uri packageRoot,
required Target target,
IOSSdk? targetIOSSdk,
int? targetAndroidNdkApi,
CCompilerConfig? cCompiler,
required LinkModePreference linkModePreference,
Map<String, Metadata>? dependencyMetadata,
Expand All @@ -75,6 +82,7 @@ class BuildConfig {
.._packageRoot = packageRoot
.._target = target
.._targetIOSSdk = targetIOSSdk
.._targetAndroidNdkApi = targetAndroidNdkApi
.._cCompiler = cCompiler ?? CCompilerConfig()
.._linkModePreference = linkModePreference
.._dependencyMetadata = dependencyMetadata;
Expand All @@ -94,6 +102,7 @@ class BuildConfig {
required Uri packageRoot,
required Target target,
IOSSdk? targetIOSSdk,
int? targetAndroidNdkApi,
CCompilerConfig? cCompiler,
required LinkModePreference linkModePreference,
Map<String, Metadata>? dependencyMetadata,
Expand All @@ -103,6 +112,7 @@ class BuildConfig {
packageName,
target.toString(),
targetIOSSdk.toString(),
targetAndroidNdkApi.toString(),
linkModePreference.toString(),
cCompiler?.ar.toString(),
cCompiler?.cc.toString(),
Expand Down Expand Up @@ -184,6 +194,7 @@ class BuildConfig {
static const packageRootConfigKey = 'package_root';
static const dependencyMetadataConfigKey = 'dependency_metadata';
static const _versionKey = 'version';
static const targetAndroidNdkApiConfigKey = 'target_android_ndk_api';

List<void Function(Config)> _readFieldsFromConfig() {
var targetSet = false;
Expand Down Expand Up @@ -227,6 +238,9 @@ class BuildConfig {
),
)
: null,
(config) => _targetAndroidNdkApi = (targetSet && _target.os == OS.android)
? config.int(targetAndroidNdkApiConfigKey)
: null,
(config) => cCompiler._ar =
config.optionalPath(CCompilerConfig.arConfigKeyFull, mustExist: true),
(config) {
Expand Down Expand Up @@ -292,6 +306,8 @@ class BuildConfig {
packageRootConfigKey: _packageRoot.toFilePath(),
Target.configKey: _target.toString(),
if (_targetIOSSdk != null) IOSSdk.configKey: _targetIOSSdk.toString(),
if (_targetAndroidNdkApi != null)
targetAndroidNdkApiConfigKey: _targetAndroidNdkApi!,
if (cCompilerYaml.isNotEmpty) CCompilerConfig.configKey: cCompilerYaml,
LinkModePreference.configKey: _linkModePreference.toString(),
if (_dependencyMetadata != null)
Expand All @@ -314,6 +330,7 @@ class BuildConfig {
if (other._packageRoot != _packageRoot) return false;
if (other._target != _target) return false;
if (other._targetIOSSdk != _targetIOSSdk) return false;
if (other._targetAndroidNdkApi != _targetAndroidNdkApi) return false;
if (other._cCompiler != _cCompiler) return false;
if (other._linkModePreference != _linkModePreference) return false;
if (!DeepCollectionEquality()
Expand All @@ -327,6 +344,7 @@ class BuildConfig {
_packageRoot,
_target,
_targetIOSSdk,
_targetAndroidNdkApi,
_cCompiler,
_linkModePreference,
DeepCollectionEquality().hash(_dependencyMetadata),
Expand Down
7 changes: 6 additions & 1 deletion pkgs/native_assets_cli/test/model/asset_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,12 @@ native-assets:
});

test('AssetPath factory', () async {
expect(() => AssetPath('wrong', null), throwsFormatException);
expect(
() => AssetPath('wrong', null),
throwsA(predicate(
(e) => e is FormatException && e.message.contains('Unknown pathType'),
)),
);
});

test('Asset hashCode copyWith', () async {
Expand Down
Loading

0 comments on commit 3e1cf18

Please sign in to comment.