FFI: FFI-Kernel-mt.171.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

FFI: FFI-Kernel-mt.171.mcz

commits-2
Marcel Taeumel uploaded a new version of FFI-Kernel to project FFI:
http://source.squeak.org/FFI/FFI-Kernel-mt.171.mcz

==================== Summary ====================

Name: FFI-Kernel-mt.171
Author: mt
Time: 26 May 2021, 6:14:47.506788 pm
UUID: 6d230712-f208-ee49-a387-8a075d9f8732
Ancestors: FFI-Kernel-mt.170

Adds (parts of the) C standard library to be used in examples and tests. Includes a rough guess for the module name across the major platforms. See #guessModuleName. Includes unix-specific #LibC as a synonym for #CStandardLibrary --- which might have to be discussed at some point.

Adds functionality check for the C standard library at image start-up time. Makes this check and the FFI check optional through preferences, which are enabled by default.

Fixes ExternalData to support #hasEqualElements:, which depends on #isSequenceable, which ExternalData arguably is because of #at:(put:).

=============== Diff against FFI-Kernel-mt.170 ===============

Item was added:
+ ExternalLibrary subclass: #CStandardLibrary
+ instanceVariableNames: ''
+ classVariableNames: 'ModuleName'
+ poolDictionaries: ''
+ category: 'FFI-Kernel-Support'!
+
+ !CStandardLibrary commentStamp: 'mt 5/26/2021 10:08' prior: 0!
+ The ISO C standard library, also known as "CRT" and "libc."
+
+ Further reading:
+ https://www.gnu.org/software/libc/
+ https://docs.microsoft.com/en-us/cpp/c-runtime-library
+ https://www.cplusplus.com/reference/clibrary/
+ https://www.iso.org/standard/82075.html!

Item was added:
+ ----- Method: CStandardLibrary class>>guessModuleName (in category 'preferences') -----
+ guessModuleName
+ "The the platform's module name for the C library."
+
+ | platform |
+ platform := FFIPlatformDescription current.
+
+ platform isMacOS ifTrue: [
+ ^ platform osVersionMajor >= 11 "Big Sur and beyond"
+ ifTrue:['libSystem.dylib']
+ ifFalse: [platform osVersionMajor >= 10
+ ifFalse: ['libc.dylib' "Mac OS 9"]
+ ifTrue: [platform osVersionMinor >= 7 "at least OS X 10.7 (Lion)"
+ ifTrue: ['libobjc.dylib']
+ ifFalse: [platform osVersionMinor >= 5 "at least Mac OS X 10.5 (Leopard)"
+ ifTrue: ['libgcc_s.1.dylib']
+ ifFalse: ['libc.dylib']]]]].
+
+ platform isWindows ifTrue: [
+ ^ 'msvcrt.dll'].
+
+ platform isUnix ifTrue: [
+ ^ platform osVersion = 'linux-gnu'
+ ifTrue: ['libc.so.6']
+ ifFalse: ['libc.so']].
+
+ ^ nil!

Item was added:
+ ----- Method: CStandardLibrary class>>moduleName (in category 'preferences') -----
+ moduleName
+ <preference: 'C runtime/standard library (aka. CRT and libc)'
+ categoryList: #('FFI Kernel')
+ description: 'Name for or path to the ISO/IEC 9899 C standard library.'
+ type: #String>
+ ^ ModuleName ifNil: [self guessModuleName]!

Item was added:
+ ----- Method: CStandardLibrary class>>moduleName: (in category 'preferences') -----
+ moduleName: nameOrNil
+
+ ModuleName := nameOrNil = String empty ifFalse: [nameOrNil].
+ self clearAllCaches.
+
+ "Check the provided name only if overwritten by clients. See #guessModuleName and FFIPlatformDescription class>> #startUp:."
+ ModuleName ifNotNil: [FFIPlatformDescription checkCStandardLibrary].!

Item was added:
+ ----- Method: CStandardLibrary class>>resetDefault (in category 'instance creation') -----
+ resetDefault
+ "Overwritten to release all function handles."
+
+ super resetDefault.
+ CStandardLibrary methodsDo: [:m | m externalLibraryName: nil].!

Item was added:
+ ----- Method: CStandardLibrary>>abs: (in category 'stdlib.h - integer arithmetics') -----
+ abs: n
+ "Returns the absolute value of parameter n"
+
+ <cdecl: int32_t abs (int32_t)>
+ ^ self externalCallFailed  !

