website/programming/bridging.md
2025-08-03 16:27:25 +02:00

211 lines
No EOL
4.4 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
layout: default
title: Bridging between languages
categories: programming
---
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`](https://github.com/artur-gurgul/codebook):
``` 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`
```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)
```sh
swiftc point.swift -emit-module  -module-name Point -emit-library -static
```
**Using**
```swift
import Point
let p = Point(x: 4, y: 20)
print("Hello library!", p.x, p.y)
```
compile with
```sh
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
// 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`:
```c++
#include <stdio.h>
extern "C" {
void PrintHello(const char* u) {
printf("Hello: %s\n", u);
}
}
```
And `example.hxx`:
```c++
#pragma once
void PrintHello(const char* u)
```
`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
```bash
clang++ -c -Wall -o lib.o ./example.cxx
ar rc ./libexample.a ./lib.o
```
#### Creating dynamic library
```bash
clang++ -dynamiclib -o libexample.dylib example.cxx
```
## Statically linking an example library in Go
```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
```shell
gem install ffi
```
```ruby
require 'ffi'
module Example
extend FFI::Library
ffi_lib './example.dylib'
attach_function :SayHello, [:string]
end
```
```ruby
Example.SayHello("Hello")
```
More informations about FFI: [https://en.wikipedia.org/wiki/Foreign_function_interface](https://en.wikipedia.org/wiki/Foreign_function_interface)
#### Call shared library from Python
```python
import ctypes
libc = ctypes.CDLL('./example.dylib')
libc.SayHello("Hello")
```
## Interesting websites
- [https://blog.filippo.io/building-python-modules-with-go-1-5/](https://blog.filippo.io/building-python-modules-with-go-1-5/)
- [https://id-rsa.pub/post/go15-calling-go-shared-libs-from-firefox-addon/](https://id-rsa.pub/post/go15-calling-go-shared-libs-from-firefox-addon/)