feat(dist): website data, library installs, XCFramework, dist tarball
Closes the remaining artifact rows of the final audit (docs/rewrite/notes/final-Z4.md): - webgen: config.mdx, actions.mdx, commands.mdx (byte-identical to Zig's webgen output once its missing stdout flush is added) - `just install-lib`: libghostty (+ ghostty.h, modulemap) and libghostty-vt with versioned symlinks, headers and libghostty-vt.pc - scripts/xcframework.sh: per-arch builds, lipo and xcodebuild -create-xcframework for GhosttyKit (dry-run verified only) - `just install` builds --profile production so the installed app id is com.mitchellh.ghostty; other profiles install the -debug id/name - `just update-translations`: xgettext/msgmerge pipeline; extracted msgids equal upstream's .pot (found and fixed an untranslated string in the child-exited banner) - `just dist` / `distcheck`: versioned source tarball with VERSION and a prebuilt GTK resource bundle - Windows: icon, version resource and DPI/common-controls manifest embedded via embed-resource, GUI subsystem Test Plan: - just install-lib /tmp/p release all && pkg-config --cflags \ --libs /tmp/p/share/pkgconfig/libghostty-vt.pc - just distcheck
This commit is contained in:
1 parent
8af6ab68d3
commit
3f3f6680a5
12 files changed
+793
-21
No files matched your search
@@ -1,16 +1,44 @@
|
||||
//! Link the final binary with lazy symbol binding.
|
||||
//! Root build script.
|
||||
//!
|
||||
//! Rust links executables with `-z now` (eager binding) by default. The GTK
|
||||
//! apprt compiles in code for newer GTK/libadwaita API (e.g. the GTK 4.16 CSS
|
||||
//! * Linux: link the final binary with lazy symbol binding. Rust links
|
||||
//! executables with `-z now` (eager binding) by default. The GTK apprt
|
||||
//! compiles in code for newer GTK/libadwaita API (e.g. the GTK 4.16 CSS
|
||||
//! diagnostics) that is only ever called after a runtime `at_least` check,
|
||||
//! exactly like the Zig build, which links GTK dynamically with lazy binding.
|
||||
//! With eager binding the dynamic loader would refuse to start the program on
|
||||
//! an older library that merely lacks such a symbol; with lazy binding the
|
||||
//! symbol is only resolved if the guarded code actually runs.
|
||||
//! exactly like the Zig build, which links GTK dynamically with lazy
|
||||
//! binding. With eager binding the dynamic loader would refuse to start the
|
||||
//! program on an older library that merely lacks such a symbol; with lazy
|
||||
//! binding the symbol is only resolved if the guarded code actually runs.
|
||||
//! * Windows (Zig: `GhosttyExe.zig`): use the GUI subsystem and embed
|
||||
//! `dist/windows/ghostty.rc` (icon, version resource and the manifest that
|
||||
//! declares per-monitor DPI awareness and the common-controls v6 activation
|
||||
//! context).
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
if std::env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("linux") {
|
||||
println!("cargo:rustc-link-arg-bins=-Wl,-z,lazy");
|
||||
match std::env::var("CARGO_CFG_TARGET_OS").as_deref() {
|
||||
Ok("linux") => println!("cargo:rustc-link-arg-bins=-Wl,-z,lazy"),
|
||||
Ok("windows") => windows(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn windows() {
|
||||
println!("cargo:rerun-if-changed=dist/windows/ghostty.rc");
|
||||
println!("cargo:rerun-if-changed=dist/windows/ghostty.ico");
|
||||
println!("cargo:rerun-if-changed=dist/windows/ghostty.manifest");
|
||||
|
||||
// `exe.subsystem = .Windows`.
|
||||
if std::env::var("CARGO_CFG_TARGET_ENV").as_deref() == Ok("msvc") {
|
||||
println!("cargo:rustc-link-arg-bins=/SUBSYSTEM:WINDOWS");
|
||||
println!("cargo:rustc-link-arg-bins=/ENTRY:mainCRTStartup");
|
||||
} else {
|
||||
println!("cargo:rustc-link-arg-bins=-Wl,--subsystem,windows");
|
||||
}
|
||||
|
||||
// `exe.addWin32ResourceFile(.{ .file = "dist/windows/ghostty.rc" })`.
|
||||
// The resource is only linked into the binary targets, not the
|
||||
// (nonexistent) library target of this package.
|
||||
embed_resource::compile_for("dist/windows/ghostty.rc", ["ghostty"], embed_resource::NONE)
|
||||
.manifest_required()
|
||||
.expect("failed to embed the Windows resource file");
|
||||
}
|
||||
@@ -15,6 +15,7 @@ pub mod fish;
|
||||
pub mod mdgen;
|
||||
pub mod sublime;
|
||||
pub mod vim;
|
||||
pub mod webdata;
|
||||
pub mod zsh;
|
||||
|
||||
#[allow(clippy::needless_raw_string_hashes)]
|
||||
@@ -43,6 +44,14 @@ pub enum Mode {
|
||||
Man1,
|
||||
/// `ghostty(5)` man page markdown (Zig: `mdgen_ghostty_5`).
|
||||
Man5,
|
||||
/// Website `config.mdx` (Zig: `webgen_config`).
|
||||
WebdataConfig,
|
||||
/// Website `actions.mdx` (keybind actions; Zig: `webgen_actions`).
|
||||
WebdataActions,
|
||||
/// Website `commands.mdx` (CLI actions; Zig: `webgen_commands`).
|
||||
WebdataCommands,
|
||||
/// The Ghostty version string (embedded into source tarballs as `VERSION`).
|
||||
Version,
|
||||
}
|
||||
|
||||
impl Mode {
|
||||
@@ -58,6 +67,10 @@ impl Mode {
|
||||
("terminfo", Mode::Terminfo),
|
||||
("mdgen-ghostty-1", Mode::Man1),
|
||||
("mdgen-ghostty-5", Mode::Man5),
|
||||
("webgen-config", Mode::WebdataConfig),
|
||||
("webgen-actions", Mode::WebdataActions),
|
||||
("webgen-commands", Mode::WebdataCommands),
|
||||
("version", Mode::Version),
|
||||
];
|
||||
|
||||
/// Parse `+name` (Zig action syntax) or a bare `name`.
|
||||
@@ -82,6 +95,10 @@ impl Mode {
|
||||
Mode::Terminfo => ghostty_termio::terminfo::ghostty.encode_to_string(),
|
||||
Mode::Man1 => mdgen::ghostty_1(),
|
||||
Mode::Man5 => mdgen::ghostty_5(),
|
||||
Mode::WebdataConfig => webdata::config_mdx(),
|
||||
Mode::WebdataActions => webdata::actions_mdx(),
|
||||
Mode::WebdataCommands => webdata::commands_mdx(),
|
||||
Mode::Version => ghostty_cli::build_info::get().version_string.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,6 +191,27 @@ mod tests {
|
||||
assert!(five.contains("**`new_split`**"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn webdata_has_frontmatter_and_sections() {
|
||||
let config = webdata::config_mdx();
|
||||
assert!(config.starts_with(
|
||||
"---\ntitle: Reference\ndescription: Reference of all Ghostty configuration options.\n"
|
||||
));
|
||||
assert!(config.contains("organize these options.\n\n## `language`\n\n"));
|
||||
assert!(config.contains("## `font-family`\n"));
|
||||
assert!(!config.contains("## `_"));
|
||||
// Callouts and indented code blocks are rewritten for the website.
|
||||
assert!(config.contains("<Note>\n") || config.contains("<Warning>\n"));
|
||||
assert!(config.contains("```\n"));
|
||||
let actions = webdata::actions_mdx();
|
||||
assert!(actions.starts_with("---\ntitle: Keybinding Action Reference\n"));
|
||||
assert!(actions.contains("\n## `ignore`\nIgnore this key combination.\n"));
|
||||
let commands = webdata::commands_mdx();
|
||||
assert!(commands.contains("## version\n"));
|
||||
assert!(commands.contains("\n```\nghostty --version\n```\n\n"));
|
||||
assert!(commands.contains("\n```\nghostty +list-fonts\n```\n\n"));
|
||||
}
|
||||
|
||||
/// Every supported locale has a `.po` catalog and vice versa
|
||||
/// (Zig: `GhosttyI18n.zig` iterates `os/i18n_locales.zig`).
|
||||
#[test]
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
//! Website data generators (port of `build/GhosttyWebdata.zig` and
|
||||
//! `build/webgen/main_{config,actions,commands}.zig`). They produce the
|
||||
//! `config.mdx`, `actions.mdx` (keybind actions) and `commands.mdx` (CLI
|
||||
//! actions) files installed to `share/ghostty/webdata/`.
|
||||
|
||||
use ghostty_input::binding::ActionKey;
|
||||
|
||||
use crate::config_fields;
|
||||
|
||||
/// `webgen/main_config.zig`: the configuration reference.
|
||||
#[must_use]
|
||||
pub fn config_mdx() -> String {
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
enum Block {
|
||||
Text,
|
||||
Code,
|
||||
CalloutNote,
|
||||
CalloutWarning,
|
||||
}
|
||||
|
||||
fn end_block(w: &mut String, block: Option<Block>) {
|
||||
match block {
|
||||
Some(Block::Code) => w.push_str("```\n"),
|
||||
Some(Block::CalloutNote) => w.push_str("</Note>\n"),
|
||||
Some(Block::CalloutWarning) => w.push_str("</Warning>\n"),
|
||||
Some(Block::Text) | None => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn starts_with_ignore_case(s: &str, prefix: &str) -> bool {
|
||||
s.len() >= prefix.len()
|
||||
&& s.as_bytes()[..prefix.len()].eq_ignore_ascii_case(prefix.as_bytes())
|
||||
}
|
||||
|
||||
let mut w = String::from(
|
||||
"---\n\
|
||||
title: Reference\n\
|
||||
description: Reference of all Ghostty configuration options.\n\
|
||||
editOnGithubLink: https://github.com/ghostty-org/ghostty/edit/main/src/config/Config.zig\n\
|
||||
---\n\
|
||||
\n\
|
||||
This is a reference of all Ghostty configuration options. These\n\
|
||||
options are ordered roughly by how common they are to be used\n\
|
||||
and grouped with related options. I recommend utilizing your\n\
|
||||
browser's search functionality to find the option you're looking\n\
|
||||
for.\n\
|
||||
\n\
|
||||
In the future, we'll have a more user-friendly way to view and\n\
|
||||
organize these options.\n\
|
||||
\n",
|
||||
);
|
||||
|
||||
let fields = config_fields();
|
||||
for (i, field) in fields.iter().enumerate() {
|
||||
if field.help.is_empty() {
|
||||
continue;
|
||||
}
|
||||
w.push_str("## `");
|
||||
w.push_str(field.name);
|
||||
w.push_str("`\n");
|
||||
|
||||
// For all subsequent fields with no docs, they are grouped with the
|
||||
// previous field. (Zig breaks at `_` fields; those are already
|
||||
// filtered out of `config_fields`, which would otherwise leave a
|
||||
// gap, so the group may only extend to the next raw field.)
|
||||
for next in &fields[i + 1..] {
|
||||
if !next.help.is_empty() {
|
||||
break;
|
||||
}
|
||||
w.push_str("## `");
|
||||
w.push_str(next.name);
|
||||
w.push_str("`\n");
|
||||
}
|
||||
|
||||
w.push('\n');
|
||||
|
||||
let mut block: Option<Block> = None;
|
||||
for s in field.help.split('\n') {
|
||||
// Empty line resets our block.
|
||||
if s.is_empty() {
|
||||
end_block(&mut w, block);
|
||||
block = None;
|
||||
w.push('\n');
|
||||
continue;
|
||||
}
|
||||
|
||||
let first = block.is_none();
|
||||
if block.is_none() {
|
||||
if s.starts_with(" ") {
|
||||
block = Some(Block::Code);
|
||||
w.push_str("```\n");
|
||||
} else if starts_with_ignore_case(s, "note:") {
|
||||
block = Some(Block::CalloutNote);
|
||||
w.push_str("<Note>\n");
|
||||
} else if starts_with_ignore_case(s, "warning:") {
|
||||
block = Some(Block::CalloutWarning);
|
||||
w.push_str("<Warning>\n");
|
||||
} else {
|
||||
block = Some(Block::Text);
|
||||
}
|
||||
}
|
||||
|
||||
w.push_str(match block {
|
||||
Some(Block::CalloutNote) if first => &s["note:".len()..],
|
||||
Some(Block::CalloutWarning) if first => &s["warning:".len()..],
|
||||
Some(Block::Code) => s.strip_prefix(" ").unwrap_or(s),
|
||||
_ => s,
|
||||
});
|
||||
w.push('\n');
|
||||
}
|
||||
end_block(&mut w, block);
|
||||
w.push('\n');
|
||||
}
|
||||
w
|
||||
}
|
||||
|
||||
/// `webgen/main_actions.zig` (`input/helpgen_actions.zig`, markdown with
|
||||
/// docs): the keybind action reference.
|
||||
#[must_use]
|
||||
pub fn actions_mdx() -> String {
|
||||
let mut w = String::from(
|
||||
"---\n\
|
||||
title: Keybinding Action Reference\n\
|
||||
description: Reference of all Ghostty keybinding actions.\n\
|
||||
editOnGithubLink: https://github.com/ghostty-org/ghostty/edit/main/src/input/Binding.zig\n\
|
||||
---\n\
|
||||
\n\
|
||||
This is a reference of all Ghostty keybinding actions.\n\
|
||||
\n",
|
||||
);
|
||||
|
||||
// Doc comments are written below all related (consecutive undocumented)
|
||||
// actions, so they are buffered until the next documented action.
|
||||
let mut stream = String::new();
|
||||
for &key in ActionKey::ALL {
|
||||
let name = key.name();
|
||||
if name.starts_with('_') {
|
||||
continue;
|
||||
}
|
||||
let docs = key.help_string();
|
||||
let has_docs = !key.docs().is_empty();
|
||||
|
||||
if has_docs {
|
||||
w.push_str(&stream);
|
||||
w.push('\n');
|
||||
stream.clear();
|
||||
}
|
||||
|
||||
w.push_str("## `");
|
||||
w.push_str(name);
|
||||
w.push_str("`\n");
|
||||
|
||||
if has_docs {
|
||||
let mut iter = docs.split('\n').peekable();
|
||||
while let Some(s) = iter.next() {
|
||||
// If it is the last line and empty, then skip it.
|
||||
if iter.peek().is_none() && s.is_empty() {
|
||||
continue;
|
||||
}
|
||||
stream.push_str(s);
|
||||
stream.push('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
if !stream.is_empty() {
|
||||
w.push_str(&stream);
|
||||
}
|
||||
w
|
||||
}
|
||||
|
||||
/// `webgen/main_commands.zig`: the CLI action reference.
|
||||
#[must_use]
|
||||
pub fn commands_mdx() -> String {
|
||||
let mut w = String::from(
|
||||
"---\n\
|
||||
title: Reference\n\
|
||||
description: Reference of all Ghostty action subcommands.\n\
|
||||
editOnGithubLink: https://github.com/ghostty-org/ghostty/tree/main/src/cli\n\
|
||||
---\n\
|
||||
Ghostty includes a number of utility actions that can be accessed as subcommands.\n\
|
||||
Actions provide utilities to work with config, list keybinds, list fonts, demo themes,\n\
|
||||
and debug.\n",
|
||||
);
|
||||
|
||||
for &action in ghostty_cli::Action::ALL {
|
||||
let name = action.name();
|
||||
w.push_str("## ");
|
||||
w.push_str(name);
|
||||
w.push('\n');
|
||||
|
||||
let help = action.help_text();
|
||||
if help.is_empty() {
|
||||
continue;
|
||||
}
|
||||
for s in help.split('\n') {
|
||||
w.push_str(s);
|
||||
w.push('\n');
|
||||
}
|
||||
w.push_str("\n```\n");
|
||||
match action {
|
||||
ghostty_cli::Action::Help | ghostty_cli::Action::Version => {
|
||||
w.push_str("ghostty --");
|
||||
}
|
||||
_ => w.push_str("ghostty +"),
|
||||
}
|
||||
w.push_str(name);
|
||||
w.push_str("\n```\n\n");
|
||||
}
|
||||
w
|
||||
}
|
||||
Vendored
BIN
Binary file not shown.
|
After Width: | Height: | Size: 84 KiB |
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||
<asmv3:application>
|
||||
<asmv3:windowsSettings>
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
|
||||
</asmv3:windowsSettings>
|
||||
</asmv3:application>
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*" />
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
</assembly>
|
||||
Vendored
+36
@@ -0,0 +1,36 @@
|
||||
// LANG_NEUTRAL(0), SUBLANG_NEUTRAL(0)
|
||||
LANGUAGE 0, 0
|
||||
|
||||
#define RT_MANIFEST 1
|
||||
RT_MANIFEST 24 "ghostty.manifest"
|
||||
|
||||
#define ID_ICON_GHOSTTY 1
|
||||
ID_ICON_GHOSTTY ICON "ghostty.ico"
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
//FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,VERSION_COMMIT_HEIGHT
|
||||
//PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,VERSION_COMMIT_HEIGHT
|
||||
//FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
//FILEFLAGS VER_DBG
|
||||
//FILEOS VOS_NT
|
||||
//FILETYPE VFT_APP
|
||||
//FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
//VALUE "CompanyName", "???"
|
||||
//VALUE "FileDescription", "???"
|
||||
//VALUE "FileVersion", VERSION
|
||||
//VALUE "LegalCopyright", "(C) 2024 ???"
|
||||
VALUE "OriginalFilename", "ghostty.exe"
|
||||
VALUE "ProductName", "Ghostty"
|
||||
//VALUE "ProductVersion", VERSION
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x0409,1200
|
||||
END
|
||||
END
|
||||
@@ -0,0 +1,27 @@
|
||||
# Z4: artifact and distribution gaps
|
||||
|
||||
- Webdata (`GhosttyWebdata.zig`): `ghostty-build-data +webgen-{config,actions,commands}` (`src/webdata.rs`);
|
||||
`just webdata`, `just install-webdata PREFIX`. Byte-identical to Zig 0.15.2 output of a copy whose webgen mains
|
||||
gained `stdout.flush()`. Upstream's mains never flush the 2048-byte buffer, so the real Zig files are truncated.
|
||||
Rust emits the complete files. Also `+version` mode (build-info version string).
|
||||
- libghostty / vt install: `scripts/install-lib.sh`, `just install-lib PREFIX PROFILE WHAT`; `just install` installs vt
|
||||
(as Zig's default install does). Layout, headers and `libghostty-vt.pc` match the Zig output (soname `.so.0` set via
|
||||
patchelf, symlinks `.so`, `.so.0`, `.so.0.1.0`). libghostty adds `ghostty.h` + `module.modulemap`.
|
||||
- XCFramework: `scripts/xcframework.sh` / `just xcframework` (cargo staticlib per target, `lipo -create`,
|
||||
`xcodebuild -create-xcframework -headers crates/ghostty-lib/include`, iOS + simulator slices). Verified only with
|
||||
`DRY_RUN=1`: no macOS tools or SDK here; the darwin cross build was not attempted.
|
||||
- App id: `just install` defaults to `--profile production` (ReleaseFast); other profiles get `-debug` id/name, like
|
||||
Zig Debug/ReleaseSafe. Desktop, D-Bus, systemd and metainfo files use it. DESTDIR install checked for production
|
||||
(`com.mitchellh.ghostty`, build mode .ReleaseFast) and release (`-debug`).
|
||||
- i18n: `scripts/update-translations.sh` / `just update-translations` (xgettext with the same flags + `--keyword=tr`
|
||||
over blueprints and apprt-gtk Rust sources, py.pot, merge, msgmerge). msgids identical to upstream's .pot.
|
||||
Found and fixed: `surface_child_exited.rs` didn't translate "Command succeeded/failed" (now `tr`). Script accepts
|
||||
an OUT_DIR; po/ was not rewritten in place (location comments would churn).
|
||||
- Dist: `scripts/dist.sh`, `just dist` / `just distcheck`: `ghostty-<version>.tar.gz` with `VERSION` and the prebuilt
|
||||
`crates/ghostty-apprt-gtk/dist/ghostty.gresource` (used by apprt-gtk/build.rs outside a git checkout, like Zig's
|
||||
`ghostty_resources.c/h`). Framedata is already committed. As in Zig, VERSION is for packagers (`GHOSTTY_VERSION_STRING`).
|
||||
Uses `git ls-files` (includes uncommitted files), not `git archive HEAD`. distcheck passes.
|
||||
- Windows: `dist/windows/{ghostty.rc,ico,manifest}` copied; root `build.rs` uses `embed-resource` plus the GUI subsystem.
|
||||
The root binary can't cargo-check for Windows (GTK/wayland deps), so verified with a scratch crate using the same
|
||||
build.rs for x86_64-pc-windows-gnu: PE subsystem 2, manifest (PerMonitorV2, Common-Controls 6) present.
|
||||
- Touched outside lane: apprt-gtk `build.rs` (prebuilt gresource) and `surface_child_exited.rs` (tr).
|
||||
@@ -89,22 +89,43 @@ locales OUT="target/locale":
|
||||
# Install bin + share/ghostty (shell-integration, themes, docs) +
|
||||
# share/terminfo (compiled db, ghostty.terminfo, ghostty.termcap) + shell
|
||||
# completions, vim/neovim/bat syntax, man pages, translations, desktop file,
|
||||
# D-Bus/systemd/metainfo and icons, mirroring Ghostty's GhosttyResources.zig,
|
||||
# GhosttyDocs.zig and GhosttyI18n.zig.
|
||||
# D-Bus/systemd/metainfo and icons, plus libghostty-vt (lib, headers,
|
||||
# libghostty-vt.pc), mirroring Ghostty's GhosttyResources.zig,
|
||||
# GhosttyDocs.zig, GhosttyI18n.zig and GhosttyLibVt.zig.
|
||||
#
|
||||
# Usage: `just install [PREFIX] [FLATPAK] [SYSTEM_PACKAGE]`; honours DESTDIR.
|
||||
# Usage: `just install [PREFIX] [FLATPAK] [SYSTEM_PACKAGE] [PROFILE]`;
|
||||
# honours DESTDIR.
|
||||
# PREFIX install prefix (default /usr/local)
|
||||
# FLATPAK "true": use the Flatpak D-Bus template, no systemd unit
|
||||
# and no 1024x1024 icon (Zig: -Dflatpak)
|
||||
# SYSTEM_PACKAGE "true": install the systemd user unit to lib/systemd/user
|
||||
# instead of share/systemd/user (Zig: --system / system
|
||||
# package mode)
|
||||
install PREFIX="/usr/local" FLATPAK="false" SYSTEM_PACKAGE="false": build-release build-data docs locales
|
||||
# PROFILE cargo profile to build and install (default "production":
|
||||
# no debug assertions, the Zig ReleaseFast equivalent).
|
||||
# Like Zig's Debug/ReleaseSafe modes, any other profile
|
||||
# (dev, release) installs the "-debug" application id
|
||||
# (com.mitchellh.ghostty-debug, "Ghostty (Debug)"), which is
|
||||
# the id the binary uses at runtime when built with debug
|
||||
# assertions.
|
||||
install PREFIX="/usr/local" FLATPAK="false" SYSTEM_PACKAGE="false" PROFILE="production": build-data docs locales
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
cargo build --profile {{ PROFILE }}
|
||||
just install-lib '{{ PREFIX }}' '{{ PROFILE }}' vt
|
||||
P="${DESTDIR:-}{{ PREFIX }}"
|
||||
BD=target/release/ghostty-build-data
|
||||
install -Dm755 target/release/ghostty "$P/bin/ghostty"
|
||||
dir={{ PROFILE }}
|
||||
if [ "$dir" = dev ]; then dir=debug; fi
|
||||
# GhosttyResources.zig: Debug/ReleaseSafe get the "-debug" id and name.
|
||||
if [ "{{ PROFILE }}" = production ]; then
|
||||
APPID=com.mitchellh.ghostty
|
||||
NAME=Ghostty
|
||||
else
|
||||
APPID=com.mitchellh.ghostty-debug
|
||||
NAME="Ghostty (Debug)"
|
||||
fi
|
||||
install -Dm755 "target/$dir/ghostty" "$P/bin/ghostty"
|
||||
mkdir -p "$P/share/ghostty" "$P/share/terminfo"
|
||||
cp -R resources/shell-integration resources/themes "$P/share/ghostty/"
|
||||
find "$P/share/ghostty/shell-integration" -name '*.md' -delete
|
||||
@@ -150,20 +171,20 @@ install PREFIX="/usr/local" FLATPAK="false" SYSTEM_PACKAGE="false": build-releas
|
||||
|
||||
gen() { # template out
|
||||
mkdir -p "$(dirname "$2")"
|
||||
sed -e 's|@NAME@|Ghostty|g' -e 's|@APPID@|com.mitchellh.ghostty|g' \
|
||||
sed -e "s|@NAME@|$NAME|g" -e "s|@APPID@|$APPID|g" \
|
||||
-e "s|@GHOSTTY@|{{ PREFIX }}/bin/ghostty|g" "$1" > "$2"
|
||||
}
|
||||
gen dist/linux/app.desktop.in "$P/share/applications/com.mitchellh.ghostty.desktop"
|
||||
gen dist/linux/app.desktop.in "$P/share/applications/$APPID.desktop"
|
||||
if [ "{{ FLATPAK }}" = "true" ]; then
|
||||
gen dist/linux/dbus.service.flatpak.in "$P/share/dbus-1/services/com.mitchellh.ghostty.service"
|
||||
gen dist/linux/dbus.service.flatpak.in "$P/share/dbus-1/services/$APPID.service"
|
||||
else
|
||||
gen dist/linux/dbus.service.in "$P/share/dbus-1/services/com.mitchellh.ghostty.service"
|
||||
gen dist/linux/dbus.service.in "$P/share/dbus-1/services/$APPID.service"
|
||||
# systemd looks in lib/ for system packages and share/ otherwise.
|
||||
sysd=share
|
||||
if [ "{{ SYSTEM_PACKAGE }}" = "true" ]; then sysd=lib; fi
|
||||
gen dist/linux/systemd.service.in "$P/$sysd/systemd/user/app-com.mitchellh.ghostty.service"
|
||||
gen dist/linux/systemd.service.in "$P/$sysd/systemd/user/app-$APPID.service"
|
||||
fi
|
||||
gen dist/linux/com.mitchellh.ghostty.metainfo.xml.in "$P/share/metainfo/com.mitchellh.ghostty.metainfo.xml"
|
||||
gen dist/linux/com.mitchellh.ghostty.metainfo.xml.in "$P/share/metainfo/$APPID.metainfo.xml"
|
||||
install -Dm644 dist/linux/ghostty_dolphin.desktop "$P/share/kio/servicemenus/com.mitchellh.ghostty.desktop"
|
||||
install -Dm755 dist/linux/ghostty_nautilus.py "$P/share/nautilus-python/extensions/ghostty.py"
|
||||
ic="$P/share/icons/hicolor"
|
||||
@@ -173,8 +194,62 @@ install PREFIX="/usr/local" FLATPAK="false" SYSTEM_PACKAGE="false": build-releas
|
||||
if [ "{{ FLATPAK }}" = "true" ] && [ "${pair%%:*}" = "1024" ]; then continue; fi
|
||||
install -Dm644 "dist/icons/${pair%%:*}.png" "$ic/${pair##*:}/apps/com.mitchellh.ghostty.png"
|
||||
done
|
||||
echo "installed to $P"
|
||||
echo "installed to $P (application id $APPID)"
|
||||
|
||||
# Regenerate resources/terminfo from the terminfo source in ghostty-termio.
|
||||
terminfo:
|
||||
scripts/gen-terminfo.sh
|
||||
|
||||
# Install libghostty and libghostty-vt below PREFIX (honours DESTDIR):
|
||||
# lib/libghostty.{so,a}, include/ghostty.h, include/module.modulemap
|
||||
# (GhosttyLib.zig) and lib/libghostty-vt.so{,.0,.0.1.0},
|
||||
# include/ghostty/vt*.h, share/pkgconfig/libghostty-vt.pc (GhosttyLibVt.zig).
|
||||
# WHAT is one of: all, vt, ghostty.
|
||||
install-lib PREFIX="/usr/local" PROFILE="production" WHAT="all":
|
||||
scripts/install-lib.sh '{{ PREFIX }}' '{{ PROFILE }}' '{{ WHAT }}'
|
||||
|
||||
# Build libghostty (the embedded C API) as static and shared libraries.
|
||||
lib PROFILE="production":
|
||||
cargo build -p ghostty-lib --profile {{ PROFILE }}
|
||||
|
||||
# Build GhosttyKit.xcframework with lipo + xcodebuild (macOS only; Zig:
|
||||
# GhosttyXCFramework.zig). TARGET is "universal" (macOS arm64+x86_64, iOS,
|
||||
# iOS simulator) or "native". Set DRY_RUN=1 to only print the commands.
|
||||
xcframework TARGET="universal" PROFILE="production" OUT="macos/GhosttyKit.xcframework":
|
||||
scripts/xcframework.sh '{{ TARGET }}' '{{ PROFILE }}' '{{ OUT }}'
|
||||
|
||||
# Generate the website reference data (Zig: GhosttyWebdata.zig): config.mdx,
|
||||
# actions.mdx (keybind actions) and commands.mdx (CLI actions) in OUT.
|
||||
webdata OUT="target/webdata": build-data
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
mkdir -p "{{ OUT }}"
|
||||
for m in config actions commands; do
|
||||
target/release/ghostty-build-data "+webgen-$m" > "{{ OUT }}/$m.mdx"
|
||||
done
|
||||
|
||||
# Install the website data to PREFIX/share/ghostty/webdata (Zig:
|
||||
# `-Demit-webdata`); honours DESTDIR.
|
||||
install-webdata PREFIX="/usr/local": webdata
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
for m in config actions commands; do
|
||||
install -Dm644 "target/webdata/$m.mdx" "${DESTDIR:-}{{ PREFIX }}/share/ghostty/webdata/$m.mdx"
|
||||
done
|
||||
|
||||
# Regenerate po/com.mitchellh.ghostty.pot (xgettext over the GTK blueprints,
|
||||
# the GTK apprt Rust sources and the Nautilus extension) and msgmerge every
|
||||
# po/*.po against it (Zig: `zig build update-translations`).
|
||||
update-translations:
|
||||
scripts/update-translations.sh
|
||||
|
||||
# Create the versioned source tarball target/dist/ghostty-<version>.tar.gz with
|
||||
# the embedded VERSION file and the prebuilt dist resources (Zig: `zig build
|
||||
# dist`).
|
||||
dist:
|
||||
scripts/dist.sh target/dist
|
||||
|
||||
# Extract the dist tarball and check that it builds and tests (Zig:
|
||||
# `zig build distcheck`).
|
||||
distcheck: dist
|
||||
scripts/dist.sh --check
|
||||
Executable
+95
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env bash
|
||||
# Create the versioned source tarball (Zig: `zig build dist`,
|
||||
# build/GhosttyDist.zig) or check one (`zig build distcheck`).
|
||||
#
|
||||
# scripts/dist.sh [OUT_DIR] create OUT_DIR/ghostty-<version>.tar.gz
|
||||
# scripts/dist.sh --check [TARBALL] extract it and verify it
|
||||
#
|
||||
# The tarball extracts into `ghostty-<version>/` (expected by debhelper,
|
||||
# rpmbuild, ...) and contains, in addition to the checked-in sources:
|
||||
# * `VERSION`: the embedded Ghostty version (Zig: the `VERSION` file),
|
||||
# * the prebuilt dist resources that are not committed but built here to cut
|
||||
# the build-time dependencies of downstream packagers: the compiled GTK
|
||||
# GResource bundle `crates/ghostty-apprt-gtk/dist/ghostty.gresource`
|
||||
# (Zig: `src/apprt/gtk/ghostty_resources.{c,h}`; picked up by
|
||||
# ghostty-apprt-gtk/build.rs outside of a git checkout, replacing
|
||||
# blueprint-compiler + glib-compile-resources). The boo frame data
|
||||
# (Zig: `framedata.compressed`) is already committed
|
||||
# (`crates/ghostty-cli/src/boo_frames.deflate`).
|
||||
#
|
||||
# In a git checkout the file set is `git ls-files` (tracked files, plus
|
||||
# untracked files that are not ignored), otherwise all files except build
|
||||
# output. Files marked `export-ignore` in .gitattributes are dropped.
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
root=$PWD
|
||||
|
||||
# Resources that are generated into the tarball (dist path relative to root).
|
||||
dist_resources=(crates/ghostty-apprt-gtk/dist/ghostty.gresource)
|
||||
|
||||
version() {
|
||||
cargo build -q --release -p ghostty-build-data >&2
|
||||
"${CARGO_TARGET_DIR:-target}/release/ghostty-build-data" +version
|
||||
}
|
||||
|
||||
if [ "${1:-}" = --check ]; then
|
||||
version=$(version)
|
||||
tarball=${2:-target/dist/ghostty-$version.tar.gz}
|
||||
work=$(mktemp -d)
|
||||
trap 'rm -rf "$work"' EXIT
|
||||
tar -xzf "$tarball" -C "$work"
|
||||
src="$work/ghostty-$version"
|
||||
[ -f "$src/VERSION" ] || { echo "missing VERSION" >&2; exit 1; }
|
||||
[ "$(cat "$src/VERSION")" = "$version" ] || { echo "VERSION mismatch" >&2; exit 1; }
|
||||
for r in "${dist_resources[@]}"; do
|
||||
[ -f "$src/$r" ] || { echo "missing dist resource $r" >&2; exit 1; }
|
||||
done
|
||||
# Check that the extracted tree builds and passes its tests.
|
||||
(cd "$src" && cargo test --offline -q -p ghostty-build-data)
|
||||
echo "distcheck ok: $tarball"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
out=${1:-target/dist}
|
||||
version=$(version)
|
||||
name=ghostty-$version
|
||||
mkdir -p "$out"
|
||||
work=$(mktemp -d)
|
||||
trap 'rm -rf "$work"' EXIT
|
||||
|
||||
# Generate the dist resources.
|
||||
cargo build -q -p ghostty-apprt-gtk
|
||||
gres=$(find "${CARGO_TARGET_DIR:-target}/debug/build" -path '*ghostty-apprt-gtk-*/out/ghostty.gresource' -printf '%T@ %p\n' |
|
||||
sort -rn | head -1 | cut -d' ' -f2-)
|
||||
[ -n "$gres" ] || { echo "ghostty.gresource was not built" >&2; exit 1; }
|
||||
mkdir -p "$work/stage/crates/ghostty-apprt-gtk/dist"
|
||||
cp "$gres" "$work/stage/crates/ghostty-apprt-gtk/dist/ghostty.gresource"
|
||||
printf '%s' "$version" >"$work/stage/VERSION"
|
||||
|
||||
# The file list.
|
||||
if [ -e .git ] && command -v git >/dev/null 2>&1; then
|
||||
git ls-files -z --cached --others --exclude-standard
|
||||
else
|
||||
find . -path ./target -prune -o -path ./.git -prune -o -path ./.zig-cache -prune \
|
||||
-o -name '*.orig' -prune -o -type f -print0 | sed -z 's|^\./||'
|
||||
fi >"$work/files0"
|
||||
# export-ignore (git attribute).
|
||||
if [ -e .git ] && command -v git >/dev/null 2>&1; then
|
||||
git check-attr -z export-ignore --stdin -z <"$work/files0" |
|
||||
tr '\0' '\n' | awk 'NR%3==1{f=$0} NR%3==0 && $0=="set"{print f}' >"$work/ignored" || true
|
||||
if [ -s "$work/ignored" ]; then
|
||||
tr '\0' '\n' <"$work/files0" | grep -vxFf "$work/ignored" | tr '\n' '\0' >"$work/files0.new"
|
||||
mv "$work/files0.new" "$work/files0"
|
||||
fi
|
||||
fi
|
||||
# Drop files that no longer exist (deleted but still tracked).
|
||||
tr '\0' '\n' <"$work/files0" | while IFS= read -r f; do [ -e "$f" ] && printf '%s\0' "$f"; done >"$work/files"
|
||||
|
||||
tar --create --null --files-from "$work/files" \
|
||||
--transform "s,^,$name/," --sort=name --owner=0 --group=0 --numeric-owner \
|
||||
-f "$work/src.tar"
|
||||
(cd "$work/stage" && tar --append -f "$work/src.tar" --transform "s,^,$name/," \
|
||||
--owner=0 --group=0 --numeric-owner VERSION crates)
|
||||
gzip -n -c "$work/src.tar" >"$out/$name.tar.gz"
|
||||
echo "$out/$name.tar.gz"
|
||||
Executable
+92
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env bash
|
||||
# Install libghostty and/or libghostty-vt below a prefix, mirroring
|
||||
# build/GhosttyLib.zig (`install`, `installHeader`) and build/GhosttyLibVt.zig.
|
||||
#
|
||||
# Usage: scripts/install-lib.sh PREFIX PROFILE [all|vt|ghostty]
|
||||
# PREFIX install prefix; DESTDIR (env) is prepended for the file copies but
|
||||
# not for the paths recorded in the pkg-config file.
|
||||
# PROFILE cargo profile whose artifacts are installed (dev -> target/debug).
|
||||
# WHAT `vt`: libghostty-vt only (what `zig build` always installs);
|
||||
# `ghostty`: libghostty only (Zig: `-Dapp-runtime=none`, non-Darwin);
|
||||
# `all` (default): both.
|
||||
#
|
||||
# libghostty-vt (version 0.1.0):
|
||||
# lib/libghostty-vt.so.0.1.0 (+ libghostty-vt.so.0, libghostty-vt.so symlinks;
|
||||
# macOS: libghostty-vt.0.1.0.dylib, libghostty-vt.0.dylib, libghostty-vt.dylib)
|
||||
# include/ghostty/vt.h and include/ghostty/vt/**.h
|
||||
# share/pkgconfig/libghostty-vt.pc
|
||||
# libghostty:
|
||||
# lib/libghostty.so, lib/libghostty.a (macOS: .dylib), include/ghostty.h,
|
||||
# include/module.modulemap
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
prefix=${1:?usage: install-lib.sh PREFIX PROFILE [all|vt|ghostty]}
|
||||
profile=${2:-production}
|
||||
what=${3:-all}
|
||||
dest="${DESTDIR:-}$prefix"
|
||||
dir=$profile
|
||||
[ "$profile" = dev ] && dir=debug
|
||||
tdir=${CARGO_TARGET_DIR:-target}/$dir
|
||||
cargo_args=(--profile "$profile")
|
||||
vt_version=0.1.0
|
||||
vt_major=${vt_version%%.*}
|
||||
|
||||
case $(uname -s) in
|
||||
Darwin) dylib=dylib ;;
|
||||
*) dylib=so ;;
|
||||
esac
|
||||
|
||||
install_vt() {
|
||||
cargo build "${cargo_args[@]}" -p ghostty-vt-capi
|
||||
local src="$tdir/libghostty_vt_capi.$dylib"
|
||||
install -d "$dest/lib" "$dest/share/pkgconfig"
|
||||
if [ "$dylib" = so ]; then
|
||||
local real="libghostty-vt.so.$vt_version"
|
||||
install -m755 "$src" "$dest/lib/$real"
|
||||
# The cargo-built soname is the unversioned name; Zig's is `.so.0`.
|
||||
if command -v patchelf >/dev/null 2>&1; then
|
||||
patchelf --set-soname "libghostty-vt.so.$vt_major" "$dest/lib/$real"
|
||||
else
|
||||
echo "patchelf not found: soname stays libghostty-vt.so" >&2
|
||||
fi
|
||||
ln -sf "$real" "$dest/lib/libghostty-vt.so.$vt_major"
|
||||
ln -sf "libghostty-vt.so.$vt_major" "$dest/lib/libghostty-vt.so"
|
||||
else
|
||||
local real="libghostty-vt.$vt_version.dylib"
|
||||
install -m755 "$src" "$dest/lib/$real"
|
||||
if command -v install_name_tool >/dev/null 2>&1; then
|
||||
install_name_tool -id "@rpath/libghostty-vt.$vt_major.dylib" "$dest/lib/$real"
|
||||
fi
|
||||
ln -sf "$real" "$dest/lib/libghostty-vt.$vt_major.dylib"
|
||||
ln -sf "libghostty-vt.$vt_major.dylib" "$dest/lib/libghostty-vt.dylib"
|
||||
fi
|
||||
|
||||
# Headers: include/ghostty/**.h (lib.installHeadersDirectory, .h only).
|
||||
local inc=crates/ghostty-vt-capi/include/ghostty
|
||||
while IFS= read -r h; do
|
||||
install -Dm644 "$inc/$h" "$dest/include/ghostty/$h"
|
||||
done < <(cd "$inc" && find . -type f -name '*.h' | sed 's|^\./||' | LC_ALL=C sort)
|
||||
|
||||
# pkg-config file (no trailing newline, like the Zig `b.fmt` literal).
|
||||
printf 'prefix=%s\nincludedir=${prefix}/include\nlibdir=${prefix}/lib\n\nName: libghostty-vt\nURL: https://github.com/ghostty-org/ghostty\nDescription: Ghostty VT library\nVersion: %s\nCflags: -I${includedir}\nLibs: -L${libdir} -lghostty-vt' \
|
||||
"$prefix" "$vt_version" >"$dest/share/pkgconfig/libghostty-vt.pc"
|
||||
chmod 644 "$dest/share/pkgconfig/libghostty-vt.pc"
|
||||
}
|
||||
|
||||
install_ghostty() {
|
||||
cargo build "${cargo_args[@]}" -p ghostty-lib
|
||||
install -d "$dest/lib" "$dest/include"
|
||||
install -m755 "$tdir/libghostty.$dylib" "$dest/lib/libghostty.$dylib"
|
||||
install -m644 "$tdir/libghostty.a" "$dest/lib/libghostty.a"
|
||||
install -m644 crates/ghostty-lib/include/ghostty.h "$dest/include/ghostty.h"
|
||||
install -m644 crates/ghostty-lib/include/module.modulemap "$dest/include/module.modulemap"
|
||||
}
|
||||
|
||||
case $what in
|
||||
all) install_vt; install_ghostty ;;
|
||||
vt) install_vt ;;
|
||||
ghostty) install_ghostty ;;
|
||||
*) echo "unknown component: $what" >&2; exit 2 ;;
|
||||
esac
|
||||
echo "installed libraries to $dest"
|
||||
Executable
+74
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env bash
|
||||
# Update the translation catalogs in po/ (Zig: `zig build update-translations`,
|
||||
# build/GhosttyI18n.zig `createUpdateStep`).
|
||||
#
|
||||
# 1. xgettext over the GTK blueprint files and the Rust sources of the GTK
|
||||
# apprt (Zig: src/apprt/gtk/**/*.zig) -> gtk.pot. The `tr(...)` function
|
||||
# of `ghostty_os::i18n` is the Rust counterpart of Zig's `_(...)`.
|
||||
# 2. xgettext over the Nautilus extension -> py.pot.
|
||||
# 3. xgettext merge (py.pot first, because of xgettext's charset behaviour
|
||||
# when merging) -> po/com.mitchellh.ghostty.pot.
|
||||
# 4. msgmerge every po/<locale>.po against the new template.
|
||||
#
|
||||
# Usage: scripts/update-translations.sh [OUT_DIR]
|
||||
# OUT_DIR where to write the .pot/.po files (default: po/, i.e. in place).
|
||||
# The existing catalogs are always read from po/.
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
domain=com.mitchellh.ghostty
|
||||
out=${1:-po}
|
||||
mkdir -p "$out"
|
||||
tmp=$(mktemp -d)
|
||||
trap 'rm -rf "$tmp"' EXIT
|
||||
|
||||
gtk=crates/ghostty-apprt-gtk
|
||||
|
||||
# Blueprint files in the order of the GResource list (build.rs BLUEPRINTS,
|
||||
# Zig: gresource.blueprints). The arguments to xgettext must be relative
|
||||
# paths in the repo root so the location comments don't depend on where the
|
||||
# checkout lives.
|
||||
mapfile -t blueprints < <(
|
||||
sed -n 's/^[[:space:]]*(\([0-9]*\), \([0-9]*\), "\([^"]*\)"),.*/\1 \2 \3/p' "$gtk/build.rs" |
|
||||
while read -r major minor name; do
|
||||
echo "$gtk/resources/ui/$major.$minor/$name.blp"
|
||||
done
|
||||
)
|
||||
# Rust sources of the GTK apprt, sorted for a deterministic order.
|
||||
mapfile -t sources < <(cd . && find "$gtk/src" -type f -name '*.rs' | LC_ALL=C sort)
|
||||
|
||||
xgettext \
|
||||
--language=C \
|
||||
--from-code=UTF-8 \
|
||||
--keyword=tr \
|
||||
--keyword=_ \
|
||||
--keyword=C_:1c,2 \
|
||||
-o "$tmp/gtk.pot" \
|
||||
"${blueprints[@]}" "${sources[@]}"
|
||||
|
||||
xgettext \
|
||||
--language=Python \
|
||||
--from-code=UTF-8 \
|
||||
-o "$tmp/py.pot" \
|
||||
dist/linux/ghostty_nautilus.py
|
||||
|
||||
xgettext \
|
||||
--add-comments=Translators \
|
||||
--package-name="$domain" \
|
||||
--msgid-bugs-address=m@mitchellh.com \
|
||||
'--copyright-holder="Mitchell Hashimoto, Ghostty contributors"' \
|
||||
-o - \
|
||||
"$tmp/py.pot" "$tmp/gtk.pot" >"$tmp/$domain.pot"
|
||||
|
||||
for po in po/*.po; do
|
||||
lang=$(basename "$po" .po)
|
||||
msgmerge --quiet --no-fuzzy-matching "$po" "$tmp/$domain.pot" >"$tmp/$lang.po"
|
||||
done
|
||||
|
||||
# Only write once everything succeeded (Zig: UpdateSourceFiles).
|
||||
cp "$tmp/$domain.pot" "$out/$domain.pot"
|
||||
for po in po/*.po; do
|
||||
lang=$(basename "$po" .po)
|
||||
cp "$tmp/$lang.po" "$out/$lang.po"
|
||||
done
|
||||
echo "updated $out/$domain.pot and $(ls po/*.po | wc -l) catalogs"
|
||||
Executable
+83
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build GhosttyKit.xcframework (macOS only; mirrors build/GhosttyLib.zig
|
||||
# `initMacOSUniversal`/`initStatic`, build/GhosttyXCFramework.zig,
|
||||
# build/LipoStep.zig and build/XCFrameworkStep.zig).
|
||||
#
|
||||
# Usage: scripts/xcframework.sh [universal|native] [PROFILE] [OUT]
|
||||
# universal (default) a universal (arm64 + x86_64, via lipo) macOS static
|
||||
# library, an iOS device library and an iOS simulator library.
|
||||
# native only the static library for the host macOS architecture.
|
||||
# PROFILE cargo profile (default production)
|
||||
# OUT output path (default macos/GhosttyKit.xcframework, like Zig)
|
||||
#
|
||||
# Each slice is `libghostty.a` (the Rust staticlib already bundles every
|
||||
# dependency, so there is no libtool step) plus the `include/` directory with
|
||||
# ghostty.h and module.modulemap. Static libraries have no dSYM.
|
||||
#
|
||||
# DRY_RUN=1 prints the commands instead of running them (usable on any host).
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
target=${1:-universal}
|
||||
profile=${2:-production}
|
||||
out=${3:-macos/GhosttyKit.xcframework}
|
||||
dir=$profile
|
||||
[ "$profile" = dev ] && dir=debug
|
||||
tdir=${CARGO_TARGET_DIR:-target}
|
||||
|
||||
# Config.zig osVersionMin: macOS 13, iOS 17.
|
||||
export MACOSX_DEPLOYMENT_TARGET=13.0
|
||||
export IPHONEOS_DEPLOYMENT_TARGET=17.0
|
||||
|
||||
run() {
|
||||
if [ "${DRY_RUN:-}" = 1 ]; then
|
||||
printf '+'
|
||||
printf ' %q' "$@"
|
||||
printf '\n'
|
||||
else
|
||||
"$@"
|
||||
fi
|
||||
}
|
||||
|
||||
# Build only the static library for a Rust target triple (the crate also
|
||||
# declares a cdylib, which needs no linking for the xcframework).
|
||||
build() {
|
||||
run cargo rustc --profile "$profile" -p ghostty-lib --lib --crate-type staticlib --target "$1"
|
||||
}
|
||||
lib() { echo "$tdir/$1/$dir/libghostty.a"; }
|
||||
|
||||
host_arch=$(uname -m)
|
||||
case $host_arch in
|
||||
arm64 | aarch64) native=aarch64-apple-darwin ;;
|
||||
*) native=x86_64-apple-darwin ;;
|
||||
esac
|
||||
|
||||
args=()
|
||||
case $target in
|
||||
universal)
|
||||
build aarch64-apple-darwin
|
||||
build x86_64-apple-darwin
|
||||
build aarch64-apple-ios
|
||||
build aarch64-apple-ios-sim
|
||||
|
||||
universal_dir="$tdir/universal-apple-darwin/$dir"
|
||||
run mkdir -p "$universal_dir"
|
||||
run lipo -create -output "$universal_dir/libghostty.a" \
|
||||
"$(lib aarch64-apple-darwin)" "$(lib x86_64-apple-darwin)"
|
||||
args+=(-library "$universal_dir/libghostty.a" -headers crates/ghostty-lib/include)
|
||||
args+=(-library "$(lib aarch64-apple-ios)" -headers crates/ghostty-lib/include)
|
||||
args+=(-library "$(lib aarch64-apple-ios-sim)" -headers crates/ghostty-lib/include)
|
||||
;;
|
||||
native)
|
||||
build "$native"
|
||||
args+=(-library "$(lib "$native")" -headers crates/ghostty-lib/include)
|
||||
;;
|
||||
*)
|
||||
echo "usage: $0 [universal|native] [PROFILE] [OUT]" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
|
||||
# The output path is static, so delete the old framework first.
|
||||
run rm -rf "$out"
|
||||
run xcodebuild -create-xcframework "${args[@]}" -output "$out"
|
||||
Reference in new issue
Block a user