Bridging between languages

We can cross call functions from languages that:

  • Both are compilable → Strategy: Create a binary library and call function from it.
  • Library in interpreted and the project in compiled → Strategy: Create an interpreter context, then load the files and execute them.
  • Library in compiled and the project in interpreted → Strategy: Use FFI.
  • Both are interpreted
    • Probably give up. Bridging will be possible, but messy and complicated
    • Create two programs and exchange data between them using pipe, sockets, message quesues, databses etc.

Creating shared and static library in Go

An example code that is shared example.go:

package main

import "C"
import "fmt"

//export SayHello
func SayHello(hello *C.char) {
        fmt.Print(C.GoString(hello))
}

func main() {}
  • The main function is neccecery to include into library, because the final product has to have for example the GC rutines.
  • The comment starting from //export {function name} tells the comiler that this the function will be called from the outside.

Creating static library

go build -o example.a -buildmode=c-archive example.go

Creating dynamic library

go build -o example.dylib -buildmode=c-shared example.go

Creating shared and static library in Swift

point.swift

public struct Point {
    public let x: Int
    public let y: Int

    public init(x: Int, y: Int) {
        self.x = x
        self.y = y
    }
}

and compile with command (module name is optional)

swiftc point.swift -emit-module  -module-name Point -emit-library -static

Using

import Point

let p = Point(x: 4, y: 20)
print("Hello library!", p.x, p.y)

compile with

swiftc main.swift -L ./lib/ -I ./lib/ -lpoint

Dynamic library in Swift

swiftc point.swift -emit-module -emit-library

it produces

  • libpoint.a
  • point.swiftdoc
  • point.swiftmodule
  • point.swiftsourceinfo

Compile main program the same way as it has been down with the static one

Library searching paths /usr/lib//usr/local/lib/ 

Create package that emits library

// swift-tools-version:5.3
import PackageDescription

let package = Package(
    name: "MyLibrary",
    products: [
        /// type: automatic, based on the environment
        .library(name: "MyLibrary", 
                 // type: .dynamic, .static
                 targets: ["MyLibrary"]
        ),
    ],
    targets: [
        .target(name: "MyLibrary", dependencies: []),
    ]
)

Calling function from library in Go

First off we will create C++ library that we will use in out Go program. File example.cxx:

{% highlight c++ %} #include <stdio.h>

extern "C" {

void PrintHello(const char* u) { printf("Hello: %s\n", u); }

} {% endhighlight %}

And example.hxx:

{% highlight c++ %} #pragma once void PrintHello(const char* u) {% endhighlight %}

extern "C" {} informs the compiler that we want the function names to be preserved. That is, to not "mangle" the names as is done for C++ code:

Creating static library

clang++ -c -Wall -o lib.o ./example.cxx
ar rc ./libexample.a ./lib.o

Creating dynamic library

clang++ -dynamiclib -o libexample.dylib example.cxx

Statically linking an example library in Go

package main

// #cgo CFLAGS: -I.
// #cgo LDFLAGS: -L. -lexample
//
// #include <example.hxx>
import "C"

func main() {
    C.PrintHello(C.CString("Hello Golang"))
}

The program is linked staticaly with libexample when you build it.

Example of using library with FFI in Ruby

{% highlight shell %} gem install ffi {% endhighlight %}

require 'ffi'
module Example
  extend FFI::Library
  ffi_lib './example.dylib'
  attach_function :SayHello, [:string]
end
Example.SayHello("Hello")

More informations about FFI: https://en.wikipedia.org/wiki/Foreign_function_interface

Call shared library from Python

import ctypes
libc = ctypes.CDLL('./example.dylib')
libc.SayHello("Hello")

Interesting websites