go-libwebp

Experimental translation from libwebp to Go source.
Log | Files | Refs | README | LICENSE

commit d21fe910e3488d0208c11234b687ef6a04bfcd23
parent 8b827e0b7a69b5d251c68104c24c5b731256819e
Author: Jack Mordaunt <jackmordaunt.dev@gmail.com>
Date:   Sun, 20 Sep 2026 15:07:29 -0300

tools: port transpile.sh to ccgo v4

ccgo v3 could not do this job any more: it does not build on Go 1.27, and
against libwebp 1.6.0 it failed to resolve objects at all, either reporting
"no objects to link" from the archive or panicking in ccgo.go:1281:find on
explicit object paths.

v4 is a direct compiler, so the autotools configure, the compile database and
the static archive all go away; it takes the source files. It also supplies
target predefines through --goos/--goarch, but not target libc headers, so
each cross target still needs a header source:

  linux/amd64     the host
  linux/arm64     aarch64-linux-gnu-gcc
  darwin/*        zig's bundled any-macos-any headers
  windows/*       x86_64-w64-mingw32-gcc

zig is what removes the osxcross requirement, and with it the need for an
Apple SDK that cannot be redistributed. It does not help for linux: ccgo
cannot parse zig's generic-glibc bits/types.h.

Two patches are carried. libwebp declares GetCoeffs as a volatile function
pointer and v4 cannot emit a call through one; threading is disabled here so
dropping volatile is safe, and it is applied in place with a restore trap
because ccgo resolves modernc.org/libc through the module it runs from.
sharpyuv_stub.c replaces the sharpyuv library, whose sharpyuv_gamma.c is the
only caller of expf/logf in libwebp — modernc.org/libc provides Xexpf and
Xlogf for linux only, so transpiling it fails to link on darwin and windows.
Nothing reaches sharpyuv unless WebPConfig.use_sharp_yuv is set, which this
package never does.

Diffstat:
Atools/sharpyuv_stub.c | 37+++++++++++++++++++++++++++++++++++++
Mtools/transpile.sh | 251++++++++++++++++++++++++-------------------------------------------------------
2 files changed, 114 insertions(+), 174 deletions(-)

diff --git a/tools/sharpyuv_stub.c b/tools/sharpyuv_stub.c @@ -0,0 +1,37 @@ +// Stub replacements for libwebp's sharpyuv library, used by the transpiled +// backend only. +// +// sharpyuv/sharpyuv_gamma.c is the only file in libwebp that calls expf() and +// logf(), and modernc.org/libc provides Xexpf/Xlogf for linux targets only. +// Transpiling sharpyuv therefore fails to link on darwin and windows. +// +// Nothing here is reachable: sharpyuv is entered only through +// WebPConfig.use_sharp_yuv, and this package always encodes via +// WebPEncodeRGBA / WebPEncodeLosslessRGBA, which use the default config. +// SharpYuvConvert returning 0 is the library's own failure signal, so a +// caller that did enable sharp YUV would get a clean encode error rather +// than wrong output. + +#include "sharpyuv/sharpyuv.h" +#include "sharpyuv/sharpyuv_csp.h" +#include "src/dsp/cpu.h" + +void SharpYuvInit(VP8CPUInfo cpu_info_func) { (void)cpu_info_func; } + +const SharpYuvConversionMatrix* SharpYuvGetConversionMatrix( + SharpYuvMatrixType matrix_type) { + (void)matrix_type; + return NULL; +} + +int SharpYuvConvert(const void* r_ptr, const void* g_ptr, const void* b_ptr, + int rgb_step, int rgb_stride, int rgb_bit_depth, + void* y_ptr, int y_stride, void* u_ptr, int u_stride, + void* v_ptr, int v_stride, int yuv_bit_depth, int width, + int height, const SharpYuvConversionMatrix* yuv_matrix) { + (void)r_ptr; (void)g_ptr; (void)b_ptr; (void)rgb_step; (void)rgb_stride; + (void)rgb_bit_depth; (void)y_ptr; (void)y_stride; (void)u_ptr; + (void)u_stride; (void)v_ptr; (void)v_stride; (void)yuv_bit_depth; + (void)width; (void)height; (void)yuv_matrix; + return 0; +} diff --git a/tools/transpile.sh b/tools/transpile.sh @@ -1,178 +1,81 @@ #!/bin/sh +# +# Transpile libwebp to Go with ccgo v4, one file per GOOS/GOARCH. +# +# Requires: +# ccgo v4 go install modernc.org/ccgo/v4@latest +# zig darwin headers (replaces osxcross; no Apple SDK needed) +# x86_64-w64-mingw32-gcc windows headers +# aarch64-linux-gnu-gcc linux/arm64 headers +# +# ccgo v4 supplies target predefines via --goos/--goarch but not target libc +# headers, so each cross target needs a header source. zig covers darwin from +# its bundled any-macos-any headers, which is what removes the osxcross and +# Apple SDK requirement. It does not cover linux: ccgo cannot parse zig's +# generic-glibc bits/types.h, so linux/arm64 still uses a real cross compiler +# and linux/amd64 just uses the host. set -eux -cd ./c-lib/ - -# Linux transpile. - -NATIVE_CC=$(which gcc) -NATIVE_CXX=$(which c++) -NATIVE_AR=$(which ar) - -make distclean || true -./autogen.sh -./configure \ - CC=$NATIVE_CC \ - CXX=$NATIVE_CXX \ - --host=x86_64-linux-gnu \ - --disable-libwebpmux \ - --disable-libwebpdemux \ - --disable-sse4.1 \ - --disable-sse2 \ - --disable-neon \ - --disable-neon-rtcd \ - --disable-threading \ - --disable-gl \ - --disable-sdl \ - --disable-png \ - --disable-jpeg \ - --disable-tiff \ - --disable-gif \ - --disable-wic \ - --disable-shared - -rm cdb-linux.json || true - -CC=$NATIVE_CC \ -CXX=$NATIVE_CXX \ -AR=$NATIVE_AR \ -ccgo -compiledb cdb-linux.json make - -CC=$NATIVE_CC \ -CXX=$NATIVE_CXX \ -AR=$NATIVE_AR \ -ccgo -pkgname webp -trace-translation-units -o ../lib/transpiled/webp/libwebp_linux_amd64.go cdb-linux.json src/.libs/libwebp.a - -gofmt -s -w ../lib/transpiled/webp/libwebp_linux_amd64.go - -# Linux arm64. - -LINUX_ARM_HOST=aarch64-linux-gnu -LINUX_ARM_CC=$(which $LINUX_ARM_HOST-gcc) -LINUX_ARM_CXX=$(which $LINUX_ARM_HOST-c++) -LINUX_ARM_AR=$(which $LINUX_ARM_HOST-ar) - -make distclean || true -./autogen.sh -./configure \ - CC=$LINUX_ARM_CC \ - CXX=$LINUX_ARM_CXX \ - --host=$LINUX_ARM_HOST \ - --disable-libwebpmux \ - --disable-libwebpdemux \ - --disable-sse4.1 \ - --disable-sse2 \ - --disable-neon \ - --disable-neon-rtcd \ - --disable-threading \ - --disable-gl \ - --disable-sdl \ - --disable-png \ - --disable-jpeg \ - --disable-tiff \ - --disable-gif \ - --disable-wic \ - --disable-shared - -rm cdb-linux-arm64.json || true - -CC=$LINUX_ARM_CC \ -CXX=$LINUX_ARM_CXX \ -AR=$LINUX_ARM_AR \ -ccgo -compiledb cdb-linux-arm64.json make - -CC=$LINUX_ARM_CC \ -CXX=$LINUX_ARM_CXX \ -AR=$LINUX_ARM_AR \ -ccgo -pkgname webp -trace-translation-units -o ../lib/transpiled/webp/libwebp_linux_arm64.go cdb-linux-arm64.json src/.libs/libwebp.a - -gofmt -s -w ../lib/transpiled/webp/libwebp_linux_arm64.go - -# macOS transpile. - -MACOS_HOST=x86_64-apple-darwin15 -MACOS_CC=$(which $MACOS_HOST-cc) -MACOS_CXX=$(which $MACOS_HOST-c++) -MACOS_AR=$(which $MACOS_HOST-ar) - -make distclean || true -./autogen.sh -./configure \ - CC=$MACOS_CC \ - CXX=$MACOS_CXX \ - --host=$MACOS_HOST \ - --disable-libwebpmux \ - --disable-libwebpdemux \ - --disable-sse4.1 \ - --disable-sse2 \ - --disable-neon \ - --disable-neon-rtcd \ - --disable-threading \ - --disable-gl \ - --disable-sdl \ - --disable-png \ - --disable-jpeg \ - --disable-tiff \ - --disable-gif \ - --disable-wic \ - --disable-shared - -rm cdb-darwin.json || true - -CC=$MACOS_CC \ -CXX=$MACOS_CXX \ -AR=$MACOS_AR \ -ccgo -compiledb cdb-darwin.json make - -CC=$MACOS_CC \ -CXX=$MACOS_CXX \ -AR=$MACOS_AR \ -ccgo -pkgname webp -trace-translation-units -o ../lib/transpiled/webp/libwebp_darwin_amd64.go cdb-darwin.json src/.libs/libwebp.a - -gofmt -s -w ../lib/transpiled/webp/libwebp_darwin_amd64.go - -# Windows transpile. - -WINDOWS_HOST=x86_64-w64-mingw32 -WINDOWS_CC=$(which x86_64-w64-mingw32-gcc) -WINDOWS_CXX=$(which x86_64-w64-mingw32-g++) -WINDOWS_AR=$(which x86_64-w64-mingw32-ar) - -make distclean || true -./autogen.sh -./configure \ - CC=$WINDOWS_CC \ - CXX=$WINDOWS_CXX \ - --host=$WINDOWS_HOST \ - --disable-libwebpmux \ - --disable-libwebpdemux \ - --disable-sse4.1 \ - --disable-sse2 \ - --disable-neon \ - --disable-neon-rtcd \ - --disable-threading \ - --disable-gl \ - --disable-sdl \ - --disable-png \ - --disable-jpeg \ - --disable-tiff \ - --disable-gif \ - --disable-wic \ - --disable-shared - -rm cdb-windows.json || true - -CC=$WINDOWS_CC \ -CXX=$WINDOWS_CXX \ -AR=$WINDOWS_AR \ -ccgo -compiledb cdb-windows.json make - -CC=$WINDOWS_CC \ -CXX=$WINDOWS_CXX \ -AR=$WINDOWS_AR \ -ccgo -windows -pkgname webp -trace-translation-units -o ../lib/transpiled/webp/libwebp_windows_amd64.go cdb-windows.json src/.libs/libwebp.a - -gofmt -s -w ../lib/transpiled/webp/libwebp_windows_amd64.go - - +HERE=$(cd "$(dirname "$0")" && pwd) +SRC=$HERE/../c-lib +OUT=$HERE/../lib/transpiled/webp +ZIG=${ZIG:-zig} +ZIGLIB=$($ZIG env | sed -n 's/.*\.lib_dir[ ]*=[ ]*"\([^"]*\)".*/\1/p') + +# dsp.h only enables SIMD when HAVE_CONFIG_H is set together with +# WEBP_HAVE_SSE2, so an empty config.h selects the scalar paths. ccgo has no +# -msse2 to turn off. +INC=$(mktemp -d) +mkdir -p "$INC/src/webp" +# HAVE_BUILTIN_BSWAP* matter: endian_inl_utils.h only probes for the builtins +# when HAVE_CONFIG_H is absent, so without these libwebp falls back to x86 +# inline asm, which ccgo turns into a runtime assertion that fires on the +# first lossy decode. A real autotools configure detects these too. +cat > "$INC/src/webp/config.h" <<'CONFIG' +#define HAVE_BUILTIN_BSWAP16 1 +#define HAVE_BUILTIN_BSWAP32 1 +#define HAVE_BUILTIN_BSWAP64 1 +CONFIG +trap 'rm -rf "$INC"' EXIT + +# libwebp declares GetCoeffs as a volatile function pointer; ccgo v4 cannot +# emit a call through one and aborts. Threading is disabled in this build, so +# dropping volatile is safe. +# +# Patched in place rather than in a scratch copy: ccgo resolves +# modernc.org/libc through the module it is run from, so it has to run inside +# this repository. +VP8DEC=$SRC/src/dec/vp8_dec.c +cp "$VP8DEC" "$VP8DEC.orig" +trap 'mv -f "$VP8DEC.orig" "$VP8DEC"; rm -rf "$INC"' EXIT +sed -i 's/^static volatile GetCoeffsFunc GetCoeffs = NULL;/static GetCoeffsFunc GetCoeffs = NULL;/' \ + "$VP8DEC" + +transpile() { + goos=$1 + goarch=$2 + shift 2 + echo "=== $goos/$goarch ===" + ( cd "$SRC" && ccgo \ + --goos="$goos" --goarch="$goarch" \ + --package-name=webp \ + -ignore-asm-errors \ + "$@" \ + -o "$OUT/libwebp_${goos}_${goarch}.go" \ + -DNDEBUG -DHAVE_CONFIG_H -I"$INC" -I. \ + src/dec/*.c src/enc/*.c src/utils/*.c src/dsp/*.c \ + "$HERE/sharpyuv_stub.c" ) + gofmt -w "$OUT/libwebp_${goos}_${goarch}.go" +} + +MACOS="-nostdinc -isystem $ZIGLIB/include -isystem $ZIGLIB/libc/include/any-macos-any" + +transpile linux amd64 +transpile linux arm64 --cpp=aarch64-linux-gnu-gcc +transpile darwin amd64 $MACOS +transpile darwin arm64 $MACOS +transpile windows amd64 --cpp=x86_64-w64-mingw32-gcc +transpile windows arm64 --cpp=x86_64-w64-mingw32-gcc + +ls -la "$OUT"