This is a simple experiment to test the interoperability between Golang and Scala in GraalVM.
The JVM and GraalVM are not required to be installed, as the Scala CLI will download and use the GraalVM JVM.
scala-cli --power package . \
--suppress-experimental-feature-warning \
--server=false \
--jvm=graalvm-java17 \
--graalvm-jvm-id=graalvm-java17:22 \
--native-image \
-o lib/libscala -f \
-- \
--no-fallback --shared
go build -o bin/main golang/main.go
mkdir bin
cp lib/libscala.dylib bin
./bin/main
We want to reuse the existing implementations of some Scala libraries in Golang code.
We use GraalVM Native Image to compile the Scala code to a shared native library binary and the Golang/CGO code to an executable binary that calls the shared library binary.
GraalVM Native Image is a technology to ahead-of-time compile JVM bytecode to a native binary (shared library or an executable). It supports polyglot programming by allowing to include code from different languages in the same binary (using LLVM, WASM or Truffle) or to be linked from different binaries.
We use scala-cli
with
--native-image
and --shared
to compile the Scala code to a shared (dynamically linked) native library binary. As of the time of writing,
GraalVM Native Image does not support statically linked
native library binaries.
To export any JVM method to be called from a native binary, we use the org.graalvm.nativeimage.c.function.CEntryPoint
from a compile time dependency on GraalVM SDK.
Since the method is called from a native binary, it must be static
and we use @scala.annotation.static
on a companion object method to achieve that.
Golang has a powerful feature called CGO that allows calling C functions and C libraries from Golang code.
To use CGO we import a pseudo-package "C"
and use the so-called preamble with C
and CGO directives to tell
the compiler how to link the C shared library binary with the Golang binary:
CFLAGS
withI
option to specify the compile time include path for the C header filesLDFLAGS
withL
option to specify the compile time library search path for the C shared library binary;l
option to specify the library name for the C shared library binary; and the combination of-Wl
,-rpath
and$ORIGIN
to specify the runtime shared library path relative to the executable for the C shared library binary.#include
directives to include the C header files for the C shared library binary at compile time.
We use the C
pseudo-package and the Native Image C API to call the Scala shared library binary from the Golang code.
We distribute the Golang binary and the Scala shared library binary together in the same directory. The binary is linked to the shared library binary at runtime using the relative runtime shared library path.