Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add native_dynamic_linking to test_data #1437

Merged
merged 4 commits into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 68 additions & 2 deletions pkgs/native_assets_builder/test/helpers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,22 @@ import 'dart:io';
import 'package:logging/logging.dart';
import 'package:native_assets_builder/src/utils/run_process.dart'
as run_process;
import 'package:native_assets_cli/native_assets_cli.dart';
import 'package:native_assets_cli/native_assets_cli_internal.dart' as internal;
import 'package:test/test.dart';
import 'package:yaml/yaml.dart';

extension UriExtension on Uri {
String get name => pathSegments.where((e) => e != '').last;

Uri get parent => File(toFilePath()).parent.uri;

FileSystemEntity get fileSystemEntity {
if (path.endsWith(Platform.pathSeparator) || path.endsWith('/')) {
return Directory.fromUri(this);
}
return File.fromUri(this);
}
}

const keepTempKey = 'KEEP_TEMPORARY_DIRECTORIES';
Expand Down Expand Up @@ -112,8 +123,63 @@ final pkgNativeAssetsBuilderUri = findPackageRoot('native_assets_builder');

final testDataUri = pkgNativeAssetsBuilderUri.resolve('test_data/');

extension on Uri {
String get name => pathSegments.where((e) => e != '').last;
String unparseKey(String key) => key.replaceAll('.', '__').toUpperCase();

/// Archiver provided by the environment.
///
/// Provided on Dart CI.
final Uri? ar = Platform
.environment[unparseKey(internal.CCompilerConfigImpl.arConfigKeyFull)]
?.asFileUri();

/// Compiler provided by the environment.
///
/// Provided on Dart CI.
final Uri? cc = Platform
.environment[unparseKey(internal.CCompilerConfigImpl.ccConfigKeyFull)]
?.asFileUri();

/// Linker provided by the environment.
///
/// Provided on Dart CI.
final Uri? ld = Platform
.environment[unparseKey(internal.CCompilerConfigImpl.ldConfigKeyFull)]
?.asFileUri();

/// Path to script that sets environment variables for [cc], [ld], and [ar].
///
/// Provided on Dart CI.
final Uri? envScript = Platform.environment[
unparseKey(internal.CCompilerConfigImpl.envScriptConfigKeyFull)]
?.asFileUri();

/// Arguments for [envScript] provided by environment.
///
/// Provided on Dart CI.
final List<String>? envScriptArgs = Platform.environment[
unparseKey(internal.CCompilerConfigImpl.envScriptArgsConfigKeyFull)]
?.split(' ');

extension on String {
Uri asFileUri() => Uri.file(this);
}

extension AssetIterable on Iterable<Asset> {
Future<bool> allExist() async {
final allResults = await Future.wait(map((e) => e.exists()));
final missing = allResults.contains(false);
return !missing;
}
}

extension on Asset {
Future<bool> exists() async {
final path_ = file;
return switch (path_) {
null => true,
_ => await path_.fileSystemEntity.exists(),
};
}
}

Future<void> copyTestProjects({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// 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:ffi';

void main(List<String> arguments) {
final addLibraryPath = arguments[0];
final a = int.parse(arguments[1]);
final b = int.parse(arguments[2]);
final addLibrary = DynamicLibrary.open(addLibraryPath);
final add = addLibrary.lookupFunction<Int32 Function(Int32, Int32),
int Function(int, int)>('add');
print(add(a, b));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// 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.

@OnPlatform({
'mac-os': Timeout.factor(2),
'windows': Timeout.factor(10),
})
library;

import 'dart:io';

import 'package:native_assets_cli/native_assets_cli_internal.dart';
import 'package:test/test.dart';

import '../helpers.dart';

void main() async {
late Uri tempUri;
const name = 'native_dynamic_linking';

setUp(() async {
tempUri = (await Directory.systemTemp.createTemp()).uri;
});

tearDown(() async {
await Directory.fromUri(tempUri).delete(recursive: true);
});

for (final dryRun in [true, false]) {
final testSuffix = dryRun ? ' dry_run' : '';
test('native_dynamic_linking build$testSuffix', () async {
final testTempUri = tempUri.resolve('test1/');
await Directory.fromUri(testTempUri).create();
final testPackageUri = testDataUri.resolve('$name/');
final dartUri = Uri.file(Platform.resolvedExecutable);

final processResult = await Process.run(
dartUri.toFilePath(),
[
'hook/build.dart',
'-Dout_dir=${tempUri.toFilePath()}',
'-Dpackage_name=$name',
'-Dpackage_root=${testPackageUri.toFilePath()}',
'-Dtarget_os=${OSImpl.current}',
'-Dversion=${HookConfigImpl.latestVersion}',
'-Dlink_mode_preference=dynamic',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add -Dlinking_enabled=0 (see fixes to tests in #1507)

Or possibly better, use BuildConfig constructor and write the config to a file and pass that in.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

'-Ddry_run=$dryRun',
if (!dryRun) ...[
'-Dtarget_architecture=${ArchitectureImpl.current}',
'-Dbuild_mode=debug',
if (cc != null) '-Dcc=${cc!.toFilePath()}',
if (envScript != null)
'-D${CCompilerConfigImpl.envScriptConfigKeyFull}='
'${envScript!.toFilePath()}',
if (envScriptArgs != null)
'-D${CCompilerConfigImpl.envScriptArgsConfigKeyFull}='
'${envScriptArgs!.join(' ')}',
],
],
workingDirectory: testPackageUri.toFilePath(),
);
if (processResult.exitCode != 0) {
print(processResult.stdout);
print(processResult.stderr);
print(processResult.exitCode);
}
expect(processResult.exitCode, 0);

final buildOutputUri = tempUri.resolve('build_output.json');
final buildOutput = HookOutputImpl.fromJsonString(
await File.fromUri(buildOutputUri).readAsString());
final assets = buildOutput.assets;
final dependencies = buildOutput.dependencies;
if (dryRun) {
expect(assets.length, greaterThanOrEqualTo(3));
expect(dependencies, <Uri>[]);
} else {
expect(assets.length, 3);
expect(await assets.allExist(), true);
expect(
dependencies,
[
testPackageUri.resolve('src/debug.c'),
testPackageUri.resolve('src/math.c'),
testPackageUri.resolve('src/add.c'),
],
);

final addLibraryPath = assets
.firstWhere((asset) => asset.id.endsWith('add.dart'))
.file!
.toFilePath();
final addResult = await runProcess(
executable: dartExecutable,
arguments: [
'run',
pkgNativeAssetsBuilderUri
.resolve('test/test_data/native_dynamic_linking_add.dart')
.toFilePath(),
addLibraryPath,
'1',
'2',
],
environment: {
// Add the directory containing the linked dynamic libraries to the
// PATH so that the dynamic linker can find them.
if (Platform.isWindows)
'PATH': '${tempUri.toFilePath()};${Platform.environment['PATH']}',
},
throwOnUnexpectedExitCode: true,
logger: logger,
);
expect(addResult.stdout, 'Adding 1 and 2.\n3\n');
}
});
}
}