-
Notifications
You must be signed in to change notification settings - Fork 42
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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,126 @@ | ||
// 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:convert'; | ||
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 config = BuildConfigImpl( | ||
outputDirectory: tempUri, | ||
packageName: name, | ||
packageRoot: testPackageUri, | ||
targetOS: OSImpl.current, | ||
version: HookConfigImpl.latestVersion, | ||
linkModePreference: LinkModePreferenceImpl.dynamic, | ||
dryRun: dryRun, | ||
linkingEnabled: false, | ||
targetArchitecture: dryRun ? null : ArchitectureImpl.current, | ||
buildMode: dryRun ? null : BuildModeImpl.debug, | ||
cCompiler: dryRun | ||
? null | ||
: CCompilerConfigImpl( | ||
compiler: cc, | ||
envScript: envScript, | ||
envScriptArgs: envScriptArgs, | ||
), | ||
); | ||
|
||
final buildConfigUri = testTempUri.resolve('build_config.json'); | ||
File.fromUri(buildConfigUri) | ||
.writeAsStringSync(jsonEncode(config.toJson())); | ||
|
||
final processResult = await Process.run( | ||
dartUri.toFilePath(), | ||
[ | ||
'hook/build.dart', | ||
'--config=${buildConfigUri.toFilePath()}', | ||
], | ||
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'); | ||
} | ||
}); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
An example library that builds 3 native libraries, 2 of which are dynamically | ||
linked to each other. | ||
|
||
## Usage | ||
|
||
Run tests with `dart --enable-experiment=native-assets test`. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import 'package:native_dynamic_linking/add.dart'; | ||
|
||
void main() => print('${add(24, 18)}'); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Run with `flutter pub run ffigen --config ffigen.yaml`. | ||
name: AddBindings | ||
description: | | ||
Bindings for `src/add.h`. | ||
|
||
Regenerate bindings with `flutter pub run ffigen --config ffigen.yaml`. | ||
output: 'lib/add.dart' | ||
headers: | ||
entry-points: | ||
- 'src/add.h' | ||
include-directives: | ||
- 'src/add.h' | ||
preamble: | | ||
// 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. | ||
comments: | ||
style: any | ||
length: full | ||
ffi-native: |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// 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 'package:logging/logging.dart'; | ||
import 'package:native_assets_cli/native_assets_cli.dart'; | ||
import 'package:native_toolchain_c/native_toolchain_c.dart'; | ||
|
||
void main(List<String> args) async { | ||
await build(args, (config, output) async { | ||
final logger = Logger('') | ||
..level = Level.ALL | ||
..onRecord.listen((record) => print(record.message)); | ||
|
||
final builders = [ | ||
CBuilder.library( | ||
name: 'debug', | ||
assetName: 'debug', | ||
sources: [ | ||
'src/debug.c', | ||
], | ||
), | ||
CBuilder.library( | ||
name: 'math', | ||
assetName: 'math', | ||
sources: [ | ||
'src/math.c', | ||
], | ||
// TODO(https://github.com/dart-lang/native/issues/190): Use specific | ||
// API for linking once available. | ||
flags: config.dynamicLinkingFlags('debug'), | ||
), | ||
CBuilder.library( | ||
name: 'add', | ||
assetName: 'add.dart', | ||
sources: [ | ||
'src/add.c', | ||
], | ||
// TODO(https://github.com/dart-lang/native/issues/190): Use specific | ||
// API for linking once available. | ||
flags: config.dynamicLinkingFlags('math'), | ||
) | ||
]; | ||
|
||
// Note: This builders need to be run sequentially because they depend on | ||
// each others output. | ||
for (final builder in builders) { | ||
await builder.run( | ||
config: config, | ||
output: output, | ||
logger: logger, | ||
); | ||
} | ||
}); | ||
} | ||
|
||
extension on BuildConfig { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Code like this, switching over OSs, seems like something which should actually live in a helper package. Or is it specific to this example? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or is this covered by #190? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've started working on an option for |
||
List<String> dynamicLinkingFlags(String libraryName) => switch (targetOS) { | ||
OS.macOS => [ | ||
'-L${outputDirectory.toFilePath()}', | ||
'-l$libraryName', | ||
], | ||
OS.linux => [ | ||
r'-Wl,-rpath=$ORIGIN', | ||
'-L${outputDirectory.toFilePath()}', | ||
'-l$libraryName', | ||
], | ||
OS.windows => [ | ||
outputDirectory.resolve('$libraryName.dll').toFilePath(), | ||
], | ||
_ => throw UnimplementedError('Unsupported OS: $targetOS'), | ||
}; | ||
} |
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. | ||
|
||
// AUTO GENERATED FILE, DO NOT EDIT. | ||
// | ||
// Generated by `package:ffigen`. | ||
// ignore_for_file: type=lint | ||
import 'dart:ffi' as ffi; | ||
|
||
@ffi.Native<ffi.Int32 Function(ffi.Int32, ffi.Int32)>(symbol: 'add') | ||
external int add( | ||
int a, | ||
int b, | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please exercise the test data in a new test in pkgs/native_assets_builder/test/