Use a C Library in Swift on Linux

Use a C library in Swift on Linux

Use a System Module to import the OpenGL header file:
https://github.com/apple/swift-package-manager/blob/master/Documentation/SystemModules.md

Assuming you have a directory layout like:

COpenGL/
Package.swift
module.modulemap
.git/

YourApp/
Package.swift
main.swift
.git/

the COpenGL/module.modulemap file will look something like:

module COpenGL [system] {
header "/usr/include/gl/gl.h"
link "gl"
export *
}

This has to be created in a separate git repo, with a version tag:

touch Package.swift
git init
git add .
git commit -m "Initial Commit"
git tag 1.0.0

Then declare it as a dependency in YourApp/Package.swift file

import PackageDescription

let package = Package(
dependencies: [
.Package(url: "../COpenGL", majorVersion: 1)
]
)

Then in your main.swift file you can import it:

import COpenGL
// use opengl calls here...

Linking a C library and its supporting library in Swift (linux)

Adding a second link line for libgslcblas will do the trick:

module CGSL [system] {
header "/usr/include/gsl/gsl_rng.h"
link "gsl"
link "gslcblas"
export *
}

You may also need to add link "m", even though I didn't have to do that on my box (Ubuntu 14.04).

I did not find a specific advice on this in Swift documentation and had to make an educated guess, but it worked. Swift on Linux is work in progress and the Package Manager is only available with Swift 3.0 development snapshots, Swift 3.0 being an unstable, actively developed latest version of the language. The very fact that such a common scenario is not well documented should give you an idea of the technology's maturity.

As an alternative to the Package Manager you might want to consider using a bridging header as described in an answer to this question:
Compile C code and expose it to Swift under Linux.

Whichever way you do it, a bigger challenge will be calling the GSL API from Swift because the API uses a lot of non-primitive types. To work around that problem consider writing a C wrapper with a simplified interface that can be easily called from Swift. The wrapper can then be called by using a bridging header or system modules.

Compile C code and expose it to Swift under Linux

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

Use static C library with Swift package manager

I'm not aware of a way to specify library locations in a module map, but here is what worked for me:

example$ swift build -Xlinker -L../CMult

You can find some other useful options by running

swift build --help

As for LD_LIBRARY_PATH, that's for searching shared libraries. For static it would be LIBRARY_PATH, but that one didn't work with swift build when I tried it. It does work with gcc, though.



Related Topics



Leave a reply



Submit