Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

32 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Vala on Windows

A practical guide for writing, building, debugging, and packaging Vala applications on Windows.

The easiest path is Ooblerg: install a graphical package manager, install native-sdk, vala, gtk4, and any other libraries you need, then build from normal Windows terminals, VS Code, PowerShell, or cmd.exe. You do not need to develop inside an MSYS2 shell unless you specifically want that workflow.

MSYS2 is documented below as an alternative because it is widely used and has a large package set. For new Vala/GTK 4 projects, start with Ooblerg.

Contents

Recommended setup: Ooblerg

Ooblerg is a Windows package manager and MinGW-w64 sysroot for native GTK/GObject/Vala/SQGI desktop development.

It provides:

  • a graphical package manager for installing and removing packages;
  • a local Windows user sysroot under %LOCALAPPDATA%\Ooblerg\sysroot;
  • a mingw64\bin directory that can be added to the current user's PATH;
  • Windows-native build tools, compilers, debuggers, GTK 4, Vala, SQGI, GStreamer, GDAL, SDL, and related libraries.

Install tools and libraries

  1. Download and install Ooblerg from https://ooblerg.xyz.

  2. Launch Ooblerg Package Manager.

  3. Refresh the package index.

  4. Install at least:

    native-sdk
    vala
    gtk4
    

    Useful extras:

    sqgi
    libgee
    libsoup3
    gstreamer
    gdal
    
  5. Use the Ooblerg package manager's PATH integration to add the sysroot binary directory to the current user's Windows PATH.

The important directory is:

%LOCALAPPDATA%\Ooblerg\sysroot\mingw64\bin

Restart any already-open terminals or VS Code windows after changing PATH.

Check the install

Open PowerShell or cmd.exe and run:

valac --version
gcc --version
meson --version
ninja --version
pkg-config --modversion gtk4

If these commands work from a normal Windows terminal, your editor and build scripts can use them too.

Why this is simpler than MSYS2

MSYS2 is mature and widely used, but it is a full Unix-like development environment for Windows. It ships multiple toolchains and shells, and uses a rolling release model. It works well but it can make VS Code tasks, terminals, debugger configuration, and packaging scripts feel more complicated for new Vala users.

Ooblerg is narrower on purpose. It provides a graphical package manager, installs packages into a single Windows user sysroot, and places that sysroot's mingw64\bin directory on the normal Windows PATH. Tools such as valac, gcc, meson, ninja, and pkg-config are then available from PowerShell, Command Prompt, VS Code, and other standard Windows tooling.

Ooblerg currently provides one toolchain: mingw64, matching the Ubuntu 24.04 cross-compiler baseline used by sqgipkg. Its packages are pinned around Ubuntu 24.04 versions, giving Windows development and Ubuntu CI packaging a stable cross-platform reference point.

Do not put both Ooblerg and MSYS2 mingw64\bin directories on PATH for the same project. Pick one environment per terminal/session so pkg-config, DLL lookup, headers, and import libraries all come from the same sysroot.

Build a console Vala app

Create a project directory:

mkdir vala-hello
cd vala-hello

Create meson.build:

project('vala-hello', ['c', 'vala'], version: '0.1.0')

glib_dep = dependency('glib-2.0')

executable(
  'vala-hello',
  'main.vala',
  dependencies: [glib_dep],
  install: true,
)

Create main.vala:

public static int main (string[] args) {
    print ("Hello from Vala on Windows!\n");
    return 0;
}

Build and run:

meson setup builddir
meson compile -C builddir
.\builddir\vala-hello.exe

Build a GTK 4 Vala app

Install gtk4 in Ooblerg first.

Create meson.build:

project('vala-gtk4-demo', ['c', 'vala'], version: '0.1.0')

gtk4_dep = dependency('gtk4')

executable(
  'vala-gtk4-demo',
  'main.vala',
  dependencies: [gtk4_dep],
  win_subsystem: 'windows',
  install: true,
)

Create main.vala:

using Gtk;

public class DemoApp : Gtk.Application {
    public DemoApp () {
        Object (application_id: "org.example.ValaGtk4Demo");
    }

    protected override void activate () {
        var window = new Gtk.ApplicationWindow (this);
        window.title = "Vala GTK 4";
        window.default_width = 480;
        window.default_height = 320;

        var button = new Gtk.Button.with_label ("Click me");
        button.clicked.connect (() => {
            button.label = "Hello from Vala";
        });

        window.set_child (button);
        window.present ();
    }
}

public static int main (string[] args) {
    var app = new DemoApp ();
    return app.run (args);
}

Build and run:

meson setup builddir
meson compile -C builddir
.\builddir\vala-gtk4-demo.exe

