#!/bin/bash # Script to update the vendored gioui.org package # # Usage: ./scripts/update-gio.sh [version] # version: optional gio version (default: latest) # # Example: # ./scripts/update-gio.sh # Update to latest # ./scripts/update-gio.sh v0.9.0 # Update to specific version # # IMPORTANT: After updating, you must re-apply the CGO build constraint patches. # See the "Patching for cross-compilation" section below. set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(dirname "$SCRIPT_DIR")" GIO_DIR="$REPO_ROOT/gio" VERSION="${1:-latest}" echo "Updating vendored gio to version: $VERSION" # Determine the module path to download if [ "$VERSION" = "latest" ]; then MODULE="gioui.org@latest" else MODULE="gioui.org@$VERSION" fi # Download the module to get its path echo "Downloading $MODULE..." MOD_PATH=$(go mod download -json "$MODULE" | grep -o '"Dir": "[^"]*"' | cut -d'"' -f4) if [ -z "$MOD_PATH" ]; then echo "Error: Failed to download module" exit 1 fi echo "Module downloaded to: $MOD_PATH" # Get the actual version ACTUAL_VERSION=$(go mod download -json "$MODULE" | grep -o '"Version": "[^"]*"' | cut -d'"' -f4) echo "Actual version: $ACTUAL_VERSION" # Remove old gio directory echo "Removing old gio directory..." rm -rf "$GIO_DIR" # Copy new gio echo "Copying new gio..." mkdir -p "$GIO_DIR" cp -r "$MOD_PATH"/* "$GIO_DIR"/ # Fix permissions (module cache files are read-only) echo "Fixing permissions..." chmod -R u+w "$GIO_DIR" # Apply CGO build constraint patches for cross-compilation support echo "Applying CGO build constraint patches..." # Patch files that require CGO to add cgo build constraint patch_file() { local file="$1" local old_constraint="$2" local new_constraint="$3" if [ -f "$file" ]; then sed -i "s|$old_constraint|$new_constraint|" "$file" echo " Patched: $file" fi } # app/os_darwin.go - add cgo constraint if [ -f "$GIO_DIR/app/os_darwin.go" ]; then # Add build constraint at the top of the file sed -i '1a\//go:build darwin \&\& cgo\n// +build darwin,cgo' "$GIO_DIR/app/os_darwin.go" echo " Patched: app/os_darwin.go" fi # app/os_macos.go patch_file "$GIO_DIR/app/os_macos.go" \ "//go:build darwin && !ios" \ "//go:build darwin \&\& !ios \&\& cgo" # app/os_ios.go patch_file "$GIO_DIR/app/os_ios.go" \ "//go:build darwin && ios" \ "//go:build darwin \&\& ios \&\& cgo" # internal/gl/gl_unix.go patch_file "$GIO_DIR/internal/gl/gl_unix.go" \ "//go:build darwin || linux || freebsd || openbsd" \ "//go:build (darwin || linux || freebsd || openbsd) \&\& cgo" # internal/vk/vulkan.go patch_file "$GIO_DIR/internal/vk/vulkan.go" \ "//go:build linux || freebsd" \ "//go:build (linux || freebsd || android) \&\& cgo" # internal/vk/vulkan_android.go patch_file "$GIO_DIR/internal/vk/vulkan_android.go" \ "//go:build !nowayland" \ "//go:build android \&\& cgo" # app/vulkan.go, vulkan_android.go, vulkan_wayland.go, vulkan_x11.go for f in vulkan.go vulkan_android.go vulkan_wayland.go vulkan_x11.go; do if [ -f "$GIO_DIR/app/$f" ]; then # Add cgo to build constraints sed -i 's/!novulkan$/!novulkan \&\& cgo/' "$GIO_DIR/app/$f" echo " Patched: app/$f" fi done # gpu/internal/vulkan/vulkan.go patch_file "$GIO_DIR/gpu/internal/vulkan/vulkan.go" \ "//go:build (linux || freebsd) && !novulkan" \ "//go:build (linux || freebsd || android) \&\& !novulkan \&\& cgo" # gpu/headless/headless_vulkan.go patch_file "$GIO_DIR/gpu/headless/headless_vulkan.go" \ "//go:build (linux || freebsd) && !novulkan" \ "//go:build (linux || freebsd) \&\& !novulkan \&\& cgo" # internal/vk/vulkan_wayland.go and vulkan_x11.go for f in vulkan_wayland.go vulkan_x11.go; do if [ -f "$GIO_DIR/internal/vk/$f" ]; then # Add cgo to build constraints sed -i 's/!nowayland$\|!nox11$/& \&\& cgo/' "$GIO_DIR/internal/vk/$f" echo " Patched: internal/vk/$f" fi done # Create stub files for platforms without CGO echo "Creating stub files for non-CGO builds..." # Darwin stub cat > "$GIO_DIR/app/os_darwin_nocgo.go" << 'EOF' // SPDX-License-Identifier: Unlicense OR MIT //go:build darwin && !cgo // +build darwin,!cgo package app func osMain() { panic("gioui: CGO is required for darwin/macOS/iOS builds") } func newWindow(win *callbacks, options []Option) { panic("gioui: CGO is required for darwin/macOS/iOS builds") } EOF echo " Created: app/os_darwin_nocgo.go" # GL Unix stub cat > "$GIO_DIR/internal/gl/gl_unix_nocgo.go" << 'EOF' // SPDX-License-Identifier: Unlicense OR MIT //go:build (darwin || linux || freebsd || openbsd) && !cgo && !js // +build darwin linux freebsd openbsd // +build !cgo // +build !js package gl import ( "errors" "unsafe" ) type Context interface{} type Functions struct{} func NewFunctions(ctx Context, forceES bool) (*Functions, error) { return nil, errors.New("gl: CGO is required for OpenGL on this platform") } func (f *Functions) ActiveTexture(texture Enum) {} func (f *Functions) AttachShader(p Program, s Shader) {} func (f *Functions) BeginQuery(target Enum, query Query) {} func (f *Functions) BindAttribLocation(p Program, a Attrib, name string) {} func (f *Functions) BindBuffer(target Enum, b Buffer) {} func (f *Functions) BindBufferBase(target Enum, index int, b Buffer) {} func (f *Functions) BindFramebuffer(target Enum, fb Framebuffer) {} func (f *Functions) BindImageTexture(unit int, t Texture, level int, layered bool, layer int, access, format Enum) {} func (f *Functions) BindRenderbuffer(target Enum, rb Renderbuffer) {} func (f *Functions) BindTexture(target Enum, t Texture) {} func (f *Functions) BindVertexArray(a VertexArray) {} func (f *Functions) BlendEquation(mode Enum) {} func (f *Functions) BlendFuncSeparate(srcRGB, dstRGB, srcA, dstA Enum) {} func (f *Functions) BlitFramebuffer(sx0, sy0, sx1, sy1, dx0, dy0, dx1, dy1 int, mask Enum, filter Enum) {} func (f *Functions) BufferData(target Enum, size int, usage Enum, data []byte) {} func (f *Functions) BufferSubData(target Enum, offset int, data []byte) {} func (f *Functions) CheckFramebufferStatus(target Enum) Enum { return 0 } func (f *Functions) Clear(mask Enum) {} func (f *Functions) ClearColor(red, green, blue, alpha float32) {} func (f *Functions) ClearDepthf(d float32) {} func (f *Functions) CompileShader(s Shader) {} func (f *Functions) CopyTexSubImage2D(target Enum, level, xoffset, yoffset, x, y, w, h int) {} func (f *Functions) CreateBuffer() Buffer { return Buffer{} } func (f *Functions) CreateFramebuffer() Framebuffer { return Framebuffer{} } func (f *Functions) CreateProgram() Program { return Program{} } func (f *Functions) CreateQuery() Query { return Query{} } func (f *Functions) CreateRenderbuffer() Renderbuffer { return Renderbuffer{} } func (f *Functions) CreateShader(ty Enum) Shader { return Shader{} } func (f *Functions) CreateTexture() Texture { return Texture{} } func (f *Functions) CreateVertexArray() VertexArray { return VertexArray{} } func (f *Functions) DeleteBuffer(v Buffer) {} func (f *Functions) DeleteFramebuffer(v Framebuffer) {} func (f *Functions) DeleteProgram(p Program) {} func (f *Functions) DeleteQuery(query Query) {} func (f *Functions) DeleteRenderbuffer(v Renderbuffer) {} func (f *Functions) DeleteShader(s Shader) {} func (f *Functions) DeleteTexture(v Texture) {} func (f *Functions) DeleteVertexArray(a VertexArray) {} func (f *Functions) DepthFunc(fn Enum) {} func (f *Functions) DepthMask(mask bool) {} func (f *Functions) Disable(cap Enum) {} func (f *Functions) DisableVertexAttribArray(a Attrib) {} func (f *Functions) DispatchCompute(x, y, z int) {} func (f *Functions) DrawArrays(mode Enum, first, count int) {} func (f *Functions) DrawElements(mode Enum, count int, ty Enum, offset int) {} func (f *Functions) Enable(cap Enum) {} func (f *Functions) EnableVertexAttribArray(a Attrib) {} func (f *Functions) EndQuery(target Enum) {} func (f *Functions) Finish() {} func (f *Functions) Flush() {} func (f *Functions) FramebufferRenderbuffer(target, attachment, renderbuffertarget Enum, renderbuffer Renderbuffer) {} func (f *Functions) FramebufferTexture2D(target, attachment, texTarget Enum, t Texture, level int) {} func (f *Functions) GenerateMipmap(target Enum) {} func (f *Functions) GetBinding(pname Enum) Object { return Object{} } func (f *Functions) GetBindingi(pname Enum, idx int) Object { return Object{} } func (f *Functions) GetError() Enum { return NO_ERROR } func (f *Functions) GetFloat(pname Enum) float32 { return 0 } func (f *Functions) GetFloat4(pname Enum) [4]float32 { return [4]float32{} } func (f *Functions) GetFramebufferAttachmentParameteri(target, attachment, pname Enum) int { return 0 } func (f *Functions) GetInteger(pname Enum) int { return 0 } func (f *Functions) GetInteger4(pname Enum) [4]int { return [4]int{} } func (f *Functions) GetIntegeri(pname Enum, idx int) int { return 0 } func (f *Functions) GetProgramBinary(p Program) []byte { return nil } func (f *Functions) GetProgrami(p Program, pname Enum) int { return 0 } func (f *Functions) GetProgramInfoLog(p Program) string { return "" } func (f *Functions) GetQueryObjectuiv(query Query, pname Enum) uint { return 0 } func (f *Functions) GetRenderbufferParameteri(target, pname Enum) int { return 0 } func (f *Functions) GetShaderi(s Shader, pname Enum) int { return 0 } func (f *Functions) GetShaderInfoLog(s Shader) string { return "" } func (f *Functions) GetString(pname Enum) string { return "" } func (f *Functions) GetStringi(pname Enum, index int) string { return "" } func (f *Functions) GetUniformBlockIndex(p Program, name string) uint { return INVALID_INDEX } func (f *Functions) GetUniformLocation(p Program, name string) Uniform { return Uniform{V: -1} } func (f *Functions) GetVertexAttrib(index int, pname Enum) int { return 0 } func (f *Functions) GetVertexAttribBinding(index int, pname Enum) Object { return Object{} } func (f *Functions) GetVertexAttribPointer(index int, pname Enum) uintptr { return 0 } func (f *Functions) InvalidateFramebuffer(target, attachment Enum) {} func (f *Functions) IsEnabled(cap Enum) bool { return false } func (f *Functions) LinkProgram(p Program) {} func (f *Functions) MapBufferRange(target Enum, offset, length int, access Enum) []byte { return nil } func (f *Functions) MemoryBarrier(barriers Enum) {} func (f *Functions) PixelStorei(pname Enum, param int) {} func (f *Functions) ReadPixels(x, y, width, height int, format, ty Enum, data []byte) {} func (f *Functions) RenderbufferStorage(target, internalformat Enum, width, height int) {} func (f *Functions) Scissor(x, y, width, height int) {} func (f *Functions) ShaderSource(s Shader, src string) {} func (f *Functions) TexImage2D(target Enum, level int, internalFormat Enum, width, height int, format, ty Enum) {} func (f *Functions) TexParameteri(target, pname Enum, param int) {} func (f *Functions) TexStorage2D(target Enum, levels int, internalFormat Enum, width, height int) {} func (f *Functions) TexSubImage2D(target Enum, level, xoff, yoff, width, height int, format, ty Enum, data []byte) {} func (f *Functions) Uniform1f(dst Uniform, v float32) {} func (f *Functions) Uniform1i(dst Uniform, v int) {} func (f *Functions) Uniform2f(dst Uniform, v0, v1 float32) {} func (f *Functions) Uniform3f(dst Uniform, v0, v1, v2 float32) {} func (f *Functions) Uniform4f(dst Uniform, v0, v1, v2, v3 float32) {} func (f *Functions) UniformBlockBinding(p Program, uniformBlockIndex uint, uniformBlockBinding uint) {} func (f *Functions) UnmapBuffer(target Enum) bool { return false } func (f *Functions) UseProgram(p Program) {} func (f *Functions) VertexAttribPointer(dst Attrib, size int, ty Enum, normalized bool, stride, offset int) {} func (f *Functions) Viewport(x, y, width, height int) {} func uploadBuffer(data []byte) *byte { return nil } func sliceOf(ptr unsafe.Pointer, cap int) []byte { return nil } EOF echo " Created: internal/gl/gl_unix_nocgo.go" # VK stub cat > "$GIO_DIR/internal/vk/vulkan_nocgo.go" << 'EOF' // SPDX-License-Identifier: Unlicense OR MIT //go:build (linux || freebsd || android) && !cgo // +build linux freebsd android // +build !cgo package vk import ( "errors" "unsafe" ) type ( Instance uintptr Surface uintptr ) func CreateInstance(name string, exts ...string) (Instance, error) { return 0, errors.New("vulkan: CGO is required") } func DestroyInstance(inst Instance) {} func CreateAndroidSurface(inst Instance, window unsafe.Pointer) (Surface, error) { return 0, errors.New("vulkan: CGO is required for Android") } func CreateWaylandSurface(inst Instance, display, surface uintptr) (Surface, error) { return 0, errors.New("vulkan: CGO is required for Wayland") } func CreateXlibSurface(inst Instance, display, window uintptr) (Surface, error) { return 0, errors.New("vulkan: CGO is required for X11") } func DestroySurface(inst Instance, surface Surface) {} func GetPhysicalDeviceQueueFamilyPropertiesCount(pd uintptr) int { return 0 } func GetPhysicalDeviceSurfaceSupport(pd uintptr, queue uint32, surf Surface) bool { return false } EOF echo " Created: internal/vk/vulkan_nocgo.go" # Update go.mod echo "Updating go.mod..." cd "$REPO_ROOT" go mod tidy echo "" echo "Successfully updated gio to $ACTUAL_VERSION" echo "" echo "The go.mod replace directive points to ./gio" echo "" echo "Cross-compilation support:" echo " - Linux: Full support (native CGO)" echo " - macOS: Compiles without CGO, but panics at runtime" echo " - Windows: Full support (pure Go)" echo " - WASM: Full support (pure Go)" echo " - Android: Requires CGO cross-compiler (NDK)" echo "" echo "Note: Some external dependencies (clipboard, typesetting) may have their own" echo "platform limitations that are outside the scope of this vendoring."