Item was added:
+ ----- Method: CStandardLibrary>>bsearch:with:with:with:with: (in category 'stdlib.h - searching and sorting') -----
+ bsearch: key with: base with: num with: size with: compar
+
+ <cdecl: void* bsearch (const void*, const void*, size_t, size_t, void*)>
+ ^ self externalCallFailed  !

Item was added:
+ ----- Method: CStandardLibrary>>qsort:with:with:with: (in category 'stdlib.h - searching and sorting') -----
+ qsort: base with: num with: size with: compar
+
+ <cdecl: void qsort (void*, size_t, size_t, void*)>
+ ^ self externalCallFailed  !

Item was added:
+ ----- Method: ExternalData>>isSequenceable (in category 'testing') -----
+ isSequenceable
+ "The receiver implements #at: and #at:put:."
+
+ ^ true!

Item was changed:
  Object subclass: #FFIPlatformDescription
  instanceVariableNames: 'name osVersion subtype wordSize endianness'
+ classVariableNames: 'CheckCStandardLibraryOnStartUp CheckFFIOnStartUp LastPlatform'
- classVariableNames: 'LastPlatform'
  poolDictionaries: ''
  category: 'FFI-Kernel-Support'!
 
  !FFIPlatformDescription commentStamp: 'mt 6/2/2020 15:18' prior: 0!
  This class stores the information about the current (host) platform. It supports testing instances for platform compatibility and specificity. The entire FFI machinery should go through here, when making platform-specific decisions such as when figuring out the #wordSize for pointers to external memory (i.e., ExternalAddress class >> #new) or when looking up compatible definitions for external pools (i.e., ExternalPool class >> #compatibleResolvedDefinitions).
 
 
  1. DETECT PLATFORM CHANGE ON STARTUP
 
  This class is registered for system startup. It then checks whether the current platform is different from the last one. In that case, a selection of FFI classes gets notified such as ExternalObject and ExternalType.
 
 
  2. PLATFORM SPECIFICITY
 
  Platform descriptions may be unspecific, that is, some of their values may be undefined. For example, (FFIPlatformDescription name: 'unix') creates a valid description but is not specific about #osVersion or #wordSize. When comparing such descriptions, precedence of the platform values are:
 
  platform name > osVersion > subtype > wordSize
 
  So, if one description has a #name and the other does not, the first one is more specific. If both have #name but only the second one has #osVersion, the second one is more specific. If one has only #wordSize and another one has only #subtype, the second one is more specific because #subtype has a higher precedence than #wordSize.
 
 
  3. PLATFORM COMPATIBILITY
 
  Platform descriptions implement a notion of compatibility, which is coupled to its notion of specificity as mentioned before. Using the same rules of precedence, compatibility is checked by comparing the description's values. If not specificed, compatibility is assumed. If specified, values must match via #= to be regarded compatible.
 
  Here is an interesting edge case of two compatible platform descriptions:
 
  | p1 p2 |
  p1 := FFIPlatformDescription name: 'Win32' osVersion: '' subtype: 'IX86' wordSize: nil.
  p2 := FFIPlatformDescription name: '' osVersion: 'linux-gnu' subtype: '' wordSize: 8.
  p1 isCompatibleWith: p2.
 
  Consequently, the developer has to be careful with unspecific platform descriptions, which are used, for example, in the definitions of external pools.
 
 
  4. FURTHER READING
 
  - all references to FFIPlatformDescription
  - all senders of #wordSize
  - class comments of ExternalAddress, ExternalType, ExternalPool, ExternalObject
  !

Item was added:
+ ----- Method: FFIPlatformDescription class>>checkCStandardLibrary (in category 'system startup') -----
+ checkCStandardLibrary
+ "Try to use C Standard Library. Warn if not possible."
+
+ [ [self assert: [(CStandardLibrary default abs: -5) = 5]
+ ] ifError: [:msg |
+ self notify: 'C standard library not available. Please check module name in preferences.', String cr, String cr, msg]
+ ] fork. "Do not interrupt the startup list."!