Remove win_subsystem: 'windows' while debugging if you want a console window for print() output.

Use VS Code without a custom shell

With Ooblerg on PATH, VS Code can use its normal PowerShell or cmd.exe terminal.

A minimal .vscode/tasks.json:

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "meson setup",
      "type": "shell",
      "command": "meson setup builddir --wipe",
      "problemMatcher": []
    },
    {
      "label": "build",
      "type": "shell",
      "command": "meson compile -C builddir",
      "group": {
        "kind": "build",
        "isDefault": true
      },
      "problemMatcher": []
    },
    {
      "label": "run",
      "type": "shell",
      "command": ".\\builddir\\vala-gtk4-demo.exe",
      "dependsOn": "build",
      "problemMatcher": []
    }
  ]
}

Optional debugging with GDB:

  1. Install gdb through Ooblerg, or install native-sdk, which includes it.
  2. Install a VS Code GDB debugging extension.
  3. Point the debugger at the executable in builddir and use gdb from PATH.

Example .vscode/launch.json for the Native Debug extension:

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "gdb",
      "request": "launch",
      "name": "Debug Vala GTK app",
      "target": "${workspaceFolder}\\builddir\\vala-gtk4-demo.exe",
      "cwd": "${workspaceFolder}",
      "gdbpath": "gdb"
    }
  ]
}

Package with sqgipkg on Ubuntu CI

Ooblerg and sqgipkg solve different parts of the Vala-on-Windows workflow:

  • Ooblerg is the local Windows development environment. Use it to install valac, GTK 4, Meson, Ninja, GDB, and runtime libraries into a normal Windows sysroot on PATH.
  • sqgipkg is the release packager that produces Windows installers and Linux AppImages. It runs on Ubuntu 24.04, not Windows, and is intended to be used as a GitHub Actions workflow with an Ubuntu 24.04 runner.

The recommended workflow for Windows developers is:

  1. Develop and test the app locally with Ooblerg.
  2. Commit the app source, Meson files, resources, icons, and sqgipkg.json manifest.
  3. Commit a GitHub Actions workflow under .github/workflows/release.yml.
  4. Let an ubuntu-24.04 GitHub runner build the release artifacts with sqgipkg.
  5. Download test artifacts from the workflow run, or publish them automatically from version tags.

That keeps the Windows setup focused on development. The Windows machine does not need a packaging stack, a Linux shell, or a local sqgipkg install.

What sqgipkg produces from CI

From one Ubuntu runner, sqgipkg can produce release artifacts such as:

  • Linux x86_64 AppImage;
  • Linux aarch64 AppImage;
  • Windows x86_64 NSIS installer.

The app does not need to be an SQGI script app. A Vala, C, C++, GTK, libadwaita, GStreamer, or other native GObject-style application should use a native entry manifest. The manifest tells sqgipkg where the built Linux executable and Windows .exe will be, which target packages to stage, and how to build the native project for each target.

sqgipkg docs and example

Use these references:

What to add to your repo

A Vala/GTK project usually needs two packaging files. For a one-app repository, put sqgipkg.json at the project root. In this repository, the packageable app lives in gtk_app/, so its manifest is gtk_app/sqgipkg.json.

First, add sqgipkg.json. Use the Verminal manifest as the shape to copy and adapt. It should describe:

  • app name, app ID, icons, resources, and desktop metadata;
  • entry.type: "native";
  • Linux executable paths, usually with per-architecture entry_linux paths;
  • the Windows executable path through entry_windows;
  • Linux target architectures such as x86_64 and aarch64;
  • Debian/Ubuntu packages to stage into private Linux sysroots;
  • linux.deb.suite: "noble" when the Linux package sysroot should be pinned to Ubuntu 24.04;
  • Windows runtime packages such as GTK 4, GStreamer, or other MinGW packages needed by the app;
  • Meson/Ninja build steps for each target;
  • optional NSIS installer metadata such as installer name, install directory, shortcuts, and execution level.

Second, add .github/workflows/release.yml. Use this repository's workflow or the Verminal workflow as the copy-and-adapt example. The workflow should:

  • run on ubuntu-24.04;
  • check out your application;
  • check out supercamel/sqgi so the runner can build and install sqgipkg;
  • install host build dependencies, cross compilers, MinGW-w64, NSIS, and AppImage tooling;
  • build and install SQGI / sqgipkg on the runner;
  • run the AppImage targets for each Linux architecture;
  • run the Windows NSIS target;
  • collect the generated AppImages and Windows setup .exe;
  • upload artifacts for workflow runs;
  • publish release assets when the pushed ref is a version tag such as v1.0.0.

