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 incompiled
→ Strategy: Create an interpreter context, then load the files and execute them. - Library in
compiled
and the project ininterpreted
→ Strategy: UseFFI
. - 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")