SimonR
SimonR

Reputation: 23

Accessing a third party Mac API through Firemonkey

I have an SDK from a hardware manufacturer which provides Windows and Mac APIs. In Windows this is a standard COM DLL. On the Mac, it's in a bundle in the Library. Can someone give me a starting point on how to access the functions from a Firemonkey app please?

The Plist file mentions

    <key>CFBundleExecutable</key>

and

    <key>CFBundlePackageType</key>
    <string>BNDL</string>

and the bundle contains a file with no file extension but a 'kind' of 'Unix executable'

The include file contains the following (abridged) code to gain access to the API from C++ in XCode :

typedef IDiscovery* (*CreateDiscoveryFunc)(void);

static pthread_once_t           gOnceControl            = PTHREAD_ONCE_INIT;
static CreateDiscoveryFunc      gCreateDiscoveryFunc    = NULL;

static void InitAPI (void)
{
    bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR(kAPI_BundlePath), kCFURLPOSIXPathStyle, true);
    if (bundleURL != NULL)
    {
        gBundleRef = CFBundleCreate(kCFAllocatorDefault, bundleURL);
        if (gBundleRef != NULL)
        {
            gCreateDiscoveryFunc = (CreateDiscoveryFunc)CFBundleGetFunctionPointerForName(gBundleRef, CFSTR("GetDiscoveryInstance"));
        }
        CFRelease(bundleURL);
    }
}

IDiscovery*             CreateDiscoveryInstance (void)
{
    pthread_once(&gOnceControl, InitAPI);
    
    if (gCreateDiscoveryFunc == NULL)
        return NULL;

    return gCreateDiscoveryFunc();
}

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    mDiscovery = NULL;
    mDevice = NULL;
    
    mDiscovery = CreateDiscoveryInstance();
    if (! mDiscovery)
    {
        /* Show an alert to say the API may not be installed, and quit program */
    } 

    NSString* address = [mAddressTextField stringValue];    
    ConnectToFailure    failReason;
    
    HRESULT hr = mDiscovery->ConnectTo((CFStringRef)address, &mDevice, &failReason);

}

If I can get the mDevice object, then I should be able to get all the other objects I need to use the API.

Could this 'Unix executable' just be a DYLIB?

Upvotes: 2

Views: 117

Answers (1)

Siguza
Siguza

Reputation: 23880

Run file path/to/file on that binary and it should tell you what it is.

If it says Mach-O 64-bit bundle, then you'll have to use dlopen() and dlsym() to access its exported functions.
If it says Mach-O 64-bit dynamically linked shared library, then it's a shared library and it can be linked against at compile time.

Of note here though, the fact that your binary has no extension makes me think it's in the form of a "framework". That is, it would have the format of a shared library but a path of some/path/SomeName.framework/Versions/Current/SomeName. If so, you can link against it using -F some/path -framework SomeName.

If the binary is not in the form of a framework though and is just a shared library with no suffix, then linking to it is going to be somewhat of a pain, since clang/ld64 only really accept lib<string>.dylib or lib<string>.tbd. Renaming the library would invalidate its install name, and yet you need that for the compiler toolchain to find it.
If you truly are in this scenario, then the easiest workaround is to create a tbd file off your dylib (which is just a text file that lists all linking information of the dylib and can be used in its place for dynamic linking). To do so, you'd use:

xcrun tapi stubify -o some/path/libsomething.tbd path/to/binary

And then when linking, you'd use -L some/path -l something.

Upvotes: 1

Related Questions