HomeiOS DevelopmentThe best way to use a Swift library in C

The best way to use a Swift library in C


The best way to construct a C appropriate Swift library?


With the intention to create a Swift library that is going to work with C, we’ve to mess around with unsafe reminiscence pointers to create a C appropriate interface. Thankfully I used to be capable of finding a pleasant instance, which served me as a very good start line, on the Swift boards created by Cory Benfield, so that is what we will use on this case. Thanks you. 🙏


remaining class MyType {
    var rely: Int = 69
}

@_cdecl("mytype_create")
public func mytype_create() -> OpaquePointer {
    let sort = MyType()
    let retained = Unmanaged.passRetained(sort).toOpaque()
    return OpaquePointer(retained)
}

@_cdecl("mytype_get_count")
public func mytype_get_count(_ sort: OpaquePointer) -> CInt {
    let sort = Unmanaged<MyType>.fromOpaque(UnsafeRawPointer(sort)).takeUnretainedValue()
    return CInt(sort.rely)
}

@_cdecl("mytype_destroy")
public func mytype_destroy(_ sort: OpaquePointer) {
    _ = Unmanaged<MyType>.fromOpaque(UnsafeRawPointer(sort)).takeRetainedValue()
}


The excellent news is that we do not essential should create a separate header file for our interfaces, however the Swift compiler can generate it for us if we offer the -emit-objc-header flag.


I’ve an article about the swiftc command for novices and I additionally wrote some issues about the Swift compiler, the place I discuss in regards to the out there flags. This time we will use the -module-name choice to specify our module identify, we will generate the required recordsdata utilizing the -emit-dependencies flag, parse the supply recordsdata as a library (-parse-as-library), since we might prefer to generate a Swift library present the mandatory goal and model data and emit a header file.



swiftc 
        -module-name mytype 
        -emit-dependencies 
        -parse-as-library 
        -c mytype.swift 
        -target arm64-apple-macosx12.0 
        -swift-version 5 
        -emit-objc-header 
        -emit-objc-header-path mytype.h


swiftc 
    -module-name mytype 
    -emit-dependencies 
    -parse-as-library 
    -c mytype.swift 
    -swift-version 5 
    -emit-objc-header 
    -emit-objc-header-path mytype.h


This could generate a mytype.h and a mytype.o file plus some extra Swift module associated output recordsdata. We’ll use these recordsdata to construct our remaining executable, however there are a number of extra extra issues I might like to say.


Below Linux the header file will not work. It incorporates a line #embody Basis/Basis.h and naturally there isn’t any such header file for Linux. It’s attainable to put in the GNUstep package deal (e.g. through yum: sudo yum set up gnustep-base gnustep-base-devel gcc-objc, however for me the clang command nonetheless complained in regards to the location of the objc.h file. Anyway, I simply eliminated the iclude Basis assertion from the header file and I used to be good to go. 😅


The second factor I might like to say is that if you wish to export a category for Swift, that is going to be a bit more durable, as a result of courses will not be included within the generated header file. You may have two choices on this case. The primary one is to show them into Goal-C courses, however this may result in issues when utilizing Linux, anyway, that is how you are able to do it:


import Basis

@objc public remaining class MyType: NSObject {
    public var rely: Int = 69
}


I favor the second possibility, when you do not change the Swift file, however you create a separate header file and outline your object sort as a struct with a customized sort (mytype_struct.h).

typedef struct mytype mytype_t;


We’ll want this kind (with the corresponding header file), as a result of the mytype_create operate returns a pointer that we are able to use to name the opposite mytype_get_count methodology. 🤔


Compiling C sources utilizing Swift libraries


So how will we use these uncovered Swift objects in C? Within the C programming language you simply should import the headers after which voilá you should utilize every little thing outlined in these headers.


#embody <stdio.h>
#embody "mytype.h"

int principal() {
    mytype_t *merchandise = mytype_create();

    int i = mytype_get_count(merchandise);
 
    printf("Hiya, World! %dn", i);

    return 0;
}


We are able to use clang to compile the principal.c file into an object file utilizing the mandatory header recordsdata.



clang -x objective-c -include mytype.h -include mytype_struct.h -c principal.c


clang -include mytype.h -include mytype_struct.h -c principal.c


This command will construct a principal.o file, which we are able to use to create the ultimate executable. 💪


Linking the ultimate executable


This was the toughest half to determine, however I used to be capable of hyperlink the 2 object recordsdata collectively after a number of hours of battling the ld command and different framework instruments I made a decision to provide it up and let swiftc maintain the job, since it might construct and hyperlink each C and Swift-based executables.


We’ll want an inventory of the thing recordsdata that we will hyperlink collectively.


ls *.o > LinkFileList


Then we are able to name swiftc to do the job for us. I suppose it will invoke the ld command below the hood, however I am not a linker professional, so if extra about this, be happy to succeed in out and present me extra information in regards to the course of. I’ve to learn this ebook for positive. 📚



swiftc 
        -sdk /Purposes/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.1.sdk 
        -F /Purposes/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Frameworks 
        -I /Purposes/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/usr/lib 
        -L /Purposes/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/usr/lib 
        -L /Customers/tib/swiftfromc/ 
        -module-name Instance 
        -emit-executable 
        -Xlinker -rpath 
        -Xlinker @loader_path @/Customers/tib/swiftfromc/LinkFileList 
        -Xlinker -rpath 
        -Xlinker /Purposes/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx 
        -Xlinker -rpath 
        -Xlinker /Purposes/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift-5.5/macosx 
        -target arm64-apple-macosx12.1 
        -Xlinker -add_ast_path 
        -Xlinker /Customers/tib/swiftfromc/mytype.swiftmodule 
        -L /Purposes/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib


swiftc 
    -L /residence/ec2-user/swiftfromc 
    -module-name Instance 
    -emit-executable 
    -Xlinker -rpath 
    -Xlinker @loader_path @/residence/ec2-user/swiftfromc/LinkFileList


The command above will produce the ultimate linked executable file that you would be able to run through the use of the ./Instance snippet and hopefully you may see the “Hiya, World! 69” message. 🙈


If you wish to know extra in regards to the rpath linker flag, I extremely suggest studying the article by Marcin Krzyzanowski. If you wish to learn extra about Swift / Goal-C interoperability and utilizing the swiftc command, it’s best to take a look at this text by RDerik. Lastly if you wish to name C code from Swift and go the opposite means, it’s best to check out my different weblog put up.



RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments