How to call c function from .dylib file in SPM package swift 5

Hi.. i have .dylib and .h file of c code . i want to call c function in SPM package .i am using xCode for developing SPM package.
Q1. how can i call c function in SPM package ?
Q2. what all method are available to call c function in SPM package ?

In your earlier thread I pointed you to an even earlier thread that has a bunch of helpful info about this. Did you try that approach? If so, where did you get stuck?

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

@eskimo , i am working on that , any other method that is available for importing c function ?

any other method that is available for importing c function ?

Not that I’m aware of.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

Hello @eskimo , please may you guide me step by step through the process of above mentioned method . i am creating mac OS cmd project inside that i have created SPM package . In SPM package i want to use c binary file (.dylib , .h) and create some function using c binary file in swift . i want to expose those function of SPM to main file .

There’s two parts to this:

  • Calling a C dynamic library from Swift (A)

  • Doing that in SPM (B)

As I’ve mentioned on an earlier threads, I can’t help with B. However, that thread does have some suggestions from others about how to proceed.

With regards A, I tested this here in my office today using the following steps:

  1. Using Xcode 11.1 GM seed on macOS 10.14.6, I created a new project macOS > App template.

  2. Within that project I created a new target from the macOS > Library template, selecting None (Plain C/C++) in the Framework popup and Dynamic in the Type popup.

  3. In the library target, I created a file from the macOS > C File template, making sure that “Also create a header file” was checked.

  4. In the header I added this code:

     struct WaffleVarnish {
         int glossiness;
         int durability;
     };
     typedef struct WaffleVarnish WaffleVarnish;
    
     extern WaffleVarnish waffleVarnishDoubleDurability(WaffleVarnish existing);
    

    .

  5. In the C file I added this code:

     extern WaffleVarnish waffleVarnishDoubleDurability(WaffleVarnish existing) {
         existing.durability *= 2;
         existing.glossiness /= 2;
         return existing;
     }
    

    .

  6. I built the library target, just to make sure it was working.

  7. I switched to the app target and added a target dependency on the library target.

  8. I then created a Copy Files build phase to copy the library to the Frameworks directory of the app.

  9. Still in the app target, I use the macOS > Cocoa Class template to create an Objective-C class called Hack. This is an easy way to trigger the creation of a bridging header.

  10. I then deleted Hack.h and Hack.m because I don’t need them.

  11. In the bridging header I added this:

    #include "QTestLib.h"
    
    typedef WaffleVarnish (*WaffleVarnishDoubleDurabilityFunctionPointer)(WaffleVarnish existing);
    

    QTestLib.h is the name of the C header from step 3.

  12. I then added the following code to the app:

    let libURL = Bundle.main.bundleURL
        .appendingPathComponent("Contents")
        .appendingPathComponent("Frameworks")
        .appendingPathComponent("libQTestLib.dylib")
    guard let lib = dlopen(libURL.path, RTLD_LAZY) else {
        // … handle error …
        return
    }
    guard let sym = dlsym(lib, "waffleVarnishDoubleDurability") else {
        // … handle error …
        return
    }
    let waffleVarnishDoubleDurability = unsafeBitCast(sym, to: WaffleVarnishDoubleDurabilityFunctionPointer.self)
    let before = WaffleVarnish(glossiness: 32, durability: 10)
    let after = waffleVarnishDoubleDurability(before)
    print(after)
    

    .

  13. When I run this, it prints:

    WaffleVarnish(glossiness: 16, durability: 20)
    

    .

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

3 Likes

@eskimo - I am trying to use the Nikon SDK to access some of their camera's and have limited experience with using what appears to be a dynamic library or plug in. However the response above appears to make more sense that what I have been trying to do - would it be appropriate to post on the Swift forum to get some help with calling the Nikon libraries from Swift. I am not even entirely sure what all the library files are or which are the correct ones to use so really need some basic guidance from folks who might understand which of the SDK files are the ones to be using and what the best approach is for calling them from Swift. Sadly Nikon provide no support for their SDK at all.

For those reading along at home, duncangroenewald started a new thread for this.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

Is it possible to do this now with SPM? I've searched for a couple hours, but everything that I find is from several years ago. Or they are examples for system libraries. This post is the most relevant.

I have a Package.swift that Xcode seems happy with, but I can't seem to access the function I have defined in MyLibrary.h.

// swift-tools-version:5.3
import PackageDescription

let package = Package(
    name: "SwiftLib",
    products: [
        .library(
            name: "SwiftLib",
            targets: ["MyCLib", "SwiftLib"]),
    ],
    dependencies: [
    ],
    targets: [
      .target(
        name: "SwiftLib",
        dependencies: ["MyCLib"],
        path: "Sources/SwiftLib")
      ,
      .target(
        name: "MyCLib",
        dependencies: [],
        resources: [
          Resource.copy("libMyCLib.dylib"),
        ],
        cSettings: [
          .headerSearchPath("include/")
        ]
        //publicHeadersPath: "include/"
      ),
      .testTarget(
        name: "SwiftLibraryTests",
        dependencies: ["SwiftLibrary"]
      ),
    ]
)

I managed to get a configuration like this working (calling C code from Swift) in a sample Xcode project. What I'm trying to do now is nicely wrap it all up in a Package.