SRL Archive - Development

Multi-platform library loading...


moparisthebest

2010-09-15 02:26:56

I've been thinking about a good, cross-platform way to load libraries. Currently, if we try to load libsmart, for example, Simba will try to load libsmart.so under Linux, regardless of whether Simba is compiled as a 32-bit or 64-bit system. This doesn't always work, as libsmart.so might be either. So two different plans come to mind:

Best plan:
  1. Load libsmart.so and detect if it matches our architecture (if this can be done, perhaps as simple as seeing if it was loaded successfully)
  2. If it wasn't successful, or doesn't match our architecture, look for and load libsmart64.so or libsmart32.so depending on what we are compiled for

Backup plan (if the detection can't be done):
  1. Load libsmart64.so or libsmart32.so FIRST, if they exist we are basically guaranteed to get the right one (no 64-bit plugin would be named libsmart32.so)
  2. If the more specific library doesn't exist, fall back to trying to load libsmart.so

One of the above plans would prevent those nasty 'incompatible binary format' errors, and would enable the use of my Simba all-in-one release without the renaming of plugins every time you switch operating systems.

Either of the changes should be easy to do in Units/MMLCore/libloader.pas, so does anyone know if the first option can be done? Or should the second option be done? OR do you have a plan C? :stirthepot:

(wow, that's 3 threads for me today in this section, goodnight!)

Wizzup?

2010-09-15 05:02:18

I think we should be able to check able the magic number, no? IIRC that gices the arch as well:
$ file libsmart.so 
libsmart.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, stripped

moparisthebest

2010-09-17 18:48:15

Depends on what you want to do, my 'backup plan' would be much easier to implement, but actually looking for the right plugin would be the right way to go about it, just slightly more time-consuming to write.

moparisthebest

2010-09-20 01:34:34

I went ahead and made my first attempt at hacking with FPC, my "Best plan" actually worked with a try/except statement, making detecting the file type sort of useless. If it loads right the first time, it will load just as fast as now, if it doesn't load for whatever reasons, it will try the other name. It should be good to go, the patch is attached.

Basically, I renamed the existing 'LoadPlugin' to 'LoadPluginNoFallback', and added this function:

  function TGenericLoader.LoadPlugin(PluginName: string): Integer;
var
CpuBits: String = {$IFDEF CPU32}'32';{$ELSE}'64';{$ENDIF}
begin
try
Result := LoadPluginNoFallback(PluginName);
except
on exception do Result:= LoadPluginNoFallback(PluginName+CpuBits);
end;

end;

And then made LoadPluginNoFallback private, as no one outside the class (err, unit?) should call it anyway.

This is what the command line looks like when I run the 32-bit windows Simba (under WINE of course), with a 64-bit libsmart.dll and a 32-bit libsmart32.dll in the Plugins folder:
Adding Plugin Path: /home/mopar/simba/test/Plugins\
Loading plugin libsmart at /home/mopar/simba/test/Plugins\
Trying to load PE image for unsupported architecture (AMD-64)
Loading plugin libsmart32 at /home/mopar/simba/test/Plugins\
Running SMART Constructor
SMART Initialized!
So the standard user would never even see this! :)

So can this be commited soonish so the all-in-one package works without a hitch? (except of course that SRL is no where near usable in a case-sensitive filesystem…, but that's a rant for another day)

Wizzup?

2010-09-28 10:25:39

Committed; 67ebb56.
I hope however this won't cause double plugin loading. (Simba loading a library called a32.dll on 64 bit, and then trying a64.dll. And then it goes onto the next file in the directory (a64.dll) and tries to load that one as well.

Nava2

2010-09-28 11:05:56

From: Wizzup?
Committed; 67ebb56.
I hope however this won't cause double plugin loading. (Simba loading a library called a32.dll on 64 bit, and then trying a64.dll. And then it goes onto the next file in the directory (a64.dll) and tries to load that one as well.


This could be fixed by adding a define inside the compiled libraries.


{$ifndef libsmart}
{$DEFINE libsmart}
//... all the other code.
{$endif}

Thus, if you try to load the first library, it fails, when the second is loaded it will define it and stop further library loading. Might as well adopt the C style for this stuff, since it works :p.

Wizzup?

2010-09-28 11:42:28

A compiler directive inside compiled libraries?

Nava2

2010-09-28 16:43:39

From: Wizzup?
A compiler directive inside compiled libraries?


It was a good idea at first :(

moparisthebest

2010-09-28 23:28:32

From: Wizzup?
Committed; 67ebb56.
I hope however this won't cause double plugin loading. (Simba loading a library called a32.dll on 64 bit, and then trying a64.dll. And then it goes onto the next file in the directory (a64.dll) and tries to load that one as well.


The 32-bit dll can't be loaded on 64-bit arch, so it throws an exception and the 64-bit lib is loaded. That should be how it works anyway.

Wizzup?

2010-09-29 04:35:56

From: moparisthebest
The 32-bit dll can't be loaded on 64-bit arch, so it throws an exception and the 64-bit lib is loaded. That should be how it works anyway.


What I mean is:

For each file in plugins:
- Try to load 32 bit plugin(which is the file in this case); fails -> load 64 bit.
the the loop moves on to the file which can be the 64 bit lib, and it will try to load it. Right? It'll fail cause afaik you can't load libs twice. At least, that's what I think.

moparisthebest

2010-09-29 11:30:02

From: Wizzup?
What I mean is:

For each file in plugins:
- Try to load 32 bit plugin(which is the file in this case); fails -> load 64 bit.
the the loop moves on to the file which can be the 64 bit lib, and it will try to load it. Right? It'll fail cause afaik you can't load libs twice. At least, that's what I think.


It only tries to load the second one if the first one fails and throws an exception, which means the lib wasn't loaded and allows the correct one to be loaded. Right? Unless pascal exception handling works differently than every other programming language I've ever used. I did test this with 32-bit and 64-bit Simba running under linux and it worked correctly both ways.

Wizzup?

2010-09-29 11:45:44

From: moparisthebest
It only tries to load the second one if the first one fails and throws an exception, which means the lib wasn't loaded and allows the correct one to be loaded. Right? Unless pascal exception handling works differently than every other programming language I've ever used. I did test this with 32-bit and 64-bit Simba running under linux and it worked correctly both ways.


What I mean is:


pf = ['libsmart.so', ['libsmart64.so', 'irokiplugin.so']
for i in pf:
if loadlibsomething(i):
print 'Loaded bla'
elif loadlibsomething(i + '64'):
print 'Loaded bla64'

That would first load 'libsmart64.so' since libsmart.so is not x64, and it then proceeds to load the next file.

————-

I just realized I'm totally wrong though. Simba doesn't load all plugins in the directory Plugins/ at all. One has to specify the plugin to load. So whatever my worries were doesn't matter since it doesn't apply at all.

moparisthebest

2010-09-29 22:51:29

I thought it only loaded on request, so that's why I was confused about your concerns. Either way, I'm glad it works as expected. :)