Item was added:
+ ----- Method: FFIPlatformDescription class>>checkCStandardLibraryOnStartUp (in category 'preferences') -----
+ checkCStandardLibraryOnStartUp
+ <preference: 'Check C standard library on start-up'
+ categoryList: #('FFI Kernel')
+ description: 'When enabled, performs a simple check of the C standard library when Squeak is resuming.'
+ type: #Boolean>
+ ^ CheckCStandardLibraryOnStartUp ifNil: [true]!

Item was added:
+ ----- Method: FFIPlatformDescription class>>checkCStandardLibraryOnStartUp: (in category 'preferences') -----
+ checkCStandardLibraryOnStartUp: aBoolean
+
+ CheckCStandardLibraryOnStartUp := aBoolean.!

Item was added:
+ ----- Method: FFIPlatformDescription class>>checkFFIOnStartUp (in category 'preferences') -----
+ checkFFIOnStartUp
+ <preference: 'Check FFI on start-up'
+ categoryList: #('FFI Kernel')
+ description: 'When enabled, performs a simple check of the FFI plugin when Squeak is resuming.'
+ type: #Boolean>
+ ^ CheckFFIOnStartUp ifNil: [true]!

Item was added:
+ ----- Method: FFIPlatformDescription class>>checkFFIOnStartUp: (in category 'preferences') -----
+ checkFFIOnStartUp: aBoolean
+
+ CheckFFIOnStartUp := aBoolean.!

Item was changed:
  ----- Method: FFIPlatformDescription class>>startUp: (in category 'system startup') -----
  startUp: resuming
  "Notify all FFI classes about platform changes."
 
  resuming ifTrue: [
  LastPlatform in: [:lastPlatform | self newCurrent in: [:currentPlatform |
  lastPlatform = currentPlatform
  ifTrue: [
  self flag: #discuss. "mt: Maybe add #platformResuming?"
  ExternalAddress allBeNull.
  ExternalType cleanupUnusedTypes ]
  ifFalse: [
  LastPlatform := currentPlatform. "Update now. See #current."
  { ExternalAddress. ExternalType. ExternalStructure. ExternalPool }
  do: [:cls | cls
  platformChangedFrom: lastPlatform
  to: currentPlatform] ]]].
+ self checkFFIOnStartUp ifTrue: [self checkFFI].
+ self checkCStandardLibraryOnStartUp ifTrue: [self checkCStandardLibrary]].!
- self checkFFI].!

Item was added:
+ ----- Method: FFIPlatformDescription>>isMacOS (in category 'testing') -----
+ isMacOS
+
+ ^ self name = 'Mac OS'!

Item was added:
+ ----- Method: FFIPlatformDescription>>osVersionBuild (in category 'accessing') -----
+ osVersionBuild
+ "Answers the build version number for the platform. Only defined for macOS and Windows platforms. Usually 0 on Windows platforms."
+
+ ^ (self osVersion findTokens: $.) second!

Item was added:
+ ----- Method: FFIPlatformDescription>>osVersionMajor (in category 'accessing') -----
+ osVersionMajor
+ "Answers the major version number for the platform. Only defined for macOS and Windows platforms."
+
+ | token |
+ token := (self osVersion findTokens: $.) first.
+ self isMacOS
+ ifTrue: [ "e.g. Mac OS 90.3 92.2 109.1 1015.2 1100.0"
+ ^ ((token beginsWith: '9')
+ ifTrue: [token first]
+ ifFalse: [token first: 2]) asInteger].
+ ^ token asInteger "e.g. Windows 10.0"!

Item was added:
+ ----- Method: FFIPlatformDescription>>osVersionMinor (in category 'accessing') -----
+ osVersionMinor
+ "Answers the minor version number for the platform. Only defined for macOS."
+
+ | token |
+ token := (self osVersion findTokens: $.) first.
+ self isMacOS
+ ifTrue: [ "e.g. 90.3 92.2 109.1 1015.2 1100.0"
+ ^ ((token beginsWith: '9')
+ ifTrue: [token allButFirst: 1]
+ ifFalse: [token allButFirst: 2]) asInteger].
+ ^ nil!

Item was added:
+ CStandardLibrary subclass: #LibC
+ instanceVariableNames: ''
+ classVariableNames: ''
+ poolDictionaries: ''
+ category: 'FFI-Kernel-Support'!
+
+ !LibC commentStamp: 'mt 5/26/2021 10:09' prior: 0!
+ Just a synonym for convenient reference.!