Do not install this module with the usual go get workflow. Go may fetch the
repository through the module proxy without downloading the large Git LFS
objects, leaving files such as cflat_windows_amd64.syso as LFS pointers.
GOPROXY=direct alone is not sufficient because Go still fetches the Git
repository rather than the GitHub Release ZIP.
If you already have Go-GetLFS installed, this single command is sufficient:
goget-lfs github.com/kanryu/slint@v0.1.1No additional Git, Git LFS, or go mod commands are required when using
Go-GetLFS.
Instead, fetch the module directly with Git LFS and use it as a local module:
git lfs install
git clone --depth 1 --branch v0.1.1 --single-branch https://github.com/kanryu/slint.git third_party/slint
git -C third_party/slint lfs pull
go mod edit -replace github.com/kanryu/slint=./third_party/slint
go mod tidy
go build ./...This bypasses proxy.golang.org and ensures that the native
cflat_windows_amd64.syso file is available as a real binary. Verify the
module selection with:
go list -m all
The output should include the following line, confirming that the local module is being used:
github.com/kanryu/slint => ./third_party/slint
Slint is a modern, general-purpose GUI framework for building user interfaces that run on desktop, mobile, web, and embedded platforms. It is implemented in Rust and is designed to provide a native user experience across operating systems and processor architectures while keeping the UI description concise and declarative.
For the official project information, visit the Slint website and the official Slint Git repository.
Instead of constructing every widget from ordinary application code, you
describe windows, controls, layout, properties, and bindings in Slint's own
markup language. A .slint file can look like this:
export component HelloWindow inherits Window {
width: 400px;
height: 240px;
Text {
text: "Hello from Slint";
horizontal-alignment: center;
vertical-alignment: center;
}
}Slint keeps the UI description separate from the application's business logic. The framework can compile Slint markup ahead of time, optimize its property expressions, and use configurable rendering backends. It also provides an interpreter, which is the mode used by this binding: the application supplies the Slint source at startup and the Slint runtime creates the UI from it.
Slint provides two ways to use Slint markup. In compiler mode, the markup is compiled directly into code for the target programming language. In interpreter mode, the application loads the Slint markup at runtime and the Slint engine interprets it and renders the GUI.
The Slint compiler currently supports direct code generation for Rust and C++. Other languages, including Go, use the Slint interpreter instead. This package provides the Go interface for creating a Slint interpreter context, loading Slint markup, setting properties, processing events, and rendering the GUI.
The following is the main function from examples/hello, showing the basic
interpreter usage:
func main() {
// Slint's host-side event pump must stay on one OS thread. In
// particular, do not let the Go scheduler move the callback/event
// handling loop between native threads.
runtime.LockOSThread()
app, err := slint.New(`
export component App inherits Window {
width: 320px;
height: 180px;
in-out property <string> message: "Slint from Go";
Text {
text: message;
horizontal-alignment: center;
vertical-alignment: center;
}
}
`)
if err != nil {
panic(err)
}
defer app.Close()
if err := app.SetStringProperty("message", "SlintCFlat + Go"); err != nil {
panic(err)
}
fmt.Println("Slint context created; running:", app.IsRunning())
for app.IsRunning() {
for {
event, ok, err := app.PollEvent()
if err != nil {
panic(err)
}
if !ok {
break
}
if err := app.DispatchEvent(event); err != nil {
panic(err)
}
}
time.Sleep(10 * time.Millisecond)
}
}This project provides SlintBinder as the slint-bundler command. It takes a
directory containing Slint files as input, follows their imports, and writes
one deterministic .slint file as output. For example:
slint-bundler ui -o generated/ui_bundle.slint
Slint UI is often easier to maintain as multiple files under a ui directory:
a router, a window component, reusable widgets, and page components. SlintBinder
recursively reads that directory, resolves the imports between the files, and
combines them into the output file.
Slint markup uses a syntax familiar to Node.js developers and supports imports between modules. Slint markup is normally organized across multiple files and nested directories in the project tree. This structure is also useful when checking the design in the Slint Viewer extension for VS Code.
However, that project structure is inconvenient when the UI is bundled into a Go executable. The Slint interpreter used by the Go application can process the UI more simply and quickly when all Slint markup is combined into one source file and supplied as a string.
The application can then embed the generated file and give its contents to the Slint interpreter at startup. This keeps the UI organized as a normal folder tree during development while allowing the final Go application to carry one self-contained Slint source string.
The SlintBinder command is implemented in Go. Build it with:
make slint-bundler
With Go 1.24 or later, register the GitHub module as a tool dependency with:
go get -tool github.com/kanryu/slint/cmd/slint-bundler@latest
Then build and run the tool with:
go tool slint-bundler
The go get -tool command records the tool in go.mod; go tool builds it
from the recorded module dependency when it runs. If you want to install a
standalone executable in Go's standard binary directory instead, use:
go install github.com/kanryu/slint/cmd/slint-bundler@latest
For example:
bin/slint-bundler <slint-directory> -o appbundle.slint
The examples/hello sample and the Makefile are in the project root. To
generate the files for the host OS, run:
Native libraries (.a and .syso files) are managed with Git LFS. Install Git
LFS and run git lfs install before cloning. If you have already cloned the
repository and the files are still LFS pointers, run git lfs pull to download
the actual files.
make
This generates cflat_windows_amd64.syso on Windows. Linux amd64 copies its
archive to
internal/cflat_native/cflat_linux_amd64.syso
and runs Hike's Go backend.
You can also select a target explicitly:
make syso-windows-amd64
make syso-linux-amd64
make syso-linux-arm64
make syso-linux-arm32
make syso-darwin-arm64
Override a Hikepack-backed target's static library with SLINT_LIB_<target>.
On Linux amd64, build the Hello example with make -C examples/hello. The
Makefile copies the release archive into internal/cflat_native under its
platform .syso name, runs hikec go to generate the bridge, and builds the
executable. The corresponding target linux entry in hike.mod records the
release archive and Linux system libraries. A working hikec installation is
required.
Install Go, Git LFS, GNU Make, Hike (hikec), and a C compiler/linker supported
by cgo. The build also needs the development files for the native libraries
listed in hike.mod, including Fontconfig. Fetch the native archive from Git
LFS and build the Hello example:
git lfs install
git lfs pull
make -C examples/hello build
make -C examples/hello runThe native library is packaged from
deps/slint-cflat-linux-amd64/libslint_cflat.a by the syso-linux-amd64
target. The Hello Makefile invokes this target automatically before building.
Running the application requires a graphical desktop session with a supported
X11 or Wayland display backend, as well as the shared libraries required by
Slint. In particular, libxkbcommon-x11.so.0 is needed at runtime. If the
application fails to start because a shared library is missing, inspect its
dependencies with:
ldd examples/hello/helloInstall the missing runtime packages using your distribution's package manager.
For example, on Debian or Ubuntu, libxkbcommon-x11-0 provides
libxkbcommon-x11.so.0; the Fontconfig runtime library is also required.
Runtime package names vary by distribution. Linux amd64 is the Linux
configuration documented and verified for this binding.
hikepack places external static libraries in separate .syso files, keeping
them separate from Hike-generated files when passing them to Go. Before
running the build, add hikepack to your PATH or specify its location, for
example:
make HIKEPACK="C:/path/to/hikepack.exe" syso-windows-amd64
Note that Go's COFF linker cannot handle the overflow form used when a single
object contains more than 65,535 relocations. If you can rebuild the external
Slint library, split code generation into smaller units to keep the relocation
count per object below this limit. If a prebuilt archive exceeds this limit,
the .syso produced by hikepack may be readable by LLVM but unusable during
Go's final link.
The Makefile assumes an environment with POSIX commands such as rm. On
Windows, the executable output name automatically gets the .exe extension.
The important build detail is that hikec go and external-library packaging
are separate operations. hikec go compiles .go.hike files into a Hike
.syso object and generates the Go declarations and assembly stubs. It does
not link a Rust or C static archive into that object. Do not append a static
archive to the output with a general-purpose clang -r command: Rust
staticlib archives contain their own runtime objects, Windows import
members, COFF directives, and relocation records. Flattening such an archive
can create a .syso that LLVM accepts but Go's internal COFF linker rejects.
Declare the foreign functions in Hike, and describe the native inputs in
hike.mod instead:
package ./internal/cflat {
target windows {
# Keep the generated Hike object separate from the archive package.
hike-object: "none"
link: "deps/slint-cflat-windows/libslint_cflat.a"
link: "-Wl,-u,slint_c_create"
link: "-lgdi32"
link: "-lopengl32"
link: "-luser32"
link: "-lkernel32"
}
}
The file archive and the system-library flags have different roles. The
archive is preserved byte-for-byte and exposed through a generated native
package. The -l... entries are deferred to the final external link, because
absorbing Windows import libraries into the archive with --whole-archive
causes duplicate definitions. The -Wl,-u,... entry is useful to force the
public Slint entry point to remain reachable, but it is not passed through as
a cgo flag.
Build the package with hikepack, not directly with hikec go:
hikepack syso -v -target windows .
hikepack performs the following steps:
- Runs the Hike Go backend and creates the generated Go declarations and assembly stubs.
- Reads the target-specific native configuration from
hike.mod. - Keeps the external
.aarchive intact instead of flattening it into the Hike object. - Places the archive-backed
.sysofile in the package's native companion directory. - Generates the small platform-specific linker package that defers ordinary system-library flags to Go's final external link.
This separation is the key to using a Rust/Slint static library from Hike:
Hike owns the ABI bridge and Go stubs, while hikepack owns native archive
packaging. The Makefile invokes hikepack syso for each supported target and
therefore should not repeat the old clang -r <hike-object> <library>.a
step.
Install Go, Git LFS, GNU Make, Hike (hikec), and hikepack. For the external
Go link, install the MSYS2 UCRT64 LLVM toolchain, including Clang and LLD. Make
sure hikec, hikepack, make, and the UCRT64 tools are available from the
shell's PATH.
After cloning or updating the repository, fetch the native libraries managed by
Git LFS. In PowerShell, set CC to the UCRT64 Clang executable and build the
Hello example:
git lfs install
git lfs pull
$env:CC = "C:\msys64\ucrt64\bin\clang.exe"
$env:CGO_ENABLED = "1"
make syso-windows-amd64
make -C examples/hello buildThe first command runs hikepack syso -v -target windows ., which reads the
Windows linker configuration from hike.mod, generates the Hike bridge, and
packages the Windows static archive. The Hello Makefile runs this native step
automatically, so the explicit make syso-windows-amd64 is optional when
building Hello. To launch the sample, run make -C examples/hello run.
If Hike tools are not on PATH, pass their full paths to Make:
make HIKEC="C:/path/to/hikec.exe" HIKEPACK="C:/path/to/hikepack.exe" syso-windows-amd64The Makefiles use POSIX utilities such as rm and mkdir; run them from an
MSYS2/UCRT64 shell or another environment that provides GNU Make and these
utilities. The native target currently supports Windows amd64.
The Windows static library must be built with the same GNU/LLVM object and
linker model that the Hike/Go package expects. A normal MSVC build, or a build
that reuses a different rustc wrapper, can produce an archive whose COFF
relocations cannot be consumed by the final Go link.
From the SlintCFlat source tree, configure the Rust toolchain explicitly before building:
Remove-Item Env:RUSTC_WRAPPER -ErrorAction SilentlyContinue
$env:RUSTC = "$env:USERPROFILE\.cargo\bin\rustc.exe"
$env:CARGO_TARGET_X86_64_PC_WINDOWS_GNULLVM_LINKER = `
"C:\local\gnu\msys64\ucrt64\bin\clang.exe"
$env:RUSTFLAGS = "-C link-arg=-fuse-ld=lld"
rustup target add --toolchain stable x86_64-pc-windows-gnullvm
rustup run stable rustc -vV
rustup run stable cargo clean
rustup run stable cargo build `
--release `
--target x86_64-pc-windows-gnullvmThe important details are the x86_64-pc-windows-gnullvm target, the UCRT
Clang linker, and LLD selected through RUSTFLAGS. Run cargo clean after
changing these settings so that objects from a previous MSVC or GNU target are
not mixed into the new static archive. Copy the resulting target-specific
libslint_cflat.a and headers into deps/slint-cflat-windows before running
hikepack syso in this repository.
The MVC router sample is in examples/mvc-router. It does not use SQLite; it
displays a list of files in the current directory. The sample's Makefile uses
slint-bundler to combine the UI Slint files into generated/ui_bundle.slint,
which is then passed to slint.New from a Go string variable populated with
go:embed.
cd examples/mvc-router
make bundle
go test .
For the purposes of GitHub repository distribution, this project is licensed under MIT License.
In practice, this thin binding layer is intended to be treated functionally as an extension or part of Slint itself. You are free to use, link, and redistribute this wrapper under any licensing terms that you have agreed to with Slint (including the Slint Commercial License or alternative proprietary terms).