From ce352ec5a585d6e41e38ff374ab4af7987d6b43b Mon Sep 17 00:00:00 2001 From: Hannes Winkler Date: Tue, 16 May 2023 15:00:50 +0200 Subject: [PATCH 1/2] library loader: use dart:ffi Abi instead of uname() - dart:ffi has it's own Abi class now, which you can use for architecture detection - (used internally for @AbiSpecificInteger for example) - make nativeUname() use `/proc/sys/kernel` files instead of uname binding - make `CpuArch._internal()` use `Abi.current()` for architecture detection, instead of querying uname --- lib/src/cpu_architecture.dart | 116 ++++++++-------------------------- lib/src/library.dart | 63 +++++++++--------- 2 files changed, 57 insertions(+), 122 deletions(-) diff --git a/lib/src/cpu_architecture.dart b/lib/src/cpu_architecture.dart index 4f0aaaf..5b708c0 100644 --- a/lib/src/cpu_architecture.dart +++ b/lib/src/cpu_architecture.dart @@ -1,20 +1,31 @@ -import 'dart:ffi'; // For FFI +import 'dart:ffi'; +import 'dart:io'; -import 'package:ffi/ffi.dart'; +/// Uname class, container for the Linux uname struct values. +class Uname { + String sysname; + String nodename; + String release; + String version; + String machine; + Uname(this.sysname, this.nodename, this.release, this.version, this.machine); +} -typedef NativeCall = int Function(Pointer); +/// Calls the native uname() function. +Uname nativeUname() { + final ostype = File('/proc/sys/kernel/ostype').readAsStringSync(); + final hostname = File('/proc/sys/kernel/hostname').readAsStringSync(); + final osrelease = File('/proc/sys/kernel/osrelease').readAsStringSync(); + final version = File('/proc/sys/kernel/version').readAsStringSync(); -/// Supported CPU architectures -enum CpuArchitecture { x86, x86_64, arm, arm64, notSupported, undefined } + // Kernels since 6.1 also have `/proc/sys/kernel/arch`. + final machine = (Process.runSync('uname', ['-m']).stdout as String).trim(); -final DynamicLibrary nativeAddLib = DynamicLibrary.open("libc.so.6"); -NativeCall uname = nativeAddLib - .lookup)>>("uname") - .asFunction(); + return Uname(ostype, hostname, osrelease, version, machine); +} -// https://en.wikipedia.org/wiki/Uname +enum CpuArchitecture { x86, x86_64, arm, arm64, notSupported, undefined } -/// Class which holds the CPU architecture of the SoC. class CpuArch { static CpuArch? _cpuArch; String machine; @@ -28,92 +39,19 @@ class CpuArch { CpuArch._internal() : machine = "", cpuArch = CpuArchitecture.notSupported { - Uname uname = nativeUname(); - machine = uname.machine; - switch (uname.machine) { - case 'i686': - case 'i386': + switch (Abi.current()) { + case Abi.linuxIA32: cpuArch = CpuArchitecture.x86; break; - case 'x86_64': + case Abi.linuxX64: cpuArch = CpuArchitecture.x86_64; break; - case 'aarch64': - case 'aarch64_be': - case 'arm64': - case 'armv8b': - case 'armv8l': + case Abi.linuxArm64: cpuArch = CpuArchitecture.arm64; break; - case 'armv': - case 'armv6l': - case 'armv7l': + case Abi.linuxArm: cpuArch = CpuArchitecture.arm; break; } } } - -/// Uname class, container for the Linux uname struct values. -class Uname { - String sysname; - String nodename; - String release; - String version; - String machine; - Uname(this.sysname, this.nodename, this.release, this.version, this.machine); -} - -/// Calls the native uname() function. -Uname nativeUname() { - // allocate a memory buffer for struct utsname - size value derived from this source - // https://man7.org/linux/man-pages/man2/uname.2.html - const len = 6 * 257; // maxium size - const enumElements = 5; - - Pointer data = calloc(len); - - try { - if (uname(data) != 0) { - throw Exception('Calling uname() failed.'); - } - - // calculate _UTSNAME_LENGTH - var utslen = 0; - label: - for (int i = 0; i < len; ++i) { - if (data[i] == 0) { - for (int j = i + 1; j < len; ++j) { - if (data[j] != 0) { - utslen = j; - break label; - } - } - } - } - - var values = []; - - // extract these 5 strings from the memory - // - // char sysname[]; /* Operating system name (e.g., "Linux") */ - // char nodename[]; /* Name within "some implementation-defined network" */ - // char release[]; /* Operating system release (e.g., "2.6.28") */ - // char version[]; /* Operating system version */ - // char machine[]; /* Hardware identifier */ - for (int i = 0; i < enumElements; ++i) { - var start = utslen * i; - StringBuffer buf = StringBuffer(); - for (int i = start; i < len; ++i) { - if (data[i] == 0) { - break; - } - buf.write(String.fromCharCode(data[i])); - } - values.add(buf.toString()); - } - return Uname(values[0], values[1], values[2], values[3], values[4]); - } finally { - malloc.free(data); - } -} diff --git a/lib/src/library.dart b/lib/src/library.dart index b404908..62955ce 100644 --- a/lib/src/library.dart +++ b/lib/src/library.dart @@ -7,8 +7,6 @@ import 'dart:ffi'; import 'dart:io'; import 'dart:typed_data'; -import 'package:dart_periphery/src/cpu_architecture.dart'; - import 'native/lib_base64.dart'; const pkgName = 'dart_periphery'; @@ -51,43 +49,42 @@ void setCustomLibrary(String absolutePath) { _peripheryLibPath = absolutePath; } +const libraryNameForAbi = { + Abi.linuxIA32: 'libperiphery_x86.so', + Abi.linuxX64: 'libperiphery_x86_64.so', + Abi.linuxArm: 'libperiphery_arm.so', + Abi.linuxArm64: 'libperiphery_arm64.so', +}; + +bool _abiSupported(Abi abi) { + return libraryNameForAbi.containsKey(abi); +} + /// Bypasses the autodetection of the CPU architecture. -void setCPUarchitecture(CpuArchitecture arch) { - if (arch == CpuArchitecture.notSupported || - arch == CpuArchitecture.undefined) { +void setCPUarchitecture(Abi abi) { + if (_abiSupported(abi)) { throw LibraryException( LibraryErrorCode.invalidParameter, "Invalid parameter"); } - var cpu = arch.toString(); - cpu = cpu.substring(cpu.indexOf(".") + 1).toLowerCase(); - library = 'libperiphery_$cpu.so'; + + library = libraryNameForAbi[abi]!; } -String _autoDetectCPUarch() { - CpuArch arch = CpuArch(); - if (arch.cpuArch == CpuArchitecture.notSupported) { +String _autoDetectCPUarch([Abi? abi]) { + abi ??= Abi.current(); + + if (_abiSupported(abi)) { throw LibraryException(LibraryErrorCode.cpuArchDetectionFailed, - "Unable to detect CPU architecture, found '${arch.machine}' . Use 'setCustomLibrary(String absolutePath)' - see documentation https://github.com/pezi/dart_periphery, or create an issue https://github.com/pezi/dart_periphery/issues"); + "Unable to detect CPU architecture, found '$abi' . Use 'setCustomLibrary(String absolutePath)' - see documentation https://github.com/pezi/dart_periphery, or create an issue https://github.com/pezi/dart_periphery/issues"); } - var cpu = arch.cpuArch.toString(); - cpu = cpu.substring(cpu.indexOf(".") + 1).toLowerCase(); - return 'libperiphery_$cpu.so'; + + return libraryNameForAbi[abi]!; } /// dart_periphery loads the library from the actual directory. /// See [native-libraries](https://pub.dev/packages/dart_periphery#native-libraries) for details. -void useLocalLibrary([CpuArchitecture arch = CpuArchitecture.undefined]) { - if (arch == CpuArchitecture.undefined) { - _peripheryLibPath = './${_autoDetectCPUarch()}'; - } else { - if (arch == CpuArchitecture.notSupported) { - throw LibraryException( - LibraryErrorCode.invalidParameter, "Invalid parameter"); - } - var cpu = arch.toString(); - cpu = cpu.substring(cpu.indexOf(".") + 1).toLowerCase(); - _peripheryLibPath = './libperiphery_$cpu.so'; - } +void useLocalLibrary([Abi? abi]) { + _peripheryLibPath = './${_autoDetectCPUarch(abi)}'; } enum LibraryErrorCode { @@ -192,18 +189,18 @@ DynamicLibrary loadPeripheryLib() { // store the appropriate in the system temp directory String base64EncodedLib = ''; - CpuArch arch = CpuArch(); - switch (arch.cpuArch) { - case CpuArchitecture.arm: + final abi = Abi.current(); + switch (abi) { + case Abi.linuxArm: base64EncodedLib = arm; break; - case CpuArchitecture.arm64: + case Abi.linuxArm64: base64EncodedLib = arm64; break; - case CpuArchitecture.x86: + case Abi.linuxIA32: base64EncodedLib = x86; break; - case CpuArchitecture.x86_64: + case Abi.linuxX64: base64EncodedLib = x86_64; break; default: From c0c6bb906fe9ebdf398732f147472e901d497399 Mon Sep 17 00:00:00 2001 From: Hannes Winkler Date: Wed, 17 May 2023 22:15:53 +0200 Subject: [PATCH 2/2] library loader: fix typo in abi support checking throw an error if `!_abiSupported`, not `_abiSupported` --- lib/src/library.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/library.dart b/lib/src/library.dart index 62955ce..bd5e3f5 100644 --- a/lib/src/library.dart +++ b/lib/src/library.dart @@ -62,7 +62,7 @@ bool _abiSupported(Abi abi) { /// Bypasses the autodetection of the CPU architecture. void setCPUarchitecture(Abi abi) { - if (_abiSupported(abi)) { + if (!_abiSupported(abi)) { throw LibraryException( LibraryErrorCode.invalidParameter, "Invalid parameter"); } @@ -73,7 +73,7 @@ void setCPUarchitecture(Abi abi) { String _autoDetectCPUarch([Abi? abi]) { abi ??= Abi.current(); - if (_abiSupported(abi)) { + if (!_abiSupported(abi)) { throw LibraryException(LibraryErrorCode.cpuArchDetectionFailed, "Unable to detect CPU architecture, found '$abi' . Use 'setCustomLibrary(String absolutePath)' - see documentation https://github.com/pezi/dart_periphery, or create an issue https://github.com/pezi/dart_periphery/issues"); }