Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* text=auto eol=lf
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ jobs:
platform: aarch64-linux
suffix: .so
target: aarch64-linux-gnu
- os: windows-latest
platform: x86_64-windows
suffix: .dll
target: x86_64-windows-gnu
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
Expand All @@ -104,14 +108,25 @@ jobs:
version: 0.15.2

- name: Build native module
shell: bash
run: |
if [ -n "${{ matrix.target }}" ]; then
zig build -Dtarget=${{ matrix.target }} -Doptimize=ReleaseFast -Dcpu=baseline
else
zig build -Doptimize=ReleaseFast -Dcpu=baseline
fi

- name: Upload Windows module artifact
if: runner.os == 'Windows'
uses: actions/upload-artifact@v4
with:
name: ghostel-module-${{ matrix.platform }}
path: |
zig-out/bin/ghostel-module${{ matrix.suffix }}
zig-out/bin/conpty-module${{ matrix.suffix }}

- name: Upload module artifact
if: runner.os != 'Windows'
uses: actions/upload-artifact@v4
with:
name: ghostel-module-${{ matrix.platform }}
Expand Down Expand Up @@ -139,10 +154,19 @@ jobs:
platform: aarch64-macos
suffix: .dylib
emacs_version: 'snapshot'
- os: windows-latest
platform: x86_64-windows
suffix: .dll
emacs_version: 'snapshot'
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: purcell/setup-emacs@master
if: runner.os != 'Windows'
with:
version: ${{ matrix.emacs_version }}
- uses: jcs090218/setup-emacs@master
if: runner.os == 'Windows'
with:
version: ${{ matrix.emacs_version }}

Expand All @@ -156,6 +180,7 @@ jobs:
name: ghostel-module-${{ matrix.platform }}

- name: Run native module tests
shell: bash
run: |
emacs --batch -Q -L . \
-l ert \
Expand Down
46 changes: 32 additions & 14 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,25 @@ jobs:
- os: ubuntu-latest
platform: x86_64-linux
suffix: .so
- os: macos-latest
platform: aarch64-macos
suffix: .dylib
- os: macos-latest
platform: x86_64-macos
suffix: .dylib
target: x86_64-macos
- os: ubuntu-latest
platform: aarch64-linux
suffix: .so
target: aarch64-linux-gnu
- os: windows-latest
platform: x86_64-windows
suffix: .dll
target: x86_64-windows-gnu
- os: windows-latest
platform: aarch64-windows
suffix: .dll
target: aarch64-windows-gnu
- os: macos-latest
platform: x86_64-macos
suffix: .dylib
target: x86_64-macos
- os: macos-latest
platform: aarch64-macos
suffix: .dylib
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
Expand All @@ -35,27 +43,37 @@ jobs:
version: 0.15.2

- name: Build native module
shell: bash
run: |
if [ -n "${{ matrix.target }}" ]; then
zig build -Dtarget=${{ matrix.target }} -Doptimize=ReleaseFast -Dcpu=baseline
else
zig build -Doptimize=ReleaseFast -Dcpu=baseline
fi

