Skip to content

Commit e3ef3a9

Browse files
authored
Merge pull request #9 from zcg/fix/windows-zls-exe-name
Fix Windows executable names for Zig and ZLS
2 parents 1549fc5 + 93e60c9 commit e3ef3a9

3 files changed

Lines changed: 46 additions & 27 deletions

File tree

src/command/install.zig

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@
44
//! Optionally installs ZLS (Zig Language Server) alongside Zig.
55

66
const std = @import("std");
7-
const zvm_mod = @import("../core/zvm.zig");
7+
88
const cli = @import("../cli.zig");
9-
const platform = @import("../core/platform.zig");
109
const Console = @import("../core/Console.zig");
11-
const version_map = @import("../network/version_map.zig");
10+
const crypto = @import("../core/crypto.zig");
11+
const platform = @import("../core/platform.zig");
12+
const zvm_mod = @import("../core/zvm.zig");
1213
const http_client = @import("../network/http_client.zig");
14+
const version_map = @import("../network/version_map.zig");
1315
const archive = @import("archive.zig");
14-
const crypto = @import("../core/crypto.zig");
1516

1617
/// Main entry point for the `zvm install` command.
1718
/// Resolves the requested version, checks if already installed,
@@ -45,7 +46,7 @@ pub fn run(
4546
if (version_map.getMasterVersion(vmap)) |remote_ver| {
4647
var ver_buf: [std.fs.max_path_bytes]u8 = undefined;
4748
const ver_path = zvm.versionPath(&ver_buf, version);
48-
const zig_path = try std.fmt.allocPrint(allocator, "{s}/zig", .{ver_path});
49+
const zig_path = try std.fmt.allocPrint(allocator, "{s}/{s}", .{ ver_path, platform.executableName("zig") });
4950
defer allocator.free(zig_path);
5051

5152
const result = std.process.run(allocator, zvm.io, .{
@@ -305,7 +306,7 @@ fn verifyInstall(
305306
) !bool {
306307
var ver_buf: [std.fs.max_path_bytes]u8 = undefined;
307308
const ver_path = zvm.versionPath(&ver_buf, version);
308-
const zig_path = try std.fmt.allocPrint(allocator, "{s}/zig", .{ver_path});
309+
const zig_path = try std.fmt.allocPrint(allocator, "{s}/{s}", .{ ver_path, platform.executableName("zig") });
309310
defer allocator.free(zig_path);
310311

311312
// Create a temporary test file in the cache directory
@@ -357,7 +358,7 @@ fn installZls(
357358
// Get the installed Zig version string
358359
var ver_buf: [std.fs.max_path_bytes]u8 = undefined;
359360
const ver_path = zvm.versionPath(&ver_buf, version);
360-
const zig_path = try std.fmt.allocPrint(allocator, "{s}/zig", .{ver_path});
361+
const zig_path = try std.fmt.allocPrint(allocator, "{s}/{s}", .{ ver_path, platform.executableName("zig") });
361362
defer allocator.free(zig_path);
362363

363364
const result = std.process.run(allocator, zvm.io, .{
@@ -431,6 +432,7 @@ fn installZls(
431432
return;
432433
},
433434
};
435+
const zls_exe_name = platform.executableName("zls");
434436

435437
// Download ZLS archive
436438
const zls_archive_name = if (std.mem.lastIndexOfScalar(u8, zls_tarball, '/')) |idx| zls_tarball[idx + 1 ..] else "zls-archive";
@@ -443,6 +445,7 @@ fn installZls(
443445
// Extract to a temporary directory
444446
var temp_buf: [std.fs.max_path_bytes * 2]u8 = undefined;
445447
const temp_dir = try std.fmt.bufPrint(&temp_buf, "{s}/zls-temp", .{zvm.cache_dir});
448+
std.Io.Dir.cwd().deleteTree(zvm.io, temp_dir) catch {};
446449
std.Io.Dir.cwd().createDirPath(zvm.io, temp_dir) catch {};
447450

448451
archive.extractArchive(allocator, zvm.io, zls_archive_path, temp_dir) catch {
@@ -459,18 +462,21 @@ fn installZls(
459462
var iter = temp_handle.iterate();
460463
while (try iter.next(zvm.io)) |entry| {
461464
// Flat layout: zls binary at root of archive
462-
if (entry.kind == .file and (std.mem.eql(u8, entry.name, "zls") or std.mem.eql(u8, entry.name, "zls.exe"))) {
465+
if (entry.kind == .file and std.mem.eql(u8, entry.name, zls_exe_name)) {
463466
var src_buf: [std.fs.max_path_bytes * 2]u8 = undefined;
464467
const src = try std.fmt.bufPrint(&src_buf, "{s}/{s}", .{ temp_dir, entry.name });
465468

466469
var dst_buf: [std.fs.max_path_bytes * 2]u8 = undefined;
467-
const dst = try std.fmt.bufPrint(&dst_buf, "{s}/{s}/zls", .{ zvm.data_dir, version });
470+
const dst = try std.fmt.bufPrint(&dst_buf, "{s}/{s}/{s}", .{ zvm.data_dir, version, zls_exe_name });
468471

469472
try platform.copyFile(zvm.io, src, dst);
473+
deleteLegacyZlsWithoutExtension(zvm, version, zls_exe_name);
470474

471-
_ = std.process.run(allocator, zvm.io, .{
472-
.argv = &.{ "chmod", "+x", dst },
473-
}) catch {};
475+
if (!platform.isWindows()) {
476+
_ = std.process.run(allocator, zvm.io, .{
477+
.argv = &.{ "chmod", "+x", dst },
478+
}) catch {};
479+
}
474480
console.success("Installed ZLS", .{});
475481
found = true;
476482
break;
@@ -486,18 +492,21 @@ fn installZls(
486492

487493
var inner_iter = inner_dir.iterate();
488494
while (try inner_iter.next(zvm.io)) |inner_entry| {
489-
if (std.mem.eql(u8, inner_entry.name, "zls") or std.mem.eql(u8, inner_entry.name, "zls.exe")) {
495+
if (inner_entry.kind == .file and std.mem.eql(u8, inner_entry.name, zls_exe_name)) {
490496
var src_buf: [std.fs.max_path_bytes * 2]u8 = undefined;
491497
const src = try std.fmt.bufPrint(&src_buf, "{s}/{s}/{s}", .{ temp_dir, entry.name, inner_entry.name });
492498

493499
var dst_buf: [std.fs.max_path_bytes * 2]u8 = undefined;
494-
const dst = try std.fmt.bufPrint(&dst_buf, "{s}/{s}/zls", .{ zvm.data_dir, version });
500+
const dst = try std.fmt.bufPrint(&dst_buf, "{s}/{s}/{s}", .{ zvm.data_dir, version, zls_exe_name });
495501

496502
try platform.copyFile(zvm.io, src, dst);
503+
deleteLegacyZlsWithoutExtension(zvm, version, zls_exe_name);
497504

498-
_ = std.process.run(allocator, zvm.io, .{
499-
.argv = &.{ "chmod", "+x", dst },
500-
}) catch {};
505+
if (!platform.isWindows()) {
506+
_ = std.process.run(allocator, zvm.io, .{
507+
.argv = &.{ "chmod", "+x", dst },
508+
}) catch {};
509+
}
501510
console.success("Installed ZLS", .{});
502511
found = true;
503512
break;
@@ -515,3 +524,13 @@ fn installZls(
515524
std.Io.Dir.cwd().deleteFile(zvm.io, zls_archive_path) catch {};
516525
std.Io.Dir.cwd().deleteTree(zvm.io, temp_dir) catch {};
517526
}
527+
528+
/// Remove the extensionless ZLS file left by older Windows installs.
529+
/// No-op on Linux/macOS where the expected executable name is already "zls".
530+
fn deleteLegacyZlsWithoutExtension(zvm: *zvm_mod.ZVM, version: []const u8, zls_exe_name: []const u8) void {
531+
if (std.mem.eql(u8, zls_exe_name, "zls")) return;
532+
533+
var legacy_dst_buf: [std.fs.max_path_bytes * 2]u8 = undefined;
534+
const legacy_dst = std.fmt.bufPrint(&legacy_dst_buf, "{s}/{s}/zls", .{ zvm.data_dir, version }) catch return;
535+
std.Io.Dir.cwd().deleteFile(zvm.io, legacy_dst) catch {};
536+
}

src/command/run.zig

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
//! Spawns the zig binary from the requested version directory as a child process.
33

44
const std = @import("std");
5-
const zvm_mod = @import("../core/zvm.zig");
5+
66
const Console = @import("../core/Console.zig");
7+
const platform = @import("../core/platform.zig");
8+
const zvm_mod = @import("../core/zvm.zig");
79

810
/// Run a Zig command using a specific installed version.
911
/// All arguments after the version are passed through to the zig binary.
@@ -20,10 +22,10 @@ pub fn run(
2022
std.process.exit(1);
2123
}
2224

23-
// Build the zig binary path: data_dir/<version>/zig
25+
// Build the zig binary path: data_dir/<version>/zig[.exe]
2426
var path_buf: [std.fs.max_path_bytes]u8 = undefined;
2527
const version_dir = zvm.versionPath(&path_buf, version);
26-
const zig_path = try std.fmt.allocPrint(allocator, "{s}/zig", .{version_dir});
28+
const zig_path = try std.fmt.allocPrint(allocator, "{s}/{s}", .{ version_dir, platform.executableName("zig") });
2729
defer allocator.free(zig_path);
2830

2931
// Build argv: [zig_path, arg1, arg2, ...]

src/command/upgrade.zig

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
const std = @import("std");
66
const builtin = @import("builtin");
77
const build_options = @import("build_options");
8-
const zvm_mod = @import("../core/zvm.zig");
8+
99
const Console = @import("../core/Console.zig");
1010
const platform = @import("../core/platform.zig");
11-
const http_client = @import("../network/http_client.zig");
1211
const update_check = @import("../core/update_check.zig");
12+
const zvm_mod = @import("../core/zvm.zig");
13+
const http_client = @import("../network/http_client.zig");
1314

1415
/// Search for the extracted binary inside self_dir, including subdirectories.
1516
/// The archive may extract into a versioned directory like zvm-v0.1.1-aarch64-macos/.
@@ -160,10 +161,7 @@ pub fn run(
160161
// Find the extracted binary and replace the current installation.
161162
// The archive may extract into a subdirectory (e.g. zvm-v0.1.1-aarch64-macos/zvm),
162163
// so search recursively.
163-
const exe_name = comptime switch (builtin.os.tag) {
164-
.windows => "zvm.exe",
165-
else => "zvm",
166-
};
164+
const exe_name = platform.executableName("zvm");
167165

168166
// Resolve the current zvm install directory
169167
const install_dir = blk: {
@@ -231,7 +229,7 @@ pub fn run(
231229
defer allocator.free(active);
232230
var ver_buf: [std.fs.max_path_bytes]u8 = undefined;
233231
const ver_path = zvm.versionPath(&ver_buf, active);
234-
const zig_path = std.fmt.allocPrint(allocator, "{s}/zig", .{ver_path}) catch return;
232+
const zig_path = std.fmt.allocPrint(allocator, "{s}/{s}", .{ ver_path, platform.executableName("zig") }) catch return;
235233
defer allocator.free(zig_path);
236234

237235
const ver_result = std.process.run(allocator, zvm.io, .{

0 commit comments

Comments
 (0)