Скомпилируйте GoLang как мобильную библиотеку
У вас есть проект GoLang, который нужно запускать в программе iOS. Вы можете все переписать на Swift, но вы надеетесь, что будет проще просто скомпилировать GoLang как модуль.
Хорошие новости: это возможно!
Программа go
позволяет не только кросс-компиляции для различных платформ, но она также позволяет экспортировать методы и генерировать файлы заголовков C.
Примечание: Вы можете использовать для этого gomobile.
Функции экспорта
При компиляции GoLang как модуля вы потеряете доступ к функции main()
. Вместо этого вы будете вызывать определенные методы из среды хоста.
Определить экспортируемые функции
Вы можете сделать это, создав специальный комментарий, который гласит //export <functionName>
:
//export functionName
func functionName () {
// do stuff
}
Мост к C
Теперь, когда вы можете экспортировать функции, вам нужно предоставить эти функции через мост C, что вы можете сделать, импортировав модуль «C»:
import "C"
Давайте создадим простой проект GoLang, который возвращает строку при вызове функции из внешней библиотеки. Мы можем назвать этот файл sayHelloLib.go
:
package main
import "C"
//export sayHello
func sayHello() string {
return "Hello"
}
Включить специальные функции для мобильных устройств
При экспорте на мобильный телефон необходимо учитывать несколько моментов. В частности, мы хотим убедиться, что мы используем cgo
, что позволяет программам Go интерполировать с библиотеками C. Это важно для использования возможности запускать программы GoLang на Android или iOS.
Мы делаем это, устанавливая переменную окружения CGO_ENABLED=1
Другое соображение - размер двоичного файла. Поскольку мобильный телефон обычно имеет меньше памяти, чем обычный компьютер, Apple представила так называемый Bitcode, который использует некоторые хитрые приемы компьютерной инженерии для оптимизации двоичных файлов, например, путем упаковки нескольких типов данных в один 64-битный фрейм памяти.
Apple требует в своих программах двоичных файлов с поддержкой Bitcode, поэтому давайте включим это, установив переменную среды CGO-CFLAGS="-fembed-bitcode"
:
Собирая все вместе, мы получаем следующее:
$ export CGO_ENABLED=1
$ CGO_CFLAGS="-fembed-bitcode"
Компиляция
Основная команда для создания двоичного файла из проекта GoLang такова:
$ go build
Если вы компилируете определенный файл или файлы в папке, вы укажете go
, какой файл или папку вы компилируете:
$ go build /path/to/gofile/or/folder
Изменить имя выходного файла
Вы можете указать GoLang, как назвать выходной файл, передав -o outputfilename
параметр в go build
. Обычно мобильным двоичным файлам присваивают расширение .a
:
$ go build -o outputfilename.a /path/to/gofile/or/folder
Кросс-компиляция
Для кросс-компиляции вам необходимо указать go
, какая ОС (GOOS
), архитектура (GOARCH
) и, в зависимости от вашей целевой платформы, ваш SDK (SDK
), установив соответствующие переменные среды GoLang.
Например, если вы компилируете для устройства Android, вы должны установить переменные среды GOOS
и GOARCH
для Android / arm64.
$ export GOOS=android
$ export GOARCH=arm64
Если вы компилируете на устройство iOS, вы будете устанавливать переменные среды GOOS
, GOARCH
и SDK
для Darwin / arm64:
$ export GOOS=darwin
$ export GOARCH=arm64
$ export SDK=iphoneos
Для симулятора iOS вы измените переменную SDK
среды для симулятора iPhone.
$ export SDK=iphonesimulator
Затем вы можете запустить команду сборки:
$ go build -o outputfilename.a /path/to/gofile/or/folder
Вы должны увидеть новый файл outputfilename.a
в рабочей папке.
Создать файл заголовка C
Cgo позволяет экспортировать файлы заголовков C с вашим двоичным кодом. Этот файл важен, потому что он позволяет вам вызывать функции из вашего проекта GoLang как модуль. Вы можете сделать это, передав в программу -buildmode=c-archive
параметр go build
:
$ go build -buildmode c-archive -o outputfilename.a /path/to/file
Вы заметите два новых файла:
outputfilename.a
, скомпилированный двоичный файл.outputfilename.h
, заголовочный файл C.
Этот файл C-заголовка будет включать вашу экспортированную функцию:
// ...
#ifdef __cplusplus
extern "C" {
#endif
extern void sayHello();
#ifdef __cplusplus
}
#endif
Обрезать жир
Наконец, вы можете избавиться от некоторых неиспользуемых символов, передав -trimpath
функции go build
. Это удалит информацию о пути к проекту из окончательного двоичного файла:
$ go build -buildmode c-archive -trimpath -o outputfilename.a /path/to/file
Вы можете прочитать об этом в документации go help build
, в разделе -trimpath
:
-trimpath
remove all file system paths from the resulting executable.
Instead of absolute file system paths, the recorded file names
will begin with either "go" (for the standard library),
or a module path@version (when using modules),
or a plain import path (when using GOPATH).
Собираем все вместе
Теперь, когда вы все это прочитали, это должно иметь смысл:
$ export GOOS=darwin // ios: darwin, android: android
$ export GOARCH=arm64
$ export SDK=iphoneos // iPhone simulator: iphonesimulator
$ CGO_ENABLED=1
$ CGO_CFLAGS="-fembed-bitcode
$ go build -buildmode c-archive -trimpath -o outputfilename.a /path/to/file
Это создаст два файла, которые вы будете использовать в качестве модуля в своем проекте:
outputfilename.a
, двоичный модульoutputfile.h
, который сообщает вашему компилятору, как использовать двоичный файл
Вы сможете включить эти файлы в проект, а затем вызвать метод sayHello()
, например:
#include <stdio.h>
#include "outputfile.h"
// ...
void main() {
printf(sayHello())
}