This gist is a simple example on how to call a function written in swift from C/C++, without taking the detour via Objective-C/C++.
In this example we're going to invoke a function called say_hello
, which,
as the name already suggests, prints "Hello, World!" to the terminal.
say_hello is defined as following:
// func.swift
@_cdecl("say_hello")
public func say_hello(){
print("Hello, World!")
}
This is just the canonical "Hello, World!"-example wrapped in a function
called say\_hello
. The only thing, that stands out, is the attribute @_cdecl("say\_hello")
.
@_cdecl
is an undocumented attribute, which according to vague informations found on the web,
enforces C-name mangling. Note: @_cdecl
solely enforces the name mangling; not the calling convention!
In order to link our code with a C/C++ application, will need a library. In order to compile our code as a linked library,
specify -emit-library
when compiling the .swift-file.
We want to link our swift code with our C/C++ applications, which means, that we'll need this code to be compiled as a library. In order to compiler our code as a linked library, just specify '-emit-library' when compiling the .swift-file.
swiftc func.swift -emit-library
This will result in a linked library called "libfunc.dylib" (or "libfunc.so" on Linux, I suppose),
which exports our function say_hello
as _say_hello
.
Now to our C++:
// main.cpp
// only "extern" when targeting C.
extern "C" void say_hello();
int main(){
say_hello(); // Prints "Hello, World!"
return 0;
}
Here we declare say_hello
as an external reference, which will be provided by the library, we compiled before.
What's left at this point is just to compile and link our code.
gcc -std=c++11 -c main.cpp -o main.o
gcc libfunc.dylib main.o -o main
When we run the application, we're getting greeted with following:
./main
> Hello, World!
This was my first "technical article". Feedback is welcome!
None the less, I hope I could help you with this "article".
J. Kirsch
- SO Answer by Max Desiatov
- Trial'n'Error with the command line tool
nm
- Other links, that I cannot remember... :-(
Context: I came to here looking for help days ago with no knowledge of Swift, limited knowledge of Xcode13 and a book apple gives out for free. After a few days of just non-stop working with Swift to understand it's similarities to Luau, C# and C++ (heresy, I know), I came back to start learning and working with
@_cdecl
Stuff here may be wrong. I'm not 100% sure on everything. This is what worked for my project, I want it to be publicly available especially if I forget how to do it again.This is to be used in conjunction with OP's post.
For those who want to do this but are using a fresh copy of Xcode 13, no external compiler tools outside of Terminal and no understanding of Terminal itself, here's two notes for you that I had to figure out myself.
To compile the swift file into a library, you have to navigate to the project folder using the
cd ~/
command to go recursively through the directory folders to it. e.g.cd ~/Documents/ExampleProject/ExampleProject/SwiftFiles
. When you're at the directory for the target file to be compiled, you run the command that the author posted for compilingswiftc <swiftFileNameHere>.swift -emit-library
. It will open up Xcode and compile one of the two library formats from that. Note:cd ~/
is akin to going directly to your Users\YourLocalUsernameHere so if you've copied the full file path directly from Xcode 13's file properties tab, you can omit that.To import it in Xcode 13, you need to have a C/C++ project already. When you have a C/C++ project, you need to click on the .xcproj file in the hierarchy on the left. In the library, you want to go to either
General > Frameworks and Libraries
orBuild Phases > Link Binary with Libraries
General > Frameworks and Libraries
, you want to click on the + icon in the bottom left corner of the section and thenAdd Other...
. A file browser will come up and you need to navigate to and select the dylib/so file you wish to link. When it's appeared in the list, set it's Embed property toEmbed without Signing
orEmbed & Sign
. You may need to go intoBuild Phases > Link Binary with Library
to check if the file has also been added as aRequired
file and not anOptional
one.Build Phases > Link Binary with Library
you repeat the sameAdd Other...
step as with above. When the file appears within the list here, you want to check if the file has been added as aRequired
file. Once done, go to theGeneral > Frameworks and Libraries
tab and set the dylib/so file's Embed property toEmbed without Signing
orEmbed & Sign
.