Пролог
Недавно я столкнулся с задачей собрать своё Go‑приложение написаное вокруг библиотеки github.com/webview/webview_go
, которая является обёрткой для C/C++ библиотеки webview, для Linux, из чего вытекает необходимость использования CGO. Казалось бы, что сложного? Укажи GOOS=linux, пропиши компилятор CC= и CXX=, выполни go build — и готово. Но нет, CGO и зависимости вроде GTK превратили это в настоящий квест. После нескольких часов борьбы с ошибками вроде Package webkit2gtk-4.0 was not found in the pkg-config search path.
, я наконец‑то разобрался, как это сделать без виртуальной машины, используя Zig и Docker (я знаю что на macOS докер крутится в виртуалке, тут он только для получения файлов для компиляции). В этой статье делюсь своим решением — надеюсь, оно сэкономит вам время.
Инструменты
-
Zig: Компилятор для C‑кода в CGO. Zig умеет кросс‑компиляцию и заменяет GCC/Clang для сборки под Linux.
-
Docker: Чтобы вытащить нужные Linux‑библиотеки без запуска полноценной VM при последующих сборках.
-
Go: Ну, тут всё понятно.
Сборка
Так как мы пользуем CGO это значит, что нам нужны заголовочные файлы и библиотеки для целевой платформы (Linux x86_64), которых на macOS нет. Компилятор который может собирать C под любые платформы, я давно пользуюсь zig для этих дел, потому изобретать нового не стал. Вообще zig хорошо интегрируется во многие проекты, так например для Rust можно собирать через cargo zigbuild, но разговор тут не про это.
Установка Zig
Первым делом Zig — он будет нашим мостом для компиляции C‑кода под Linux.
brew install zig
Создание sysroot
В sysroot будут хранится библиотеки и заголовки для целевой платформы, ими zig будет пользоваться при сборке.
Создаём папку для sysroot:
mkdir -p linux-sysroot
Запускаем контейнер Ubuntu:
docker run -it ubuntu:latest bash
Внутри контейнера обновляем пакеты и ставим зависимости:
apt update apt install -y libgtk-3-dev libwebkit2gtk-4.0-dev
У меня установилось около гигабайта файлов, к слову итоговый sysroot столько и занимал в будущем, я думаю можно удалить от туда много лишнего чтоб не расходовать место на диске.
Теперь перенесем нужные файлы на хост, для переноса архивирую в tar, так как при копировании из контейнера на хост ломались ссылки на файлы что в итоге не давало скомпилировать приложение.
tar -czf /tmp/sysroot.tar.gz /usr/lib/x86_64-linux-gnu /usr/include tar -czf /tmp/wayland.tar.gz /usr/share/pkgconfig/wayland-protocols.pc /usr/share/wayland-protocols
Выходим из контейнера exit
И найдем id контейнера в котором мы работали:
docker ps -a
Копируем файлы на хост и распаковываем:
docker cp <container_id>:/tmp/sysroot.tar.gz . docker cp <container_id>:/tmp/wayland.tar.gz . tar -xzf sysroot.tar.gz -C ./linux-sysroot tar -xzf wayland.tar.gz -C ./linux-sysroot
если ваше приложение тянет другие C библиотеки, то проделайте аналогичное действие и с ними, но
/usr/lib/x86_64-linux-gnu
и/usr/include
вполне должно хватить для многого
Настройка окружения
Чтобы pkg-config
видел наши .pc
‑файлы, добавляем пути:
export PKG_CONFIG_PATH="$PWD/linux-sysroot/usr/lib/x86_64-linux-gnu/pkgconfig:$PWD/linux-sysroot/usr/share/pkgconfig:$PKG_CONFIG_PATH"
Проверяем:
pkg-config --cflags --libs gtk+-3.0 webkit2gtk-4.0
Если ваш вывод похож на мой, то sysroot был найден:
-I/usr/include/webkitgtk-4.0 -I/usr/include/gtk-3.0 -I/usr/include/pango-1.0 -I/usr/include -I/usr/local/Cellar/xorgproto/2024.1/include -I/usr/include/cairo -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/at-spi2-atk/2.0 -I/usr/include/at-spi-2.0 -I/usr/include/dbus-1.0 -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include -I/usr/include/atk-1.0 -I/usr/include/fribidi -I/usr/include/harfbuzz -I/usr/include/pixman-1 -I/usr/include/uuid -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/gio-unix-2.0 -I/usr/include/libsoup-2.4 -pthread -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/libxml2 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -L/usr/lib/x86_64-linux-gnu -lwebkit2gtk-4.0 -lgtk-3 -lgdk-3 -lpangocairo-1.0 -lcairo-gobject -lgdk_pixbuf-2.0 -latk-1.0 -lpango-1.0 -lharfbuzz -lcairo -lsoup-2.4 -lgio-2.0 -ljavascriptcoregtk-4.0 -lgobject-2.0 -lglib-2.0
На этом этапе все готово для сборки, по непонятной причине пути из pkg-config
не подтянулись в zig автоматически, потому вручную каждый из параметров прописал через параметр -isystem
для zig cc
и zig c++
. Чтоб вам не заниматься этим привожу ниже получившийся список.
#!/bin/bash SYSROOT="$PWD/linux-sysroot" INCLUDE_PATHS=( "$SYSROOT/usr/include" "$SYSROOT/usr/include/webkitgtk-4.0" "$SYSROOT/usr/include/gtk-3.0" "$SYSROOT/usr/include/glib-2.0" "$SYSROOT/usr/lib/x86_64-linux-gnu/glib-2.0/include" "$SYSROOT/usr/include/pango-1.0" "$SYSROOT/usr/include/harfbuzz" "$SYSROOT/usr/include/cairo" "$SYSROOT/usr/include/gdk-pixbuf-2.0" "$SYSROOT/usr/include/at-spi2-atk/2.0" "$SYSROOT/usr/include/at-spi-2.0" "$SYSROOT/usr/include/dbus-1.0" "$SYSROOT/usr/lib/x86_64-linux-gnu/dbus-1.0/include" "$SYSROOT/usr/include/atk-1.0" "$SYSROOT/usr/include/fribidi" "$SYSROOT/usr/include/pixman-1" "$SYSROOT/usr/include/uuid" "$SYSROOT/usr/include/freetype2" "$SYSROOT/usr/include/libpng16" "$SYSROOT/usr/include/gio-unix-2.0" "$SYSROOT/usr/include/libsoup-2.4" "$SYSROOT/usr/include/libmount" "$SYSROOT/usr/include/blkid" "$SYSROOT/usr/include/libxml2" "$SYSROOT/usr/lib/x86_64-linux-gnu" ) ISYSTEM_FLAGS=$(printf " -isystem %s" "${INCLUDE_PATHS[@]}") CGO_ENABLED=1 \ GOOS=linux \ GOARCH=amd64 \ CC="zig cc -target x86_64-linux-gnu$ISYSTEM_FLAGS" \ CXX="zig c++ -target x86_64-linux-gnu$ISYSTEM_FLAGS" \ CGO_LDFLAGS="-L$SYSROOT/usr/lib/x86_64-linux-gnu" \ PKG_CONFIG_PATH="$SYSROOT/usr/lib/x86_64-linux-gnu/pkgconfig:$SYSROOT/usr/share/pkgconfig" \ go build -o $RELEASE_DIR/WebViewApp-nix-amd64 -ldflags="-s -w" main.go
После выполнения собрался заветный файлик и каким‑то образом ещё и заработал. Контейнер который использовался ранее можно смело удалять. Теоретически аналогичным путём можно собрать и под arm и вообще что угодно.
Итог
Я в очередной раз поражаюсь возможностями zig и беспомощностью go в плане гибкости настройки компиляции.
Если у вас есть похожая задача, надеюсь, этот гайд поможет. Вопросы или предложения — пишите в комментариях!
зы. моя первая статья на данном ресурсе, так что надеюсь не нарушил никаких местных религий
ссылка на оригинал статьи https://habr.com/ru/articles/894426/
Добавить комментарий