const std = @import("std"); const common = @import("../build_common.zig"); //build_tclvfs86 - tclvfs (TRUNK, 1.4.2 era) loadable extension for the 8.6 //suite (G-099). Forked from suite_tcl90/build_tclvfs/build_tclvfs_shared.zig //(duplication-with-a-note posture) with the 8.6 differences: // - the dll is BUILT UNDER THE TCL8 TEA-NMAKE NAME (vfst.dll, e.g // vfs142t.dll - rules.vc PRJLIBNAME8 with PROJECT=vfs, SUFX 't' kept on a // tcl86 host): the configured library/vfs.tcl.in loads @PKG_LIB_FILE8@ // with NO explicit init symbol, so Tcl's load-time package-name guessing // derives the _Init name from the file's alpha prefix - 'vfs...' guesses // Vfs_Init (correct); a 'tclvfs...' spelling guesses Tclvfs_Init and // fails. @PKG_LIB_FILE9@ is still substituted so the script is complete. // - the 9.0 fork's ZIPFS_BUILD / TCL_WIDE_INT_TYPE defines dropped (9-isms). // - trunk vfs.c uses the same lowercase BUILD_vfs export guard as forTcl9 // (verified in the staged tree), so the guard define carries over. //The include-order shim carries over: under zig's mingw headers '__stat64' is //a MACRO for _stat64 (_mingw_stat64.h, pulled in by ); tcl.h's //'typedef struct __stat64 Tcl_StatBuf' parsed BEFORE that include binds a raw //forever-incomplete __stat64 tag (8.6 tcl.h uses the same typedef under //_WIN64). Compiling a generated TU that includes first makes the //macro visible when tcl.h parses. pub const TclvfsInfo = struct { dotversion: []const u8, //e.g "1.4.2" nodots: []const u8, //e.g "142" dll_file: []const u8, //the tcl8-named dll this suite builds, e.g "vfs142t.dll" dll9_file: []const u8, //tcl9 spelling for template substitution completeness major: []const u8, minor: []const u8, }; pub fn versionInfo(b: *std.Build, comptime tree_from_root: []const u8) TclvfsInfo { const dotversion = common.acInitVersion(b, tree_from_root); const nodots = common.stripChars(b, dotversion, "."); var parts = std.mem.splitScalar(u8, dotversion, '.'); const major = parts.next() orelse "0"; const minor = parts.next() orelse "0"; return .{ .dotversion = dotversion, .nodots = nodots, .dll_file = b.fmt("vfs{s}t.dll", .{nodots}), .dll9_file = b.fmt("tcl9vfs{s}.dll", .{nodots}), .major = b.dupe(major), .minor = b.dupe(minor), }; } //configure-products (vfs.tcl, pkgIndex.tcl) generated from their .in templates //at configure time. fn configuredContent(b: *std.Build, comptime subdir: []const u8, comptime template: []const u8, info: TclvfsInfo) []const u8 { var t: []const u8 = common.readSourceFile(b, subdir ++ "/" ++ template); t = common.replaceAll(b, t, "@PACKAGE_VERSION@", info.dotversion); t = common.replaceAll(b, t, "@PKG_LIB_FILE9@", info.dll9_file); t = common.replaceAll(b, t, "@PKG_LIB_FILE8@", info.dll_file); return t; } //install the tclvfs script package (lib/vfs) into the prefix - the two //generated configure-products, the library scripts + template dir copied, and //the dll alongside (vfs.tcl loads it from its own dir via ::vfs::self). pub fn install_tclvfs_package(comptime subdir: []const u8, b: *std.Build, tclvfs_compile: *std.Build.Step.Compile) !void { const info = versionInfo(b, subdir); const pkgsub = b.fmt("lib/vfs{s}", .{info.dotversion}); const install_scripts = b.addInstallDirectory(.{ .source_dir = b.path(subdir ++ "/library"), .install_dir = .prefix, .install_subdir = pkgsub, .include_extensions = &.{".tcl"}, }); b.getInstallStep().dependOn(&install_scripts.step); //template dir wholesale (carries non-.tcl support files such as tclIndex) const install_template = b.addInstallDirectory(.{ .source_dir = b.path(subdir ++ "/library/template"), .install_dir = .prefix, .install_subdir = b.fmt("{s}/template", .{pkgsub}), }); b.getInstallStep().dependOn(&install_template.step); const wf = b.addWriteFiles(); inline for (.{ .{ "library/vfs.tcl.in", "vfs.tcl" }, .{ "pkgIndex.tcl.in", "pkgIndex.tcl" }, }) |pair| { const gen = wf.add(pair[1], configuredContent(b, subdir, pair[0], info)); const inst = b.addInstallFileWithDir(gen, .prefix, b.fmt("{s}/{s}", .{ pkgsub, pair[1] })); b.getInstallStep().dependOn(&inst.step); } const dll_inst = b.addInstallFileWithDir(tclvfs_compile.getEmittedBin(), .prefix, b.fmt("{s}/{s}", .{ pkgsub, info.dll_file })); b.getInstallStep().dependOn(&dll_inst.step); } pub fn build_tclvfs86(comptime tcldir: []const u8, comptime subdir: []const u8, b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, stublib: *std.Build.Step.Compile) !*std.Build.Step.Compile { const info = versionInfo(b, subdir); const lib = b.addLibrary(.{ .linkage = .dynamic, .name = b.fmt("vfs{s}t", .{info.nodots}), .root_module = b.createModule(.{ .target = target, .optimize = optimize, }), }); var flags = std.array_list.Managed([]const u8).init(b.allocator); defer flags.deinit(); try flags.appendSlice(&.{ "-Wall", "-O3", "-fomit-frame-pointer" }); try flags.appendSlice(&.{ "-DPACKAGE_NAME=\"vfs\"", "-DPACKAGE_TARNAME=\"vfs\"", b.fmt("-DPACKAGE_VERSION=\"{s}\"", .{info.dotversion}), b.fmt("-DPACKAGE_STRING=\"vfs {s}\"", .{info.dotversion}), "-DPACKAGE_BUGREPORT=\"\"", "-DPACKAGE_URL=\"\"", //vfs.c guards paths behind HAVE_SYS_STAT_H and needs the //COMPLETE Tcl_StatBuf - see the include-order shim below. "-DHAVE_SYS_STAT_H=1", "-DTCL_CFG_OPTIMIZED=1", "-DUSE_TCL_STUBS=1", }); if (target.result.os.tag == .windows) { try flags.appendSlice(&.{ "-DBUILD_vfs=/**/", }); } lib.root_module.addIncludePath(b.path(subdir)); lib.root_module.addIncludePath(b.path(subdir ++ "/generic")); lib.root_module.addIncludePath(b.path(tcldir ++ "/generic")); if (target.result.os.tag == .windows) { lib.root_module.addIncludePath(b.path(tcldir ++ "/win")); } else { lib.root_module.addIncludePath(b.path(tcldir ++ "/unix")); } //Include-order shim (overlay TU - source trees never written): see the //header comment for the __stat64 macro-vs-tag story. const wf_shim = b.addWriteFiles(); const vfs_shim = wf_shim.add("vfs_statorder_shim.c", \\/* generated include-order shim - see build_tclvfs86.zig */ \\#include \\#include "vfs.c" \\ ); lib.root_module.addCSourceFile(.{ .file = vfs_shim, .flags = flags.items, }); lib.root_module.linkLibrary(stublib); lib.root_module.link_libc = true; lib.root_module.addWin32ResourceFile(.{ .file = b.path(subdir ++ "/win/tclvfs.rc"), .flags = &.{ b.fmt("-DPACKAGE_MAJOR={s}", .{info.major}), b.fmt("-DPACKAGE_MINOR={s}", .{info.minor}), b.fmt("-DPACKAGE_VERSION={s}", .{info.dotversion}), b.fmt("-DDOTVERSION={s}", .{info.dotversion}), b.fmt("-DCOMMAVERSION={s}", .{info.dotversion}), b.fmt("-DVERSION={s}", .{info.nodots}), }, }); //ignored for non-windows targets return lib; }