mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 12:24:24 +00:00
[samples/ffi] Fix samples and run them as test
Change-Id: I49eeba32d99c9cf916d25150b46fa6d74ece0092 Cq-Include-Trybots: luci.dart.try:vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64-try,app-kernel-linux-debug-x64-try,vm-kernel-linux-debug-ia32-try,vm-dartkb-linux-debug-simarm64-try,vm-kernel-win-debug-x64-try,vm-kernel-win-debug-ia32-try,vm-dartkb-linux-debug-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-dartkb-linux-release-x64-abi-try,vm-kernel-precomp-android-release-arm64-try,vm-kernel-asan-linux-release-x64-try,vm-kernel-linux-release-simarm-try,vm-kernel-linux-release-simarm64-try,vm-kernel-precomp-android-release-arm_x64-try,vm-kernel-precomp-obfuscate-linux-release-x64-try,vm-kernel-reload-rollback-linux-debug-x64-try,vm-kernel-precomp-mac-release-simarm_x64-try,dart-sdk-linux-try,analyzer-analysis-server-linux-try,analyzer-linux-release-try,front-end-linux-release-x64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/122382 Commit-Queue: Daco Harkes <dacoharkes@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
parent
ef742aa6f0
commit
aa36c1fbc5
13 changed files with 221 additions and 248 deletions
|
@ -2,11 +2,9 @@
|
|||
// 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.
|
||||
|
||||
library FfiTest;
|
||||
|
||||
import 'dart:ffi';
|
||||
|
||||
import 'package:ffi/ffi.dart' as ffi;
|
||||
import "package:ffi/ffi.dart";
|
||||
|
||||
/// Sample struct for dart:ffi library.
|
||||
class Coordinate extends Struct {
|
||||
|
@ -18,20 +16,10 @@ class Coordinate extends Struct {
|
|||
|
||||
Pointer<Coordinate> next;
|
||||
|
||||
// Implementation generated by @ffi.struct annotation.
|
||||
external static int sizeOf();
|
||||
|
||||
Coordinate elementAt(int index) => addressOf.elementAt(index).ref;
|
||||
|
||||
static Coordinate allocate({int count: 1}) =>
|
||||
ffi.allocate<Coordinate>(count: count).ref;
|
||||
|
||||
/// Allocate a new [Coordinate] in C memory and populate its fields.
|
||||
factory Coordinate(double x, double y, Coordinate next) {
|
||||
Coordinate result = Coordinate.allocate()
|
||||
factory Coordinate.allocate(double x, double y, Pointer<Coordinate> next) {
|
||||
return allocate<Coordinate>().ref
|
||||
..x = x
|
||||
..y = y
|
||||
..next = next.addressOf;
|
||||
return result;
|
||||
..next = next;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,18 +2,19 @@
|
|||
// 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' as ffi;
|
||||
import 'dart:ffi';
|
||||
import 'dart:io' show Platform;
|
||||
|
||||
String _platformPath(String name, {String path}) {
|
||||
if (path == null) path = "";
|
||||
if (Platform.isLinux) return path + "lib" + name + ".so";
|
||||
if (Platform.isLinux || Platform.isAndroid)
|
||||
return path + "lib" + name + ".so";
|
||||
if (Platform.isMacOS) return path + "lib" + name + ".dylib";
|
||||
if (Platform.isWindows) return path + name + ".dll";
|
||||
throw Exception("Platform not implemented");
|
||||
}
|
||||
|
||||
ffi.DynamicLibrary dlopenPlatformSpecific(String name, {String path}) {
|
||||
DynamicLibrary dlopenPlatformSpecific(String name, {String path}) {
|
||||
String fullPath = _platformPath(name, path: path);
|
||||
return ffi.DynamicLibrary.open(fullPath);
|
||||
return DynamicLibrary.open(fullPath);
|
||||
}
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
import 'dart:ffi';
|
||||
import 'package:ffi/ffi.dart';
|
||||
|
||||
main(List<String> arguments) {
|
||||
main() {
|
||||
print('start main');
|
||||
|
||||
{
|
||||
// basic operation: allocate, get, set, and free
|
||||
// Basic operation: allocate, get, set, and free.
|
||||
Pointer<Int64> p = allocate();
|
||||
p.value = 42;
|
||||
int pValue = p.value;
|
||||
|
@ -18,7 +18,7 @@ main(List<String> arguments) {
|
|||
}
|
||||
|
||||
{
|
||||
// undefined behavior before set
|
||||
// Undefined behavior before set.
|
||||
Pointer<Int64> p = allocate();
|
||||
int pValue = p.value;
|
||||
print('If not set, returns garbage: ${pValue}');
|
||||
|
@ -26,7 +26,7 @@ main(List<String> arguments) {
|
|||
}
|
||||
|
||||
{
|
||||
// pointers can be created from an address
|
||||
// Pointers can be created from an address.
|
||||
Pointer<Int64> pHelper = allocate();
|
||||
pHelper.value = 1337;
|
||||
|
||||
|
@ -40,31 +40,31 @@ main(List<String> arguments) {
|
|||
}
|
||||
|
||||
{
|
||||
// address is zeroed out after free
|
||||
// Address is zeroed out after free.
|
||||
Pointer<Int64> p = allocate();
|
||||
free(p);
|
||||
print('After free, address is zero: ${p.address}');
|
||||
}
|
||||
|
||||
{
|
||||
// allocating too much throws an exception
|
||||
// Allocating too much throws an exception.
|
||||
try {
|
||||
int maxMint = 9223372036854775807; // 2^63 - 1
|
||||
allocate<Int64>(count: maxMint);
|
||||
} on RangeError {
|
||||
} on Error {
|
||||
print('Expected exception on allocating too much');
|
||||
}
|
||||
try {
|
||||
int maxInt1_8 = 1152921504606846975; // 2^60 -1
|
||||
allocate<Int64>(count: maxInt1_8);
|
||||
} on ArgumentError {
|
||||
} on Error {
|
||||
print('Expected exception on allocating too much');
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// pointers can be cast into another type
|
||||
// resulting in the corresponding bits read
|
||||
// Pointers can be cast into another type,
|
||||
// resulting in the corresponding bits read.
|
||||
Pointer<Int64> p1 = allocate();
|
||||
p1.value = 9223372036854775807; // 2^63 - 1
|
||||
|
||||
|
@ -78,7 +78,7 @@ main(List<String> arguments) {
|
|||
}
|
||||
|
||||
{
|
||||
// data can be tightly packed in memory
|
||||
// Data can be tightly packed in memory.
|
||||
Pointer<Int8> p = allocate(count: 8);
|
||||
for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) {
|
||||
p.elementAt(i).value = i * 3;
|
||||
|
@ -90,20 +90,18 @@ main(List<String> arguments) {
|
|||
}
|
||||
|
||||
{
|
||||
// exception on storing a value that does not fit
|
||||
// Values that don't fit are truncated.
|
||||
Pointer<Int32> p11 = allocate();
|
||||
|
||||
try {
|
||||
p11.value = 9223372036854775807;
|
||||
} on ArgumentError {
|
||||
print('Expected exception on calling set with a value that does not fit');
|
||||
}
|
||||
p11.value = 9223372036854775807;
|
||||
|
||||
print(p11);
|
||||
|
||||
free(p11);
|
||||
}
|
||||
|
||||
{
|
||||
// doubles
|
||||
// Doubles.
|
||||
Pointer<Double> p = allocate();
|
||||
p.value = 3.14159265359;
|
||||
print('${p.runtimeType} value: ${p.value}');
|
||||
|
@ -113,7 +111,7 @@ main(List<String> arguments) {
|
|||
}
|
||||
|
||||
{
|
||||
// floats
|
||||
// Floats.
|
||||
Pointer<Float> p = allocate();
|
||||
p.value = 3.14159265359;
|
||||
print('${p.runtimeType} value: ${p.value}');
|
||||
|
@ -123,8 +121,8 @@ main(List<String> arguments) {
|
|||
}
|
||||
|
||||
{
|
||||
// IntPtr varies in size based on whether the platform is 32 or 64 bit
|
||||
// addresses of pointers fit in this size
|
||||
// IntPtr varies in size based on whether the platform is 32 or 64 bit.
|
||||
// Addresses of pointers fit in this size.
|
||||
Pointer<IntPtr> p = allocate();
|
||||
int p14addr = p.address;
|
||||
p.value = p14addr;
|
||||
|
@ -134,36 +132,28 @@ main(List<String> arguments) {
|
|||
}
|
||||
|
||||
{
|
||||
// void pointers are unsized
|
||||
// the size of the element it is pointing to is undefined
|
||||
// this means they cannot be allocated, read, or written
|
||||
// this would would fail to compile:
|
||||
// allocate<Void>();
|
||||
// Void pointers are unsized.
|
||||
// The size of the element it is pointing to is undefined,
|
||||
// they cannot be allocated, read, or written.
|
||||
|
||||
Pointer<IntPtr> p1 = allocate();
|
||||
Pointer<Void> p2 = p1.cast();
|
||||
print('${p2.runtimeType} address: ${p2.address}');
|
||||
|
||||
// this fails to compile, we cannot read something unsized
|
||||
// p2.load<int>();
|
||||
|
||||
// this fails to compile, we cannot write something unsized
|
||||
// p2.store(1234);
|
||||
|
||||
free(p1);
|
||||
}
|
||||
|
||||
{
|
||||
// pointer to a pointer to something
|
||||
// Pointer to a pointer to something.
|
||||
Pointer<Int16> pHelper = allocate();
|
||||
pHelper.value = 17;
|
||||
|
||||
Pointer<Pointer<Int16>> p = allocate();
|
||||
|
||||
// storing into a pointer pointer automatically unboxes
|
||||
// Storing into a pointer pointer automatically unboxes.
|
||||
p.value = pHelper;
|
||||
|
||||
// reading from a pointer pointer automatically boxes
|
||||
// Reading from a pointer pointer automatically boxes.
|
||||
Pointer<Int16> pHelper2 = p.value;
|
||||
print('${pHelper2.runtimeType} value: ${pHelper2.value}');
|
||||
|
||||
|
@ -175,23 +165,22 @@ main(List<String> arguments) {
|
|||
}
|
||||
|
||||
{
|
||||
// the pointer to pointer types must match up
|
||||
// The pointer to pointer types must match up.
|
||||
Pointer<Int8> pHelper = allocate();
|
||||
pHelper.value = 123;
|
||||
|
||||
Pointer<Pointer<Int16>> p = allocate();
|
||||
|
||||
// this fails to compile due to type mismatch
|
||||
// p.store(pHelper);
|
||||
// Trying to store `pHelper` into `p.val` would result in a type mismatch.
|
||||
|
||||
free(pHelper);
|
||||
free(p);
|
||||
}
|
||||
|
||||
{
|
||||
// null pointer in Dart points to address 0 in c++
|
||||
// `nullptr` points to address 0 in c++.
|
||||
Pointer<Pointer<Int8>> pointerToPointer = allocate();
|
||||
Pointer<Int8> value = null;
|
||||
Pointer<Int8> value = nullptr;
|
||||
pointerToPointer.value = value;
|
||||
value = pointerToPointer.value;
|
||||
print("Loading a pointer to the 0 address is null: ${value}");
|
||||
|
@ -199,27 +188,17 @@ main(List<String> arguments) {
|
|||
}
|
||||
|
||||
{
|
||||
// sizeof returns element size in bytes
|
||||
// The toplevel function sizeOf returns element size in bytes.
|
||||
print('sizeOf<Double>(): ${sizeOf<Double>()}');
|
||||
print('sizeOf<Int16>(): ${sizeOf<Int16>()}');
|
||||
print('sizeOf<IntPtr>(): ${sizeOf<IntPtr>()}');
|
||||
}
|
||||
|
||||
{
|
||||
// only concrete sub types of NativeType can be allocated
|
||||
// this would fail to compile:
|
||||
// allocate();
|
||||
}
|
||||
|
||||
{
|
||||
// only concrete sub types of NativeType can be asked for size
|
||||
// this would fail to compile:
|
||||
// sizeOf();
|
||||
}
|
||||
|
||||
{
|
||||
// with IntPtr pointers, one can manually setup aribtrary data
|
||||
// With IntPtr pointers, one could manually setup aribtrary data
|
||||
// structres in C memory.
|
||||
//
|
||||
// However, it is advised to use Pointer<Pointer<...>> for that.
|
||||
|
||||
void createChain(Pointer<IntPtr> head, int length, int value) {
|
||||
if (length == 0) {
|
||||
|
|
|
@ -2,16 +2,16 @@
|
|||
// 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' as ffi;
|
||||
import 'dart:ffi';
|
||||
|
||||
import 'dylib_utils.dart';
|
||||
|
||||
typedef NativeDoubleUnOp = ffi.Double Function(ffi.Double);
|
||||
typedef NativeDoubleUnOp = Double Function(Double);
|
||||
|
||||
typedef DoubleUnOp = double Function(double);
|
||||
|
||||
main(List<String> arguments) {
|
||||
ffi.DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
|
||||
main() {
|
||||
DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
|
||||
print(l);
|
||||
print(l.runtimeType);
|
||||
|
||||
|
|
|
@ -2,69 +2,48 @@
|
|||
// 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' as ffi;
|
||||
import 'dart:ffi';
|
||||
|
||||
import 'package:ffi/ffi.dart';
|
||||
|
||||
import 'dylib_utils.dart';
|
||||
|
||||
typedef NativeUnaryOp = ffi.Int32 Function(ffi.Int32);
|
||||
typedef NativeBinaryOp = ffi.Int32 Function(ffi.Int32, ffi.Int32);
|
||||
typedef NativeUnaryOp = Int32 Function(Int32);
|
||||
typedef NativeBinaryOp = Int32 Function(Int32, Int32);
|
||||
typedef UnaryOp = int Function(int);
|
||||
typedef BinaryOp = int Function(int, int);
|
||||
typedef GenericBinaryOp<T> = int Function(int, T);
|
||||
typedef NativeQuadOpSigned = ffi.Int64 Function(
|
||||
ffi.Int64, ffi.Int32, ffi.Int16, ffi.Int8);
|
||||
typedef NativeQuadOpUnsigned = ffi.Uint64 Function(
|
||||
ffi.Uint64, ffi.Uint32, ffi.Uint16, ffi.Uint8);
|
||||
typedef NativeFunc4 = ffi.IntPtr Function(ffi.IntPtr);
|
||||
typedef NativeDoubleUnaryOp = ffi.Double Function(ffi.Double);
|
||||
typedef NativeFloatUnaryOp = ffi.Float Function(ffi.Float);
|
||||
typedef NativeDecenaryOp = ffi.IntPtr Function(
|
||||
ffi.IntPtr,
|
||||
ffi.IntPtr,
|
||||
ffi.IntPtr,
|
||||
ffi.IntPtr,
|
||||
ffi.IntPtr,
|
||||
ffi.IntPtr,
|
||||
ffi.IntPtr,
|
||||
ffi.IntPtr,
|
||||
ffi.IntPtr,
|
||||
ffi.IntPtr);
|
||||
typedef NativeDoubleDecenaryOp = ffi.Double Function(
|
||||
ffi.Double,
|
||||
ffi.Double,
|
||||
ffi.Double,
|
||||
ffi.Double,
|
||||
ffi.Double,
|
||||
ffi.Double,
|
||||
ffi.Double,
|
||||
ffi.Double,
|
||||
ffi.Double,
|
||||
ffi.Double);
|
||||
typedef NativeVigesimalOp = ffi.Double Function(
|
||||
ffi.IntPtr,
|
||||
ffi.Float,
|
||||
ffi.IntPtr,
|
||||
ffi.Double,
|
||||
ffi.IntPtr,
|
||||
ffi.Float,
|
||||
ffi.IntPtr,
|
||||
ffi.Double,
|
||||
ffi.IntPtr,
|
||||
ffi.Float,
|
||||
ffi.IntPtr,
|
||||
ffi.Double,
|
||||
ffi.IntPtr,
|
||||
ffi.Float,
|
||||
ffi.IntPtr,
|
||||
ffi.Double,
|
||||
ffi.IntPtr,
|
||||
ffi.Float,
|
||||
ffi.IntPtr,
|
||||
ffi.Double);
|
||||
typedef Int64PointerUnOp = ffi.Pointer<ffi.Int64> Function(
|
||||
ffi.Pointer<ffi.Int64>);
|
||||
typedef NativeQuadOpSigned = Int64 Function(Int64, Int32, Int16, Int8);
|
||||
typedef NativeQuadOpUnsigned = Uint64 Function(Uint64, Uint32, Uint16, Uint8);
|
||||
typedef NativeFunc4 = IntPtr Function(IntPtr);
|
||||
typedef NativeDoubleUnaryOp = Double Function(Double);
|
||||
typedef NativeFloatUnaryOp = Float Function(Float);
|
||||
typedef NativeDecenaryOp = IntPtr Function(IntPtr, IntPtr, IntPtr, IntPtr,
|
||||
IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr);
|
||||
typedef NativeDoubleDecenaryOp = Double Function(Double, Double, Double, Double,
|
||||
Double, Double, Double, Double, Double, Double);
|
||||
typedef NativeVigesimalOp = Double Function(
|
||||
IntPtr,
|
||||
Float,
|
||||
IntPtr,
|
||||
Double,
|
||||
IntPtr,
|
||||
Float,
|
||||
IntPtr,
|
||||
Double,
|
||||
IntPtr,
|
||||
Float,
|
||||
IntPtr,
|
||||
Double,
|
||||
IntPtr,
|
||||
Float,
|
||||
IntPtr,
|
||||
Double,
|
||||
IntPtr,
|
||||
Float,
|
||||
IntPtr,
|
||||
Double);
|
||||
typedef Int64PointerUnOp = Pointer<Int64> Function(Pointer<Int64>);
|
||||
typedef QuadOp = int Function(int, int, int, int);
|
||||
typedef DoubleUnaryOp = double Function(double);
|
||||
typedef DecenaryOp = int Function(
|
||||
|
@ -93,14 +72,14 @@ typedef VigesimalOp = double Function(
|
|||
int,
|
||||
double);
|
||||
|
||||
main(List<String> arguments) {
|
||||
main() {
|
||||
print('start main');
|
||||
|
||||
ffi.DynamicLibrary ffiTestFunctions =
|
||||
DynamicLibrary ffiTestFunctions =
|
||||
dlopenPlatformSpecific("ffi_test_functions");
|
||||
|
||||
{
|
||||
// int32 bin op
|
||||
// A int32 bin op.
|
||||
BinaryOp sumPlus42 =
|
||||
ffiTestFunctions.lookupFunction<NativeBinaryOp, BinaryOp>("SumPlus42");
|
||||
|
||||
|
@ -110,7 +89,7 @@ main(List<String> arguments) {
|
|||
}
|
||||
|
||||
{
|
||||
// various size arguments
|
||||
// Various size arguments.
|
||||
QuadOp intComputation = ffiTestFunctions
|
||||
.lookupFunction<NativeQuadOpSigned, QuadOp>("IntComputation");
|
||||
var result = intComputation(125, 250, 500, 1000);
|
||||
|
@ -124,7 +103,7 @@ main(List<String> arguments) {
|
|||
}
|
||||
|
||||
{
|
||||
// unsigned int parameters
|
||||
// Unsigned int parameters.
|
||||
QuadOp uintComputation = ffiTestFunctions
|
||||
.lookupFunction<NativeQuadOpUnsigned, QuadOp>("UintComputation");
|
||||
var result = uintComputation(0xFF, 0xFFFF, 0xFFFFFFFF, -1);
|
||||
|
@ -135,9 +114,8 @@ main(List<String> arguments) {
|
|||
}
|
||||
|
||||
{
|
||||
// architecture size argument
|
||||
ffi.Pointer<ffi.NativeFunction<NativeFunc4>> p =
|
||||
ffiTestFunctions.lookup("Times3");
|
||||
// Architecture size argument.
|
||||
Pointer<NativeFunction<NativeFunc4>> p = ffiTestFunctions.lookup("Times3");
|
||||
UnaryOp f6 = p.asFunction();
|
||||
var result = f6(1337);
|
||||
print(result);
|
||||
|
@ -145,7 +123,7 @@ main(List<String> arguments) {
|
|||
}
|
||||
|
||||
{
|
||||
// function with double
|
||||
// Function with double.
|
||||
DoubleUnaryOp times1_337Double = ffiTestFunctions
|
||||
.lookupFunction<NativeDoubleUnaryOp, DoubleUnaryOp>("Times1_337Double");
|
||||
var result = times1_337Double(2.0);
|
||||
|
@ -154,7 +132,7 @@ main(List<String> arguments) {
|
|||
}
|
||||
|
||||
{
|
||||
// function with float
|
||||
// Function with float.
|
||||
DoubleUnaryOp times1_337Float = ffiTestFunctions
|
||||
.lookupFunction<NativeFloatUnaryOp, DoubleUnaryOp>("Times1_337Float");
|
||||
var result = times1_337Float(1000.0);
|
||||
|
@ -163,7 +141,7 @@ main(List<String> arguments) {
|
|||
}
|
||||
|
||||
{
|
||||
// function with many arguments: arguments get passed in registers and stack
|
||||
// Function with many arguments: arguments get passed in registers and stack.
|
||||
DecenaryOp sumManyInts = ffiTestFunctions
|
||||
.lookupFunction<NativeDecenaryOp, DecenaryOp>("SumManyInts");
|
||||
var result = sumManyInts(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
|
||||
|
@ -172,7 +150,7 @@ main(List<String> arguments) {
|
|||
}
|
||||
|
||||
{
|
||||
// function with many double arguments
|
||||
// Function with many double arguments.
|
||||
DoubleDecenaryOp sumManyDoubles = ffiTestFunctions.lookupFunction<
|
||||
NativeDoubleDecenaryOp, DoubleDecenaryOp>("SumManyDoubles");
|
||||
var result =
|
||||
|
@ -182,7 +160,7 @@ main(List<String> arguments) {
|
|||
}
|
||||
|
||||
{
|
||||
// function with many arguments, ints and doubles mixed
|
||||
// Function with many arguments, ints and doubles mixed.
|
||||
VigesimalOp sumManyNumbers = ffiTestFunctions
|
||||
.lookupFunction<NativeVigesimalOp, VigesimalOp>("SumManyNumbers");
|
||||
var result = sumManyNumbers(1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9, 10.0, 11,
|
||||
|
@ -195,49 +173,49 @@ main(List<String> arguments) {
|
|||
// pass an array / pointer as argument
|
||||
Int64PointerUnOp assign1337Index1 = ffiTestFunctions
|
||||
.lookupFunction<Int64PointerUnOp, Int64PointerUnOp>("Assign1337Index1");
|
||||
ffi.Pointer<ffi.Int64> p2 = allocate(count: 2);
|
||||
p2.store(42);
|
||||
p2.elementAt(1).store(1000);
|
||||
Pointer<Int64> p2 = allocate(count: 2);
|
||||
p2.value = 42;
|
||||
p2[1] = 1000;
|
||||
print(p2.elementAt(1).address.toRadixString(16));
|
||||
print(p2.elementAt(1).load<int>());
|
||||
ffi.Pointer<ffi.Int64> result = assign1337Index1(p2);
|
||||
print(p2.elementAt(1).load<int>());
|
||||
print(p2[1]);
|
||||
Pointer<Int64> result = assign1337Index1(p2);
|
||||
print(p2[1]);
|
||||
print(assign1337Index1);
|
||||
print(assign1337Index1.runtimeType);
|
||||
print(result);
|
||||
print(result.runtimeType);
|
||||
print(result.address.toRadixString(16));
|
||||
print(result.load<int>());
|
||||
print(result.value);
|
||||
}
|
||||
|
||||
{
|
||||
// passing in null for an int argument throws a null pointer exception
|
||||
// Passing in null for an int argument throws a null pointer exception.
|
||||
BinaryOp sumPlus42 =
|
||||
ffiTestFunctions.lookupFunction<NativeBinaryOp, BinaryOp>("SumPlus42");
|
||||
|
||||
int x = null;
|
||||
try {
|
||||
sumPlus42(43, x);
|
||||
} on ArgumentError {
|
||||
} on Error {
|
||||
print('Expected exception on passing null for int');
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// passing in null for a double argument throws a null pointer exception
|
||||
// Passing in null for a double argument throws a null pointer exception.
|
||||
DoubleUnaryOp times1_337Double = ffiTestFunctions
|
||||
.lookupFunction<NativeDoubleUnaryOp, DoubleUnaryOp>("Times1_337Double");
|
||||
|
||||
double x = null;
|
||||
try {
|
||||
times1_337Double(x);
|
||||
} on ArgumentError {
|
||||
} on Error {
|
||||
print('Expected exception on passing null for double');
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// passing in null for an int argument throws a null pointer exception
|
||||
// Passing in null for an int argument throws a null pointer exception.
|
||||
VigesimalOp sumManyNumbers = ffiTestFunctions
|
||||
.lookupFunction<NativeVigesimalOp, VigesimalOp>("SumManyNumbers");
|
||||
|
||||
|
@ -245,22 +223,22 @@ main(List<String> arguments) {
|
|||
try {
|
||||
sumManyNumbers(1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9, 10.0, 11, 12.0, 13,
|
||||
14.0, 15, 16.0, 17, 18.0, x, 20.0);
|
||||
} on ArgumentError {
|
||||
} on Error {
|
||||
print('Expected exception on passing null for int');
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// passing in null for a pointer argument results in a nullptr in c
|
||||
// Passing in nullptr for a pointer argument results in a nullptr in c.
|
||||
Int64PointerUnOp nullableInt64ElemAt1 =
|
||||
ffiTestFunctions.lookupFunction<Int64PointerUnOp, Int64PointerUnOp>(
|
||||
"NullableInt64ElemAt1");
|
||||
|
||||
ffi.Pointer<ffi.Int64> result = nullableInt64ElemAt1(null);
|
||||
Pointer<Int64> result = nullableInt64ElemAt1(nullptr);
|
||||
print(result);
|
||||
print(result.runtimeType);
|
||||
|
||||
ffi.Pointer<ffi.Int64> p2 = allocate(count: 2);
|
||||
Pointer<Int64> p2 = allocate(count: 2);
|
||||
result = nullableInt64ElemAt1(p2);
|
||||
print(result);
|
||||
print(result.runtimeType);
|
||||
|
|
|
@ -2,27 +2,26 @@
|
|||
// 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' as ffi;
|
||||
|
||||
import 'dylib_utils.dart';
|
||||
import 'dart:ffi';
|
||||
|
||||
import 'coordinate.dart';
|
||||
import 'dylib_utils.dart';
|
||||
|
||||
typedef NativeCoordinateOp = Coordinate Function(Coordinate);
|
||||
typedef NativeCoordinateOp = Pointer<Coordinate> Function(Pointer<Coordinate>);
|
||||
|
||||
typedef CoordinateTrice = Coordinate Function(
|
||||
ffi.Pointer<ffi.NativeFunction<NativeCoordinateOp>>, Coordinate);
|
||||
typedef CoordinateTrice = Pointer<Coordinate> Function(
|
||||
Pointer<NativeFunction<NativeCoordinateOp>>, Pointer<Coordinate>);
|
||||
|
||||
typedef BinaryOp = int Function(int, int);
|
||||
typedef NativeIntptrBinOp = ffi.IntPtr Function(ffi.IntPtr, ffi.IntPtr);
|
||||
typedef NativeIntptrBinOpLookup
|
||||
= ffi.Pointer<ffi.NativeFunction<NativeIntptrBinOp>> Function();
|
||||
typedef NativeIntptrBinOp = IntPtr Function(IntPtr, IntPtr);
|
||||
typedef NativeIntptrBinOpLookup = Pointer<NativeFunction<NativeIntptrBinOp>>
|
||||
Function();
|
||||
|
||||
typedef NativeApplyTo42And74Type = ffi.IntPtr Function(
|
||||
ffi.Pointer<ffi.NativeFunction<NativeIntptrBinOp>>);
|
||||
typedef NativeApplyTo42And74Type = IntPtr Function(
|
||||
Pointer<NativeFunction<NativeIntptrBinOp>>);
|
||||
|
||||
typedef ApplyTo42And74Type = int Function(
|
||||
ffi.Pointer<ffi.NativeFunction<NativeIntptrBinOp>>);
|
||||
Pointer<NativeFunction<NativeIntptrBinOp>>);
|
||||
|
||||
int myPlus(int a, int b) {
|
||||
print("myPlus");
|
||||
|
@ -31,51 +30,51 @@ int myPlus(int a, int b) {
|
|||
return a + b;
|
||||
}
|
||||
|
||||
main(List<String> arguments) {
|
||||
main() {
|
||||
print('start main');
|
||||
|
||||
ffi.DynamicLibrary ffiTestFunctions =
|
||||
DynamicLibrary ffiTestFunctions =
|
||||
dlopenPlatformSpecific("ffi_test_functions");
|
||||
|
||||
{
|
||||
// pass a c pointer to a c function as an argument to a c function
|
||||
ffi.Pointer<ffi.NativeFunction<NativeCoordinateOp>>
|
||||
transposeCoordinatePointer =
|
||||
// Pass a c pointer to a c function as an argument to a c function.
|
||||
Pointer<NativeFunction<NativeCoordinateOp>> transposeCoordinatePointer =
|
||||
ffiTestFunctions.lookup("TransposeCoordinate");
|
||||
ffi.Pointer<ffi.NativeFunction<CoordinateTrice>> p2 =
|
||||
Pointer<NativeFunction<CoordinateTrice>> p2 =
|
||||
ffiTestFunctions.lookup("CoordinateUnOpTrice");
|
||||
CoordinateTrice coordinateUnOpTrice = p2.asFunction();
|
||||
Coordinate c1 = Coordinate(10.0, 20.0, null);
|
||||
Coordinate c1 = Coordinate.allocate(10.0, 20.0, nullptr);
|
||||
c1.next = c1.addressOf;
|
||||
Coordinate result = coordinateUnOpTrice(transposeCoordinatePointer, c1);
|
||||
Coordinate result =
|
||||
coordinateUnOpTrice(transposeCoordinatePointer, c1.addressOf).ref;
|
||||
print(result.runtimeType);
|
||||
print(result.x);
|
||||
print(result.y);
|
||||
}
|
||||
|
||||
{
|
||||
// return a c pointer to a c function from a c function
|
||||
ffi.Pointer<ffi.NativeFunction<NativeIntptrBinOpLookup>> p14 =
|
||||
// Return a c pointer to a c function from a c function.
|
||||
Pointer<NativeFunction<NativeIntptrBinOpLookup>> p14 =
|
||||
ffiTestFunctions.lookup("IntptrAdditionClosure");
|
||||
NativeIntptrBinOpLookup intptrAdditionClosure = p14.asFunction();
|
||||
|
||||
ffi.Pointer<ffi.NativeFunction<NativeIntptrBinOp>> intptrAdditionPointer =
|
||||
Pointer<NativeFunction<NativeIntptrBinOp>> intptrAdditionPointer =
|
||||
intptrAdditionClosure();
|
||||
BinaryOp intptrAddition = intptrAdditionPointer.asFunction();
|
||||
print(intptrAddition(10, 27));
|
||||
}
|
||||
|
||||
{
|
||||
ffi.Pointer<ffi.NativeFunction<NativeIntptrBinOp>> pointer =
|
||||
ffi.Pointer.fromFunction(myPlus);
|
||||
Pointer<NativeFunction<NativeIntptrBinOp>> pointer =
|
||||
Pointer.fromFunction(myPlus, 0);
|
||||
print(pointer);
|
||||
|
||||
ffi.Pointer<ffi.NativeFunction<NativeApplyTo42And74Type>> p17 =
|
||||
Pointer<NativeFunction<NativeApplyTo42And74Type>> p17 =
|
||||
ffiTestFunctions.lookup("ApplyTo42And74");
|
||||
ApplyTo42And74Type applyTo42And74 = p17.asFunction();
|
||||
|
||||
// int result = applyTo42And74(pointer);
|
||||
// print(result);
|
||||
int result = applyTo42And74(pointer);
|
||||
print(result);
|
||||
}
|
||||
|
||||
print("end main");
|
||||
|
|
|
@ -2,31 +2,32 @@
|
|||
// 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' as ffi;
|
||||
|
||||
import 'dylib_utils.dart';
|
||||
import 'dart:ffi';
|
||||
|
||||
import 'coordinate.dart';
|
||||
import 'dylib_utils.dart';
|
||||
|
||||
typedef NativeCoordinateOp = Coordinate Function(Coordinate);
|
||||
import 'package:ffi/ffi.dart';
|
||||
|
||||
main(List<String> arguments) {
|
||||
typedef NativeCoordinateOp = Pointer<Coordinate> Function(Pointer<Coordinate>);
|
||||
|
||||
main() {
|
||||
print('start main');
|
||||
|
||||
ffi.DynamicLibrary ffiTestFunctions =
|
||||
DynamicLibrary ffiTestFunctions =
|
||||
dlopenPlatformSpecific("ffi_test_functions");
|
||||
|
||||
{
|
||||
// pass a struct to a c function and get a struct as return value
|
||||
ffi.Pointer<ffi.NativeFunction<NativeCoordinateOp>> p1 =
|
||||
// Pass a struct to a c function and get a struct as return value.
|
||||
Pointer<NativeFunction<NativeCoordinateOp>> p1 =
|
||||
ffiTestFunctions.lookup("TransposeCoordinate");
|
||||
NativeCoordinateOp f1 = p1.asFunction();
|
||||
|
||||
Coordinate c1 = Coordinate(10.0, 20.0, null);
|
||||
Coordinate c2 = Coordinate(42.0, 84.0, c1);
|
||||
Coordinate c1 = Coordinate.allocate(10.0, 20.0, nullptr);
|
||||
Coordinate c2 = Coordinate.allocate(42.0, 84.0, c1.addressOf);
|
||||
c1.next = c2.addressOf;
|
||||
|
||||
Coordinate result = f1(c1);
|
||||
Coordinate result = f1(c1.addressOf).ref;
|
||||
|
||||
print(c1.x);
|
||||
print(c1.y);
|
||||
|
@ -38,25 +39,25 @@ main(List<String> arguments) {
|
|||
}
|
||||
|
||||
{
|
||||
// pass an array of structs to a c funtion
|
||||
ffi.Pointer<ffi.NativeFunction<NativeCoordinateOp>> p1 =
|
||||
// Pass an array of structs to a c funtion.
|
||||
Pointer<NativeFunction<NativeCoordinateOp>> p1 =
|
||||
ffiTestFunctions.lookup("CoordinateElemAt1");
|
||||
NativeCoordinateOp f1 = p1.asFunction();
|
||||
|
||||
Coordinate c1 = Coordinate.allocate(count: 3);
|
||||
Coordinate c2 = c1.elementAt(1);
|
||||
Coordinate c3 = c1.elementAt(2);
|
||||
c1.x = 10.0;
|
||||
c1.y = 10.0;
|
||||
c1.next = c3.addressOf;
|
||||
c2.x = 20.0;
|
||||
c2.y = 20.0;
|
||||
c2.next = c1.addressOf;
|
||||
c3.x = 30.0;
|
||||
c3.y = 30.0;
|
||||
c3.next = c2.addressOf;
|
||||
Pointer<Coordinate> c1 = allocate<Coordinate>(count: 3);
|
||||
Pointer<Coordinate> c2 = c1.elementAt(1);
|
||||
Pointer<Coordinate> c3 = c1.elementAt(2);
|
||||
c1.ref.x = 10.0;
|
||||
c1.ref.y = 10.0;
|
||||
c1.ref.next = c3;
|
||||
c2.ref.x = 20.0;
|
||||
c2.ref.y = 20.0;
|
||||
c2.ref.next = c1;
|
||||
c3.ref.x = 30.0;
|
||||
c3.ref.y = 30.0;
|
||||
c3.ref.next = c2;
|
||||
|
||||
Coordinate result = f1(c1);
|
||||
Coordinate result = f1(c1).ref;
|
||||
|
||||
print(result.x);
|
||||
print(result.y);
|
||||
|
|
|
@ -8,14 +8,14 @@ import 'package:ffi/ffi.dart';
|
|||
|
||||
import 'coordinate.dart';
|
||||
|
||||
main(List<String> arguments) {
|
||||
main() {
|
||||
print('start main');
|
||||
|
||||
{
|
||||
// allocates each coordinate separately in c memory
|
||||
Coordinate c1 = Coordinate(10.0, 10.0, null);
|
||||
Coordinate c2 = Coordinate(20.0, 20.0, c1);
|
||||
Coordinate c3 = Coordinate(30.0, 30.0, c2);
|
||||
// Allocates each coordinate separately in c memory.
|
||||
Coordinate c1 = Coordinate.allocate(10.0, 10.0, nullptr);
|
||||
Coordinate c2 = Coordinate.allocate(20.0, 20.0, c1.addressOf);
|
||||
Coordinate c3 = Coordinate.allocate(30.0, 30.0, c2.addressOf);
|
||||
c1.next = c3.addressOf;
|
||||
|
||||
Coordinate currentCoordinate = c1;
|
||||
|
@ -30,31 +30,31 @@ main(List<String> arguments) {
|
|||
}
|
||||
|
||||
{
|
||||
// allocates coordinates consecutively in c memory
|
||||
Coordinate c1 = Coordinate.allocate(count: 3);
|
||||
Coordinate c2 = c1.elementAt(1);
|
||||
Coordinate c3 = c1.elementAt(2);
|
||||
c1.x = 10.0;
|
||||
c1.y = 10.0;
|
||||
c1.next = c3.addressOf;
|
||||
c2.x = 20.0;
|
||||
c2.y = 20.0;
|
||||
c2.next = c1.addressOf;
|
||||
c3.x = 30.0;
|
||||
c3.y = 30.0;
|
||||
c3.next = c2.addressOf;
|
||||
// Allocates coordinates consecutively in c memory.
|
||||
Pointer<Coordinate> c1 = allocate<Coordinate>(count: 3);
|
||||
Pointer<Coordinate> c2 = c1.elementAt(1);
|
||||
Pointer<Coordinate> c3 = c1.elementAt(2);
|
||||
c1.ref.x = 10.0;
|
||||
c1.ref.y = 10.0;
|
||||
c1.ref.next = c3;
|
||||
c2.ref.x = 20.0;
|
||||
c2.ref.y = 20.0;
|
||||
c2.ref.next = c1;
|
||||
c3.ref.x = 30.0;
|
||||
c3.ref.y = 30.0;
|
||||
c3.ref.next = c2;
|
||||
|
||||
Coordinate currentCoordinate = c1;
|
||||
Coordinate currentCoordinate = c1.ref;
|
||||
for (var i in [0, 1, 2, 3, 4]) {
|
||||
currentCoordinate = currentCoordinate.next.ref;
|
||||
print("${currentCoordinate.x}; ${currentCoordinate.y}");
|
||||
}
|
||||
|
||||
free(c1.addressOf);
|
||||
free(c1);
|
||||
}
|
||||
|
||||
{
|
||||
Coordinate c = Coordinate(10, 10, null);
|
||||
Coordinate c = Coordinate.allocate(10, 10, nullptr);
|
||||
print(c is Coordinate);
|
||||
print(c is Pointer<Void>);
|
||||
print(c is Pointer);
|
||||
|
|
23
samples/ffi/samples_test.dart
Normal file
23
samples/ffi/samples_test.dart
Normal file
|
@ -0,0 +1,23 @@
|
|||
// Copyright (c) 2019, 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.
|
||||
//
|
||||
// This file exercises the sample files so that they are tested.
|
||||
//
|
||||
// SharedObjects=ffi_test_dynamic_library ffi_test_functions
|
||||
|
||||
import 'sample_ffi_data.dart' as sample1;
|
||||
import 'sample_ffi_dynamic_library.dart' as sample2;
|
||||
import 'sample_ffi_functions_callbacks.dart' as sample3;
|
||||
import 'sample_ffi_functions_structs.dart' as sample4;
|
||||
import 'sample_ffi_functions.dart' as sample5;
|
||||
import 'sample_ffi_structs.dart' as sample6;
|
||||
|
||||
main() {
|
||||
sample1.main();
|
||||
sample2.main();
|
||||
sample3.main();
|
||||
sample4.main();
|
||||
sample5.main();
|
||||
sample6.main();
|
||||
}
|
|
@ -49,5 +49,5 @@ android {
|
|||
|
||||
Within the `native-libraries` folder, the libraries are organized by ABI.
|
||||
Therefore, we must copy the compiled `libsqlite3.so` into `native-libraries/arm64-v8a/libsqlite3.so`.
|
||||
If multiple sub-directories are present, the libraries from the sub-directory corresponding to the target ABI will be available in the application's linking path, so the library can be loaded with `ffi.DynamicLibrary.open("libsqlite3.so")` in Dart.
|
||||
If multiple sub-directories are present, the libraries from the sub-directory corresponding to the target ABI will be available in the application's linking path, so the library can be loaded with `DynamicLibrary.open("libsqlite3.so")` in Dart.
|
||||
Finally, pass `--target-platform=android-arm64` to the `flutter` command when running or building the app since `libsqlite3.so` was compiled for the `arm64-v8a` ABI.
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// 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' as ffi;
|
||||
import 'dart:ffi';
|
||||
import 'dart:io' show Platform;
|
||||
|
||||
String _platformPath(String name, {String path}) {
|
||||
|
@ -14,7 +14,7 @@ String _platformPath(String name, {String path}) {
|
|||
throw Exception("Platform not implemented");
|
||||
}
|
||||
|
||||
ffi.DynamicLibrary dlopenPlatformSpecific(String name, {String path}) {
|
||||
DynamicLibrary dlopenPlatformSpecific(String name, {String path}) {
|
||||
String fullPath = _platformPath(name, path: path);
|
||||
return ffi.DynamicLibrary.open(fullPath);
|
||||
return DynamicLibrary.open(fullPath);
|
||||
}
|
||||
|
|
|
@ -5,16 +5,17 @@
|
|||
// VMOptions=--optimization-counter-threshold=5
|
||||
|
||||
import "dart:ffi";
|
||||
import "dart:io";
|
||||
|
||||
import "package:ffi/ffi.dart";
|
||||
import "package:test/test.dart";
|
||||
|
||||
import '../lib/sqlite.dart';
|
||||
|
||||
void main() {
|
||||
final dbPath = Platform.script.resolve("test.db").path;
|
||||
test("sqlite integration test", () {
|
||||
// TODO(dacoharkes): Put the database relative to this file,
|
||||
// instead of where the script was invoked from.
|
||||
Database d = Database("test.db");
|
||||
Database d = Database(dbPath);
|
||||
d.execute("drop table if exists Cookies;");
|
||||
d.execute("""
|
||||
create table Cookies (
|
||||
|
@ -107,8 +108,8 @@ void main() {
|
|||
});
|
||||
|
||||
test("concurrent db open and queries", () {
|
||||
Database d = Database("test.db");
|
||||
Database d2 = Database("test.db");
|
||||
Database d = Database(dbPath);
|
||||
Database d2 = Database(dbPath);
|
||||
d.execute("drop table if exists Cookies;");
|
||||
d.execute("""
|
||||
create table Cookies (
|
||||
|
@ -141,7 +142,7 @@ void main() {
|
|||
});
|
||||
|
||||
test("stress test", () {
|
||||
Database d = Database("test.db");
|
||||
Database d = Database(dbPath);
|
||||
d.execute("drop table if exists Cookies;");
|
||||
d.execute("""
|
||||
create table Cookies (
|
||||
|
|
|
@ -17,8 +17,11 @@ sample_extension/test/sample_extension_app_snapshot_test: Pass, RuntimeError # I
|
|||
[ $compiler == none && $runtime == vm && $system == fuchsia ]
|
||||
*: Skip # Not yet triaged.
|
||||
|
||||
[ $arch == simarm || $arch == simarm64 || $builder_tag == asan ]
|
||||
ffi/samples_test: SkipByDesign # FFI skips, see ffi.status
|
||||
|
||||
[ $arch != x64 || $compiler != dartk || $system != linux || $hot_reload || $hot_reload_rollback ]
|
||||
ffi/sqlite/test/sqlite_test: Skip # FFI not supported or libsqlite3.so not available.
|
||||
ffi/sqlite/test/sqlite_test: SkipByDesign # FFI not supported or libsqlite3.so not available.
|
||||
|
||||
[ $compiler == app_jitk || $compiler == dartkp ]
|
||||
sample_extension/test/sample_extension_app_snapshot_test: SkipByDesign
|
||||
|
|
Loading…
Reference in a new issue