- name: Strip non-exported symbols (macOS)
if: runner.os == 'macOS'
run: strip -x ghostel-module${{ matrix.suffix }}
- name: Strip non-exported symbols
shell: bash
run: |
for f in zig-out/bin/*-module${{ matrix.suffix }}; do
strip -x "$f" 2>/dev/null || strip "$f" 2>/dev/null || true
done

- name: Rename artifact for release
- name: Package release artifact
shell: bash
run: |
mv ghostel-module${{ matrix.suffix }} \
ghostel-module-${{ matrix.platform }}${{ matrix.suffix }}
files=(
ghostel-module${{ matrix.suffix }}
)
if [[ "${{ matrix.os }}" == "windows-latest" ]]; then
files+=(conpty-module${{ matrix.suffix }})
fi
tar -C zig-out/bin -cJf ghostel-module-${{ matrix.platform }}.tar.xz "${files[@]}"

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ghostel-module-${{ matrix.platform }}
path: ghostel-module-${{ matrix.platform }}${{ matrix.suffix }}
path: ghostel-module-${{ matrix.platform }}.tar.xz

release:
needs: build
Expand Down
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ bench-quick:
bash bench/run-bench.sh --quick

clean:
rm -f ghostel-module.dylib ghostel-module.so
rm -f ghostel-module.dylib ghostel-module.so ghostel-module.dll
rm -f conpty-module.dll
rm -f $(ELC)
rm -rf zig-out .zig-cache
97 changes: 95 additions & 2 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const is_release = optimize != .Debug;
const target_os = target.result.os.tag;
const resolved_target = target.result;
const target_os = resolved_target.os.tag;
const emacs_module_dir = resolveEmacsModuleDir(b);
const ghostty_dep = b.dependency("ghostty", .{
.target = target,
Expand Down Expand Up @@ -42,6 +43,9 @@ pub fn build(b: *std.Build) void {
lib.setVersionScript(b.path("symbols.map"));
}
}
if (target_os == .windows) {
addWindowsRuntimeLibraries(b, lib, resolved_target);
}

b.installArtifact(lib);

Expand All @@ -51,7 +55,49 @@ pub fn build(b: *std.Build) void {
);
b.getInstallStep().dependOn(&copy_step.step);


// ConPTY module — Windows-only pseudoconsole backend.
if (target_os == .windows) {
const emacs_mod = b.createModule(.{
.root_source_file = b.path("src/emacs.zig"),
.target = target,
.optimize = optimize,
.link_libc = true,
});
emacs_mod.addSystemIncludePath(emacs_module_dir);

const dyn_loader_abi_mod = b.createModule(.{
.root_source_file = dynLoaderAbiSourcePath(b),
.target = target,
.optimize = optimize,
.link_libc = true,
});
dyn_loader_abi_mod.addImport("emacs", emacs_mod);

const conpty_mod = b.createModule(.{
.root_source_file = conptyModuleSourcePath(b),
.target = target,
.optimize = optimize,
.link_libc = true,
.strip = if (is_release) true else null,
});
conpty_mod.addSystemIncludePath(emacs_module_dir);
conpty_mod.addImport("emacs", emacs_mod);
conpty_mod.addImport("dyn_loader_abi", dyn_loader_abi_mod);

const conpty_lib = b.addLibrary(.{
.name = "conpty-module",
.linkage = .dynamic,
.root_module = conpty_mod,
});
addWindowsRuntimeLibraries(b, conpty_lib, resolved_target);
b.installArtifact(conpty_lib);

const copy_conpty = b.addInstallFile(
conpty_lib.getEmittedBin(),
"bin/conpty-module.dll",
);
b.getInstallStep().dependOn(&copy_conpty.step);
}
}

fn addModuleIncludes(
Expand Down Expand Up @@ -126,6 +172,53 @@ fn dirHasEmacsModuleHeader(allocator: std.mem.Allocator, dir: []const u8) bool {
fn moduleOutputName(target_os: std.Target.Os.Tag) []const u8 {
return switch (target_os) {
.macos => "../ghostel-module.dylib",
.windows => "bin/ghostel-module.dll",
else => "../ghostel-module.so",
};
}

fn conptyModuleSourcePath(b: *std.Build) std.Build.LazyPath {
const dep = b.dependency("emacs_util_mods", .{});
return dep.path("src/conpty/module.zig");
}

fn dynLoaderAbiSourcePath(b: *std.Build) std.Build.LazyPath {
const dep = b.dependency("emacs_util_mods", .{});
return dep.path("src/dyn-loader/abi.zig");
}

fn addWindowsRuntimeLibraries(
b: *std.Build,
lib: *std.Build.Step.Compile,
rt: std.Target,
) void {
lib.linkSystemLibrary("kernel32");
// Future-proofing for MSVC toolchain builds (CI currently uses gnu ABI).
if (rt.abi != .msvc) return;

lib.linkSystemLibrary("libvcruntime");

const arch = rt.cpu.arch;
const sdk = std.zig.WindowsSdk.find(b.allocator, arch) catch null;
if (sdk) |s| {
if (s.windows10sdk) |w10| {
const arch_str: []const u8 = switch (arch) {
.x86_64 => "x64",
.x86 => "x86",
.aarch64 => "arm64",
else => "x64",
};
const ucrt_lib_path = std.fmt.allocPrint(
b.allocator,
"{s}\\Lib\\{s}\\ucrt\\{s}",
.{ w10.path, w10.version, arch_str },
) catch null;

if (ucrt_lib_path) |path| {
lib.addLibraryPath(.{ .cwd_relative = path });
}
}
}

lib.linkSystemLibrary("libucrt");
}
4 changes: 4 additions & 0 deletions build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,9 @@
.url = "https://github.com/ghostty-org/ghostty/archive/01825411ab2720e47e6902e9464e805bc6a062a1.tar.gz",
.hash = "ghostty-1.3.2-dev-5UdBCzaaBwVjJOr-ltYINjybeEOAmLAauH5oq8-cdNGN",
},
.emacs_util_mods = .{
.url = "https://github.com/kiennq/emacs-util-mods/archive/9cfcbad1a402791b30207035041bcd56c233e033.tar.gz",
.hash = "N-V-__8AALWTAwBBgckZRfhk13frxax0Lb5asvETTxUBYroW",
},
},
}
Loading
Loading