iOS Development

How one can use a Swift library in C

Written by admin


How one can construct a C suitable Swift library?


So as to create a Swift library that is going to work with C, we’ve got to mess around with unsafe reminiscence pointers to create a C suitable interface. Fortuitously 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’ll use on this case. Thanks you. 🙏


ultimate class MyType {
    var depend: Int = 69
}

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

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

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


The excellent news is that we do not crucial must 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 speak concerning the accessible flags. This time we’ll use the -module-name choice to specify our module identify, we’ll generate the required recordsdata utilizing the -emit-dependencies flag, parse the supply recordsdata as a library (-parse-as-library), since we would prefer to generate a Swift library present the required goal and model info 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 further Swift module associated output recordsdata. We will use these recordsdata to construct our ultimate executable, however there are a couple of extra further issues I would like to say.


Underneath Linux the header file will not work. It accommodates a line #embody Basis/Basis.h and naturally there isn’t a such header file for Linux. It’s potential to put in the GNUstep bundle (e.g. by way of yum: sudo yum set up gnustep-base gnustep-base-devel gcc-objc, however for me the clang command nonetheless complained concerning 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 would like to say is that if you wish to export a category for Swift, that is going to be a bit tougher, as a result of courses will not be included within the generated header file. You could have two choices on this case. The primary one is to show them into Goal-C courses, however it will result in issues when utilizing Linux, anyway, that is how you are able to do it:


import Basis

@objc public ultimate class MyType: NSObject {
    public var depend: Int = 69
}


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

typedef struct mytype mytype_t;


We will want this kind (with the corresponding header file), as a result of the mytype_create operate returns a pointer that we will 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 must import the headers after which voilá you should utilize every little thing outlined in these headers.


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

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

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

    return 0;
}


We will use clang to compile the major.c file into an object file utilizing the required header recordsdata.



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


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


This command will construct a major.o file, which we will 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 couple of hours of fighting the ld command and different framework instruments I made a decision to provide it up and let swiftc maintain the job, since it could possibly construct and hyperlink each C and Swift-based executables.


We will want a listing of the thing recordsdata that we’ll hyperlink collectively.


ls *.o > LinkFileList


Then we will name swiftc to do the job for us. I suppose it’s going to invoke the ld command below the hood, however I am not a linker professional, so if you realize extra about this, be at liberty to succeed in out and present me extra information concerning the course of. I’ve to learn this guide for certain. 📚



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 /dwelling/ec2-user/swiftfromc 
    -module-name Instance 
    -emit-executable 
    -Xlinker -rpath 
    -Xlinker @loader_path @/dwelling/ec2-user/swiftfromc/LinkFileList


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


If you wish to know extra concerning 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 is best to take a look at this text by RDerik. Lastly if you wish to name C code from Swift and go the opposite manner, it is best to check out my different weblog submit.



About the author

admin

Leave a Comment