Said Sikira Said Sikira - 7 months ago 144
Swift Question

Compile C code and expose it to Swift under Linux

Is there a way to compile native C or C++ code and expose it to Swift on Linux? I can see that several Apple libraries like libdispatch are written in pure C and that you can access them in Swift just by importing them.

To set the example let's say that I have two files

Car.c
and
Car.h
that define structure named
Car
. Is there a way that I can compile them and use them in Swift by writing import statement?

import Car


I've tried writing
module.modulemap
file inside directory where
.c
,
.h
and
Package.swift
files are located:

module Car {
header "Car.h"
export *
}


and running
swift build
. This yield error:

<unknown>:0: error: unexpected 'commands' value (expected map)
<unknown>:0: error: unable to load build file


I'm using Swift version 3.0-dev (March 24 2016)

[Update 1]

I've contacted Max(mxcl) - one of the creators of Swift Package Manager and he told me to get rid of the the
modulemap
and put the
.c
and
.h
files directly in
Sources
folder. After I did that package compiled but it's not available as module. Also I can't call any of the defined functions in the
.h
file.

Answer

If you build a library out of your C code, you can create a system module for it, which can then be imported into Swift, see this answer: Use a C library in Swift on Linux.

Another way to approach this task is to create a bridging header, as suggested by @Philip. Here is an oversimplified example. Let's consider the following C code:

/* In car.h */
int getInt();

/* In car.c */
int getInt() { return 123; }

We will use car.h as the bridging header. The swift source is (in file junk.swift):

print("Hi from swift!")
var i = getInt()
print("And here is an int from C: \(i)!")

First, create an object file, car.o, from car.c:

gcc -c car.c

Now build an executable, junk, as follows:

swiftc -import-objc-header car.h junk.swift car.o -o junk

Running the executable gives:

$ ./junk
Hi from swift!
And here is an int from C: 123!

The -import-objc-header option is hidden. To see it and a bunch of other hidden options, run:

swiftc -help-hidden 

I did this using Swift 3.0 development snapshot for Ubuntu 14.04 from April 12, available here: https://swift.org/builds/development/ubuntu1404/swift-DEVELOPMENT-SNAPSHOT-2016-04-12-a/swift-DEVELOPMENT-SNAPSHOT-2016-04-12-a-ubuntu14.04.tar.gz

Now, if you want to use C++, you will need to create a wrapper, written in a C++ source file and compiled with a C++ compiler, but with functions callable from C by using extern "C". Those functions can then be called from Swift as any C function. See, for example, this answer: Can I mix Swift with C++? Like the Objective - C .mm files