[ad_1]
Methods to construct a C suitable Swift library?
As a way to create a Swift library that is going to work with C, we have now 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 superb start line, on the Swift boards created by Cory Benfield, so that is what we’ll use on this case. Thanks you. 🙏
last class MyType {
var rely: 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.rely)
}
@_cdecl("mytype_destroy")
public func mytype_destroy(_ kind: OpaquePointer) {
_ = Unmanaged<MyType>.fromOpaque(UnsafeRawPointer(kind)).takeRetainedValue()
}
The excellent news is that we do not obligatory need to 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 learners and I additionally wrote some issues about the Swift compiler, the place I speak concerning the obtainable flags. This time we’ll use the -module-name choice to specify our module identify, we’ll generate the required information utilizing the -emit-dependencies flag, parse the supply information as a library (-parse-as-library), since we would wish to generate a Swift library present the required 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 information. We’ll use these information to construct our last executable, however there are just a few extra extra issues I might like to say.
Beneath Linux the header file will not work. It incorporates a line #embrace Basis/Basis.h and naturally there isn’t a such header file for Linux. It’s doable 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 might 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 lessons will not be included within the generated header file. You’ve two choices on this case. The primary one is to show them into Goal-C lessons, however it will result in issues when utilizing Linux, anyway, that is how you are able to do it:
import Basis
@objc public last class MyType: NSObject {
public var rely: Int = 69
}
I desire the second possibility, 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’ll want this sort (with the corresponding header file), as a result of the mytype_create perform returns a pointer that we are able to use to name the opposite mytype_get_count technique. 🤔
Compiling C sources utilizing Swift libraries
So how will we use these uncovered Swift objects in C? Within the C programming language you simply need to import the headers after which voilá you should use every part outlined in these headers.
#embrace <stdio.h>
#embrace "mytype.h"
int essential() {
mytype_t *merchandise = mytype_create();
int i = mytype_get_count(merchandise);
printf("Hi there, World! %dn", i);
return 0;
}
We will use clang to compile the essential.c file into an object file utilizing the required header information.
clang -x objective-c -include mytype.h -include mytype_struct.h -c essential.c
clang -include mytype.h -include mytype_struct.h -c essential.c
This command will construct a essential.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 in a position to hyperlink the 2 object information collectively after just a few hours of combating the ld command and different framework instruments I made a decision to offer it up and let swiftc maintain the job, since it may well construct and hyperlink each C and Swift-based executables.
We’ll want an inventory of the thing information that we’ll hyperlink collectively.
ls *.o > LinkFileList
Then we are able to 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 knowledgeable, so if you understand extra about this, be happy to achieve out and present me extra information concerning the course of. I’ve to learn this e-book for certain. 📚
swiftc
-sdk /Functions/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.1.sdk
-F /Functions/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Frameworks
-I /Functions/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/usr/lib
-L /Functions/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 /Functions/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx
-Xlinker -rpath
-Xlinker /Functions/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 /Functions/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 you can run through the use of the ./Instance snippet and hopefully you may see the “Hi there, 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, you need to take a look at this text by RDerik. Lastly if you wish to name C code from Swift and go the opposite approach, you need to check out my different weblog publish.
[ad_2]
