build: add Meson wrapper for libghostty-vt
Add Meson build system integration mirroring the existing CMake wrapper. The top-level meson.build delegates to zig build lib-vt using --prefix-lib-dir and --prefix-include-dir to place outputs directly in the Meson build directory, avoiding stamp files and source tree pollution. A sentinel .h output ensures Meson orders the zig build before any downstream compiles. Downstream projects can consume the library either as a Meson subproject via a .wrap file or through pkg-config after install. The dist/meson/README.md documents both approaches. Includes a c-vt-meson example, CI job in test.yml for auto-discovered Meson examples, meson and ninja in the nix devShell, and gitignore updates for Meson build artifacts.pull/11702/head
parent
9ba2614ac1
commit
08bbc5b752
|
|
@ -87,6 +87,7 @@ jobs:
|
||||||
- build-dist
|
- build-dist
|
||||||
- build-examples-zig
|
- build-examples-zig
|
||||||
- build-examples-cmake
|
- build-examples-cmake
|
||||||
|
- build-examples-meson
|
||||||
- build-flatpak
|
- build-flatpak
|
||||||
- build-libghostty-vt
|
- build-libghostty-vt
|
||||||
- build-libghostty-vt-android
|
- build-libghostty-vt-android
|
||||||
|
|
@ -175,6 +176,7 @@ jobs:
|
||||||
outputs:
|
outputs:
|
||||||
zig: ${{ steps.list.outputs.zig }}
|
zig: ${{ steps.list.outputs.zig }}
|
||||||
cmake: ${{ steps.list.outputs.cmake }}
|
cmake: ${{ steps.list.outputs.cmake }}
|
||||||
|
meson: ${{ steps.list.outputs.meson }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
|
@ -187,6 +189,9 @@ jobs:
|
||||||
cmake=$(ls example/*/CMakeLists.txt 2>/dev/null | xargs -n1 dirname | xargs -n1 basename | jq -R -s -c 'split("\n") | map(select(. != ""))')
|
cmake=$(ls example/*/CMakeLists.txt 2>/dev/null | xargs -n1 dirname | xargs -n1 basename | jq -R -s -c 'split("\n") | map(select(. != ""))')
|
||||||
echo "$cmake" | jq .
|
echo "$cmake" | jq .
|
||||||
echo "cmake=$cmake" >> "$GITHUB_OUTPUT"
|
echo "cmake=$cmake" >> "$GITHUB_OUTPUT"
|
||||||
|
meson=$(ls example/*/meson.build 2>/dev/null | xargs -n1 dirname | xargs -n1 basename | jq -R -s -c 'split("\n") | map(select(. != ""))')
|
||||||
|
echo "$meson" | jq .
|
||||||
|
echo "meson=$meson" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
build-examples-zig:
|
build-examples-zig:
|
||||||
strategy:
|
strategy:
|
||||||
|
|
@ -261,6 +266,45 @@ jobs:
|
||||||
nix develop -c cmake -B build -DFETCHCONTENT_SOURCE_DIR_GHOSTTY=${{ github.workspace }}
|
nix develop -c cmake -B build -DFETCHCONTENT_SOURCE_DIR_GHOSTTY=${{ github.workspace }}
|
||||||
nix develop -c cmake --build build
|
nix develop -c cmake --build build
|
||||||
|
|
||||||
|
build-examples-meson:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
dir: ${{ fromJSON(needs.list-examples.outputs.meson) }}
|
||||||
|
name: Example ${{ matrix.dir }}
|
||||||
|
runs-on: namespace-profile-ghostty-xsm
|
||||||
|
needs: [test, list-examples]
|
||||||
|
env:
|
||||||
|
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
|
||||||
|
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
|
||||||
|
- name: Setup Cache
|
||||||
|
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
/nix
|
||||||
|
/zig
|
||||||
|
|
||||||
|
# Install Nix and use that to run our tests so our environment matches exactly.
|
||||||
|
- uses: cachix/install-nix-action@1ca7d21a94afc7c957383a2d217460d980de4934 # v31.10.1
|
||||||
|
with:
|
||||||
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
|
- uses: cachix/cachix-action@1eb2ef646ac0255473d23a5907ad7b04ce94065c # v17
|
||||||
|
with:
|
||||||
|
name: ghostty
|
||||||
|
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||||
|
|
||||||
|
- name: Build Example
|
||||||
|
run: |
|
||||||
|
cd example/${{ matrix.dir }}
|
||||||
|
mkdir -p subprojects
|
||||||
|
ln -s "${{ github.workspace }}" subprojects/ghostty
|
||||||
|
nix develop -c meson setup build
|
||||||
|
nix develop -c meson compile -C build
|
||||||
|
|
||||||
build-flatpak:
|
build-flatpak:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,13 @@
|
||||||
zig-cache/
|
zig-cache/
|
||||||
.zig-cache/
|
.zig-cache/
|
||||||
zig-out/
|
zig-out/
|
||||||
|
# CMake
|
||||||
build-cmake/
|
build-cmake/
|
||||||
CMakeCache.txt
|
CMakeCache.txt
|
||||||
CMakeFiles/
|
CMakeFiles/
|
||||||
|
|
||||||
|
# Meson
|
||||||
|
build-meson/
|
||||||
/build.zig.zon.bak
|
/build.zig.zon.bak
|
||||||
/result*
|
/result*
|
||||||
/.nixos-test-history
|
/.nixos-test-history
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
# Meson Support for libghostty-vt
|
||||||
|
|
||||||
|
The top-level `meson.build` wraps the Zig build system so that Meson
|
||||||
|
projects can consume libghostty-vt without invoking `zig build` manually.
|
||||||
|
Running `meson compile` triggers `zig build lib-vt` automatically.
|
||||||
|
|
||||||
|
This means downstream projects do require a working Zig compiler on
|
||||||
|
`PATH` to build, but don't need to know any Zig-specific details.
|
||||||
|
|
||||||
|
## Using a subproject (recommended)
|
||||||
|
|
||||||
|
Create `subprojects/ghostty.wrap`:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[wrap-git]
|
||||||
|
url = https://github.com/ghostty-org/ghostty.git
|
||||||
|
revision = main
|
||||||
|
depth = 1
|
||||||
|
```
|
||||||
|
|
||||||
|
Then in your project's `meson.build`:
|
||||||
|
|
||||||
|
```meson
|
||||||
|
ghostty_proj = subproject('ghostty')
|
||||||
|
ghostty_vt_dep = ghostty_proj.get_variable('ghostty_vt_dep')
|
||||||
|
|
||||||
|
executable('myapp', 'main.c', dependencies: ghostty_vt_dep)
|
||||||
|
```
|
||||||
|
|
||||||
|
This fetches the Ghostty source, builds libghostty-vt via Zig during your
|
||||||
|
Meson build, and links it into your target. Headers are added to the
|
||||||
|
include path automatically.
|
||||||
|
|
||||||
|
### Using a local checkout
|
||||||
|
|
||||||
|
If you already have the Ghostty source checked out, symlink or copy it
|
||||||
|
into your `subprojects/` directory:
|
||||||
|
|
||||||
|
```shell-session
|
||||||
|
ln -s /path/to/ghostty subprojects/ghostty
|
||||||
|
meson setup build
|
||||||
|
meson compile -C build
|
||||||
|
```
|
||||||
|
|
||||||
|
## Using pkg-config (install-based)
|
||||||
|
|
||||||
|
Build and install libghostty-vt first:
|
||||||
|
|
||||||
|
```shell-session
|
||||||
|
cd /path/to/ghostty
|
||||||
|
meson setup build
|
||||||
|
meson compile -C build
|
||||||
|
meson install -C build
|
||||||
|
```
|
||||||
|
|
||||||
|
Then in your project:
|
||||||
|
|
||||||
|
```meson
|
||||||
|
ghostty_vt_dep = dependency('libghostty-vt')
|
||||||
|
|
||||||
|
executable('myapp', 'main.c', dependencies: ghostty_vt_dep)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
See `example/c-vt-meson/` for a complete working example.
|
||||||
|
|
@ -2,4 +2,8 @@
|
||||||
dist/
|
dist/
|
||||||
node_modules/
|
node_modules/
|
||||||
example.wasm*
|
example.wasm*
|
||||||
|
# CMake / Meson
|
||||||
build/
|
build/
|
||||||
|
|
||||||
|
# Meson
|
||||||
|
subprojects/
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
# c-vt-meson
|
||||||
|
|
||||||
|
Demonstrates consuming libghostty-vt from a Meson project using a
|
||||||
|
subproject. Creates a terminal, writes VT sequences into it, and
|
||||||
|
formats the screen contents as plain text.
|
||||||
|
|
||||||
|
## Building this example
|
||||||
|
|
||||||
|
Since this example lives inside the Ghostty repo, point the subproject
|
||||||
|
at the local checkout instead of fetching from GitHub:
|
||||||
|
|
||||||
|
```shell-session
|
||||||
|
cd example/c-vt-meson
|
||||||
|
mkdir -p subprojects
|
||||||
|
ln -s ../../.. subprojects/ghostty
|
||||||
|
meson setup build
|
||||||
|
meson compile -C build
|
||||||
|
./build/c_vt_meson
|
||||||
|
```
|
||||||
|
|
||||||
|
## Real World Usage
|
||||||
|
|
||||||
|
Create a `subprojects/ghostty.wrap` file in your project:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[wrap-git]
|
||||||
|
url = https://github.com/ghostty-org/ghostty.git
|
||||||
|
revision = main
|
||||||
|
depth = 1
|
||||||
|
```
|
||||||
|
|
||||||
|
Then in your `meson.build`:
|
||||||
|
|
||||||
|
```meson
|
||||||
|
ghostty_proj = subproject('ghostty')
|
||||||
|
ghostty_vt_dep = ghostty_proj.get_variable('ghostty_vt_dep')
|
||||||
|
|
||||||
|
executable('myapp', 'src/main.c', dependencies: ghostty_vt_dep)
|
||||||
|
```
|
||||||
|
|
||||||
|
Meson will clone the repository into `subprojects/ghostty/` on first
|
||||||
|
build and invoke `zig build lib-vt` automatically.
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
project('c-vt-meson', 'c',
|
||||||
|
version: '0.1.0',
|
||||||
|
meson_version: '>= 1.1.0',
|
||||||
|
)
|
||||||
|
|
||||||
|
ghostty_proj = subproject('ghostty')
|
||||||
|
ghostty_vt_dep = ghostty_proj.get_variable('ghostty_vt_dep')
|
||||||
|
|
||||||
|
executable('c_vt_meson', 'src/main.c',
|
||||||
|
dependencies: ghostty_vt_dep,
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ghostty/vt.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// Create a terminal with a small grid
|
||||||
|
GhosttyTerminal terminal;
|
||||||
|
GhosttyTerminalOptions opts = {
|
||||||
|
.cols = 80,
|
||||||
|
.rows = 24,
|
||||||
|
.max_scrollback = 0,
|
||||||
|
};
|
||||||
|
GhosttyResult result = ghostty_terminal_new(NULL, &terminal, opts);
|
||||||
|
assert(result == GHOSTTY_SUCCESS);
|
||||||
|
|
||||||
|
// Write some VT-encoded content into the terminal
|
||||||
|
const char *commands[] = {
|
||||||
|
"Hello from a \033[1mMeson\033[0m-built program!\r\n",
|
||||||
|
"Line 2: \033[4munderlined\033[0m text\r\n",
|
||||||
|
"Line 3: \033[31mred\033[0m \033[32mgreen\033[0m \033[34mblue\033[0m\r\n",
|
||||||
|
};
|
||||||
|
for (size_t i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) {
|
||||||
|
ghostty_terminal_vt_write(terminal, (const uint8_t *)commands[i],
|
||||||
|
strlen(commands[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format the terminal contents as plain text
|
||||||
|
GhosttyFormatterTerminalOptions fmt_opts =
|
||||||
|
GHOSTTY_INIT_SIZED(GhosttyFormatterTerminalOptions);
|
||||||
|
fmt_opts.emit = GHOSTTY_FORMATTER_FORMAT_PLAIN;
|
||||||
|
fmt_opts.trim = true;
|
||||||
|
|
||||||
|
GhosttyFormatter formatter;
|
||||||
|
result = ghostty_formatter_terminal_new(NULL, &formatter, terminal, fmt_opts);
|
||||||
|
assert(result == GHOSTTY_SUCCESS);
|
||||||
|
|
||||||
|
uint8_t *buf = NULL;
|
||||||
|
size_t len = 0;
|
||||||
|
result = ghostty_formatter_format_alloc(formatter, NULL, &buf, &len);
|
||||||
|
assert(result == GHOSTTY_SUCCESS);
|
||||||
|
|
||||||
|
printf("Plain text (%zu bytes):\n", len);
|
||||||
|
fwrite(buf, 1, len, stdout);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
ghostty_formatter_free(formatter);
|
||||||
|
ghostty_terminal_free(terminal);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,150 @@
|
||||||
|
# Meson wrapper for libghostty-vt
|
||||||
|
#
|
||||||
|
# This file delegates to `zig build lib-vt` to produce the shared library,
|
||||||
|
# headers, and pkg-config file. It exists so that Meson-based projects can
|
||||||
|
# consume libghostty-vt without interacting with the Zig build system
|
||||||
|
# directly. However, downstream users do still require `zig` on the PATH.
|
||||||
|
# Please consult the Ghostty docs for the required Zig version:
|
||||||
|
#
|
||||||
|
# https://ghostty.org/docs/install/build
|
||||||
|
#
|
||||||
|
# Building within the Ghostty repo
|
||||||
|
# ---------------------------------
|
||||||
|
#
|
||||||
|
# meson setup build
|
||||||
|
# meson compile -C build
|
||||||
|
# meson install -C build
|
||||||
|
#
|
||||||
|
# Pass extra flags to the Zig build with -Dzig-build-flags:
|
||||||
|
#
|
||||||
|
# meson setup build -Dzig-build-flags='-Demit-macos-app=false'
|
||||||
|
#
|
||||||
|
# Integrating into a downstream Meson project
|
||||||
|
# ---------------------------------------------
|
||||||
|
#
|
||||||
|
# Option 1 — Meson subproject with a .wrap file (recommended):
|
||||||
|
#
|
||||||
|
# Create subprojects/ghostty.wrap:
|
||||||
|
#
|
||||||
|
# [wrap-git]
|
||||||
|
# url = https://github.com/ghostty-org/ghostty.git
|
||||||
|
# revision = main
|
||||||
|
# depth = 1
|
||||||
|
#
|
||||||
|
# Then in your meson.build:
|
||||||
|
#
|
||||||
|
# ghostty_proj = subproject('ghostty')
|
||||||
|
# ghostty_vt_dep = ghostty_proj.get_variable('ghostty_vt_dep')
|
||||||
|
# executable('myapp', 'main.c', dependencies: ghostty_vt_dep)
|
||||||
|
#
|
||||||
|
# Option 2 — pkg-config (after installing to a prefix):
|
||||||
|
#
|
||||||
|
# ghostty_vt_dep = dependency('libghostty-vt')
|
||||||
|
# executable('myapp', 'main.c', dependencies: ghostty_vt_dep)
|
||||||
|
#
|
||||||
|
# See dist/meson/README.md for more details and example/c-vt-meson/ for a
|
||||||
|
# complete working example.
|
||||||
|
|
||||||
|
project('ghostty-vt', 'c',
|
||||||
|
version: '0.1.0',
|
||||||
|
meson_version: '>= 1.1.0',
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- Options ----------------------------------------------------------------
|
||||||
|
|
||||||
|
zig_build_flags = get_option('zig-build-flags')
|
||||||
|
|
||||||
|
# --- Find Zig ----------------------------------------------------------------
|
||||||
|
|
||||||
|
zig = find_program('zig', required: true)
|
||||||
|
message('Found zig: ' + zig.full_path())
|
||||||
|
|
||||||
|
# --- Build via zig build -----------------------------------------------------
|
||||||
|
|
||||||
|
# Use --prefix to direct zig build output into the Meson build directory
|
||||||
|
# so the library is a proper declared output of the custom target.
|
||||||
|
zig_out_dir = meson.current_build_dir() / 'zig-out'
|
||||||
|
|
||||||
|
# Determine library filenames per platform.
|
||||||
|
if host_machine.system() == 'darwin'
|
||||||
|
ghostty_vt_libname = 'libghostty-vt.dylib'
|
||||||
|
ghostty_vt_soname = 'libghostty-vt.0.dylib'
|
||||||
|
ghostty_vt_realname = 'libghostty-vt.0.1.0.dylib'
|
||||||
|
elif host_machine.system() == 'windows'
|
||||||
|
ghostty_vt_libname = 'ghostty-vt.dll'
|
||||||
|
ghostty_vt_realname = 'ghostty-vt.dll'
|
||||||
|
ghostty_vt_soname = ''
|
||||||
|
else
|
||||||
|
ghostty_vt_libname = 'libghostty-vt.so'
|
||||||
|
ghostty_vt_soname = 'libghostty-vt.so.0'
|
||||||
|
ghostty_vt_realname = 'libghostty-vt.so.0.1.0'
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Custom target: run zig build lib-vt with --prefix pointing into the build dir.
|
||||||
|
# Use --prefix-lib-dir to place the library directly in the custom_target
|
||||||
|
# output directory, and --prefix-include-dir for the headers.
|
||||||
|
#
|
||||||
|
# We declare a sentinel .h file as a second output so that Meson creates a
|
||||||
|
# compile-time ordering dependency (Meson only orders compiles before
|
||||||
|
# custom_target outputs that look like headers).
|
||||||
|
zig_build_cmd = [zig, 'build', 'lib-vt',
|
||||||
|
'--prefix-lib-dir', meson.current_build_dir(),
|
||||||
|
'--prefix-include-dir', zig_out_dir / 'include',
|
||||||
|
]
|
||||||
|
if zig_build_flags != ''
|
||||||
|
zig_build_cmd += zig_build_flags.split()
|
||||||
|
endif
|
||||||
|
|
||||||
|
zig_build_lib_vt = custom_target('zig_build_lib_vt',
|
||||||
|
output: [ghostty_vt_realname, 'ghostty-vt-sentinel.h'],
|
||||||
|
command: [
|
||||||
|
'sh', '-c', '"$@" && touch @OUTPUT1@', 'sh',
|
||||||
|
zig_build_cmd,
|
||||||
|
],
|
||||||
|
console: true,
|
||||||
|
install: true,
|
||||||
|
install_dir: [get_option('libdir'), false],
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- Declare dependency for subproject consumers ------------------------------
|
||||||
|
|
||||||
|
ghostty_vt_lib = declare_dependency(
|
||||||
|
compile_args: ['-I' + zig_out_dir / 'include'],
|
||||||
|
sources: zig_build_lib_vt,
|
||||||
|
link_args: [
|
||||||
|
'-L' + meson.current_build_dir(),
|
||||||
|
'-lghostty-vt',
|
||||||
|
'-Wl,-rpath,' + meson.current_build_dir(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
# Expose for subproject() consumers via get_variable('ghostty_vt_dep')
|
||||||
|
ghostty_vt_dep = ghostty_vt_lib
|
||||||
|
|
||||||
|
# --- Install ------------------------------------------------------------------
|
||||||
|
|
||||||
|
if host_machine.system() != 'windows'
|
||||||
|
# Install symlinks
|
||||||
|
meson.add_install_script('sh', '-c',
|
||||||
|
'ln -sf "@0@" "$DESTDIR@1@/@2@"'.format(
|
||||||
|
ghostty_vt_realname,
|
||||||
|
get_option('prefix') / get_option('libdir'),
|
||||||
|
ghostty_vt_soname,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
meson.add_install_script('sh', '-c',
|
||||||
|
'ln -sf "@0@" "$DESTDIR@1@/@2@"'.format(
|
||||||
|
ghostty_vt_soname,
|
||||||
|
get_option('prefix') / get_option('libdir'),
|
||||||
|
ghostty_vt_libname,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Install headers
|
||||||
|
meson.add_install_script('sh', '-c',
|
||||||
|
'cp -r "@0@/include/ghostty" "$DESTDIR@1@/"'.format(
|
||||||
|
zig_out_dir,
|
||||||
|
get_option('prefix') / get_option('includedir'),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
option('zig-build-flags', type: 'string', value: '',
|
||||||
|
description: 'Additional flags to pass to zig build')
|
||||||
|
|
@ -9,6 +9,8 @@
|
||||||
flatpak-builder,
|
flatpak-builder,
|
||||||
gdb,
|
gdb,
|
||||||
cmake,
|
cmake,
|
||||||
|
meson,
|
||||||
|
ninja,
|
||||||
#, glxinfo # unused
|
#, glxinfo # unused
|
||||||
ncurses,
|
ncurses,
|
||||||
nodejs,
|
nodejs,
|
||||||
|
|
@ -93,6 +95,8 @@ in
|
||||||
[
|
[
|
||||||
# For builds
|
# For builds
|
||||||
cmake
|
cmake
|
||||||
|
meson
|
||||||
|
ninja
|
||||||
doxygen
|
doxygen
|
||||||
jq
|
jq
|
||||||
llvmPackages_latest.llvm
|
llvmPackages_latest.llvm
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue