Use a C library in Swift on Linux

To follow on to MBuhot's excellent answer, I just did this to get a Swift OpenGL "hello world" running on a couple of Linux systems and I can add a little more detail.

In my case, I needed both OpenGL and the GLUT functions, so I first created a COpenGL system module. The source for this module can be found on GitHub, but basically it's a directory with two files: an empty Package.swift, and the following module.modulemap:

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

Note the capital GL in the header and link options, which I needed to match Mesa's headers and libraries.

For the GLUT functions, I created a similar CFreeGLUT module (again, on GitHub) with the following module.modulemap:

module CFreeGLUT [system] {
    header "/usr/include/GL/freeglut.h"
    link "glut"
    export *
}

For the application, if you want to use the Swift Package Manager, you'll need to create a Package.swift in the main directory that looks like this:

import PackageDescription

let package = Package(
    dependencies: [
        .package(url: "https://github.com/BradLarson/COpenGL.git", from: "1.0.0"),
        .package(url: "https://github.com/BradLarson/CFreeGLUT.git", from: "1.0.0")
    ]
) 

The above pulls from my GitHub versions of the system modules, but you can edit the paths to have them point to local copies, if you'd like.

I used the Red Book's "hello world" application as my basis, which looks like the following when converted to Swift:

import COpenGL
import CFreeGLUT

func renderFunction() {
    glClearColor(0.0, 0.0, 0.0, 0.0)
    glClear(UInt32(GL_COLOR_BUFFER_BIT))
    glColor3f(1.0, 0.0, 0.0)
    glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0)
    glBegin(UInt32(GL_POLYGON))
        glVertex2f(-0.5, -0.5)
        glVertex2f(-0.5, 0.5)
        glVertex2f(0.5, 0.5)
        glVertex2f(0.5, -0.5)
    glEnd()
    glFlush()
}

var localArgc = CommandLine.argc
glutInit(&localArgc, CommandLine.unsafeArgv)
glutInitDisplayMode(UInt32(GLUT_SINGLE))
glutInitWindowSize(500,500)
glutInitWindowPosition(100,100)
glutCreateWindow("OpenGL - First window demo")
glutDisplayFunc(renderFunction)
glutMainLoop()

Place that into a main.swift file within the Sources subdirectory. Run swift build and the Swift Package Manager will go out, download the system modules, build the application, and link the modules against it.

If you don't want to use the Swift Package Manager, you can still manually use these system modules from the command line. To do so, download them into a local directory and explicitly reference them when compiling:

swiftc -I ./COpenGL -I ./CFreeGLUT main.swift

The module maps will be read and you'll be able to access OpenGL and the GLUT functions from within your Swift application 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...

Tags:

Linux

Swift