When accessing the ICU library one could consider to handle the problem of using different versions of ICU. The creators of ICU actually have a very “pessimistic” view of using a DLL: for each new version they create new names of functions and libraries.
As an example:
The versions of ICU are named “44”, “46”, “48”, “49” and “50”. Libraries are named according to this pattern: “icuuc49.dll” od “icuuc50.dll”.
The exported function names are working the same way: “ucal_add_49”, “ucal_add_50” …
The good thing here is, that the names are always identical in length and they have the same semantical meaning.
My first attempt to define the functions was following the classical VA way:
"%%PRAGMA DECLARE (name: ICUFunctions isPool: true ) (pool: ICUFunctions declarations: ( (name: UCalAdd isConstant: true valueExpression: 'PlatformFunction fromArray: #(''C'' ''ucal_add_50'' nil ''icuin'' #(pointer int32 int32 pointer) #void)') ...
the normal way and the results are global constant – not changeable.
When playing around with reconfiguration of these definitions I changed the PRAGMA method to:
... (pool: ICUFunctions declarations: ( (name: UCalAdd isConstant: false valueExpression: 'PlatformFunction fromArray: #(''C'' ''ucal_add_50'' nil ''icuin'' #(pointer int32 int32 pointer) #void)') ...
but to my surprise nothing changed. I was not able to change the content of UCalAdd though I defined the variable as non constant. Reading the documentation shows the problem (as I interpet it this way). All pool variables filled with a valueExpression are defined as a non changeable constant and the values of this pool dictionary is inserted directly into the byte code of a compiled method.
Therefore the definitions of the pool variables and setting the values have to be two different things:
"%%PRAGMA DECLARE (name: ICUFunctions isPool: true ) (pool: ICUFunctions declarations: ( (name: UCalAdd isConstant: false ) ...
and
initializeUCalFunctions "we do NOT define the platform function within the PRAGMA methods, because then they are not changeable any more" UCalAdd := PlatformFunction fromArray: #('C' 'ucal_add_49' nil 'icuin' (pointer int32 int32 pointer) void). ...
Now the methods (after recompiling) accesses the values of the pool variable in a dynamical way.
And now to the original question: how to reconfigure the platform functions. The only thing we have to do here now is:
* rename the function name (e.g. from uCal_Add_49 to uCal_Add_50)
* rename the library used for this function call
"Pretty ugly non public stuff VersionSuffic helds the new version "_50" CommonModule helds the new library name e.g. "icuin50.dll" ICUFunctions helds ALL function definitions " ICUFunctions keysAndValuesDo: [:key :eachPlatformFunction | | functionName newFunctionName libraryIndex oldLibraryName newLibraryName | "we get the old function name" functionName := eachPlatformFunction name. "in ICU we have two $_ in the function name. the three last characters have to be replaced " newFunctionName := (functionName copyFrom: 1 to: functionName size - 3) , VersionSuffix. "get the old library name ..." oldLibraryName := eachPlatformFunction library physicalName asString. "and create the new library name with the additional version information - based on the old library name " newLibraryName := (oldLibraryName indexOfSubCollection: (CommonModule copyFrom: 1 to: 4) ifAbsent: [0]) = 1 ifTrue: [CommonModule] ifFalse: [I18NModule]. "retrieve a possible new library index from VA" libraryIndex := PlatformLibrary libraryIndex: newLibraryName. "we set a new relation to a possible new library" eachPlatformFunction libraryIndex: libraryIndex; "and set address of the function to zero to force VA to rebind it again before using it" unbind. "and change the function name" newFunctionName memcpyFrom: 0 to: newFunctionName size - 1 into: eachPlatformFunction startingAt: 12 + eachPlatformFunction parameterCount. ]