The Windows installer produced by this workflow is built from the Ubuntu runner. It does not use the developer's local Ooblerg sysroot. Ooblerg gives contributors a convenient Windows development environment; sqgipkg creates its own target sysroots during CI so release builds are reproducible.

Why Ubuntu 24.04 / noble is pinned

Ooblerg and sqgipkg are both pinned around an Ubuntu 24.04 (noble) package baseline so local Windows development and CI packaging do not drift apart.

In practice, that means:

  • Ooblerg provides Windows MinGW-w64 packages built from a stable Ubuntu 24.04-era source/toolchain set.
  • GitHub Actions should use runs-on: ubuntu-24.04 for release packaging.
  • sqgipkg.json should use "suite": "noble" for Linux sysroot creation.

sqgipkg runs on Ubuntu, not Windows, and CI does not reuse the developer's local Ooblerg install. The shared part is the pinned package baseline: Vala, GLib, GTK, GObject Introspection, Meson/pkg-config discovery, Linux AppImage staging, and Windows NSIS staging all stay aligned.

MSYS2 alternative

Use MSYS2 if you want the traditional shell-based workflow or need packages that Ooblerg does not currently provide.

  1. Install MSYS2 from https://www.msys2.org/.

  2. Open the MINGW64 shell.

  3. Update MSYS2:

    pacman -Syu

    Close and reopen the MINGW64 shell if MSYS2 asks you to, then run the update again.

  4. Install Vala and build tools:

    pacman -S --needed \
      mingw-w64-x86_64-toolchain \
      mingw-w64-x86_64-vala \
      mingw-w64-x86_64-meson \
      mingw-w64-x86_64-ninja \
      mingw-w64-x86_64-pkgconf \
      mingw-w64-x86_64-gdb
  5. For GTK 4 development:

    pacman -S --needed mingw-w64-x86_64-gtk4
  6. For NSIS installers:

    pacman -S --needed mingw-w64-x86_64-nsis

VS Code with MSYS2

If you use MSYS2, configure VS Code to launch the MSYS2 shell so Meson, pkg-config, DLL lookup, and compiler paths all agree:

{
  "terminal.integrated.profiles.windows": {
    "MSYS2 MINGW64": {
      "path": "C:\\msys64\\usr\\bin\\bash.exe",
      "args": ["--login", "-i"],
      "env": {
        "MSYSTEM": "MINGW64",
        "CHERE_INVOKING": "1"
      }
    }
  },
  "terminal.integrated.defaultProfile.windows": "MSYS2 MINGW64"
}

Add C:\msys64\mingw64\bin to PATH only for MSYS2-based projects, and avoid mixing it with Ooblerg's mingw64\bin in the same session.

Existing examples in this repo

  • vala_hello/ is the small console app from the README.
  • gtk_app/ is the GTK 4 app from the README and includes gtk_app/sqgipkg.json for release packaging.
  • .github/workflows/release.yml packages gtk_app/ on ubuntu-24.04 with sqgipkg, producing Linux AppImages and a Windows NSIS installer.
  • .github/workflows/main.yml builds the examples with MSYS2 as an alternative environment check.

The old manual deployment scripts are preserved under legacy-msys2-manual-deploy/ as historical references. For new projects, prefer sqgipkg in CI for release packaging because it understands target sysroots, generated launchers, GTK/GI runtime data, AppImage output, and NSIS output.

Troubleshooting

valac is not recognized

Install vala in Ooblerg, enable the Ooblerg PATH integration, and restart the terminal or VS Code window.

Check:

where valac
valac --version

Package gtk4 was not found in the pkg-config search path

Install gtk4 in Ooblerg. Then check that pkg-config is the Ooblerg one:

where pkg-config
pkg-config --modversion gtk4

If the path points at MSYS2, Git for Windows, Chocolatey, or another toolchain, clean up PATH for that terminal.

The app builds but cannot find DLLs at runtime

Run it from a terminal that has Ooblerg's mingw64\bin on PATH, or use the CI sqgipkg workflow so the required DLLs and runtime data are staged with the app.

GTK opens with a console window

For GUI apps, use:

win_subsystem: 'windows'

Remove that while debugging if you need console output.

CI works for Linux but not Windows

Add a temporary workflow step before the NSIS step that runs sqgipkg --target win-dir and uploads that directory as an artifact. That makes it easier to inspect the staged .exe, DLLs, icons, launchers, and runtime data before debugging installer generation.

Once the staged directory is correct, switch the workflow back to the normal Windows installer target.

CI output names do not match the README

sqgipkg names output files from name in gtk_app/sqgipkg.json. If you change:

"name": "ValaGtk4Demo"

update the artifact copy paths in .github/workflows/release.yml too.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages