[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:
Daco Harkes 2019-10-23 22:20:37 +00:00 committed by commit-bot@chromium.org
parent ef742aa6f0
commit aa36c1fbc5
13 changed files with 221 additions and 248 deletions

View file

@ -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;
}
}

View file

@ -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);
}

View file

@ -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) {

View file

@ -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);

View file

@ -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);

View file

@ -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");

View file

@ -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);

View file

@ -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);

View 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();
}

View file

@ -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.

View file

@ -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);
}

View file

@ -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 (

View file

@ -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