const std = @import("std"); const fs = std.fs; const builtin = @import("builtin"); const common = @import("build_common.zig"); const build_tommath = @import("build_libtommath/build_libtommath.zig").build_libtommath; const build_zlib = @import("build_zlib/build_zlib.zig").build_zlib; // ******************** // tclvfs experiments //const tclvfs_static = @import("build_tclvfs/build_tclvfs_static.zig"); const tclvfs_shared = @import("build_tclvfs/build_tclvfs_shared.zig"); // ******************** //vqtcl/vlerq removed from the suite (old-tclkit experiment; see note near the former //compile site and TEMP_REFERENCE/metakit + TEMP_REFERENCE/KitCreator for future work) const build_tclthread = @import("build_tclthread/build_tclthread.zig").build_tclthread; const build_tk = @import("build_tk/build_tk.zig").build_tk; //G-098 const TkBuild = @import("build_tk/build_tk.zig").TkBuild; //G-103 const tcl_major_version = "9"; const tcl_nodot_version = "90"; //VER in makefile const tcl_dot_version = "9.0"; //VERSION in makefile const tcl_patch_suffix = "0"; const tcl_source_folder = "../tcl905"; const tcl_patch_level = tcl_dot_version ++ tcl_patch_suffix; //e.g 9.0b2 - generic/tcl.h TCL_PATCH_LEVEL (note TCL_PATCH_LEVEL in configure may be different e.g just the suffix "b2") // e.g result: tclsh90.exe & tclsh90s.exe const tclsh_shared = "tclsh" ++ tcl_nodot_version; //leave off exe suffix - zig adds .exe automatically for windows const tclsh_static = "tclsh" ++ tcl_nodot_version ++ "s"; //jmn3 var static_build: bool = true; //minimum zig version //const req_zig_version = "0.13.0"; //comptime { // const req_zig = std.SemanticVersion.parse(req_zig_version) catch unreachable; // if (builtin.zig_version.order(req_zig) == .lt) { // @compileError(std.fmt.comptimePrint( // "Your Zig version v{} does not meet the minimum build requirement of v{}", // .{ builtin.zig_version, req_zig }, // )); // } //} comptime { //The suite pin (G-102 acceptance: the recipe records the zig version it is //written against). The recipe is 0.16-API and does not build under 0.14/0.15; //punk-getzig materializes the pinned toolchain (see README Pinned zig). const required_zig = "0.16.0"; const current_zig = builtin.zig_version; const min_zig = std.SemanticVersion.parse(required_zig) catch unreachable; if (current_zig.order(min_zig) == .lt) { const error_message = \\This recipe is written against zig {} (see README Pinned zig) and \\does not build with older zigs. bin/punk-getzig fetches the pinned \\toolchain; https://ziglang.org/download/ hosts releases. \\ ; @compileError(std.fmt.comptimePrint(error_message, .{min_zig})); } } const targets: []const std.Target.Query = &.{ //.{ .cpu_arch = .aarch64, .os_tag = .macos }, //.{ .cpu_arch = .aarch64, .os_tag = .linux }, //.{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .musl }, // tried this^ - built but: // apparently when linking against musl libc for fully static binaries, the dlopen function will only be a stub // which stops us loading binary modules. //From andrewrk on https://github.com/luvit/luvi/issues/231 //The other option zig cc provides you is "static except glibc" builds, //and if you pick an old enough glibc version (e.g. matching holy-build-box) //then your binary tarballs will work on any linux distro that uses glibc and //standard dynamic linker path (which is most). This is the $arch-linux-gnu target. .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .gnu }, .{ .cpu_arch = .x86_64, .os_tag = .windows }, }; pub fn build(b: *std.Build) !void { //G-102 invocation modes. This recipe serves two build roots: // STAGED mode - build root is the staged recipe copy (_build//build) with // the source trees materialized beside it (../tcl905 etc) either by suite.tcl's // fossil flow or by this recipe's own bootstrap staging. Full build graph. // BOOTSTRAP mode - build root is the TRACKED suite dir (sources.config present, // no ../tcl905): only the staging steps are registered - 'zig build stage' // materializes the pinned build.zig.zon sources + a recipe copy into the // _build stage, and 'zig build bootstrap' chains the staged build after it. // This is the no-tclsh entry point. if (!common.pathExists(b, tcl_source_folder)) { if (common.pathExists(b, "sources.config")) { try bootstrapMode(b); return; } @panic("suite recipe: no source trees found beside the recipe (" ++ tcl_source_folder ++ " missing). Use 'zig build stage' (or bootstrap) from the tracked suite dir for the " ++ "pinned zon flow, or 'tclsh suite.tcl build' for the fossil dev flow."); } const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); //set up and display some of the same prefix-dependent vars as Makefile for maintainability const prefix = try std.fmt.allocPrint(b.allocator, "{s}", .{b.install_path}); const exec_prefix = prefix; std.debug.print("prefix {s}\n", .{prefix}); std.debug.print("exec_prefix {s}\n", .{exec_prefix}); const bindir = b.pathJoin(&.{ prefix, "bin" }); std.debug.print("bindir {s}\n", .{bindir}); const libdir = b.pathJoin(&.{ prefix, "lib" }); //TCL_PACKAGE_PATH ? std.debug.print("libdir {s}\n", .{libdir}); const includedir = b.pathJoin(&.{ prefix, "include" }); std.debug.print("includedir {s}\n", .{includedir}); const datarootdir = b.pathJoin(&.{ prefix, "share" }); std.debug.print("datarootdir {s}\n", .{datarootdir}); const runstatedir = b.pathJoin(&.{ prefix, "run" }); std.debug.print("runstatedir {s}\n", .{runstatedir}); const mandir = b.pathJoin(&.{ prefix, "man" }); std.debug.print("mandir {s}\n", .{mandir}); const tcl_library = b.pathJoin(&.{ prefix, "lib", "tcl" ++ tcl_dot_version }); std.debug.print("tcl_library {s}\n", .{tcl_library}); const bin_install_dir = bindir; std.debug.print("bin_install_dir {s}\n", .{bin_install_dir}); const lib_install_dir = libdir; //TCL_PACKAGE_PATH ? std.debug.print("lib_install_dir {s}\n", .{lib_install_dir}); const script_install_dir = tcl_library; std.debug.print("script_install_dir {s}\n", .{script_install_dir}); const script_install_dir_rel = b.pathJoin(&.{ "lib", "tcl" ++ tcl_dot_version }); const module_install_dir = b.pathJoin(&.{ script_install_dir, "..", "tcl" ++ tcl_major_version }); std.debug.print("module_install_dir {s}\n", .{module_install_dir}); const module_install_dir_rel = b.pathJoin(&.{ script_install_dir_rel, "..", "tcl" ++ tcl_major_version }); const include_install_dir = tcl_library; std.debug.print("include_install_dir {s}\n", .{include_install_dir}); //target.result.os.tag = . //mac dylib? var tcl_shlib_ext: []const u8 = undefined; switch (target.result.os.tag) { .windows => { tcl_shlib_ext = try std.fmt.allocPrint(b.allocator, "{s}", .{".dll"}); }, .macos => { tcl_shlib_ext = try std.fmt.allocPrint(b.allocator, "{s}", .{".dylib"}); }, else => { tcl_shlib_ext = try std.fmt.allocPrint(b.allocator, "{s}", .{".so"}); }, } const tcl_dll_file = try std.fmt.allocPrint(b.allocator, "tcl" ++ tcl_nodot_version ++ "{s}", .{tcl_shlib_ext}); std.debug.print("tcl_dll_file {s}\n", .{tcl_dll_file}); //const tcl_lib_file = "libtcl" ++ tcl_nodot_version ++ ".dll.a"; const tcl_lib_file = try std.fmt.allocPrint(b.allocator, "libtcl" ++ tcl_nodot_version ++ "{s}" ++ ".a", .{tcl_shlib_ext}); std.debug.print("tcl_lib_file {s}\n", .{tcl_lib_file}); const tcl_zip_file = "libtcl" ++ tcl_dot_version ++ tcl_patch_suffix ++ ".zip"; std.debug.print("tcl_zip_file {s}\n", .{tcl_zip_file}); const tcl_vfs_path = b.pathJoin(&.{ "libtcl.vfs", "tcl_library" }); std.debug.print("tcl_vfs_path {s}\n", .{tcl_vfs_path}); const tcl_vfs_root = "libtcl.vfs"; std.debug.print("tcl_vfs_root {s}\n", .{tcl_vfs_root}); const tcl_stub_lib_file = "libtclstub.a"; std.debug.print("tcl_stub_lib_file {s}\n", .{tcl_stub_lib_file}); //const tcl_stub_lib_file = "libtclstub87.a"; const dde_dll_file = "tcl9dde14.dll"; std.debug.print("dde_dll_file {s}\n", .{dde_dll_file}); const dde_dll_file8 = "tcldde14.dll"; std.debug.print("dde_dll_file8 {s}\n", .{dde_dll_file8}); const reg_dll_file = "tcl9registry13.dll"; std.debug.print("reg_dll_file {s}\n", .{reg_dll_file}); const reg_dll_file8 = "tclregistry13.dll"; std.debug.print("reg_dll_file8 {s}\n", .{reg_dll_file8}); //pass the subdirectory as the build_tcl90/build_libtommath sees it ? //const tommath_sourcedir = b.pathJoin(&.{ "..", "tcl" ++ tcl_nodot_version, "libtommath" }); const tommath_sourcedir = tcl_source_folder ++ "/libtommath"; //var tommath_sourcedir: []const u8 = undefined; //if (target.result.os.tag == .windows) { // //tommath_sourcedir = tcl_source_folder ++ "/libtommath"; // tommath_sourcedir = b.pathJoin(&.{ "..", "tcl" ++ tcl_nodot_version, "libtommath" }); //} else { // //tommath_sourcedir = b.pathJoin(&.{ "..", "libtommath" }); // tommath_sourcedir = b.pathJoin(&.{ "..", "tcl" ++ tcl_nodot_version, "libtommath" }); //} //const tommath_lib_compile = try build_tommath(tommath_sourcedir, b, target, optimize); const zlib_sourcedir = tcl_source_folder ++ "/compat/zlib"; //const zlib_sourcedir = "../zlib" ++ "/compat/zlib"; var zlib_lib_compile: *std.Build.Step.Compile = undefined; zlib_lib_compile = try build_zlib(zlib_sourcedir, b, target, optimize); //if (target.result.os.tag != .windows) { //} // ================================================ //Generated configure-products (G-102): created into the build cache and consumed //via overlay include dirs / overlay rc copies. Source trees (staged fossil //checkouts or zon-fetched trees) are never written - suite.tcl formerly generated //these files into the checkout (and before 2026-07-21 this recipe carried an //addUpdateSourceFiles tree-write variant behind the unused 'prepare-source' step). // //tclUuid.h (tclEvent.c/tclTest.c #include it; upstream configure generates it) const wrap_exe = b.addExecutable(.{ .name = "wrapfiletofile", .root_module = b.createModule(.{ .root_source_file = b.path("tools/wrapfiletofile.zig"), .target = b.graph.host, }), }); const wrap_run = b.addRunArtifact(wrap_exe); wrap_run.addArgs(&.{ "-prefix", "#define TCL_VERSION_UUID \\", "-prefixnl", "1", "-input", }); wrap_run.addFileArg(b.path(tcl_source_folder ++ "/manifest.uuid")); wrap_run.addArg("-output"); const tcluuid_file1 = wrap_run.addOutputFileArg("tclUuid.h"); //include-dir overlay: using the generator's output dir as an include path also //gives each consuming compile its dependency on the generation step. Added FIRST //at each consuming module so a stale tree-written tclUuid.h (pre-G-102 flows) //can never shadow the generated one. const tcluuid_include_dir = tcluuid_file1.dirname(); //tclsh.exe.manifest (tclsh.rc references it; upstream configure substitutes the //.in). Generated at configure time; tclsh.rc is compiled from an overlay COPY //in the same generated dir because rc resource references resolve //rc-file-relative BEFORE include paths - a stale manifest beside the tree's //tclsh.rc would otherwise win over any include-path overlay. const tclh_content = common.readSourceFile(b, tcl_source_folder ++ "/generic/tcl.h"); const tcl_h_version = common.parseDefineString(tclh_content, "TCL_VERSION") orelse @panic("TCL_VERSION not found in tcl.h"); const tcl_h_patchlevel = common.parseDefineString(tclh_content, "TCL_PATCH_LEVEL") orelse @panic("TCL_PATCH_LEVEL not found in tcl.h"); const tcl_win_version = common.winResourceVersion(b, tcl_h_version, tcl_h_patchlevel); std.debug.print("tcl.h: TCL_PATCH_LEVEL {s} (TCL_WIN_VERSION {s})\n", .{ tcl_h_patchlevel, tcl_win_version }); const tclsh_manifest_content = common.replaceAll(b, common.replaceAll(b, common.readSourceFile(b, tcl_source_folder ++ "/win/tclsh.exe.manifest.in"), "@TCL_WIN_VERSION@", tcl_win_version), "@MACHINE@", "AMD64"); const wf_tclshrc = b.addWriteFiles(); _ = wf_tclshrc.add("tclsh.exe.manifest", tclsh_manifest_content); const tclshrc_overlay = wf_tclshrc.addCopyFile(b.path(tcl_source_folder ++ "/win/tclsh.rc"), "tclsh.rc"); //Runs of the built (non-zip) shell execute the CACHED artifact, which has no //../lib/tcl9.0 beside it - point such runs at the source tree's own script //library so init.tcl resolves (the zip shell's runs must NOT get this: its //attached library is the thing under test). const tcl_library_src = common.replaceAll(b, b.pathFromRoot(tcl_source_folder ++ "/library"), "\\", "/"); // ================================================ var ac_flags = std.array_list.Managed([]const u8).init(b.allocator); defer ac_flags.deinit(); try ac_flags.appendSlice(&.{ "-pipe", "-finput-charset=UTF-8", "-DPACKAGE_NAME=\"tcl\"", "-DPACKAGE_TARNAME=\"tcl\"", "-DPACKAGE_VERSION=\"" ++ tcl_dot_version ++ "\"", "-DPACKAGE_STRING=\"tcl " ++ tcl_dot_version ++ "\"", "-DPACKAGE_BUGREPORT=\"\"", "-DPACKAGE_URL=\"\"", "-DTCL_CFGVAL_ENCODING=\"utf-8\"", //WARNING - it is not enough to set TCL_COMPILE_DEBUG & TCL_COMPILE_STATS to 0 - if they exist they will affect performance //"-DTCL_COMPILE_DEBUG=0", //"-DTCL_COMPILE_STATS=0", "-DTCL_CFG_DO64BIT=1", "-DHAVE_NO_SEH=1", //required for tclWinFCmd.c or we get undeclared identifier '__try' //JMN2 //"-DHAVE_CPUID=1", //"-DHAVE_STDLIB_H=1", //"-DHAVE_STRING_H=1", //"-DHAVE_INTTYPES_H=1", //"-DHAVE_STDINT_H=1", //"-DHAVE_STRINGS_H=1", //"-DHAVE_SYS_STAT_H=1", //"-DHAVE_SYS_TYPES_H=1", //"-DHAVE_UNISTD_H=1", //probably needs to be 0 if using msvc ? //"-DSTDC_HEADERS=1", //"-DNDEBUG=1", //"-DHAVE_STDBOOL_H=1", //"-DHAVE_CAST_TO_UNION=1", //"-DHAVE_INTPTR_T=1", //"-DHAVE_UINTPTR_T=1", //"-DHAVE_INTRIN_H=1", "-DMP_64BIT=1", "-DHAVE_ZLIB=1", "-DZIPFS_BUILD=1", //JMN todo "-DTCL_CFG_OPTIMIZED=1", "-DTCL_THREADS=1", //probably not required try std.fmt.allocPrint(b.allocator, "-DTCL_PACKAGE_PATH=\"{s}\"", .{lib_install_dir}), }); //"-DTCL_NO_DEPRECATED", //"-fno-lto", //"-DMODULE_SCOPE=extern", if (target.result.os.tag == .windows) { try ac_flags.appendSlice(&.{ //"-DTCL_WITH_EXTERNAL_TOMMATH", //required for windows when using tcltommath that *doesn't* come with tcl (?) "-DHAVE_STDIO_H=1", "-DMODULE_SCOPE=extern", "-DHAVE_WSPIAPI_H=1", //windows specific? }); //jjj //try ac_flags.appendSlice(&.{ // "-DHAVE_STDIO_H=1", // "-DHAVE_STDLIB_H=1", // "-DHAVE_STRING_H=1", // "-DHAVE_INTTYPES_H=1", // "-DHAVE_STDINT_H=1", // "-DHAVE_STRINGS_H=1", // "-DHAVE_SYS_STAT_H=1", // "-DHAVE_SYS_TYPES_H=1", // "-DHAVE_UNISTD_H=1", // "-DHAVE_SYS_TIME_H=1", // // // "-DNO_SYS_WAIT_H=1", // "-DNO_DLFCN_H=1", // "-DHAVE_SYS_PARAM_H=1", // // // "-DHAVE_STDBOOL_H=1", // // //}); //added to try to fix 'linsert {} 0 a b' crash //try ac_flags.appendSlice(&.{ // "-DSTDC_HEADERS=1", // "-D_REENTRANT=1", // "-D_THREAD_SAFE=1", // "-DHAVE_PTHREAD_ATTR_SETSTACKSIZE=1", // "-DHAVE_DECL_PTHREAD_MUTEX_RECURSIVE=1", // // // "-DMODULE_SCOPE=extern", // "-DHAVE_CAST_TO_UNION=1", // "-DNDEBUG=1", // "-DMP_PREC=4", // "-D_FILE_OFFSET_BITS=64", // "-DHAVE_LSEEK64=1", // "-DHAVEGETCWD=1", // "-DHAVE_MKSTEMP=1", // "-DNO_GETWD=1", // "-DNO_WAIT3=1", // "-DNO_FORK=1", // "-DNO_MKNOD=1", // "-DNO_TCDRAIN=1", // "-DNO_UNAME=1", // "-DNOREALPATH=1", // "-DNEED_FAKE_RFC2553=1", // "-DHAVE_DECL_GETHOSTBYNAME_R=0", // "-DHAVE_DECL_GETHOSTBYADDR_R=0", // "-DNO_FD_SET=1", // // // "-DHAVE_MKTIME=1", // "-DHAVE_TIMEZONE_VAR=1", // "-DHAVE_STRUCT_STAT_ST_RDEV=1", // "-DNO_FSTATFS=1", // "-Duid_t=int", // "-Dgid_t=int", // "-DHAVE_INTPTR_T=1", // "-DHAVE_UINTPTR_T=1", // "-DNO_UNION_WAIT=1", // "-DHAVE_SIGNED_CHAR=1", // "-DHAVE_PUTENV_THAT_COPIES=1", // "-DTCL_UNLOAD_DLLS=1", // "-DHAVE_CPUID=1", //}); //try ac_flags.appendSlice(&.{ // "-Dsocklen_t=int", //}); //-DHAVE_ZLIB being deprecated 2024-10 try ac_flags.appendSlice(&.{ "-DHAVE_ZLIB=1", "-DZIPFS_BUILD=1", //"-DSUPPORT_BUILTIN_ZIP_INSTALL=1", // won't compile win 2024-10-11 - bug reported }); try ac_flags.appendSlice(&.{ // should be for static build only(?) "-DTCL_WITH_INTERNAL_ZLIB", "-DTCL_TOMMATH", }); } else { try ac_flags.appendSlice(&.{ //"-DTCL_WITH_EXTERNAL_TOMMATH", "-DHAVE_MEMORY_H=1", "-DMODULE_SCOPE=extern __attribute__((__visibility__(\"hidden\")))", "-DHAVE_HIDDEN=1", "-DHAVE_SYS_PARAM_H=1", "-DUSE_THREAD_ALLOC=1", "-D_REENTRANT=1", "-D_THREAD_SAFE=1", "-DHAVE_PTHREAD_ATTR_SETSTACKSIZE=1", "-DHAVE_PTHREAD_ATFORK=1", "-D_LARGEFILE64_SOURCE=1", "-DTCL_WIDE_INT_IS_LONG=1", "-DHAVE_GETCWD=1", "-DHAVE_MKSTEMP=1", "-DHAVE_OPENDIR=1", "-DHAVE_STRTOL=1", "-DHAVE_WAITPID=1", "-DHAVE_GETNAMEINFO=1", "-DHAVE_GETADDRINFO=1", "-DHAVE_FREEADDRINFO=1", "-DHAVE_GAI_STRERROR=1", "-DHAVE_STRUCT_ADDRINFO=1", "-DHAVE_STRUCT_IN6_ADDR=1", "-DHAVE_STRUCT_SOCKADDR_IN6=1", "-DHAVE_STRUCT_SOCKADDR_STORAGE=1", "-DHAVE_GETPWUID_R_5=1", "-DHAVE_GETPWUID_R=1", "-DHAVE_GETPWNAM_R_5=1", "-DHAVE_GETPWNAM_R=1", "-DHAVE_GETGRGID_R_5=1", "-DHAVE_GETGRGID_R=1", "-DHAVE_GETGRNAME_R_5=1", "-DHAVE_GETGRNAME_R=1", "-DHAVE_DECL_GETHOSTBYNAME_R=1", "-DHAVE_GETHOSTBYNAME_R_6=1", "-DHAVE_GETHOSTBYNAME_R=1", "-DHAVE_DECL_GETHOSTBYADDR_R=1", "-DHAVE_GETHOSTBYADDR_R_8=1", "-DHAVE_GETHOSTBYADDR_R=1", "-DHAVE_TERMIOS_H=1", "-DHAVE_SYS_IOCTL_H=1", "-DHAVE_SYS_TIME_H=1", "-DTIME_WITH_SYS_TIME=1", "-DHAVE_GMTIME_R=1", "-DHAVE_LOCALTIME_R=1", "-DHAVE_TM_GMTOFF=1", "-DHAVE_TIMEXONE_VAR=1", "-DHAVE_STRUCT_STAT_ST_BLOCKS=1", "-DHAVE_STRUCT_STAT_ST_BLKSIZE=1", "-DHAVE_BLKCNT_T=1", "-DNO_UNION_WAIT=1", "-DHAVE_SIGNED_CHAR=1", "-DHAVE_LANGINFO=1", "-DHAVE_MKSTEMPS=1", //"-DHAVE_FTS=1", "-DTCL_UNLOAD_DLLS=1", //"-fPIC", try std.fmt.allocPrint(b.allocator, "-DTCL_SHLIB_EXT=\"{s}\"", .{tcl_shlib_ext}), try std.fmt.allocPrint(b.allocator, "-DTCL_LIBRARY=\"{s}\"", .{tcl_library}), }); } //msvc - test //try ac_flags.appendSlice(&.{ // "-Dinline=__inline", // "-D_CRT_SECURE_NO_DEPRECATE", // "-D_CRT_NONSTDC_NO_DEPRECATE" //}); //"-Wl,-input-charset=UTF-8", //"-finput-charset=UTF-8" var warning_flags = std.array_list.Managed([]const u8).init(b.allocator); defer warning_flags.deinit(); try warning_flags.appendSlice(&.{ "-Wall", "-Wextra", "-Wshadow", "-Wundef", "-Wwrite-strings", "-Wpointer-arith", "-Wc++-compat", "-fextended-identifiers", }); //"-Werror=return-type", var optimize_flags = std.array_list.Managed([]const u8).init(b.allocator); defer optimize_flags.deinit(); //windows? //try optimize_flags.appendSlice(&.{ // "-O0", // "-fomit-frame-pointer", // //"-g0", //}); //try optimize_flags.appendSlice(&.{ // "-O3", // "-fomit-frame-pointer", // //"-g0", //}); try optimize_flags.appendSlice(&.{ "-O3", //?? //"-O2", "-fomit-frame-pointer", //"-g", "-finput-charset=UTF-8", }); //"-fomit-frame-pointer", var c_flags = std.array_list.Managed([]const u8).init(b.allocator); defer c_flags.deinit(); try c_flags.appendSlice(optimize_flags.items); try c_flags.appendSlice(&.{ "-DMP_FIXED_CUTOFFS", "-fno-sanitize=undefined", //required on windows to fix: linsert {} 0 a a crash "-fno-sanitize-trap=undefined", //"-DMP_NO_STDINT", //"-D__USE_MINGW_ANSI_STDIO=0", //"-DTCL_MEM_DEBUG", //must be defined for all modules, or undefined for all modules that are going to be linked together }); if (target.result.os.tag == .linux) { //required to avoid error on linux-musl (at least) - review - check other targets try c_flags.appendSlice(&.{ "-fno-sanitize=undefined", }); //without it, gdb gives: //Program received signal SIGILL, Illegal instruction. //0x0000000001b6c0e6 in Tcl_UniCharToUtfDString (uniStr=0x7fffffffd605, uniLength=0, dsPtr=0x7fffffffcc00) at /mnt/c/buildtcl/2024zig/tcl90/generic/tclUtf.c:332 //332 while (*w != '\0') { } var config_flags = std.array_list.Managed([]const u8).init(b.allocator); defer config_flags.deinit(); //try config_flags.appendSlice(base_flags.items); //can't use ++ for non comptime values such as libdir,bindir... try config_flags.appendSlice(&.{ try std.fmt.allocPrint(b.allocator, "-DCFG_RUNTIME_LIBDIR=\"{s}\"", .{libdir}), try std.fmt.allocPrint(b.allocator, "-DCFG_RUNTIME_BINDIR=\"{s}\"", .{bindir}), try std.fmt.allocPrint(b.allocator, "-DCFG_RUNTIME_INCDIR=\"{s}\"", .{includedir}), try std.fmt.allocPrint(b.allocator, "-DCFG_RUNTIME_SCRDIR=\"{s}\"", .{tcl_library}), try std.fmt.allocPrint(b.allocator, "-DCFG_RUNTIME_DOCDIR=\"{s}\"", .{mandir}), }); //todo - set default install dirs: windows c:/tcl90, bsd /usr/local/tcl90?, linux /opt/tcl90? try config_flags.appendSlice(&.{ try std.fmt.allocPrint(b.allocator, "-DCFG_INSTALL_LIBDIR=\"{s}\"", .{libdir}), try std.fmt.allocPrint(b.allocator, "-DCFG_INSTALL_BINDIR=\"{s}\"", .{bindir}), try std.fmt.allocPrint(b.allocator, "-DCFG_INSTALL_INCDIR=\"{s}\"", .{includedir}), try std.fmt.allocPrint(b.allocator, "-DCFG_INSTALL_SCRDIR=\"{s}\"", .{tcl_library}), try std.fmt.allocPrint(b.allocator, "-DCFG_INSTALL_DOCDIR=\"{s}\"", .{mandir}), }); //CFG_RUNTIME_DLLFILE used also on unix? seems to be in generic/tclPkgConfig.c try config_flags.appendSlice(&.{ //"-DCFG_RUNTIME_DLLFILE=\"tcl" ++ tcl_nodot_version ++ ".dll\"", try std.fmt.allocPrint(b.allocator, "-DCFG_RUNTIME_DLLFILE=\"{s}\"", .{tcl_dll_file}), }); //BUILD_ needs to be defined for windows if (target.result.os.tag == .windows) { try config_flags.appendSlice(&.{ "-DBUILD_tcl", }); } //CC_SWITCHES = -I"${BUILD_DIR}" -I"${GENERIC_DIR_NATIVE}" -I"${TOMMATH_DIR_NATIVE}" \ //-I"${ZLIB_DIR_NATIVE}" -I"${WIN_DIR_NATIVE}" \ //${CFLAGS} ${CFLAGS_WARNING} ${SHLIB_CFLAGS} -DMP_PREC=4 \ //${AC_FLAGS} ${COMPILE_DEBUG_FLAGS} ${NO_DEPRECATED_FLAGS} var cc_flags = std.array_list.Managed([]const u8).init(b.allocator); defer cc_flags.deinit(); try cc_flags.appendSlice(c_flags.items); try cc_flags.appendSlice(warning_flags.items); try cc_flags.appendSlice(config_flags.items); try cc_flags.appendSlice(&.{ "-DMP_PREC=4", }); try cc_flags.appendSlice(ac_flags.items); var base_flags = std.array_list.Managed([]const u8).init(b.allocator); defer base_flags.deinit(); try base_flags.appendSlice(&.{ "-municode", "-Wl,--subsystem,windows", //"-DTCL_MEM_DEBUG", //must be defined for all modules, or undefined for all modules that are going to be linked together }); if (target.result.os.tag == .windows) { //TODO win64-arm, win32(?) //b.installFile(tcl_source_folder ++ "/compat/zlib/win64/zlib1.dll", "bin/zlib1.dll"); b.installFile(tcl_source_folder ++ "/libtommath/win64/libtommath.dll", "bin/libtommath.dll"); //TODO - flag to allow independent building of static vs shared build to give failure independence // if STATIC_BUILD //b.installFile(tcl_source_folder ++ "/compat/zlib/win64/zlib1.dll", "lib/zdll.lib"); b.installFile(tcl_source_folder ++ "/libtommath/win64/tommath.lib", "lib/tommath.lib"); } // ================================================================ //tcl8.7? //STUB_OBJS = \ // tclStubLib.$(OBJEXT) \ // tclTomMathStubLib.$(OBJEXT) \ // tclOOStubLib.$(OBJEXT) \ // tclWinPanic.$(OBJEXT) //tcl9 //STUB_OBJS = //tclStubLib.$(OBJEXT) //tclStubCall.$(OBJEXT) //tclStubLibTbl.$(OBJEXT) //tclTomMathStubLib.$(OBJEXT) //tclOOStubLib.$(OBJEXT) //tclWinPanic.$(OBJEXT) const finalstublib = b.addLibrary(.{ .linkage = .static, .name = if (target.result.os.tag == .windows) "libtclstub" else "tclstub", .root_module = b.createModule(.{ .target = target, .optimize = optimize, }), }); var stublib_flags = std.array_list.Managed([]const u8).init(b.allocator); try stublib_flags.appendSlice(cc_flags.items); try stublib_flags.appendSlice(&.{ "-DSTATIC_BUILD", "-fno-lto", }); //finalstublib.root_module.addIncludePath(.{ .path = tcl_source_folder ++ "/generic" }); //finalstublib.root_module.addIncludePath(.{ .src_path = tcl_source_folder ++ "/generic" }); finalstublib.root_module.addIncludePath(b.path(tcl_source_folder ++ "/generic")); if (target.result.os.tag == .windows) { //finalstublib.root_module.addIncludePath(.{ .path = tcl_source_folder ++ "/win" }); finalstublib.root_module.addIncludePath(b.path(tcl_source_folder ++ "/win")); } else { //finalstublib.root_module.addIncludePath(.{ .path = tcl_source_folder ++ "/unix" }); finalstublib.root_module.addIncludePath(b.path(tcl_source_folder ++ "/unix")); } if (target.result.os.tag == .windows) { finalstublib.root_module.addIncludePath(b.path(tcl_source_folder ++ "/libtommath")); finalstublib.root_module.addIncludePath(b.path(tcl_source_folder ++ "/compat/zlib")); } else { finalstublib.root_module.addIncludePath(b.path(tommath_sourcedir)); finalstublib.root_module.addIncludePath(b.path(zlib_sourcedir)); } finalstublib.root_module.addCSourceFile(.{ .file = b.path(tcl_source_folder ++ "/generic/tclStubLib.c"), .flags = stublib_flags.items, }); //tcl9 var stublib_call_flags = std.array_list.Managed([]const u8).init(b.allocator); try stublib_call_flags.appendSlice(cc_flags.items); try stublib_call_flags.appendSlice(config_flags.items); try stublib_call_flags.appendSlice(&.{ "-DSTATIC_BUILD", //try std.fmt.allocPrint(b.allocator, "-DCFG_RUNTIME_BINDIR=\"{s}\"", .{ bindir }), }); //if (target.result.os.tag == .windows) { // try stublib_call_flags.appendSlice(&.{ // try std.fmt.allocPrint(b.allocator, "-DCFG_RUNTIME_DLLFILE=\"{s}\"", .{ tcl_dll_file }), // }); //} finalstublib.root_module.addCSourceFile(.{ .file = b.path(tcl_source_folder ++ "/generic/tclStubCall.c"), .flags = stublib_call_flags.items, }); //tcl9 var stublib_tbl_flags = std.array_list.Managed([]const u8).init(b.allocator); try stublib_tbl_flags.appendSlice(cc_flags.items); try stublib_tbl_flags.appendSlice(&.{ "-DSTATIC_BUILD", }); finalstublib.root_module.addCSourceFile(.{ .file = b.path(tcl_source_folder ++ "/generic/tclStubLibTbl.c"), .flags = stublib_tbl_flags.items, }); var stublib_tom_flags = std.array_list.Managed([]const u8).init(b.allocator); try stublib_tom_flags.appendSlice(cc_flags.items); try stublib_tom_flags.appendSlice(&.{ "-fno-lto", }); finalstublib.root_module.addCSourceFile(.{ .file = b.path(tcl_source_folder ++ "/generic/tclTomMathStubLib.c"), .flags = stublib_tom_flags.items, }); var stublib_oo_flags = std.array_list.Managed([]const u8).init(b.allocator); try stublib_oo_flags.appendSlice(cc_flags.items); try stublib_oo_flags.appendSlice(&.{ "-fno-lto", }); finalstublib.root_module.addCSourceFile(.{ .file = b.path(tcl_source_folder ++ "/generic/tclOOStubLib.c"), .flags = stublib_oo_flags.items, }); var winpaniclib_flags = std.array_list.Managed([]const u8).init(b.allocator); try winpaniclib_flags.appendSlice(cc_flags.items); try winpaniclib_flags.appendSlice(&.{ "-DSTATIC_BUILD", }); if (target.result.os.tag == .windows) { finalstublib.root_module.addCSourceFile(.{ .file = b.path(tcl_source_folder ++ "/win/tclWinPanic.c"), .flags = winpaniclib_flags.items, }); } var windde_obj_flags = std.array_list.Managed([]const u8).init(b.allocator); defer windde_obj_flags.deinit(); try windde_obj_flags.appendSlice(cc_flags.items); try windde_obj_flags.appendSlice(&.{}); var winreg_obj_flags = std.array_list.Managed([]const u8).init(b.allocator); defer winreg_obj_flags.deinit(); try winreg_obj_flags.appendSlice(cc_flags.items); try winreg_obj_flags.appendSlice(&.{}); if (target.result.os.tag == .windows) { finalstublib.root_module.addCSourceFile(.{ .file = b.path(tcl_source_folder ++ "/win/tclWinDde.c"), .flags = windde_obj_flags.items, }); finalstublib.root_module.addCSourceFile(.{ .file = b.path(tcl_source_folder ++ "/win/tclWinReg.c"), .flags = winreg_obj_flags.items, }); } finalstublib.root_module.link_libc = true; b.installArtifact(finalstublib); // ================================================================ // Special case object targets const winpaniclib = b.addObject(.{ .name = "tclWinPanic", .root_module = b.createModule(.{ .target = target, .optimize = optimize, }), }); if (target.result.os.tag == .windows) { winpaniclib.root_module.addIncludePath(b.path(tcl_source_folder ++ "/generic/")); winpaniclib.root_module.addIncludePath(b.path(tcl_source_folder ++ "/win/")); winpaniclib.root_module.addIncludePath(b.path(tcl_source_folder ++ "/libtommath/")); winpaniclib.root_module.addIncludePath(b.path(tcl_source_folder ++ "/compat/zlib/")); winpaniclib.root_module.addCSourceFile(.{ .file = b.path(tcl_source_folder ++ "/win/tclWinPanic.c"), .flags = winpaniclib_flags.items, }); winpaniclib.root_module.link_libc = true; } if (target.result.os.tag == .windows) { const winreg_obj = b.addObject(.{ .name = "tclWinReg", .root_module = b.createModule(.{ .target = target, .optimize = optimize, }), }); winreg_obj.root_module.addIncludePath(b.path(tcl_source_folder ++ "/generic/")); winreg_obj.root_module.addIncludePath(b.path(tcl_source_folder ++ "/win/")); winreg_obj.root_module.addIncludePath(b.path(tcl_source_folder ++ "/libtommath/")); winreg_obj.root_module.addIncludePath(b.path(tcl_source_folder ++ "/compat/zlib/")); winreg_obj.root_module.addCSourceFile(.{ .file = b.path(tcl_source_folder ++ "/win/tclWinReg.c"), .flags = winreg_obj_flags.items, }); winreg_obj.root_module.link_libc = true; // const windde_obj = b.addObject(.{ .name = "tclWinDde", .root_module = b.createModule(.{ .target = target, .optimize = optimize, }), }); windde_obj.root_module.addIncludePath(b.path(tcl_source_folder ++ "/generic/")); windde_obj.root_module.addIncludePath(b.path(tcl_source_folder ++ "/win/")); windde_obj.root_module.addIncludePath(b.path(tcl_source_folder ++ "/libtommath/")); windde_obj.root_module.addIncludePath(b.path(tcl_source_folder ++ "/compat/zlib/")); windde_obj.root_module.addCSourceFile(.{ .file = b.path(tcl_source_folder ++ "/win/tclWinDde.c"), .flags = windde_obj_flags.items, }); windde_obj.root_module.link_libc = true; //DDE_OBJS } // for linking to Tclsh var appinit_path: []const u8 = undefined; if (target.result.os.tag == .windows) { appinit_path = tcl_source_folder ++ "/win/tclAppInit.c"; } else { appinit_path = tcl_source_folder ++ "/unix/tclAppInit.c"; } //end special case object targets // ------------------------------------------------------------------ //const stubarchive_install_step = &b.addInstallFileWithDir(stubarchive.getEmittedBin(), .prefix, "libtclstubXX.lib").step; //b.getInstallStep().dependOn(&b.addInstallFileWithDir(stubarchive.getEmittedBin(),.prefix,"libtclstubXX.a").step); //b.getInstallStep().dependOn(stubarchive_install_step); const wf = b.addWriteFiles(); const stublib_file = b.fmt("buildarchive\\{s}", .{finalstublib.out_filename}); const lz_stublib_file = wf.addCopyFile(finalstublib.getEmittedBin(), stublib_file); //s flag to ar should be equivalent to running ranlib const create_stublib_archive = b.addSystemCommand(&.{ "zig", "ar", "crs", "--", }); //no tcl_nodot_version for tcl9 libtclstub.a const stublib_archive_file = create_stublib_archive.addOutputFileArg("buildarchive\\" ++ tcl_stub_lib_file); //const out_ranlib = run_ranlib.addOutputFileArg("buildarchive\\tclstub.lib"); create_stublib_archive.addFileArg(lz_stublib_file); const installed_stublib_archive = b.addInstallFileWithDir(stublib_archive_file, .prefix, "lib\\" ++ tcl_stub_lib_file); //const stublib_archive = b.addInstallFileWithDir(out_ranlib , .prefix, "lib\\tclstub.lib"); installed_stublib_archive.step.dependOn(&create_stublib_archive.step); //b.getInstallStep().dependOn(&stublib_archive.step); //dde_dll_file and reg_dll_file need to be added to the zip file var dll_flags = std.array_list.Managed([]const u8).init(b.allocator); //try dll_flags.appendSlice(base_flags.items); try dll_flags.appendSlice(&.{ "-pipe", "-municode", }); if (target.result.os.tag == .windows) { try dll_flags.appendSlice(&.{ "-Wl,--enable-auto-image-base", "-static-libgcc", }); } else {} //"-Wl,-static-libgcc", //std.fs.path.stem(dde_dll_file) ;// tcl9dde14.dll - tcl9 //std.fs.path.stem(dde_dll_file8) ;// tcldde14.dll - tcl8 const dde_dll = b.addLibrary(.{ .linkage = .dynamic, .name = std.fs.path.stem(dde_dll_file), .root_module = b.createModule(.{ .target = target, .optimize = optimize, }), }); dde_dll.step.dependOn(&installed_stublib_archive.step); dde_dll.step.dependOn(&finalstublib.step); var install_dde_dll: *std.Build.Step.InstallArtifact = undefined; if (target.result.os.tag == .windows) { dde_dll.root_module.addIncludePath(b.path(tcl_source_folder ++ "/generic/")); dde_dll.root_module.addIncludePath(b.path(tcl_source_folder ++ "/win/")); dde_dll.root_module.addCSourceFile(.{ .file = b.path(tcl_source_folder ++ "/win/TclWinDde.c"), .flags = dll_flags.items, }); //LIBS //dde_dll.root_module.addLibraryPath(stublib_archive.source.dirname()); dde_dll.root_module.addObjectFile(finalstublib.getEmittedBin()); //dde_dll.root_module.addObjectFile(installed_stublib_archive.source); //dde_lib.root_module.linkSystemLibrary("tclstub" ++ tcl_nodot_version); //libtclstubXX.a //dde_lib.root_module.linkSystemLibrary("tclstub", .{}); //tcl9 dde_dll.root_module.linkSystemLibrary("netapi32", .{}); dde_dll.root_module.linkSystemLibrary("kernel32", .{}); dde_dll.root_module.linkSystemLibrary("user32", .{}); dde_dll.root_module.linkSystemLibrary("advapi32", .{}); dde_dll.root_module.linkSystemLibrary("userenv", .{}); dde_dll.root_module.linkSystemLibrary("ws2_32", .{}); //dde_dll.root_module.addObjectFile(.{ .path = tcl_source_folder ++ "/libtommath/win64/libtommath.dll.a" }); //dde_dll.root_module.addObjectFile(.{ .path = tcl_source_folder ++ "/compat/zlib/win64/libz.dll.a" }); dde_dll.root_module.addLibraryPath(b.path(tcl_source_folder ++ "/compat/zlib/win64")); dde_dll.root_module.addLibraryPath(b.path(tcl_source_folder ++ "/libtommath/win64")); //dde_dll.root_module.linkSystemLibrary("zlib1", .{}); //### JMN dde_dll.root_module.linkLibrary(zlib_lib_compile); dde_dll.root_module.linkSystemLibrary("tommath", .{}); dde_dll.root_module.link_libc = true; //b.installArtifact(dde_dll); install_dde_dll = b.addInstallArtifact( dde_dll, .{ .dest_dir = .{ .override = .{ .custom = "./lib/tcl" ++ tcl_dot_version ++ "/dde" }, }, }, ); //b.default_step.dependOn(&install_dde_dll.step); } //tcl9registry13.dll - tcl9 //tclregistry13.dll - tcl8 const reg_dll = b.addLibrary(.{ .linkage = .dynamic, .name = std.fs.path.stem(reg_dll_file), .root_module = b.createModule(.{ .target = target, .optimize = optimize, }), }); //reg_lib.step.dependOn(&stublib_archive.step); reg_dll.step.dependOn(&finalstublib.step); var install_reg_dll: *std.Build.Step.InstallArtifact = undefined; if (target.result.os.tag == .windows) { reg_dll.root_module.addIncludePath(b.path(tcl_source_folder ++ "/generic/")); reg_dll.root_module.addIncludePath(b.path(tcl_source_folder ++ "/win/")); reg_dll.root_module.addCSourceFile(.{ .file = b.path(tcl_source_folder ++ "/win/TclWinReg.c"), .flags = dll_flags.items, }); //LIBS //reg_dll.root_module.addLibraryPath(stublib_archive.source.dirname()); reg_dll.root_module.addObjectFile(finalstublib.getEmittedBin()); //reg_dll.root_module.linkSystemLibrary("tclstub" ++ tcl_nodot_version); //libtclstubXX.a //reg_dll.root_module.linkSystemLibrary("tclstub", .{}); //tcl9 reg_dll.root_module.linkSystemLibrary("netapi32", .{}); reg_dll.root_module.linkSystemLibrary("kernel32", .{}); reg_dll.root_module.linkSystemLibrary("user32", .{}); reg_dll.root_module.linkSystemLibrary("advapi32", .{}); reg_dll.root_module.linkSystemLibrary("userenv", .{}); reg_dll.root_module.linkSystemLibrary("ws2_32", .{}); //reg_dll.root_module.addObjectFile(.{ .path = tcl_source_folder ++ "/libtommath/win64/libtommath.dll.a" }); //reg_dll.root_module.addObjectFile(.{ .path = tcl_source_folder ++ "/compat/zlib/win64/libz.dll.a" }); reg_dll.root_module.addLibraryPath(b.path(tcl_source_folder ++ "/compat/zlib/win64")); reg_dll.root_module.addLibraryPath(b.path(tcl_source_folder ++ "/libtommath/win64")); //reg_dll.root_module.linkSystemLibrary("zlib1", .{}); //### JMN reg_dll.root_module.linkLibrary(zlib_lib_compile); reg_dll.root_module.linkSystemLibrary("tommath", .{}); reg_dll.root_module.link_libc = true; //b.installArtifact(reg_dll); //https://www.reddit.com/r/Zig/comments/1cxn08x/question_how_do_i_setup_a_custom_install_location/ install_reg_dll = b.addInstallArtifact( reg_dll, .{ .dest_dir = .{ .override = .{ .custom = "./lib/tcl" ++ tcl_dot_version ++ "/registry" }, }, }, ); //b.default_step.dependOn(&install_reg_dll.step); } //COREOBJS var generic_sources = std.array_list.Managed([]const u8).init(b.allocator); defer generic_sources.deinit(); try generic_sources.append(tcl_source_folder ++ "/generic/regcomp.c"); try generic_sources.append(tcl_source_folder ++ "/generic/regexec.c"); try generic_sources.append(tcl_source_folder ++ "/generic/regfree.c"); try generic_sources.append(tcl_source_folder ++ "/generic/regerror.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclAlloc.c"); //tcl9.0 try generic_sources.append(tcl_source_folder ++ "/generic/tclArithSeries.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclAssembly.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclAsync.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclBasic.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclBinary.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclCkalloc.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclClock.c"); //tcl9.0 try generic_sources.append(tcl_source_folder ++ "/generic/tclClockFmt.c"); //tcl 9? try generic_sources.append(tcl_source_folder ++ "/generic/tclCmdAH.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclCmdIL.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclCmdMZ.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclCompCmds.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclCompCmdsGR.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclCompCmdsSZ.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclCompExpr.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclCompile.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclConfig.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclDate.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclDictObj.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclDisassemble.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclEncoding.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclEnsemble.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclEnv.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclEvent.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclExecute.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclFCmd.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclFileName.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclGet.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclHash.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclHistory.c"); //tcl9.0 try generic_sources.append(tcl_source_folder ++ "/generic/tclIcu.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclIndexObj.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclInterp.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclIO.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclIOCmd.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclIOGT.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclIORChan.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclIORTrans.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclIOSock.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclIOUtil.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclLink.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclLiteral.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclListObj.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclLoad.c"); //tclmainW mainw_obj //try generic_sources.append(tcl_source_folder ++ "/generic/tclMainW.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclMain.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclNamesp.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclNotify.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclOO.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclOOBasic.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclOOCall.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclOODefineCmds.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclOOInfo.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclOOMethod.c"); //tcl9.0 try generic_sources.append(tcl_source_folder ++ "/generic/tclOOProp.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclOOStubInit.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclObj.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclOptimize.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclPanic.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclParse.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclPathObj.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclPipe.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclPkg.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclPkgConfig.c"); //pkgconfig_obj try generic_sources.append(tcl_source_folder ++ "/generic/tclPosixStr.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclPreserve.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclProc.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclProcess.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclRegexp.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclResolve.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclResult.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclScan.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclStringObj.c"); //tcl 9.0 try generic_sources.append(tcl_source_folder ++ "/generic/tclStrIdxTree.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclStrToD.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclStubInit.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclThread.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclThreadAlloc.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclThreadJoin.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclThreadStorage.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclTimer.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclTomMathInterface.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclTrace.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclUtf.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclUtil.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclVar.c"); try generic_sources.append(tcl_source_folder ++ "/generic/tclZipfs.c"); //zipfs_obj try generic_sources.append(tcl_source_folder ++ "/generic/tclZlib.c"); //PLATFORMOBJS - win_source or unix_sources var win_sources = std.array_list.Managed([]const u8).init(b.allocator); defer win_sources.deinit(); var unix_sources = std.array_list.Managed([]const u8).init(b.allocator); defer unix_sources.deinit(); switch (target.result.os.tag) { .windows => { try win_sources.append(tcl_source_folder ++ "/win/tclWin32Dll.c"); try win_sources.append(tcl_source_folder ++ "/win/tclWinChan.c"); try win_sources.append(tcl_source_folder ++ "/win/tclWinConsole.c"); try win_sources.append(tcl_source_folder ++ "/win/tclWinSerial.c"); try win_sources.append(tcl_source_folder ++ "/win/tclWinError.c"); try win_sources.append(tcl_source_folder ++ "/win/tclWinFCmd.c"); try win_sources.append(tcl_source_folder ++ "/win/tclWinFile.c"); try win_sources.append(tcl_source_folder ++ "/win/tclWinInit.c"); //wininit_obj try win_sources.append(tcl_source_folder ++ "/win/tclWinLoad.c"); try win_sources.append(tcl_source_folder ++ "/win/tclWinNotify.c"); try win_sources.append(tcl_source_folder ++ "/win/tclWinPipe.c"); //winpipe_obj try win_sources.append(tcl_source_folder ++ "/win/tclWinSock.c"); try win_sources.append(tcl_source_folder ++ "/win/tclWinThrd.c"); try win_sources.append(tcl_source_folder ++ "/win/tclWinTime.c"); }, else => { try unix_sources.append(tcl_source_folder ++ "/unix/tclUnixChan.c"); try unix_sources.append(tcl_source_folder ++ "/unix/tclUnixEvent.c"); try unix_sources.append(tcl_source_folder ++ "/unix/tclUnixFCmd.c"); try unix_sources.append(tcl_source_folder ++ "/unix/tclUnixFile.c"); try unix_sources.append(tcl_source_folder ++ "/unix/tclUnixPipe.c"); try unix_sources.append(tcl_source_folder ++ "/unix/tclUnixSock.c"); try unix_sources.append(tcl_source_folder ++ "/unix/tclUnixTime.c"); try unix_sources.append(tcl_source_folder ++ "/unix/tclUnixInit.c"); try unix_sources.append(tcl_source_folder ++ "/unix/tclUnixThrd.c"); try unix_sources.append(tcl_source_folder ++ "/unix/tclUnixCompat.c"); //NOTIFY_SRCS try unix_sources.append(tcl_source_folder ++ "/unix/tclEpollNotfy.c"); try unix_sources.append(tcl_source_folder ++ "/unix/tclKqueueNotfy.c"); try unix_sources.append(tcl_source_folder ++ "/unix/tclSelectNotfy.c"); //try unix_sources.append(tcl_source_folder ++ "/unix/tclUnixNotfy.c"); switch (target.result.os.tag) { .macos => { try unix_sources.append(tcl_source_folder ++ "/unix/tclLoadDyld.c"); //MAC_OSX_SRCS try unix_sources.append(tcl_source_folder ++ "/macosx/tclMacOSXBundle.c"); try unix_sources.append(tcl_source_folder ++ "/macosx/tclMacOSXFCmd.c"); try unix_sources.append(tcl_source_folder ++ "/macosx/tclMacOSXNotify.c"); }, else => { try unix_sources.append(tcl_source_folder ++ "/unix/tclLoadDL.c"); }, } }, } var tommath_sources = std.array_list.Managed([]const u8).init(b.allocator); //{ // //const subdir = "../libtommath"; // //const subdir = tcl_source_folder ++ "/libtommath"; // var dir = try fs.cwd().openDir(tommath_sourcedir, .{ .iterate = true }); // defer dir.close(); // var it = dir.iterate(); // const allowed_exts = [_][]const u8{ // ".c", // }; // while (try it.next()) |entry| { // if (entry.kind == .file) { // const ext = fs.path.extension(entry.name); // const include_file = for (allowed_exts) |e| { // if (std.mem.eql(u8, ext, e)) break true; // } else false; // if (include_file) { // try tommath_sources.append(b.pathJoin(&.{ // tommath_sourcedir, // entry.name, // })); // } // } // } //} try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_add.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_add_d.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_and.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_clamp.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_clear.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_clear_multi.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_cmp.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_cmp_d.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_cmp_mag.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_cnt_lsb.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_copy.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_count_bits.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_div.c"); //tcl9.0 try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_div_d.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_div_2.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_div_2d.c"); //tcl9.0 try tommath_sources.append(tommath_sourcedir ++ "/bn_s_mp_div_3.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_exch.c"); //tcl9.0 try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_expt_n.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_get_mag_u64.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_grow.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_init.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_init_copy.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_init_i64.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_init_multi.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_init_set.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_init_size.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_init_u64.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_lshd.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_mod.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_mod_2d.c"); //tcl9.0 try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_mul.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_mul_2.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_mul_2d.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_mul_d.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_neg.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_or.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_pack.c"); //tcl9.0 try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_pack_count.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_radix_size.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_radix_smap.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_read_radix.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_rshd.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_set_i64.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_set_u64.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_shrink.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_sqr.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_sqrt.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_sub.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_sub_d.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_signed_rsh.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_to_ubin.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_to_radix.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_ubin_size.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_unpack.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_xor.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_mp_zero.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_s_mp_add.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_s_mp_balance_mul.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_s_mp_karatsuba_mul.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_s_mp_karatsuba_sqr.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_s_mp_mul_digs.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_s_mp_mul_digs_fast.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_s_mp_reverse.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_s_mp_sqr_fast.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_s_mp_sqr.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_s_mp_sub.c"); //tcl 9.0 try tommath_sources.append(tommath_sourcedir ++ "/bn_s_mp_toom_mul.c"); try tommath_sources.append(tommath_sourcedir ++ "/bn_s_mp_toom_sqr.c"); // larger set var tcl_objs_static_sources = std.array_list.Managed([]const u8).init(b.allocator); defer tcl_objs_static_sources.deinit(); try tcl_objs_static_sources.appendSlice(generic_sources.items); if (target.result.os.tag == .windows) { try tcl_objs_static_sources.appendSlice(win_sources.items); } else { try tcl_objs_static_sources.appendSlice(unix_sources.items); } try tcl_objs_static_sources.appendSlice(tommath_sources.items); if (target.result.os.tag == .windows) { var panic_dde_reg_sources = std.array_list.Managed([]const u8).init(b.allocator); defer panic_dde_reg_sources.deinit(); try panic_dde_reg_sources.append(tcl_source_folder ++ "/win/tclWinPanic.c"); try panic_dde_reg_sources.append(tcl_source_folder ++ "/win/tclWinReg.c"); try panic_dde_reg_sources.append(tcl_source_folder ++ "/win/tclWinDde.c"); try tcl_objs_static_sources.appendSlice(panic_dde_reg_sources.items); } //smaller set var tcl_objs_shared_sources = std.array_list.Managed([]const u8).init(b.allocator); defer tcl_objs_shared_sources.deinit(); try tcl_objs_shared_sources.appendSlice(generic_sources.items); if (target.result.os.tag == .windows) { try tcl_objs_shared_sources.appendSlice(win_sources.items); } else { try tcl_objs_shared_sources.appendSlice(unix_sources.items); } //shouldn't need to be added ?? try tcl_objs_shared_sources.appendSlice(tommath_sources.items); var tclobjs_flags = std.array_list.Managed([]const u8).init(b.allocator); try tclobjs_flags.appendSlice(cc_flags.items); try tclobjs_flags.appendSlice(&.{ "-DBUILD_tcl", }); // ============================================================================================================== const Flaginfo = struct { flags: std.array_list.Managed([]const u8) }; var build_specials = std.StringHashMap(Flaginfo).init(b.allocator); defer build_specials.deinit(); // -------------------------------------------------------------------------------------------------------------- var mainw_flags = std.array_list.Managed([]const u8).init(b.allocator); defer mainw_flags.deinit(); try build_specials.put("tclWinPanic", .{ .flags = winpaniclib_flags }); try build_specials.put("tclWinReg", .{ .flags = winreg_obj_flags }); try build_specials.put("tclWinDde", .{ .flags = windde_obj_flags }); var appinit_flags = std.array_list.Managed([]const u8).init(b.allocator); defer appinit_flags.deinit(); try appinit_flags.appendSlice(cc_flags.items); try appinit_flags.appendSlice(&.{ "-DUNICODE", "-D_UNICODE", }); try build_specials.put("tclAppInit", .{ .flags = appinit_flags }); try mainw_flags.appendSlice(cc_flags.items); try mainw_flags.appendSlice(&.{ "-DBUILD_tcl", "-DUNICODE", "-D_UNICODE", }); try build_specials.put("tclMain", .{ .flags = mainw_flags }); var wininit_obj_flags = std.array_list.Managed([]const u8).init(b.allocator); defer wininit_obj_flags.deinit(); try wininit_obj_flags.appendSlice(cc_flags.items); try wininit_obj_flags.appendSlice(&.{ "-DBUILD_tcl", }); try build_specials.put("tclWinInit", .{ .flags = wininit_obj_flags }); //try build_specials.put("tclPkgConfig",.{ .flags = config_flags}); try build_specials.put("tclPkgConfig", .{ .flags = cc_flags }); //cc_flags includes config_flags var zipfs_flags = std.array_list.Managed([]const u8).init(b.allocator); defer zipfs_flags.deinit(); try zipfs_flags.appendSlice(cc_flags.items); try zipfs_flags.appendSlice(&.{ "-DBUILD_tcl", }); try build_specials.put("tclZipfs", .{ .flags = zipfs_flags }); //zipfs_obj.root_module.addIncludePath(.{ .path = tcl_source_folder ++ "/compat/zlib/contrib/minizip" }); var pipe_obj_flags = std.array_list.Managed([]const u8).init(b.allocator); defer pipe_obj_flags.deinit(); try pipe_obj_flags.appendSlice(cc_flags.items); try pipe_obj_flags.appendSlice(&.{ "-DBUILD_tcl", }); try build_specials.put("tclWinPipe", .{ .flags = pipe_obj_flags }); // ============================================================================================================== const tcl_objs_static = b.addLibrary(.{ .linkage = .static, .name = "tclobjs" ++ tcl_nodot_version, .root_module = b.createModule(.{ .target = target, .optimize = optimize, }), }); tcl_objs_static.root_module.addIncludePath(tcluuid_include_dir); //overlay first (G-102) tcl_objs_static.root_module.addIncludePath(b.path(tcl_source_folder ++ "/generic")); if (target.result.os.tag == .windows) { tcl_objs_static.root_module.addIncludePath(b.path(tcl_source_folder ++ "/win")); } else { tcl_objs_static.root_module.addIncludePath(b.path(tcl_source_folder ++ "/unix")); } tcl_objs_static.root_module.addIncludePath(b.path(tommath_sourcedir)); tcl_objs_static.root_module.addIncludePath(b.path(tcl_source_folder ++ "/compat/zlib")); tcl_objs_static.root_module.addIncludePath(b.path(tcl_source_folder ++ "/compat/zlib/contrib/minizip")); //only required by tclZipfs - but ok for all? //tclMain.c needs to be built twice on windows - with and without unicode flags. //The UNICODE copy is already produced by the generic sources loop (build_specials //maps tclMain -> mainw_flags); the ansi copy is added to the exe below. A second //explicit UNICODE add here was harmless under zig 0.14.0-dev.2074 (the duplicate //archive member was never extracted) but zig 0.14.1 links it -> duplicate symbols. //if (target.result.os.tag == .windows) { // tcl_objs_static.root_module.addCSourceFile(.{ // .file = b.path(tcl_source_folder ++ "/generic/tclMain.c"), // .flags = mainw_flags.items, // }); //} var current_flagset: std.array_list.Managed([]const u8) = undefined; for (tcl_objs_static_sources.items) |src| { if (build_specials.get(std.fs.path.stem(src))) |val| { //std.debug.print(">>> {s}\n", .{ std.fs.path.stem(src)}); current_flagset = val.flags; } else { //std.debug.print("--- {s}", .{ std.fs.path.stem(src)}); current_flagset = tclobjs_flags; } tcl_objs_static.root_module.addCSourceFile(.{ .file = b.path(src), .flags = current_flagset.items, }); } tcl_objs_static.root_module.link_libc = true; //b.installArtifact(tcl_objs); //const tcl_objs_shared = b.addLibrary(.{ // .linkage = .static, // .name = "tclobjsshared" ++ tcl_nodot_version, // .root_module = b.createModule(.{ .target = target, .optimize = optimize }), //}); //tcl_objs_shared.root_module.addIncludePath(b.path(tcl_source_folder ++ "/generic")); //if (target.result.os.tag == .windows) { // tcl_objs_shared.root_module.addIncludePath(b.path(tcl_source_folder ++ "/win")); //} else { // tcl_objs_shared.root_module.addIncludePath(b.path(tcl_source_folder ++ "/unix")); //} //tcl_objs_shared.root_module.addIncludePath(b.path(tommath_sourcedir)); //tcl_objs_shared.root_module.addIncludePath(b.path(tcl_source_folder ++ "/compat/zlib")); //tcl_objs_shared.root_module.addIncludePath(b.path(tcl_source_folder ++ "/compat/zlib/contrib/minizip")); //only required by tclZipfs - but ok for all? //if (target.result.os.tag == .windows) { // tcl_objs_shared.root_module.addCSourceFile(.{ // .file = b.path(tcl_source_folder ++ "/generic/tclMain.c"), // .flags = mainw_flags.items, // }); //} //var current_flagset_obj_shared: std.array_list.Managed([]const u8) = undefined; //for (tcl_objs_shared_sources.items) |src| { // if (build_specials.get(std.fs.path.stem(src))) |val| { // //std.debug.print(">>> {s}\n", .{ std.fs.path.stem(src)}); // current_flagset_obj_shared = val.flags; // } else { // //std.debug.print("--- {s}", .{ std.fs.path.stem(src)}); // current_flagset_obj_shared = tclobjs_flags; // } // tcl_objs_shared.root_module.addCSourceFile(.{ // .file = b.path(src), // .flags = current_flagset_obj_shared.items, // }); //} ////tcl_objs_shared.root_module.addObjectFile(b.path(tcl_source_folder ++ "/libtommath/win64/libtommath.dll.a")); //tcl_objs_shared.root_module.addObjectFile(b.path(tcl_source_folder ++ "/libtommath/win64/tommath.lib")); ////tcl_objs_shared.root_module.addObjectFile(b.path(tcl_source_folder ++ "/compat/zlib/win64/libz.dll.a")); //tcl_objs_shared.root_module.addObjectFile(b.path(tcl_source_folder ++ "/compat/zlib/win64/zdll.lib")); //tcl_objs_shared.root_module.link_libc = true; //-- --- --- //const tcl_lib_static = b.addLibrary(.{ // .linkage = .static, // //libtcl90.dll.a ? - zig will append .lib or .a? // .name = if (target.result.os.tag == .windows) "libtcl" ++ tcl_nodot_version ++ ".dll" else "libtcl" ++ tcl_nodot_version ++ ".so", // .root_module = b.createModule(.{ .target = target, .optimize = optimize }), //}); ////jmn3 -test //tcl_lib_static.step.dependOn(&zlib_lib_compile.step); ////tcl_lib_static.step.dependOn(&tommath_lib_compile.step); //tcl_lib_static.step.dependOn(&wf_uuidh.step); //tcl_lib_static.root_module.addIncludePath(b.path(tcl_source_folder ++ "/generic")); //if (target.result.os.tag == .windows) { // tcl_lib_static.root_module.addIncludePath(b.path(tcl_source_folder ++ "/win")); //} else { // tcl_lib_static.root_module.addIncludePath(b.path(tcl_source_folder ++ "/unix")); //} //tcl_lib_static.root_module.addIncludePath(b.path(tommath_sourcedir)); //if (target.result.os.tag == .windows) { // tcl_lib_static.root_module.addIncludePath(b.path(zlib_sourcedir)); // tcl_lib_static.root_module.addIncludePath(b.path(zlib_sourcedir ++ "/contrib/minizip")); //only required by tclZipfs - but ok for all? //} else { // //tcl_lib_static.root_module.addIncludePath(b.path("../zlib")); // //tcl_lib_static.root_module.addIncludePath(b.path("../zlib/contrib/minizip")); // tcl_lib_static.root_module.addIncludePath(b.path(zlib_sourcedir)); // tcl_lib_static.root_module.addIncludePath(b.path(zlib_sourcedir ++ "/contrib/minizip")); //only required by tclZipfs - but ok for all? //} //for (tcl_lib_sources.items) |src| { // if (build_specials.get(std.fs.path.stem(src))) |val| { // //std.debug.print(">>> {s}\n", .{ std.fs.path.stem(src)}); // current_flagset = val.flags; // } else { // //std.debug.print("--- {s}", .{ std.fs.path.stem(src)}); // current_flagset = tclobjs_flags; // } // tcl_lib_static.root_module.addCSourceFile(.{ // .file = b.path(src), // .flags = current_flagset.items, // }); //} //jmn3 //tcl_lib_static.root_module.linkLibrary(zlib_lib_compile); //tcl_lib_static.root_module.linkLibrary(tommath_lib_compile); //tcl_lib_static.root_module.link_libc = true; //b.installArtifact(tcl_lib_static); // ============================================================================================================== // ============================================================================================================== //tclXX.dll or .so var tcl_lib_shared_flags = std.array_list.Managed([]const u8).init(b.allocator); try tcl_lib_shared_flags.appendSlice(base_flags.items); try tcl_lib_shared_flags.appendSlice(&.{ "-pipe", "-municode", }); if (target.result.os.tag == .windows) { try tcl_lib_shared_flags.appendSlice(&.{ "-static-libgcc", }); //jmn3 try tcl_lib_shared_flags.appendSlice(&.{ "-Wl,-out-implib,tcl90.dll.a", }); } //try tcl_slib_flags.appendSlice(&.{ // "-DUNICODE", // "-D_UNICODE", //}); try tcl_lib_shared_flags.appendSlice(c_flags.items); const tcl_lib_shared = b.addLibrary(.{ .linkage = .dynamic, .name = "tcl" ++ tcl_nodot_version, .root_module = b.createModule(.{ .target = target, .optimize = optimize, }), }); //tcl_lib_shared.verbose_link = true; //tcl_lib_shared.setVerboseLink(true); //tcl_lib_shared.step.dependOn(&tcl_objs_shared.step); //jmn3 test //if (target.result.os.tag == .linux) { // tcl_slib.step.dependOn(&zlib_lib_compile.step); //} tcl_lib_shared.root_module.addIncludePath(tcluuid_include_dir); //overlay first (G-102) tcl_lib_shared.root_module.addIncludePath(b.path(tcl_source_folder ++ "/generic")); if (target.result.os.tag == .windows) { tcl_lib_shared.root_module.addIncludePath(b.path(tcl_source_folder ++ "/win")); tcl_lib_shared.root_module.addIncludePath(b.path(tcl_source_folder ++ "/compat/zlib")); tcl_lib_shared.root_module.addIncludePath(b.path(tcl_source_folder ++ "/compat/zlib/contrib/minizip")); } else { tcl_lib_shared.root_module.addIncludePath(b.path(tcl_source_folder ++ "/unix")); tcl_lib_shared.root_module.addIncludePath(b.path(zlib_sourcedir)); tcl_lib_shared.root_module.addIncludePath(b.path(zlib_sourcedir ++ "/contrib/minizip")); //only required by tclZipfs - but ok for all? } tcl_lib_shared.root_module.addIncludePath(b.path(tommath_sourcedir)); // --- // ?? needed for shared lib? //if (target.result.os.tag == .windows) { // tcl_lib_shared.root_module.addCSourceFile(.{ // .file = b.path(tcl_source_folder ++ "/generic/tclMain.c"), // .flags = mainw_flags.items, // }); //} // --- for (tcl_objs_shared_sources.items) |src| { if (build_specials.get(std.fs.path.stem(src))) |val| { //std.debug.print(">>> {s}\n", .{ std.fs.path.stem(src)}); current_flagset = val.flags; } else { //std.debug.print("--- {s}", .{ std.fs.path.stem(src)}); current_flagset = tclobjs_flags; } tcl_lib_shared.root_module.addCSourceFile(.{ .file = b.path(src), .flags = current_flagset.items, }); } if (target.result.os.tag == .windows) { tcl_lib_shared.root_module.addLibraryPath(b.path(tcl_source_folder ++ "/compat/zlib/win64")); tcl_lib_shared.root_module.addLibraryPath(b.path(tcl_source_folder ++ "/libtommath/win64")); } if (target.result.os.tag == .windows) { //tcl_lib_shared.root_module.addObjectFile(b.path(tcl_source_folder ++ "/libtommath/win64/libtommath.dll.a")); //tcl_lib_shared.root_module.addObjectFile(b.path(tcl_source_folder ++ "/compat/zlib/win64/libz.dll.a")); tcl_lib_shared.root_module.linkSystemLibrary("tommath", .{ .preferred_link_mode = .dynamic }); //tcl_lib_shared.root_module.linkSystemLibrary("zlib1", .{ .preferred_link_mode = .dynamic }); tcl_lib_shared.root_module.linkLibrary(zlib_lib_compile); //tcl_lib_shared.root_module.linkSystemLibrary("tommath", .{}); //tcl_lib_shared.root_module.linkSystemLibrary("zlib1", .{}); } else { //tcl_lib_shared.root_module.linkLibrary(tommath_lib_compile); tcl_lib_shared.root_module.linkLibrary(zlib_lib_compile); //tcl_lib_shared.root_module.linkSystemLibrary("zlib1", .{}); } //JMN2024 install_path problem (sub_path is expected to be relative to the build root) //tcl_lib_shared.root_module.addLibraryPath(b.path( b.pathJoin(&.{ b.install_path, "" }) )); tcl_lib_shared.root_module.link_libc = true; //SHLIB_LD_LIBS (LIBS) if (target.result.os.tag == .windows) { tcl_lib_shared.root_module.linkSystemLibrary("netapi32", .{}); tcl_lib_shared.root_module.linkSystemLibrary("kernel32", .{}); tcl_lib_shared.root_module.linkSystemLibrary("user32", .{}); tcl_lib_shared.root_module.linkSystemLibrary("advapi32", .{}); tcl_lib_shared.root_module.linkSystemLibrary("userenv", .{}); tcl_lib_shared.root_module.linkSystemLibrary("ws2_32", .{}); } //tclshlib.root_module.linkSystemLibrary("libtommath", .{}); //tclshlib.root_module.linkSystemLibrary("zlib1", .{}); tcl_lib_shared.root_module.addWin32ResourceFile(.{ .file = b.path(tcl_source_folder ++ "/win/tcl.rc"), .flags = &.{ "/I", tcl_source_folder ++ "/generic", }, }); b.installArtifact(tcl_lib_shared); var ldflags_console = std.array_list.Managed([]const u8).init(b.allocator); if (target.result.os.tag == .windows) { try ldflags_console.appendSlice(&.{ "-mconsole", "-static-libgcc", "-Wl,--enable-auto-image-base", "-Wl,--subsystem,console", "-DTCL_BROKEN_MAINARGS", }); } try ldflags_console.appendSlice(&.{ //"-mwindows", "-pipe", "-municode", }); //"-DTCL_MEM_DEBUG", var tclsh_flags = std.array_list.Managed([]const u8).init(b.allocator); try tclsh_flags.appendSlice(c_flags.items); try tclsh_flags.appendSlice(appinit_flags.items); try tclsh_flags.appendSlice(ldflags_console.items); const tclsh_exe = b.addExecutable(.{ .name = tclsh_static, //e.g tclsh90s (becomes tclsh90s.exe on windows) //.root_source_file = .{ .path = appinit_path}, .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize, }), }); //9.0.5 sources dropped TCL_BROKEN_MAINARGS: tclAppInit.c now provides _tmain, which is //wmain under -DUNICODE, so the mingw CRT must use the unicode entry (zig's -municode). tclsh_exe.mingw_unicode_entry_point = true; //tclsh_exe.setVerboseLink(true); //tclsh_exe.link_gc_sections = false; //tclsh_exe.want_lto = false; tclsh_exe.step.dependOn(&finalstublib.step); //tclsh.step.dependOn(&install_tcl_lib_file.step); tclsh_exe.step.dependOn(&tcl_objs_static.step); //tclsh_exe.step.dependOn(&tcl_lib_shared.step); //tclsh_exe.step.dependOn(&tommath_lib_compile.step); //JMN3 test //if (target.result.os.tag == .linux) { // tclsh_exe.step.dependOn(&zlib_lib_compile.step); //} tclsh_exe.root_module.addIncludePath(tcluuid_include_dir); //overlay first (G-102) tclsh_exe.root_module.addIncludePath(b.path(tcl_source_folder ++ "/generic")); if (target.result.os.tag == .windows) { tclsh_exe.root_module.addIncludePath(b.path(tcl_source_folder ++ "/win")); tclsh_exe.root_module.addIncludePath(b.path(tcl_source_folder ++ "/compat/zlib")); tclsh_exe.root_module.addIncludePath(b.path(tcl_source_folder ++ "/compat/zlib/contrib/minizip")); } else { tclsh_exe.root_module.addIncludePath(b.path(tcl_source_folder ++ "/unix")); tclsh_exe.root_module.addIncludePath(b.path(zlib_sourcedir)); tclsh_exe.root_module.addIncludePath(b.path(zlib_sourcedir ++ "/contrib/minizip")); } tclsh_exe.root_module.addIncludePath(b.path(tommath_sourcedir)); //tclMain needs to be compiled twice on windows - with and without unicode //we have already configured the one in the sources list to compile with mainw_flags (DUNICODE etc) if (target.result.os.tag == .windows) { //The ansi copy must NOT see UNICODE: undefine explicitly (the zig cc driver can //supply windows-default defines - observed with zig 0.14.1 as duplicate //Tcl_MainExW/common symbols vs the mainw copy) and use upstream's //TCL_ASCII_MAIN guard so only the ascii Tcl_MainEx variant is emitted. var mainansi_flags = std.array_list.Managed([]const u8).init(b.allocator); defer mainansi_flags.deinit(); try mainansi_flags.appendSlice(tclobjs_flags.items); try mainansi_flags.appendSlice(&.{ "-UUNICODE", "-U_UNICODE", "-DTCL_ASCII_MAIN", }); tclsh_exe.root_module.addCSourceFile(.{ .file = b.path(tcl_source_folder ++ "/generic/tclMain.c"), .flags = mainansi_flags.items, }); } tclsh_exe.root_module.addCSourceFile(.{ .file = b.path(appinit_path), .flags = tclsh_flags.items, }); // TCL_LIB_FILE libtclxx.dll.a (not the implib which is tclxx.dll.a) // -- //tclsh_exe.root_module.addObjectFile(install_tcl_lib_file.source); //tclsh_exe.root_module.addObjectFile(tcl_lib_static.getEmittedBin()); for (tcl_objs_static_sources.items) |src| { if (build_specials.get(std.fs.path.stem(src))) |val| { std.debug.print(">>> {s}\n", .{std.fs.path.stem(src)}); current_flagset = val.flags; } else { //std.debug.print("--- {s}", .{ std.fs.path.stem(src)}); current_flagset = tclobjs_flags; } tclsh_exe.root_module.addCSourceFile(.{ .file = b.path(src), .flags = current_flagset.items, }); } //tclsh_exe.root_module.addObjectFile(finalstublib.getEmittedBin()); tclsh_exe.root_module.addCSourceFile(.{ .file = b.path(tcl_source_folder ++ "/generic/tclStubLib.c"), .flags = stublib_flags.items, }); //experiment //tclsh_exe.root_module.addCSourceFiles(.{ // .files = &.{ // "generic/tclStubCall.c", // "tclStubLibTbl.c", // }, // .flags = stublib_call_flags.items, //}); //tcl9 tclsh_exe.root_module.addCSourceFile(.{ .file = b.path(tcl_source_folder ++ "/generic/tclStubCall.c"), .flags = stublib_call_flags.items, }); //tcl9 tclsh_exe.root_module.addCSourceFile(.{ .file = b.path(tcl_source_folder ++ "/generic/tclStubLibTbl.c"), .flags = stublib_tbl_flags.items, }); tclsh_exe.root_module.addCSourceFile(.{ .file = b.path(tcl_source_folder ++ "/generic/tclTomMathStubLib.c"), .flags = stublib_tom_flags.items, }); tclsh_exe.root_module.addCSourceFile(.{ .file = b.path(tcl_source_folder ++ "/generic/tclOOStubLib.c"), .flags = stublib_oo_flags.items, }); if (target.result.os.tag == .windows) { tclsh_exe.root_module.addCSourceFile(.{ .file = b.path(tcl_source_folder ++ "/win/tclWinPanic.c"), .flags = winpaniclib_flags.items, }); } if (target.result.os.tag == .windows) { tclsh_exe.root_module.linkSystemLibrary("netapi32", .{}); tclsh_exe.root_module.linkSystemLibrary("kernel32", .{}); tclsh_exe.root_module.linkSystemLibrary("user32", .{}); tclsh_exe.root_module.linkSystemLibrary("advapi32", .{}); tclsh_exe.root_module.linkSystemLibrary("userenv", .{}); tclsh_exe.root_module.linkSystemLibrary("ws2_32", .{}); } if (target.result.os.tag == .windows) { tclsh_exe.root_module.addObjectFile(b.path(tcl_source_folder ++ "/libtommath/win64/libtommath.dll.a")); //### jmn //tclsh_exe.root_module.addObjectFile(b.path(tcl_source_folder ++ "/compat/zlib/win64/libz.dll.a")); } else { //tclsh_exe.root_module.linkLibrary(tommath_lib_compile); //tclsh_exe.root_module.linkLibrary(zlib_lib_compile); } //### jmn tclsh_exe.step.dependOn(&zlib_lib_compile.step); tclsh_exe.root_module.linkLibrary(zlib_lib_compile); //tclsh.root_module.addLibraryPath(.{ .path = tcl_source_folder ++ "/compat/zlib/win64"}); //tclsh.root_module.addLibraryPath(.{ .path = tcl_source_folder ++ "/libtommath/win64"}); //tclsh.root_module.linkSystemLibrary("zlib1", .{}); //tclsh.root_module.linkSystemLibrary("tommath", .{}); //////////////////// tclvfs //const tclvfs_compile = try tclvfs_static.build_tclvfs(tcl_source_folder, "../tclvfs", b, target, optimize, finalstublib); //const build_tclvfs_step = b.step("build-tclvfs", "build tclvfs static library"); //build_tclvfs_step.dependOn(&tclvfs_compile.step); //tclsh_exe.step.dependOn(&tclvfs_compile.step); //tclsh_exe.root_module.linkLibrary(tclvfs_compile); //////////////////// const tclvfs_compile = try tclvfs_shared.build_tclvfs(tcl_source_folder, "../tclvfs", b, target, optimize, finalstublib); const build_tclvfs_step = b.step("build-tclvfs", "build tclvfs shared library"); build_tclvfs_step.dependOn(&tclvfs_compile.step); tclsh_exe.step.dependOn(&tclvfs_compile.step); // review if (target.result.os.tag == .windows) { //G-102: vfs script package (lib/vfs1.4.2) installed by the recipe - the repl //code interp wants vfs/vfs::zip (modpod mounting). Formerly suite.tcl post-build. try tclvfs_shared.install_tclvfs_package("../tclvfs", b, tclvfs_compile); } //////////////////// //vqtcl/vlerq removed from the suite (user 2026-07-20): it was an attempt at old //tclkit support and its source has no confirmed public upstream. When tclkit //builds are investigated, TEMP_REFERENCE/metakit and TEMP_REFERENCE/KitCreator //in the punkshell repo are the reference material. tclsh_exe.root_module.link_libc = true; //LDFLAGS_CONSOLE= -mconsole -pipe -static-libgcc -municode -Wl,--enable-auto-image-base //rc compiled from the overlay copy (generated tclsh.exe.manifest beside it); //tclsh.ico + tcl.h resolve via the include paths. tclsh_exe.root_module.addWin32ResourceFile(.{ .file = tclshrc_overlay, .include_paths = &.{ b.path(tcl_source_folder ++ "/generic"), b.path(tcl_source_folder ++ "/win"), }, }); const install_tclsh = b.addInstallArtifact(tclsh_exe, .{}); std.debug.print("\n", .{}); std.debug.print("tclsh.kind {s}\n", .{@tagName(tclsh_exe.kind)}); std.debug.print("prefix {s}\n", .{b.install_path}); b.getInstallStep().dependOn(&install_tclsh.step); //--------------------------------------------------------------------- //tclsh90spr: the TCLSH_PIPEREPL-patched shell (G-096). Identical to //tclsh90s except tclMain.c is replaced by patches/tclMain_piperepl_905.c //(rebased 2024 patch; gate default flipped per the G-103 punk-kit policy: //enabled unless TCLSH_PIPEREPL=0 - see patches/README.md). Kept as a //SEPARATE product so the stock shells stay byte-for-byte unpatched. const tclsh_pr_exe = b.addExecutable(.{ .name = tclsh_static ++ "pr", .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize, }), }); tclsh_pr_exe.mingw_unicode_entry_point = true; tclsh_pr_exe.step.dependOn(&finalstublib.step); tclsh_pr_exe.step.dependOn(&tcl_objs_static.step); tclsh_pr_exe.root_module.addIncludePath(tcluuid_include_dir); //overlay first (G-102) tclsh_pr_exe.root_module.addIncludePath(b.path(tcl_source_folder ++ "/generic")); if (target.result.os.tag == .windows) { tclsh_pr_exe.root_module.addIncludePath(b.path(tcl_source_folder ++ "/win")); tclsh_pr_exe.root_module.addIncludePath(b.path(tcl_source_folder ++ "/compat/zlib")); tclsh_pr_exe.root_module.addIncludePath(b.path(tcl_source_folder ++ "/compat/zlib/contrib/minizip")); } else { tclsh_pr_exe.root_module.addIncludePath(b.path(tcl_source_folder ++ "/unix")); tclsh_pr_exe.root_module.addIncludePath(b.path(zlib_sourcedir)); tclsh_pr_exe.root_module.addIncludePath(b.path(zlib_sourcedir ++ "/contrib/minizip")); } tclsh_pr_exe.root_module.addIncludePath(b.path(tommath_sourcedir)); if (target.result.os.tag == .windows) { //ansi copy of the patched main (see the stock shell's mainansi note above) var pr_mainansi_flags = std.array_list.Managed([]const u8).init(b.allocator); try pr_mainansi_flags.appendSlice(tclobjs_flags.items); try pr_mainansi_flags.appendSlice(&.{ "-UUNICODE", "-U_UNICODE", "-DTCL_ASCII_MAIN", }); tclsh_pr_exe.root_module.addCSourceFile(.{ .file = b.path("patches/tclMain_piperepl_905.c"), .flags = pr_mainansi_flags.items, }); } tclsh_pr_exe.root_module.addCSourceFile(.{ .file = b.path(appinit_path), .flags = tclsh_flags.items, }); for (tcl_objs_static_sources.items) |src| { if (build_specials.get(std.fs.path.stem(src))) |val| { current_flagset = val.flags; } else { current_flagset = tclobjs_flags; } if (std.mem.eql(u8, std.fs.path.stem(src), "tclMain")) { //the unicode copy: patched file in place of stock, same special flags tclsh_pr_exe.root_module.addCSourceFile(.{ .file = b.path("patches/tclMain_piperepl_905.c"), .flags = current_flagset.items, }); } else { tclsh_pr_exe.root_module.addCSourceFile(.{ .file = b.path(src), .flags = current_flagset.items, }); } } tclsh_pr_exe.root_module.addCSourceFile(.{ .file = b.path(tcl_source_folder ++ "/generic/tclStubLib.c"), .flags = stublib_flags.items, }); tclsh_pr_exe.root_module.addCSourceFile(.{ .file = b.path(tcl_source_folder ++ "/generic/tclStubCall.c"), .flags = stublib_call_flags.items, }); tclsh_pr_exe.root_module.addCSourceFile(.{ .file = b.path(tcl_source_folder ++ "/generic/tclStubLibTbl.c"), .flags = stublib_tbl_flags.items, }); tclsh_pr_exe.root_module.addCSourceFile(.{ .file = b.path(tcl_source_folder ++ "/generic/tclTomMathStubLib.c"), .flags = stublib_tom_flags.items, }); tclsh_pr_exe.root_module.addCSourceFile(.{ .file = b.path(tcl_source_folder ++ "/generic/tclOOStubLib.c"), .flags = stublib_oo_flags.items, }); if (target.result.os.tag == .windows) { tclsh_pr_exe.root_module.addCSourceFile(.{ .file = b.path(tcl_source_folder ++ "/win/tclWinPanic.c"), .flags = winpaniclib_flags.items, }); tclsh_pr_exe.root_module.linkSystemLibrary("netapi32", .{}); tclsh_pr_exe.root_module.linkSystemLibrary("kernel32", .{}); tclsh_pr_exe.root_module.linkSystemLibrary("user32", .{}); tclsh_pr_exe.root_module.linkSystemLibrary("advapi32", .{}); tclsh_pr_exe.root_module.linkSystemLibrary("userenv", .{}); tclsh_pr_exe.root_module.linkSystemLibrary("ws2_32", .{}); tclsh_pr_exe.root_module.addObjectFile(b.path(tcl_source_folder ++ "/libtommath/win64/libtommath.dll.a")); } tclsh_pr_exe.step.dependOn(&zlib_lib_compile.step); tclsh_pr_exe.root_module.linkLibrary(zlib_lib_compile); tclsh_pr_exe.step.dependOn(&tclvfs_compile.step); // review (parity with stock shell) tclsh_pr_exe.root_module.link_libc = true; tclsh_pr_exe.root_module.addWin32ResourceFile(.{ .file = tclshrc_overlay, .include_paths = &.{ b.path(tcl_source_folder ++ "/generic"), b.path(tcl_source_folder ++ "/win"), }, }); const install_tclsh_pr = b.addInstallArtifact(tclsh_pr_exe, .{}); b.getInstallStep().dependOn(&install_tclsh_pr.step); //--------------------------------------------------------------------- //OPTIONAL steps const install_tzdata_step = b.step("install-tzdata", "install tcl timezone data"); //addInstallDirectory is recursive const tzdata_install = b.addInstallDirectory(.{ .source_dir = b.path(tcl_source_folder ++ "/library/tzdata"), .install_dir = .prefix, .install_subdir = b.pathJoin(&.{ script_install_dir_rel, "tzdata" }), }); install_tzdata_step.dependOn(&tzdata_install.step); //**************************** //zig build install-libraries const install_libraries = b.step("install-libraries", "install tcl libraries,tzdata,msgs (not required if zipfs being used)"); install_libraries.dependOn(&tclsh_exe.step); if (target.result.os.tag == .windows) { install_libraries.dependOn(®_dll.step); install_libraries.dependOn(&dde_dll.step); } //Whole library tree -> lib/tcl9.0 (stock-install parity, G-098 finding: the //library's own pkgIndex.tcl references subdir packages such as msgcat/ opt/ //cookiejar/ - installing only top-level .tcl files leaves phantom ifneeded //entries pointing at files that were never installed). const install_library_tree = b.addInstallDirectory(.{ .source_dir = b.path(tcl_source_folder ++ "/library"), .install_dir = .prefix, .install_subdir = "lib/tcl" ++ tcl_dot_version, }); install_libraries.dependOn(&install_library_tree.step); //(G-102: the former per-file top-level library install loop - a configure-time //directory iteration - was removed as redundant: install_library_tree above //already installs the whole library tree, top-level files included, to the same //lib/tcl9.0 destination.) //Makefile for tcl9.0b1 uses target folder /opt0.4 /cookiejar0.2 - but we don't really need the version as part of the folder structure //At least some distributions of tcl9 don't include the version - which seems simpler const cookiejar_install = b.addInstallDirectory(.{ .source_dir = b.path(tcl_source_folder ++ "/library/cookiejar"), .include_extensions = &.{ ".tcl", ".gz" }, .install_dir = .prefix, //.install_subdir = b.pathJoin(&.{ script_install_dir_rel, "cookiejar0.2" }), .install_subdir = b.pathJoin(&.{ script_install_dir_rel, "cookiejar" }), }); install_libraries.dependOn(&cookiejar_install.step); //(G-102: the former decorative 'echo --Installing package X--' banner steps were //removed - 'echo' is a cmd builtin, and spawning it as a program only worked when //a coreutils echo.exe happened to be on PATH; in a scrubbed environment the five //banner spawns failed and took install-libraries down transitively.) //tm modules under the module path (lib/tcl9/9.0). Version-stamped names follow //the checkout's library tree; single source for the prefix install AND the //G-103 family staging (a kit's tm root is /app/tcl9/ - tm.tcl anchors at //the dirname of the attached tcl_library). const tm_installs = [_]struct { src: []const u8, tm: []const u8 }{ .{ .src = "/library/http/http.tcl", .tm = "http-2.10.2.tm" }, .{ .src = "/library/msgcat/msgcat.tcl", .tm = "msgcat-1.7.1.tm" }, .{ .src = "/library/tcltest/tcltest.tcl", .tm = "tcltest-2.5.11.tm" }, .{ .src = "/library/platform/platform.tcl", .tm = "platform-1.1.1.tm" }, .{ .src = "/library/platform/shell.tcl", .tm = "platform/shell-1.1.4.tm" }, }; inline for (tm_installs) |tmi| { const tm_inst = b.addInstallFileWithDir(b.path(tcl_source_folder ++ tmi.src), .prefix, b.pathJoin(&.{ module_install_dir_rel, tcl_dot_version, tmi.tm })); install_libraries.dependOn(&tm_inst.step); } //opt/*.tcl const opt_tcl_install = b.addInstallDirectory(.{ .source_dir = b.path(tcl_source_folder ++ "/library/opt"), .include_extensions = &.{".tcl"}, .install_dir = .prefix, //.install_subdir = b.pathJoin(&.{ script_install_dir_rel, "opt0.4" }), .install_subdir = b.pathJoin(&.{ script_install_dir_rel, "opt" }), }); install_libraries.dependOn(&opt_tcl_install.step); const opt_registry_install = b.addInstallDirectory(.{ .source_dir = b.path(tcl_source_folder ++ "/library/registry"), .include_extensions = &.{".tcl"}, .install_dir = .prefix, .install_subdir = b.pathJoin(&.{ script_install_dir_rel, "registry" }), }); install_libraries.dependOn(&opt_registry_install.step); const pkgindex_install = b.addInstallFile(b.path(tcl_source_folder ++ "/library/manifest.txt"), b.pathJoin(&.{ script_install_dir_rel, "pkgIndex.tcl" })); install_libraries.dependOn(&pkgindex_install.step); const encodings_install = b.addInstallDirectory(.{ .source_dir = b.path(tcl_source_folder ++ "/library/encoding"), .include_extensions = &.{".enc"}, .install_dir = .prefix, .install_subdir = b.pathJoin(&.{ script_install_dir_rel, "encoding" }), }); install_libraries.dependOn(&encodings_install.step); install_libraries.dependOn(install_tzdata_step); if (target.result.os.tag == .windows) { install_libraries.dependOn(&install_dde_dll.step); //G-098: the registry install artifact existed but was hooked to nothing - //library/registry/pkgIndex.tcl then pointed at a dll never installed //(punkshell's punk module probes 'package require registry' at load). install_libraries.dependOn(&install_reg_dll.step); } //**************************** //**************************** //zig build install-libraries const make_vfs_root = b.addWriteFiles(); const tcl_library_path = make_vfs_root.addCopyDirectory(b.path(tcl_source_folder ++ "/library"), "base/tcl_library", .{}); //_ = make_vfs_root.addCopyDirectory(b.path(tcl_source_folder ++ "/library"), "tcl_library", .{}); _ = make_vfs_root.addCopyFile(b.path(tcl_source_folder ++ "/library/manifest.txt"), "base/tcl_library/pkgIndex.tcl"); _ = make_vfs_root.addCopyFile(b.path(tcl_source_folder ++ "/library/manifest.txt"), "base/tcl_library/pkgIndex.tcl"); if (target.result.os.tag == .windows) { _ = make_vfs_root.addCopyFile(install_dde_dll.artifact.getEmittedBin(), "base/tcl_library/dde/" ++ dde_dll_file); //_ = make_vfs_root.addCopyFile(dde_dll.getEmittedBin(), "tcl_library/dde/" ++ dde_dll_file); _ = make_vfs_root.addCopyFile(reg_dll.getEmittedBin(), "base/tcl_library/registry/" ++ reg_dll_file); make_vfs_root.step.dependOn(®_dll.step); make_vfs_root.step.dependOn(&dde_dll.step); } //make_vfs_root.step.dependOn(&tclvfs_compile.step); // The build_tclvfs_xxx.zig module is responsible for what files tclvfs needs to add the vfs root // -pass it the *WriteFile we're building and let it add stuff // ***************************** // tclvfs shared/static - todo //_ = try tclvfs_static.vfsadd_tclvfs_files(tcl_source_folder, "../tclvfs", b, make_vfs_root); _ = try tclvfs_shared.vfsadd_tclvfs_files(tcl_source_folder, "../tclvfs", b, make_vfs_root); //hack const tclvfs_info = tclvfs_shared.versionInfo(b, "../tclvfs"); _ = make_vfs_root.addCopyFile(tclvfs_compile.getEmittedBin(), b.fmt("base/lib/vfs{s}/{s}", .{ tclvfs_info.dotversion, tclvfs_info.dll_file })); // ***************************** //vqtcl/vlerq zip payload removed with the rest of the vqtcl wiring (user 2026-07-20; //old-tclkit experiment - see TEMP_REFERENCE/metakit + TEMP_REFERENCE/KitCreator). //pass make_vfs_root to build_tclvfs make_vfs_root.step.dependOn(install_libraries); // ** system zip - problematic to call in the way we need from zig.build // I know of no way to get the resulting zip file to strip the containing directory path when using addDirectoryArg. // Normally this is done by passing a relative path as the input folder to be archived - but we need to use zig's addDirectoryArg instead of just addArg with a string // If we don't use addDirectoryArg - the zig cache will return stale results despite the systemzip step depending on make_vfs_root.step, etc (why??) // addDirectoryArg seems only able to provide a full path to the system command - not the relative path we would need to strip the containing folder. // -j option of zip doesn't help as it strips all paths. // This isn't a great concern here - as we have a partially built tclsh and we would prefer to use the less platform-dependant 'zipfs mkzip' functionality provided therein anyway // But it would have been nice for debug/testing purposes to compare with a system zip // zipfs mkzip may be fine for our purposes but doesn't give us some of the potential customisability of a system zip command // const systemzip = b.addSystemCommand(&.{ "zip", "-r" }); //systemzip.step.dependOn(&make_vfs_root.step); systemzip.setCwd(make_vfs_root.getDirectory()); const out_zip = systemzip.addOutputFileArg("zipfs.zip"); //systemzip.addDirectoryArg(tcl_library_path); systemzip.addArg("tcl_library"); const install_systemzip = b.addInstallFileWithDir(out_zip, .prefix, "zipfs.zip"); install_systemzip.step.dependOn(&systemzip.step); //b.getInstallStep().dependOn(&install_systemzip.step); // ** *** mkzip var mkzip_run: *std.Build.Step.Run = undefined; //mkzip_run.step.dependOn(&make_vfs_root.step); // ?????? //mkzip_run.step.dependOn(install_libraries); if (target.result.os.tag == builtin.os.tag) { mkzip_run = b.addRunArtifact(tclsh_exe); } else { mkzip_run = b.addSystemCommand(&.{"tclsh90"}); } common.scrubTclEnv(mkzip_run); mkzip_run.setEnvironmentVariable("TCL_LIBRARY", tcl_library_src); mkzip_run.addFileArg(b.path("tools/zipfs_mkzip.tcl")); mkzip_run.addArg("-outfile"); const out_mkzip = mkzip_run.addOutputFileArg("mkzipfs.zip"); mkzip_run.addArg("-indir"); mkzip_run.addDirectoryArg(tcl_library_path.dirname()); mkzip_run.addArg("-strip"); mkzip_run.addDirectoryArg(tcl_library_path.dirname()); //mkzip_run.addArg(make_vfs_root.getDirectory()); const install_mkzip = b.addInstallFileWithDir(out_mkzip, .prefix, "mkzipfs.zip"); install_mkzip.step.dependOn(&mkzip_run.step); const make_zipfs = b.step("make-zipfs", "make zipfs and attach to executable"); //make_zipfs.dependOn(&tclsh_exe.step); make_zipfs.dependOn(&install_mkzip.step); //make_zipfs.dependOn(&install_systemzip.step); //not really required // ** *** // ** *** *** mkimg var mkimg_run: *std.Build.Step.Run = undefined; if (target.result.os.tag == builtin.os.tag) { mkimg_run = b.addRunArtifact(tclsh_exe); } else { //require an existing tclsh90 - with zipfs support on the path for x-builds mkimg_run = b.addSystemCommand(&.{"tclsh90"}); } common.scrubTclEnv(mkimg_run); mkimg_run.setEnvironmentVariable("TCL_LIBRARY", tcl_library_src); mkimg_run.addFileArg(b.path("tools/zipfs_mkimg.tcl")); mkimg_run.addArg("-outfile"); var out_mkimg: std.Build.LazyPath = undefined; if (target.result.os.tag == .windows) { out_mkimg = mkimg_run.addOutputFileArg("tclsh90szip.exe"); } else { out_mkimg = mkimg_run.addOutputFileArg("tclsh90szip"); } mkimg_run.addArg("-indir"); mkimg_run.addDirectoryArg(tcl_library_path.dirname()); mkimg_run.addArg("-strip"); mkimg_run.addDirectoryArg(tcl_library_path.dirname()); if (target.result.os.tag == .windows) { //we can just leave off the -infile argument to use the calling interp as the prepended file } else { mkimg_run.addArg("-infile"); mkimg_run.addArtifactArg(tclsh_exe); } var install_mkimg: *std.Build.Step.InstallFile = undefined; if (target.result.os.tag == .windows) { install_mkimg = b.addInstallFileWithDir(out_mkimg, .prefix, "bin/tclsh90szip.exe"); } else { install_mkimg = b.addInstallFileWithDir(out_mkimg, .prefix, "bin/tclsh90szip"); } install_mkimg.step.dependOn(&mkimg_run.step); make_zipfs.dependOn(&install_mkimg.step); // ** *** *** // ** *** *** mkimg for the piperepl shell -> tclsh90sprzip(.exe) //Same attached-library wrap as tclsh90szip, but the prefix executable is the //patched shell, named explicitly via -infile (the stock wrap uses the calling //interp as its own prefix on windows). var mkimg_pr_run: *std.Build.Step.Run = undefined; if (target.result.os.tag == builtin.os.tag) { mkimg_pr_run = b.addRunArtifact(tclsh_exe); } else { //require an existing tclsh90 - with zipfs support on the path for x-builds mkimg_pr_run = b.addSystemCommand(&.{"tclsh90"}); } common.scrubTclEnv(mkimg_pr_run); mkimg_pr_run.setEnvironmentVariable("TCL_LIBRARY", tcl_library_src); mkimg_pr_run.addFileArg(b.path("tools/zipfs_mkimg.tcl")); mkimg_pr_run.addArg("-outfile"); var out_mkimg_pr: std.Build.LazyPath = undefined; if (target.result.os.tag == .windows) { out_mkimg_pr = mkimg_pr_run.addOutputFileArg("tclsh90sprzip.exe"); } else { out_mkimg_pr = mkimg_pr_run.addOutputFileArg("tclsh90sprzip"); } mkimg_pr_run.addArg("-indir"); mkimg_pr_run.addDirectoryArg(tcl_library_path.dirname()); mkimg_pr_run.addArg("-strip"); mkimg_pr_run.addDirectoryArg(tcl_library_path.dirname()); mkimg_pr_run.addArg("-infile"); mkimg_pr_run.addArtifactArg(tclsh_pr_exe); var install_mkimg_pr: *std.Build.Step.InstallFile = undefined; if (target.result.os.tag == .windows) { install_mkimg_pr = b.addInstallFileWithDir(out_mkimg_pr, .prefix, "bin/tclsh90sprzip.exe"); } else { install_mkimg_pr = b.addInstallFileWithDir(out_mkimg_pr, .prefix, "bin/tclsh90sprzip"); } install_mkimg_pr.step.dependOn(&mkimg_pr_run.step); make_zipfs.dependOn(&install_mkimg_pr.step); // ** *** *** //**************************** const thread_build = try build_tclthread(tcl_source_folder, "../tclthread", b, target, optimize, finalstublib); const build_tclthread_step = b.step("build-tclthread", "build tcl thread library"); build_tclthread_step.dependOn(&thread_build.lib.step); b.getInstallStep().dependOn(build_tclthread_step); //G-098: Tk loadable extension (windows target only for now). The build facts //are hoisted (optional) so the G-103 bi-family staging can consume them. var tk_build: ?TkBuild = null; if (target.result.os.tag == .windows) { tk_build = try build_tk(tcl_source_folder, "../tk9", b, target, optimize, finalstublib); const build_tk_step = b.step("build-tk", "build tk shared library (tcl9tk90.dll) + tk script library install"); build_tk_step.dependOn(&tk_build.?.lib.step); } //if !ZIPFS_BUILD //install without zipfs //b.getInstallStep().dependOn(install_libraries); // ================== G-102 post-tclsh phases ================== //Tcl phases executed by the FRESHLY BUILT suite shell as build steps - Tcl stays //the tool exactly where a tclsh is guaranteed to exist because the suite just //built it. Formerly suite.tcl's post-build blocks; suite.tcl now drives these //via step names. Native-host builds only (the runs execute the built artifacts). if (target.result.os.tag == builtin.os.tag) { //-- smoke: shells respond with the expected patchlevel; the zip shell proves //the attached library (tzdata + autoload) const smoke_step = b.step("smoke", "smoke-test the built shells (patchlevel; zip: attached tzdata/autoload)"); const smoke_static = b.addRunArtifact(tclsh_exe); common.scrubTclEnv(smoke_static); smoke_static.setEnvironmentVariable("TCL_LIBRARY", tcl_library_src); smoke_static.has_side_effects = true; smoke_static.addFileArg(b.path("tools/suite_smoke.tcl")); smoke_static.addArgs(&.{ "-mode", "static", "-expect", tcl_h_patchlevel }); smoke_static.step.dependOn(b.getInstallStep()); smoke_step.dependOn(&smoke_static.step); const zipexe_name = if (target.result.os.tag == .windows) tclsh_static ++ "zip.exe" else tclsh_static ++ "zip"; const smoke_zip = b.addSystemCommand(&.{b.pathJoin(&.{ b.install_path, "bin", zipexe_name })}); common.scrubTclEnv(smoke_zip); smoke_zip.has_side_effects = true; smoke_zip.addFileArg(b.path("tools/suite_smoke.tcl")); smoke_zip.addArgs(&.{ "-mode", "zip", "-expect", tcl_h_patchlevel }); smoke_zip.step.dependOn(&install_mkimg.step); smoke_step.dependOn(&smoke_zip.step); //-- tklib: pure-tcl but its installer is NOT a straight copy (module //exclusions + aggregating pkgIndex generation). Batch mode, packages only; //the -pkg-path is a cached output dir installed into the prefix. const tklib_ver = common.installerPackageVersion(b, "../tklib"); const tklib_step = b.step("tklib", "install tklib via its own installer under the suite-built shell (+Tk smoke)"); const tklib_run = b.addRunArtifact(tclsh_exe); common.scrubTclEnv(tklib_run); tklib_run.setEnvironmentVariable("TCL_LIBRARY", tcl_library_src); //cached (non-side-effect) Runs spawn with stdout IGNORED - on windows the //child then has no stdout handle and tcl errors on any puts ('can not find //channel named "stdout"', critcl's logging). Capturing gives it a real pipe. _ = tklib_run.captureStdOut(.{}); tklib_run.setCwd(b.path("../tklib")); tklib_run.addFileArg(b.path("../tklib/installer.tcl")); tklib_run.addArgs(&.{ "-no-gui", "-no-wait", "-no-apps", "-no-html", "-no-nroff", "-no-examples", "-pkg-path" }); const tklib_out = tklib_run.addOutputDirectoryArg("tklib-pkg"); const tklib_install = b.addInstallDirectory(.{ .source_dir = tklib_out, .install_dir = .prefix, .install_subdir = b.fmt("lib/tklib{s}", .{tklib_ver}), }); const tklib_smoke = b.addRunArtifact(tclsh_exe); common.scrubTclEnv(tklib_smoke); tklib_smoke.setEnvironmentVariable("TCL_LIBRARY", tcl_library_src); tklib_smoke.has_side_effects = true; tklib_smoke.addFileArg(b.path("tools/pkg_smoke.tcl")); tklib_smoke.addArgs(&.{ "-gui", "1", "tooltip" }); tklib_smoke.step.dependOn(&tklib_install.step); tklib_smoke.step.dependOn(b.getInstallStep()); //Tk dll + pkgIndex + tcl library tklib_step.dependOn(&tklib_smoke.step); //-- tcllib: same installer family (critcl DSL stubbed to no-ops - this is the //PURE-TCL side; the critcl-built tcllibc accelerators are the next step) const tcllib_ver = common.installerPackageVersion(b, "../tcllib"); const tcllib_step = b.step("tcllib", "install tcllib (pure-tcl side) via its own installer under the suite-built shell (+smoke)"); const tcllib_run = b.addRunArtifact(tclsh_exe); common.scrubTclEnv(tcllib_run); tcllib_run.setEnvironmentVariable("TCL_LIBRARY", tcl_library_src); //cached (non-side-effect) Runs spawn with stdout IGNORED - on windows the //child then has no stdout handle and tcl errors on any puts ('can not find //channel named "stdout"', critcl's logging). Capturing gives it a real pipe. _ = tcllib_run.captureStdOut(.{}); tcllib_run.setCwd(b.path("../tcllib")); tcllib_run.addFileArg(b.path("../tcllib/installer.tcl")); tcllib_run.addArgs(&.{ "-no-gui", "-no-wait", "-no-apps", "-no-html", "-no-nroff", "-no-examples", "-pkg-path" }); const tcllib_out = tcllib_run.addOutputDirectoryArg("tcllib-pkg"); const tcllib_install = b.addInstallDirectory(.{ .source_dir = tcllib_out, .install_dir = .prefix, .install_subdir = b.fmt("lib/tcllib{s}", .{tcllib_ver}), }); const tcllib_smoke = b.addRunArtifact(tclsh_exe); common.scrubTclEnv(tcllib_smoke); tcllib_smoke.setEnvironmentVariable("TCL_LIBRARY", tcl_library_src); tcllib_smoke.has_side_effects = true; tcllib_smoke.addFileArg(b.path("tools/pkg_smoke.tcl")); tcllib_smoke.addArgs(&.{ "md5", "sha1", "cmdline" }); tcllib_smoke.step.dependOn(&tcllib_install.step); tcllib_smoke.step.dependOn(b.getInstallStep()); tcllib_step.dependOn(&tcllib_smoke.step); //-- tcllibc: tcllib's critcl accelerators, critcl driving zig cc (the //tracked critcl_zig.config; zig resolved from PATH with our own dir //prepended). sak.tcl's critcl target expects a tclkitsh on windows - this //replicates its underlying invocation directly, as suite.tcl did. const tcllibc_step = b.step("tcllibc", "build+install tcllibc (critcl accelerators, zig cc) under the suite-built shell (+accel smoke)"); const critcl_run = b.addRunArtifact(tclsh_exe); common.scrubTclEnv(critcl_run); critcl_run.setEnvironmentVariable("TCL_LIBRARY", tcl_library_src); //cached (non-side-effect) Runs spawn with stdout IGNORED - on windows the //child then has no stdout handle and tcl errors on any puts ('can not find //channel named "stdout"', critcl's logging). Capturing gives it a real pipe. _ = critcl_run.captureStdOut(.{}); critcl_run.setCwd(b.path("../tcllib")); critcl_run.addFileArg(b.path("../critcl/main.tcl")); critcl_run.addArg("-config"); critcl_run.addFileArg(b.path("critcl_zig.config")); //pin the build target to the config's explicit section: critcl otherwise //GUESSES its target by probing PATH for compilers - with a gcc visible the //config defaults engaged, but a scrubbed environment fell back to critcl's //builtin msvc 'cl' target and never used the zig cc settings (G-102 finding). critcl_run.addArgs(&.{ "-target", "win32-x86_64-zig" }); critcl_run.addArg("-cache"); _ = critcl_run.addOutputDirectoryArg("critcl-cache"); critcl_run.addArg("-force"); critcl_run.addArg("-libdir"); const critcl_libout = critcl_run.addOutputDirectoryArg("critcl-lib"); critcl_run.addArgs(&.{ "-pkg", "tcllibc" }); for (common.tcllibCritclFiles(b, "../tcllib")) |cf| { critcl_run.addFileArg(b.path(b.pathJoin(&.{ "../tcllib/modules", cf }))); } const zigdir = std.fs.path.dirname(b.graph.zig_exe) orelse "."; const inherited_path = b.graph.environ_map.get("PATH") orelse ""; critcl_run.setEnvironmentVariable("PATH", b.fmt("{s}{c}{s}", .{ zigdir, std.fs.path.delimiter, inherited_path })); const tcllibc_install = b.addInstallDirectory(.{ .source_dir = critcl_libout, .install_dir = .prefix, .install_subdir = "lib", }); const tcllibc_smoke = b.addRunArtifact(tclsh_exe); common.scrubTclEnv(tcllibc_smoke); tcllibc_smoke.setEnvironmentVariable("TCL_LIBRARY", tcl_library_src); tcllibc_smoke.has_side_effects = true; tcllibc_smoke.addFileArg(b.path("tools/pkg_smoke.tcl")); tcllibc_smoke.addArgs(&.{ "-accel", "md5", "tcllibc" }); tcllibc_smoke.step.dependOn(&tcllibc_install.step); tcllibc_smoke.step.dependOn(&tcllib_install.step); //accel host packages come from tcllib tcllibc_smoke.step.dependOn(b.getInstallStep()); tcllibc_step.dependOn(&tcllibc_smoke.step); const testreports_dir = common.replaceAll(b, b.pathJoin(&.{ b.install_path, "testreports" }), "\\", "/"); // ================== G-103 runtime kit family ================== //PLAIN (stock shell + batteries), PUNK (piperepl-patched shell, gate //default-ON with TCLSH_PIPEREPL=0 opt-out, same batteries), PUNK-BI //(punk + the libraries we build: Tk dll + script lib, tklib). Working //names carry the dotted tcl patchlevel with punk-marked patched shells //(tclsh9.0.5.exe / tclsh9.0.5-punk.exe / tclsh9.0.5-punk-bi.exe - G-103 //naming decision); -r artifact copies are kit-family-artifacts' job. // //Attached-image layout (the make.tcl kit contract: what a future kit //build extracts and merges under its .vfs payload): // tcl_library/ core script library (the C-level zipfs boot looks only // for /app/main.tcl and /app/tcl_library; no main.tcl - // stock fallthrough to the interactive shell) // tcl9// tm modules (tm.tcl anchors at dirname of tcl_library) // lib// batteries with their installed-shape pkgIndexes // ($dir/../../bin dll references resolve to /app/bin) // bin/ battery dlls (loaded from zipfs via copy-to-temp - // the characterized TIP-741 cleanup wart, goal Notes) // lib/pkgIndex.tcl one-line stock hook joining lib/ to the package // search: auto_path is [tcl_library, /app] and // tclPkgUnknown re-scans auto_path growth mid-scan (the // same mechanism tcllib's own top-level index uses) if (target.result.os.tag == .windows) { const family_step = b.step("kit-family", "assemble + verify the G-103 runtime kit family (plain/punk/punk-bi): self-contained batteries-attached shells -> /family"); const family_libext_pkgindex = \\#punkshell runtime kit family (G-103): stock package-index hook extending \\#the package search into the attached image's lib/ tree (tclPkgUnknown \\#re-scans auto_path growth mid-scan - the same mechanism tcllib's own \\#top-level pkgIndex uses). The batteries keep their installed-shape \\#indexes ($dir/../../bin dll references resolve to /app/bin). \\if {$dir ni $::auto_path} {lappend ::auto_path $dir} \\ ; const tkb = tk_build.?; //windows target (checked just above) //default 2: r1 of every (9.0.5, variant) pair was PUBLISHED to punkbin //2026-07-22 and is immutable - subsequent assemblies (first content //change: tclvfs forTcl9/1.5.0) emit as r2 until r2 is itself published //and superseded. Bump this default whenever the current rev publishes. const familyrev = b.option(u32, "familyrev", "assembly revision N for the -r family artifact names (kit-family-artifacts; default 2 - r1 published 2026-07-22)") orelse 2; //G-117 schema v1 identity options. origin = canonical artifact repo the //artifacts are BUILT FOR (not necessarily where they end up hosted - //mirrors preserve it). packager = declared identity, resolution chain //-Dpackager > env PUNKBIN_PACKAGER > building checkout's git identity > //"unrecorded" (declarative, not proof - signing is the verification layer). const originurl = b.option([]const u8, "originurl", "canonical artifact repo url the family artifacts are built FOR ('origin' field; default punkbin)") orelse "https://www.gitea1.intx.com.au/jn/punkbin"; const projecturl = b.option([]const u8, "projecturl", "project url recorded in the artifact records ('project_url' field; default unrecorded)") orelse "unrecorded"; const packager = blk: { if (b.option([]const u8, "packager", "declared packager identity for the artifact records (-Dpackager > env PUNKBIN_PACKAGER > git identity > unrecorded)")) |p| break :blk p; if (b.graph.environ_map.get("PUNKBIN_PACKAGER")) |p| { if (p.len != 0) break :blk p; } var gc: u8 = undefined; const gname: ?[]const u8 = b.runAllowFail(&.{ "git", "config", "user.name" }, &gc, .ignore) catch null; if (gname != null and gc == 0) { const nm = std.mem.trim(u8, gname.?, " \t\r\n"); if (nm.len != 0) { const gmail: ?[]const u8 = b.runAllowFail(&.{ "git", "config", "user.email" }, &gc, .ignore) catch null; if (gmail != null and gc == 0) { const em = std.mem.trim(u8, gmail.?, " \t\r\n"); if (em.len != 0) break :blk b.fmt("{s} <{s}>", .{ nm, em }); } break :blk nm; } } break :blk "unrecorded"; }; const FamilyKit = struct { variant: []const u8, working_name: []const u8, prefix_exe: *std.Build.Step.Compile, tree: usize, }; const family_kits = [_]FamilyKit{ .{ .variant = "plain", .working_name = b.fmt("tclsh{s}.exe", .{tcl_h_patchlevel}), .prefix_exe = tclsh_exe, .tree = 0 }, .{ .variant = "punk", .working_name = b.fmt("tclsh{s}-punk.exe", .{tcl_h_patchlevel}), .prefix_exe = tclsh_pr_exe, .tree = 0 }, .{ .variant = "punk-bi", .working_name = b.fmt("tclsh{s}-punk-bi.exe", .{tcl_h_patchlevel}), .prefix_exe = tclsh_pr_exe, .tree = 1 }, }; //source checkout uuids (also consumed by kit-family-artifacts below) const uuid_tcl = common.manifestUuid(b, tcl_source_folder); const uuid_thread = common.manifestUuid(b, "../tclthread"); const uuid_tclvfs = common.manifestUuid(b, "../tclvfs"); const uuid_tk = common.manifestUuid(b, "../tk9"); const uuid_tcllib = common.manifestUuid(b, "../tcllib"); const uuid_tklib = common.manifestUuid(b, "../tklib"); //G-117: per-member EMBEDDED artifact record (schema v1), staged into each //member's payload tree as base/punkbin-artifact.toml (namespaced so a //future G-025 kit-stamp file can coexist; the record survives make.tcl //kit wrapping, which overlays without clearing). Finished-binary facts //(sha1, size, built) stay SIDECAR-ONLY: embed-then-hash ordering, no //circularity - the sidecar + sha1sums.txt remain the integrity authority. //build_id is a uuid-shaped sha1 digest over stable identity inputs //(artifact name incl -r, toolchain/optimize, patchlevel, the member's //source-checkout uuids) - deterministic so the zig cache holds across //configures; a correlation key, not an integrity key. var family_records: [family_kits.len][]const u8 = undefined; for (family_kits, 0..) |fk, ki| { const kbi = fk.tree == 1; const wroot = fk.working_name[0 .. fk.working_name.len - 4]; //strip ".exe" (windows branch) const artifact_name = b.fmt("{s}-r{d}.exe", .{ wroot, familyrev }); const prov_seed = if (kbi) b.fmt("tcl {s} thread {s} tclvfs {s} tcllib {s} tk {s} tklib {s}", .{ uuid_tcl, uuid_thread, uuid_tclvfs, uuid_tcllib, uuid_tk, uuid_tklib }) else b.fmt("tcl {s} thread {s} tclvfs {s} tcllib {s}", .{ uuid_tcl, uuid_thread, uuid_tclvfs, uuid_tcllib }); var idigest: [20]u8 = undefined; std.crypto.hash.Sha1.hash(b.fmt("punkbin-artifact|{s}|zig {s}|{s}|tcl{s}|{s}", .{ artifact_name, builtin.zig_version_string, @tagName(optimize), tcl_h_patchlevel, prov_seed }), &idigest, .{}); const ihex = std.fmt.bytesToHex(idigest, .lower); const build_id = b.fmt("{s}-{s}-{s}-{s}-{s}", .{ ihex[0..8], ihex[8..12], ihex[12..16], ihex[16..20], ihex[20..32] }); const batteries = if (kbi) b.fmt("[\"Thread {s}\", \"vfs {s}\", \"tcllib {s}\", \"tcllibc {s}\", \"Tk {s}\", \"tklib {s}\"]", .{ thread_build.version, tclvfs_info.dotversion, tcllib_ver, tcllib_ver, tkb.patchlevel, tklib_ver }) else b.fmt("[\"Thread {s}\", \"vfs {s}\", \"tcllib {s}\", \"tcllibc {s}\"]", .{ thread_build.version, tclvfs_info.dotversion, tcllib_ver, tcllib_ver }); const piperepl_block: []const u8 = if (std.mem.eql(u8, fk.variant, "plain")) "piperepl = false" else "piperepl = true\npiperepl_default = \"on\"\npiperepl_opt_out = \"TCLSH_PIPEREPL=0\""; const prov_lines = if (kbi) b.fmt("tcl_checkout = \"{s}\"\nthread_checkout = \"{s}\"\ntclvfs_checkout = \"{s}\"\ntk_checkout = \"{s}\"\ntcllib_checkout = \"{s}\"\ntklib_checkout = \"{s}\"", .{ uuid_tcl, uuid_thread, uuid_tclvfs, uuid_tk, uuid_tcllib, uuid_tklib }) else b.fmt("tcl_checkout = \"{s}\"\nthread_checkout = \"{s}\"\ntclvfs_checkout = \"{s}\"\ntcllib_checkout = \"{s}\"", .{ uuid_tcl, uuid_thread, uuid_tclvfs, uuid_tcllib }); family_records[ki] = b.fmt( \\#punkshell runtime artifact metadata - EMBEDDED copy (G-117 schema v1), \\#written at kit-family staging. Finished-binary facts (sha1, size, built) \\#live only in the sidecar toml + sha1sums.txt, which remain the integrity \\#authority; this copy makes a stray or renamed runtime self-describing. \\schema = 1 \\ \\[artifact] \\name = "{s}" \\class = "runtime" \\variant = "{s}" \\working_name = "{s}" \\revision = {d} \\target = "win32-x86_64" \\#build_id: offline correlation key re-joining a renamed copy to its record; \\#identical in embedded and sidecar copies. Uuid-shaped digest of stable \\#identity inputs (deterministic) - not an integrity key. \\build_id = "{s}" \\#origin: canonical artifact repo this artifact was BUILT FOR - not \\#necessarily where it is hosted; mirrors preserve it. \\origin = "{s}" \\#packager: declared identity, not proof - signing (minisign sidecars) \\#is the verification layer. \\packager = "{s}" \\project = "punkshell" \\project_url = "{s}" \\#license: summary for the distributed artifact; component license texts \\#ride inside the attached image (tcl_library/license.terms etc). \\license = "TCL" \\build_host_platform = "win32-x86_64" \\ \\[runtime] \\tcl_patchlevel = "{s}" \\{s} \\attached_batteries = {s} \\ \\[provenance] \\suite = "suite_tcl90" \\toolchain = "zig {s}" \\optimize = "{s}" \\{s} \\ , .{ artifact_name, fk.variant, fk.working_name, familyrev, build_id, originurl, packager, projecturl, tcl_h_patchlevel, piperepl_block, batteries, builtin.zig_version_string, @tagName(optimize), prov_lines }); } var family_tree_base: [family_kits.len]std.Build.LazyPath = undefined; for (family_kits, 0..) |fk, ki| { //per-member payload tree: shared content + the member's embedded record const famwf = b.addWriteFiles(); //core script library at the boot position (tzdata/encoding ride //inside the source library tree), dde/registry dlls inside const fam_tcl_library = famwf.addCopyDirectory(b.path(tcl_source_folder ++ "/library"), "base/tcl_library", .{}); _ = famwf.addCopyFile(b.path(tcl_source_folder ++ "/library/manifest.txt"), "base/tcl_library/pkgIndex.tcl"); _ = famwf.addCopyFile(install_dde_dll.artifact.getEmittedBin(), "base/tcl_library/dde/" ++ dde_dll_file); _ = famwf.addCopyFile(reg_dll.getEmittedBin(), "base/tcl_library/registry/" ++ reg_dll_file); //tm modules (same set the prefix install carries) inline for (tm_installs) |tmi| { _ = famwf.addCopyFile(b.path(tcl_source_folder ++ tmi.src), "base/tcl9/" ++ tcl_dot_version ++ "/" ++ tmi.tm); } //package-search hook for the lib/ tree _ = famwf.add("base/lib/pkgIndex.tcl", family_libext_pkgindex); //G-117 embedded artifact record (per-member; see the record block above) _ = famwf.add("base/punkbin-artifact.toml", family_records[ki]); //batteries (installed shape) try tclvfs_shared.familyadd_tclvfs_package("../tclvfs", b, famwf, b.fmt("base/lib/vfs{s}", .{tclvfs_info.dotversion}), tclvfs_compile); _ = famwf.addCopyFile(thread_build.pkgidx, b.fmt("base/lib/thread{s}/pkgIndex.tcl", .{thread_build.version})); _ = famwf.addCopyFile(thread_build.lib.getEmittedBin(), b.fmt("base/bin/{s}", .{thread_build.dll_file})); _ = famwf.addCopyDirectory(tcllib_out, b.fmt("base/lib/tcllib{s}", .{tcllib_ver}), .{}); _ = famwf.addCopyDirectory(critcl_libout, "base/lib", .{}); //carries tcllibc/ if (fk.tree == 1) { _ = famwf.addCopyDirectory(b.path("../tk9/library"), b.fmt("base/lib/{s}", .{tkb.libdir}), .{}); _ = famwf.addCopyFile(tkb.pkgidx, b.fmt("base/lib/{s}/pkgIndex.tcl", .{tkb.libdir})); _ = famwf.addCopyFile(tkb.lib.getEmittedBin(), b.fmt("base/bin/{s}", .{tkb.dll_file})); _ = famwf.addCopyDirectory(tklib_out, b.fmt("base/lib/tklib{s}", .{tklib_ver}), .{}); } family_tree_base[ki] = fam_tcl_library.dirname(); } var family_checks: [family_kits.len]*std.Build.Step = undefined; var family_installed: [family_kits.len][]const u8 = undefined; for (family_kits, 0..) |fk, ki| { const wrap = b.addRunArtifact(tclsh_exe); common.scrubTclEnv(wrap); wrap.setEnvironmentVariable("TCL_LIBRARY", tcl_library_src); wrap.addFileArg(b.path("tools/zipfs_mkimg.tcl")); wrap.addArg("-outfile"); const wrapped = wrap.addOutputFileArg(fk.working_name); wrap.addArg("-indir"); wrap.addDirectoryArg(family_tree_base[ki]); wrap.addArg("-strip"); wrap.addDirectoryArg(family_tree_base[ki]); wrap.addArg("-infile"); wrap.addArtifactArg(fk.prefix_exe); const inst = b.addInstallFileWithDir(wrapped, .prefix, b.fmt("family/{s}", .{fk.working_name})); inst.step.dependOn(&wrap.step); const installed_path = common.replaceAll(b, b.pathJoin(&.{ b.install_path, "family", fk.working_name }), "\\", "/"); family_installed[ki] = installed_path; //self-containment verification: the tool copies the kit alone into //a scratch dir and probes from there with a scrubbed environment //(no external Tcl visible - see tools/family_check.tcl) const check = b.addRunArtifact(tclsh_exe); common.scrubTclEnv(check); check.setEnvironmentVariable("TCL_LIBRARY", tcl_library_src); check.has_side_effects = true; check.addFileArg(b.path("tools/family_check.tcl")); check.addArgs(&.{ "-exe", installed_path, "-variant", fk.variant, "-expectpatch", tcl_h_patchlevel }); check.addArgs(&.{ "-thread", thread_build.version, "-vfs", tclvfs_info.dotversion, "-tcllib", tcllib_ver }); if (std.mem.eql(u8, fk.variant, "punk-bi")) { check.addArgs(&.{ "-tk", tkb.patchlevel, "-tklib", tklib_ver }); } check.step.dependOn(&inst.step); family_checks[ki] = &check.step; family_step.dependOn(&check.step); } //-- kit-family-artifacts: punkbin-layout emission (-r immutable //artifact names + per-artifact toml metadata + sha1sums), run UNDER //THE PLAIN FAMILY KIT itself - every emission doubles as a proof the //family runtime executes real tooling from its attached batteries. //Depends on the checks: only verified kits get artifact records. //Publication to the real punkbin repo stays a deliberate user step. //(familyrev + the schema v1 identity options and checkout uuids are //declared above with the family staging - the embedded records need them) const family_artifacts_step = b.step("kit-family-artifacts", "emit punkbin-layout artifact copies (-r) + toml metadata + sha1sums for the verified family kits -> /family/punkbin/"); const artifacts_outdir = common.replaceAll(b, b.pathJoin(&.{ b.install_path, "family", "punkbin", "win32-x86_64" }), "\\", "/"); const emit = b.addSystemCommand(&.{family_installed[0]}); common.scrubTclEnv(emit); emit.has_side_effects = true; emit.addFileArg(b.path("tools/family_artifacts.tcl")); emit.addArgs(&.{ "-outdir", artifacts_outdir, "-rev", b.fmt("{d}", .{familyrev}), "-target", "win32-x86_64" }); emit.addArgs(&.{ "-suite", "suite_tcl90", "-tclpatch", tcl_h_patchlevel, "-zig", builtin.zig_version_string, "-optimize", @tagName(optimize) }); emit.addArgs(&.{ "-components", b.fmt("Thread {s} vfs {s} tcllib {s} tcllibc {s}", .{ thread_build.version, tclvfs_info.dotversion, tcllib_ver, tcllib_ver }) }); emit.addArgs(&.{ "-bicomponents", b.fmt("Tk {s} tklib {s}", .{ tkb.patchlevel, tklib_ver }) }); emit.addArgs(&.{ "-provenance", b.fmt("tcl {s} thread {s} tclvfs {s} tk {s} tcllib {s} tklib {s}", .{ uuid_tcl, uuid_thread, uuid_tclvfs, uuid_tk, uuid_tcllib, uuid_tklib }) }); emit.addArgs(&.{ "-testreports", testreports_dir }); emit.addArgs(&.{ "-kits", b.fmt("plain {{{s}}} punk {{{s}}} punk-bi {{{s}}}", .{ family_installed[0], family_installed[1], family_installed[2] }) }); for (family_checks) |cs| emit.step.dependOn(cs); family_artifacts_step.dependOn(&emit.step); } // ================== //-- test-gate: the core testsuite under the built shell, gated on parsed //totals vs the tracked dispositioned baseline (all.tcl's exit code lies) const gate_step = b.step("test-gate", "tcl core testsuite under the built shell, gated on parsed totals vs expected_test_failures.txt"); const testargs_opt = b.option([]const u8, "testargs", "extra tcltest args for test-gate (e.g -file http.test)") orelse ""; const gate_run = b.addRunArtifact(tclsh_exe); common.scrubTclEnv(gate_run); gate_run.setEnvironmentVariable("TCL_LIBRARY", tcl_library_src); gate_run.has_side_effects = true; gate_run.addFileArg(b.path("tools/test_gate.tcl")); gate_run.addArgs(&.{ "-library", "tclcore" }); gate_run.addArg("-testsdir"); gate_run.addArg(common.replaceAll(b, b.pathFromRoot(tcl_source_folder ++ "/tests"), "\\", "/")); gate_run.addArg("-baseline"); gate_run.addFileArg(b.path("expected_test_failures.txt")); gate_run.addArg("-logfile"); gate_run.addArg(common.replaceAll(b, b.pathFromRoot("../tcltest.log"), "\\", "/")); gate_run.addArg("-summaryfile"); gate_run.addArg(b.fmt("{s}/tclcore.summary", .{testreports_dir})); if (testargs_opt.len != 0) { gate_run.addArgs(&.{ "-testargs", testargs_opt }); } gate_run.step.dependOn(b.getInstallStep()); gate_step.dependOn(&gate_run.step); //-- per-library testsuites (G-107): the external libraries the suite builds //and ships run their own testsuites under the suite-built shell, with a //per-library policy tier resolved at invocation (no recipe edits needed): // gate parsed totals diffed against the tracked dispositioned baseline // (core-gate semantics; default for the small load-bearing libs) // record run must complete and emit report artifacts under // /testreports/ (evidence for the exact zig-built // combinations nobody upstream tests); failures recorded, not fatal // skip named step becomes a no-op (composite tuning) //Override per-library: -Dtestpolicy-=gate|record|skip. Per-library //driver/tcltest args: -Dtestargs-="..." (e.g '-notfile x.test' to //disposition a problem file; recorded in the evidence summary). //'test-libraries' runs the default set (thread tclvfs tcllib tklib). tk's //full suite is deliberately OUTSIDE it: opt-in step 'test-tk' (needs an //interactive desktop, maps real windows, runs tens of minutes; intended //before PUBLISHING bi-family artifacts, not on every build). //NOTE zig runs independent steps concurrently - for gate determinism of //timing-sensitive suites drive combined test invocations with -j1 //(suite.tcl's test action does). const LibSuite = struct { name: []const u8, //step suffix, policy/testargs option suffix, report basename testsdir: []const u8, //run cwd (from build root) driver: []const u8, //driver script, relative to testsdir default_policy: []const u8, baseline: []const u8, //tracked baseline filename ("" = none tracked yet) default_notfiles: []const u8, //default driver -notfile exclusions ("" = none) deps: []const *std.Build.Step, //beyond the top-level install step }; const thread_test_deps = [_]*std.Build.Step{install_libraries}; const tclvfs_test_deps = [_]*std.Build.Step{install_libraries}; const tcllib_test_deps = [_]*std.Build.Step{ install_libraries, &tcllib_install.step, &tcllibc_install.step }; const tklib_test_deps = [_]*std.Build.Step{ install_libraries, &tklib_install.step, &tcllib_install.step }; const tk_test_deps = [_]*std.Build.Step{install_libraries}; const lib_suites = [_]LibSuite{ //thread's testsuite requires the tree's exact version - the recipe derives //the installed package version from the same tree (build_tclthread). .{ .name = "thread", .testsdir = "../tclthread/tests", .driver = "all.tcl", .default_policy = "gate", .baseline = "expected_test_failures_thread.txt", .default_notfiles = "", .deps = &thread_test_deps }, .{ .name = "tclvfs", .testsdir = "../tclvfs/tests", .driver = "all.tcl", .default_policy = "gate", .baseline = "expected_test_failures_tclvfs.txt", .default_notfiles = "", .deps = &tclvfs_test_deps }, //tcllib via its own support/devel/all.tcl (sak's underlying driver - //standard aggregate totals, per-file child interps). The installed //tcllibc is on the shell's package path, so accelerator-aware suites //engage the critcl accelerators ('E tcllibc ' markers in the log) - //the single highest-value run here: zig-built accelerators against a //static tclsh is a combination nobody upstream tests. .{ .name = "tcllib", .testsdir = "../tcllib", .driver = "support/devel/all.tcl", .default_policy = "record", .baseline = "", .default_notfiles = "", .deps = &tcllib_test_deps }, .{ .name = "tklib", .testsdir = "../tklib", .driver = "support/devel/all.tcl", .default_policy = "record", .baseline = "", .default_notfiles = "", .deps = &tklib_test_deps }, //tk: the native-dialog suites (winDialog 72 cases, winMsgbox 19) are //excluded by default - their message-injection automation does not //drive the real OS dialogs under the batch/suite-built shell, so each //case blocks waiting on a human (the census cannot complete unattended //with them in). Re-include for a manual interactive run with //-Dtestnotfiles-tk="" (then a human dismisses each dialog). .{ .name = "tk", .testsdir = "../tk9/tests", .driver = "all.tcl", .default_policy = "record", .baseline = "", .default_notfiles = "winDialog.test winMsgbox.test", .deps = &tk_test_deps }, }; const libtests_step = b.step("test-libraries", "library testsuites under the built shell per policy tier (default: thread+tclvfs gate, tcllib+tklib record; tk excluded - see test-tk)"); for (lib_suites) |ls| { const policy = b.option([]const u8, b.fmt("testpolicy-{s}", .{ls.name}), b.fmt("{s} testsuite policy: gate|record|skip (default {s})", .{ ls.name, ls.default_policy })) orelse ls.default_policy; const lib_testargs = b.option([]const u8, b.fmt("testargs-{s}", .{ls.name}), b.fmt("extra tcltest/driver args for the {s} testsuite", .{ls.name})) orelse ""; const lib_notfiles = b.option([]const u8, b.fmt("testnotfiles-{s}", .{ls.name}), b.fmt("test-file glob patterns excluded from the {s} run (default \"{s}\")", .{ ls.name, ls.default_notfiles })) orelse ls.default_notfiles; const is_tk = std.mem.eql(u8, ls.name, "tk"); const step = b.step(b.fmt("test-{s}", .{ls.name}), b.fmt("{s} testsuite under the built shell (policy: {s})", .{ ls.name, policy })); if (!is_tk) libtests_step.dependOn(step); if (std.mem.eql(u8, policy, "skip")) continue; if (!std.mem.eql(u8, policy, "gate") and !std.mem.eql(u8, policy, "record")) { std.debug.panic("-Dtestpolicy-{s}: unknown policy '{s}' (expected gate|record|skip)", .{ ls.name, policy }); } const run = b.addRunArtifact(tclsh_exe); common.scrubTclEnv(run); run.setEnvironmentVariable("TCL_LIBRARY", tcl_library_src); run.has_side_effects = true; run.addFileArg(b.path("tools/test_gate.tcl")); run.addArgs(&.{ "-library", ls.name, "-mode", policy }); run.addArg("-testsdir"); run.addArg(common.replaceAll(b, b.pathFromRoot(ls.testsdir), "\\", "/")); run.addArgs(&.{ "-driver", ls.driver }); if (std.mem.eql(u8, policy, "gate")) { run.addArg("-baseline"); if (ls.baseline.len != 0) { run.addFileArg(b.path(ls.baseline)); } else { //no tracked baseline yet: pass the conventional name so the //engine's missing-baseline message names the file to create run.addArg(common.replaceAll(b, b.pathFromRoot(b.fmt("expected_test_failures_{s}.txt", .{ls.name})), "\\", "/")); } } run.addArg("-logfile"); run.addArg(b.fmt("{s}/{s}.log", .{ testreports_dir, ls.name })); run.addArg("-summaryfile"); run.addArg(b.fmt("{s}/{s}.summary", .{ testreports_dir, ls.name })); if (lib_testargs.len != 0) { run.addArgs(&.{ "-testargs", lib_testargs }); } if (lib_notfiles.len != 0) { run.addArgs(&.{ "-notfiles", lib_notfiles }); } run.step.dependOn(b.getInstallStep()); for (ls.deps) |dep| run.step.dependOn(dep); step.dependOn(&run.step); } } // ================== } //G-102 bootstrap mode: registered when this recipe is invoked from the TRACKED suite //directory (see the mode note at the top of build()). The stage layout produced here //is identical to suite.tcl's fossil staging, so both flows share the staged //invocation - and the stage dir derives from THIS suite folder's name, preserving //the copy-and-tweak isolation property (a copied suite stages into _build/). fn bootstrapMode(b: *std.Build) !void { //default ReleaseFast for suite.tcl parity (standardOptimizeOption would default //Debug; the suite's runtimes are release artifacts) const optimize = b.option(std.builtin.OptimizeMode, "optimize", "optimize mode forwarded to the staged build (default ReleaseFast)") orelse .ReleaseFast; const suite_dirname = std.fs.path.basename(b.pathFromRoot("")); const stage_rel = b.pathJoin(&.{ "..", "_build", suite_dirname }); const stage_tool = b.addExecutable(.{ .name = "stagetree", .root_module = b.createModule(.{ .root_source_file = b.path("tools/stagetree.zig"), .target = b.graph.host, }), }); const stage_step = b.step("stage", "materialize pinned sources (build.zig.zon) + recipe copy into ../_build/ (existing fossil/git checkouts left untouched)"); //dependency name (build.zig.zon) -> stage dir (the recipe-coupled dir names //documented in sources.config) const source_dirs = [_][2][]const u8{ .{ "tcl", "tcl905" }, .{ "tclthread", "tclthread" }, .{ "tclvfs", "tclvfs" }, .{ "tk", "tk9" }, .{ "tklib", "tklib" }, .{ "tcllib", "tcllib" }, .{ "critcl", "critcl" }, }; var deps_pending = false; for (source_dirs) |sd| { const dep_name = sd[0]; const destdir = sd[1]; const dest_from_root = b.pathJoin(&.{ stage_rel, destdir }); //an existing fossil/git checkout is owned by the suite.tcl dev flow: skip the //whole dependency so nothing is fetched for it (stagetree guards again at //make time - this check just avoids needless fetches). if (common.pathExists(b, b.pathJoin(&.{ dest_from_root, ".fslckout" })) or common.pathExists(b, b.pathJoin(&.{ dest_from_root, "_FOSSIL_" })) or common.pathExists(b, b.pathJoin(&.{ dest_from_root, ".git" }))) { continue; } if (b.lazyDependency(dep_name, .{})) |dep| { const run = b.addRunArtifact(stage_tool); run.setName(b.fmt("stage {s}", .{destdir})); run.has_side_effects = true; //the dependency's content-addressed cache path doubles as the pin key: //a manifest pin bump changes it, invalidating the materialized copy const dep_root = dep.path("").getPath(b); run.addArgs(&.{ "-key", dep_root, "-src", dep_root, "-dest", b.pathFromRoot(dest_from_root) }); stage_step.dependOn(&run.step); } else { deps_pending = true; } } if (deps_pending) return; //zig fetches the lazy deps, then re-runs configure //recipe copy -> /build (the same item list suite.tcl stages; per-item //replace every run - recipe files are small tracked working files, no pin) const recipe_items = [_][]const u8{ "build905.zig", "build_common.zig", "build_libtommath", "build_zlib", "build_tclvfs", "build_tclthread", "build_tk", "critcl_zig.config", "expected_test_failures.txt", "expected_test_failures_thread.txt", "expected_test_failures_tclvfs.txt", "patches", "src", "tools", }; for (recipe_items) |item| { const run = b.addRunArtifact(stage_tool); run.setName(b.fmt("stage recipe {s}", .{item})); run.has_side_effects = true; run.addArgs(&.{ "-key", "-", "-src", b.pathFromRoot(item), "-dest", b.pathFromRoot(b.pathJoin(&.{ stage_rel, "build", item })) }); stage_step.dependOn(&run.step); } //bootstrap: stage, then drive the staged recipe - the same nested invocation //suite.tcl performs after its fossil staging. Per-zig-version cache dir (object //caches must never be shared across zig versions - user-confirmed hazard), same //name suite.tcl derives so both flows share the staged cache. const steps_opt = b.option([]const []const u8, "steps", "steps for the staged build (repeat the flag; default: install install-libraries make-zipfs smoke tklib tcllib tcllibc kit-family kit-family-artifacts - the full pipeline short of test-gate)") orelse @as([]const []const u8, &.{ "install", "install-libraries", "make-zipfs", "smoke", "tklib", "tcllib", "tcllibc", "kit-family", "kit-family-artifacts" }); var cachever: []const u8 = builtin.zig_version_string; cachever = common.replaceAll(b, cachever, "+", "_"); cachever = common.replaceAll(b, cachever, "/", "_"); cachever = common.replaceAll(b, cachever, ":", "_"); //forward-slash paths throughout (suite.tcl parity): the prefix flows into //-D macros like TCL_PACKAGE_PATH as a C string literal - backslashes there are //parsed as escape sequences and break the compile const nested = b.addSystemCommand(&.{ b.graph.zig_exe, "build", "--build-file", common.replaceAll(b, b.pathFromRoot(b.pathJoin(&.{ stage_rel, "build", "build905.zig" })), "\\", "/"), "--cache-dir", common.replaceAll(b, b.pathFromRoot(b.pathJoin(&.{ stage_rel, "build", b.fmt(".zig-cache-{s}", .{cachever}) })), "\\", "/"), "--prefix", common.replaceAll(b, b.pathFromRoot(b.pathJoin(&.{ stage_rel, "out" })), "\\", "/"), b.fmt("-Doptimize={s}", .{@tagName(optimize)}), }); for (steps_opt) |s| nested.addArg(s); nested.setName("staged build (nested zig build)"); nested.has_side_effects = true; //cwd = staged build dir (suite.tcl parity): parts of the recipe (e.g build_zlib's //source iteration) resolve source paths relative to the process cwd, not the //build root nested.setCwd(.{ .cwd_relative = b.pathFromRoot(b.pathJoin(&.{ stage_rel, "build" })) }); //hermetic child shells (parity with suite.tcl): steps in the staged graph run //the freshly built tclsh, which must not see the user's machine-level tcl env for ([_][]const u8{ "TCLLIBPATH", "TCL_LIBRARY", "TK_LIBRARY" }) |ev| { nested.removeEnvironmentVariable(ev); } nested.step.dependOn(stage_step); const bootstrap_step = b.step("bootstrap", "stage + run the staged recipe end-to-end (no pre-existing tclsh required)"); bootstrap_step.dependOn(&nested.step); }