> It looks like dlopen() may not be the panacea I'd hoped it would be
> since it's apparently not supported on Mac OS X. But cross-platform
> maintenance of the OpenSSL plugin via header files and linking to
> dll/so files should be very minimal.
>
This can be worked around. Here's a bit of code stolen from Nebula
Device that wraps around dll handling code for linux, win32, and Mac
OSX. I've only actually used the code on Linux so can't confirm that
the other two work. I'm confident the Win32 code does since there are
commercial projects released for Win32 using this code and the Mac OSX
code should be close at least.
#if defined( LINUX )
static void * dlopen wrapper(const char *name, bool prefix)
{
char dll name[N MAXPATH];
if (prefix) {
strcpy(dll name,"lib");
strcat(dll name,name);
} else {
strcpy(dll name,name);
}
strcat(dll name,".so");
void *dll = dlopen(dll name,RTLD NOW|RTLD GLOBAL);
// Caller will handle printing error
return dll;
}
void *n dllopen(const char *name)
{
void *dll = dlopen wrapper(name, true);
if (!dll) {
char *err1 = n strdup(dlerror());
dll = dlopen wrapper(name, false);
if (!dll) {
const char *err2 = dlerror();
n printf("Could not load dll for '%s'\n", name);
n printf("Error was:\n");
n printf("%s\n", err1);
n printf("%s\n", err2);
n free(err1);
}
}
return dll;
}
#elif defined( WIN32 )
void *n dllopen(const char *name)
{
HINSTANCE dll;
dll = LoadLibrary((LPCSTR) name);
if (!dll) {
// Find out why we failed
LPVOID lpMsgBuf;
FormatMessage(
FORMAT MESSAGE ALLOCATE BUFFER |
FORMAT MESSAGE FROM SYSTEM |
FORMAT MESSAGE IGNORE INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG NEUTRAL, SUBLANG DEFAULT),
(LPTSTR) &lpMsgBuf,
0,
NULL
);
// Display the string.
n printf("Could not load dll '%s'\nError was:\n%s\n", name,
lpMsgBuf);
// Free the buffer.
LocalFree( lpMsgBuf );
}
return (void *) dll;
}
#elif defined( MACOSX )
void *n dllopen(const char *name)
{
void* result = 0;
const int kBundleAnyType = 0;
const int kBundleNoSubdir = 0;
CFBundleRef mainBundle = CFBundleGetMainBundle();
// put the name of the bundle we want in a CFString
std::string bundleName( name );
bundleName += ".bundle";
CFStringRef cfBundleName = CFStringCreateWithCString( NULL,
bundleName.c str(),
kCFStringEncodingASCII );
CFURLRef bundleURL = CFBundleCopyResourceURL( mainBundle,
cfBundleName,
kBundleAnyType,
kBundleNoSubdir );
if ( bundleURL )
{
CFBundleRef myBundle = CFBundleCreate( kCFAllocatorDefault,
bundleURL );
Boolean loaded = CFBundleLoadExecutable( myBundle );
if ( loaded )
result = myBundle;
}
return result;
}
#else
void *n dllopen(const char *name)
{
n error("nClass::dll load() not implemented!");
return NULL;
}
#endif
And that code looks suspiciosly like
InterpreterProxy>>ioLoadFunction:From: ;-)
Cheers,
- Andreas
-> FFI support
> It looks like dlopen() may not be the panacea I'd hoped it would be
> since it's apparently not supported on Mac OS X. But cross-platform
> maintenance of the OpenSSL plugin via header files and linking to
> dll/so files should be very minimal.
That's hardly portable - some of us have utterly different mechanisms
for this sort of stuff.
Consider something like:-
primitiveAESEncryptCBC: plainText ciphertext: cipherText key: aKey iv:
anInitializationVector
"Encrypt aByteArray using the AES (Rijndael) algorithm in CBC mode"
self cCode: '' inSmalltalk: [^nil]. "tpr add return
for trivial support of simulator"
self primitive: 'primitiveAESEncryptCBC' parameters: #(#ByteArray
#ByteArray #ByteArray #ByteArray). self encrypt: plaintext to:
ciphertext key: aKey iv: anInitthingy
note that encrypttokeyiv() will be generated by the CCodeGen and then
implement it in a platform specific file. You could also implement
encrypt:to:key:iv: in a simulator class for the benefit of
InterpreterSimulator users, dropping the ^nil at the top.
In each supported platform's file you then deal with its quirks. I
would imagine the windows version would be a trivial transposing of the
original contents of your prim?
As long as a platform can do openSSL compatible munging based on the
four parameters, you're ok. Oh, consider implementing initialiseModule
in a similar manner such that each platform can do what it needs. See
various othe plugins for examples.
> namespace issues? Package names and Class names? I
> wanted to keep the interfaces the same as the existing package to the
> point where my package could be a drop-in replacement, but my
> interface ends up being a level higher than what's in the
> Cryptography package (and the lower level stuff is down in the
> primitive itself), so that plan won't work after all.
Bridges. Have the high level stuff talk to a translator class that can
pass off to openSSL or whatever is already there. Choose the translator
class by appropriate means at runtime.
tim
This is exactly what I've ended up doing. In fact the only Win32
specific thing at all is the Makefile that explicitly links to the
pre-existing DLL. Even the header file and the included OpenSSL
header files should compile regardless of the platform, as long as it
can do dynamic linking. I think it should be in good shape for
extension to other platforms, though I don't have a Mac or Acorn or
PocketPC to build makefiles for those platforms. As long as the APIs
I use don't change, it should be a matter of dropping in new
dll/so/whatever-acorn-uses as they become available.
--
Jason Dufair
Hmm. On my MacOS X box I just typed
man dlopen
and I get
DLOPEN(3) BSD Library Functions Manual
NAME dlopen, dlsym, dlerror, dlclose -
programmatic interface to the dynamic linker
...
All these functions use the native dyld(3), NSModule(3), and
NSObjectFileImage(3) functions to provide a compatibility library
so that common unix source code may be easily compiled.
...
The dlcompat package was written by
Jorge Acereda <jacereda_at_users.sourceforge.net> and
Peter O'Gorman <ogorman_at_users.sourceforge.net>
I haven't tried this yet myself, but it sure _looks_ supported.
I mean, this package is there out-of-the-box. (Darwin kernel 7.3.0)
rok