Browse Source
First real buildsuite: build905.zig (verbatim G-076-validated recipe) + helper modules + tools, driven by suite.tcl which stages the recipe into src/buildsuites/_build/suite_tcl90, arranges sources (tcl fossil core-9-0-branch --nested with FOSSIL_HOME isolation; thread/tclvfs trunk; zlib from the tcl tree's compat/zlib; vqtcl from a local dir), generates the configure-products fresh checkouts lack (tclUuid.h, tclsh.exe.manifest, thread.rc include), builds and smoke-tests. Verified PASS: static + zip shells report 9.0.5 (checkout 1a9c3b9d96), Thread 3.0.1 builds from current trunk (new generated-include fix in build_tclthread) and loads. The 2024 TCLSH_PIPEREPL/tclZipfs/tclCmdIL patches are now tracked under suite_tcl90/patches with a semantics README (not applied by default builds). Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.commaster
19 changed files with 4738 additions and 1 deletions
@ -0,0 +1,77 @@ |
|||||||
|
# suite_tcl90 - zig build of the Tcl 9.0 windows runtime (G-096) |
||||||
|
|
||||||
|
The first real, tracked buildsuite: reproducibly builds `tclsh90s.exe` (static) and |
||||||
|
`tclsh90szip.exe` (self-contained zipfs) plus the thread/vfs/vlerq extension dlls from |
||||||
|
a fresh Tcl core-9-0-branch checkout, using zig only (no MS toolchain, per the project |
||||||
|
toolchain policy). |
||||||
|
|
||||||
|
Everything transient lives under `src/buildsuites/_build/suite_tcl90/` (VCS-ignored via |
||||||
|
the repo's existing `_build` globs): staged recipe, source checkouts, zig cache, and the |
||||||
|
`out/` install prefix. The tracked content here is the recipe and its driver. |
||||||
|
|
||||||
|
## Usage |
||||||
|
|
||||||
|
tclsh suite.tcl build ?options? |
||||||
|
tclsh suite.tcl clean |
||||||
|
|
||||||
|
See `suite.tcl`'s header for options (`-zig`, `-optimize`, `-tclbranch`, `-refresh`, |
||||||
|
`-vqtcl-source`, `-steps`). The zig executable defaults to `$env(PUNK_ZIG)` or `zig` on |
||||||
|
PATH; the recipe's known-good zig is 0.14.0-dev.2074 (see Lineage) - a punk-getzig |
||||||
|
fetched pinned zig is the intended source (G-096 acceptance; wrapper rename pending). |
||||||
|
|
||||||
|
## Layout |
||||||
|
|
||||||
|
- `build905.zig` - the zig recipe (verbatim lineage copy - see Lineage). Expects its |
||||||
|
build root's SIBLING dirs to hold sources (`../tcl905`, `../zlib`, `../tclthread`, |
||||||
|
`../tclvfs`, `../vqtcl`), which is why `suite.tcl` stages it into |
||||||
|
`_build/suite_tcl90/build/` rather than building in place. |
||||||
|
- `build_libtommath/ build_zlib/ build_tclvfs/ build_vqtcl/ build_tclthread/` - helper |
||||||
|
build modules. The four tcl-dependent helpers take the tcl source dir as their |
||||||
|
`tcldir` param (a hardcoded `../tcl90/generic` include, marked "todo - fix" upstream, |
||||||
|
was fixed when these copies were made). `build_libtommath.zig` still carries the |
||||||
|
hardcoded path but is not called by the current recipe (tcl's in-tree tommath is |
||||||
|
compiled into the core; the `libtommath.dll` seen in old output dirs was a stale |
||||||
|
cache-install artifact). |
||||||
|
- `src/main.zig` - stub root module that disables zig's own start symbols so the mingw |
||||||
|
CRT provides the exe entry. |
||||||
|
- `tools/` - `wrapfiletofile.zig` (uuid-header generation used by prepare-source), |
||||||
|
`zipfs_mkzip.tcl` / `zipfs_mkimg.tcl` (make-zipfs drivers). |
||||||
|
- `patches/` - recovered 2024 experiment patches, including TCLSH_PIPEREPL |
||||||
|
(see `patches/README.md`). NOT applied by the default build - stock sources. |
||||||
|
- `suite.tcl` - the driver: stage recipe -> arrange sources -> generate the |
||||||
|
configure-produced files a fresh checkout lacks -> build -> smoke-test. |
||||||
|
|
||||||
|
## Sources |
||||||
|
|
||||||
|
| dir (sibling of build root) | origin | selection | |
||||||
|
|---|---|---| |
||||||
|
| `tcl905` | fossil `https://core.tcl-lang.org/tcl` (clone cached `~/.fossils/tcl.fossil`) | `-tclbranch`, default `core-9-0-branch` | |
||||||
|
| `zlib` | the tcl checkout's own `compat/zlib` (version-matched, includes contrib/minizip) | copied by suite.tcl | |
||||||
|
| `tclthread` | fossil `https://core.tcl-lang.org/thread` | trunk | |
||||||
|
| `tclvfs` | fossil `https://core.tcl-lang.org/tclvfs` | trunk | |
||||||
|
| `vqtcl` | local dir only (vlerq 4.1 by jcw; no public upstream confirmed) | `-vqtcl-source` | |
||||||
|
|
||||||
|
Checkouts under `_build` use `FOSSIL_HOME=<stage>` so the user's global fossil config |
||||||
|
db records nothing (stage-local `_fossil` db, deleted with `clean`). |
||||||
|
|
||||||
|
## Fresh-checkout preparations the driver performs |
||||||
|
|
||||||
|
Normally products of `configure`/`nmake` that a bare checkout lacks (G-076 findings): |
||||||
|
|
||||||
|
- `win/tclUuid.h` - generated from `manifest.uuid`. |
||||||
|
- `win/tclsh.exe.manifest` - generated from its `.in` (`TCL_WIN_VERSION` per the tree's |
||||||
|
own formula: `TCL_VERSION . releaselevel . patchlevel-stripped-of-'ab.'`). |
||||||
|
- `thread/win/thread.rc` - gains `#include "../../tcl905/generic/tcl.h"` (the zig rc |
||||||
|
compile does not receive the makefile's include paths; historically an uncommitted |
||||||
|
tweak in the 2024 checkout, now a scripted idempotent edit of the staged copy). |
||||||
|
|
||||||
|
## Lineage |
||||||
|
|
||||||
|
`build905.zig` descends from the validated ad-hoc builds in `c:/buildtcl/2024zig/build_tcl90` |
||||||
|
(reference snapshot: `TEMP_REFERENCE/2024zig`): `build90.zig` (tcl 9.0.1 era, last |
||||||
|
built 2024-11-27, zig 0.14.0-dev.2074) plus the 2026-07-20 G-076 deltas - source folder |
||||||
|
`../tcl905`, tclUuid.h copy-to-source targets derived from `tcl_source_folder`, and |
||||||
|
`mingw_unicode_entry_point = true` (9.0.5 sources dropped `TCL_BROKEN_MAINARGS`; |
||||||
|
tclAppInit's `_tmain` is `wmain` under `-DUNICODE`). Full provenance: |
||||||
|
`goals/archive/G-076-tcl9-deadconsole-fix-adoption.md` (2026-07-20 entries). Goal |
||||||
|
contract for this suite: `goals/G-096-zig-buildsuite-piperepl.md`. |
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,190 @@ |
|||||||
|
const std = @import("std"); |
||||||
|
const fs = std.fs; |
||||||
|
|
||||||
|
// Although this function looks imperative, note that its job is to |
||||||
|
// declaratively construct a build graph that will be executed by an external |
||||||
|
// runner. |
||||||
|
//pub fn build(b: *std.Build) !void {} |
||||||
|
pub fn build_libtommath(comptime subdir: []const u8, b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) !*std.Build.Step.Compile { |
||||||
|
const lib = b.addStaticLibrary(.{ |
||||||
|
.name = "tommath", |
||||||
|
.target = target, |
||||||
|
.optimize = optimize, |
||||||
|
}); |
||||||
|
|
||||||
|
var flags = std.ArrayList([]const u8).init(b.allocator); |
||||||
|
defer flags.deinit(); |
||||||
|
//try flags.appendSlice(&.{ "-Wall", "-O2" }); |
||||||
|
try flags.appendSlice(&.{ "-Wall", "-O2", "-Wextra", "-Werror=return-type" }); |
||||||
|
//libtom relies on dead code elimination - see s_mp_rand_platform.c |
||||||
|
//The -O2 seems to fix the issue where dead code elimination is not performed (on windows anyway) |
||||||
|
|
||||||
|
var sources = std.ArrayList([]const u8).init(b.allocator); |
||||||
|
{ |
||||||
|
var dir = try fs.cwd().openDir(subdir, .{ .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 sources.append(b.pathJoin(&.{ |
||||||
|
subdir, |
||||||
|
entry.name, |
||||||
|
})); |
||||||
|
} |
||||||
|
} |
||||||
|
//const ext = std.fs.path.extension(entry.basename); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//std.debug.print("sources: {any}",.{sources.items}); |
||||||
|
lib.linkLibC(); |
||||||
|
if (target.result.os.tag == .windows) { |
||||||
|
lib.linkSystemLibrary("advapi32"); //crypt |
||||||
|
} |
||||||
|
//lib.addIncludePath(.{ .path = subdir }); |
||||||
|
lib.addIncludePath(b.path(subdir)); |
||||||
|
lib.addIncludePath(b.path("../tcl90/generic")); //todo - fix |
||||||
|
lib.addCSourceFiles(.{ |
||||||
|
.files = sources.items, |
||||||
|
.flags = flags.items, |
||||||
|
}); |
||||||
|
|
||||||
|
// This declares intent for the library to be installed into the standard |
||||||
|
// location when the user invokes the "install" step (the default step when |
||||||
|
// running `zig build`). |
||||||
|
b.installArtifact(lib); |
||||||
|
|
||||||
|
const exe = b.addExecutable(.{ |
||||||
|
.name = "test_libtommath", |
||||||
|
.target = target, |
||||||
|
.optimize = optimize, |
||||||
|
}); |
||||||
|
exe.step.dependOn(&lib.step); |
||||||
|
exe.linkLibC(); |
||||||
|
if (target.result.os.tag == .windows) { |
||||||
|
//exe.linkSystemLibrary("netapi32"); |
||||||
|
//exe.linkSystemLibrary("kernel32"); |
||||||
|
//exe.linkSystemLibrary("user32"); |
||||||
|
exe.linkSystemLibrary("advapi32"); //crypt |
||||||
|
//exe.linkSystemLibrary("userenv"); |
||||||
|
//exe.linkSystemLibrary("ws2_32"); |
||||||
|
} |
||||||
|
//exe.addIncludePath(.{ .path = subdir }); |
||||||
|
exe.addIncludePath(b.path(subdir)); |
||||||
|
//exe.addIncludePath(.{ .path = subdir ++ "/demo" }); |
||||||
|
exe.addIncludePath(b.path(subdir ++ "/demo")); |
||||||
|
exe.addCSourceFile(.{ |
||||||
|
//.file = .{ .path = subdir ++ "/demo/test.c" }, |
||||||
|
.file = b.path(subdir ++ "/demo/test.c"), |
||||||
|
.flags = flags.items, |
||||||
|
}); |
||||||
|
exe.addCSourceFile(.{ |
||||||
|
//.file = .{ .path = subdir ++ "/demo/shared.c" }, |
||||||
|
.file = b.path(subdir ++ "/demo/shared.c"), |
||||||
|
.flags = flags.items, |
||||||
|
}); |
||||||
|
exe.linkLibrary(lib); |
||||||
|
|
||||||
|
// This declares intent for the executable to be installed into the |
||||||
|
// standard location when the user invokes the "install" step (the default |
||||||
|
// step when running `zig build`). |
||||||
|
b.installArtifact(exe); |
||||||
|
|
||||||
|
// This *creates* a Run step in the build graph, to be executed when another |
||||||
|
// step is evaluated that depends on it. The next line below will establish |
||||||
|
// such a dependency. |
||||||
|
const run_cmd = b.addRunArtifact(exe); |
||||||
|
|
||||||
|
if (target.result.os.tag == .windows) { |
||||||
|
try flags.appendSlice(&.{ |
||||||
|
"-Wl,--out-implib=libtommath.dll.a", |
||||||
|
}); |
||||||
|
const dll = b.addSharedLibrary(.{ |
||||||
|
.name = "libtommath", |
||||||
|
.target = target, |
||||||
|
.optimize = optimize, |
||||||
|
}); |
||||||
|
dll.linkLibC(); |
||||||
|
dll.linkSystemLibrary("advapi32"); //crypt |
||||||
|
//dll.addIncludePath(.{ .path = subdir }); |
||||||
|
dll.addIncludePath(b.path(subdir)); |
||||||
|
dll.addCSourceFiles(.{ |
||||||
|
.files = sources.items, |
||||||
|
.flags = flags.items, |
||||||
|
}); |
||||||
|
b.installArtifact(dll); |
||||||
|
} else { |
||||||
|
const shlib_tom = b.addSharedLibrary(.{ |
||||||
|
.name = "tommath", |
||||||
|
.target = target, |
||||||
|
.optimize = optimize, |
||||||
|
}); |
||||||
|
shlib_tom.linkLibC(); |
||||||
|
//shlib_tom.addIncludePath(.{ .path = subdir }); |
||||||
|
shlib_tom.addIncludePath(b.path(subdir)); |
||||||
|
shlib_tom.addCSourceFiles(.{ |
||||||
|
.files = sources.items, |
||||||
|
.flags = flags.items, |
||||||
|
}); |
||||||
|
b.installArtifact(shlib_tom); |
||||||
|
} |
||||||
|
|
||||||
|
// By making the run step depend on the install step, it will be run from the |
||||||
|
// installation directory rather than directly from within the cache directory. |
||||||
|
// This is not necessary, however, if the application depends on other installed |
||||||
|
// files, this ensures they will be present and in the expected location. |
||||||
|
run_cmd.step.dependOn(b.getInstallStep()); |
||||||
|
|
||||||
|
// This allows the user to pass arguments to the application in the build |
||||||
|
// command itself, like this: `zig build run -- arg1 arg2 etc` |
||||||
|
if (b.args) |args| { |
||||||
|
run_cmd.addArgs(args); |
||||||
|
} |
||||||
|
|
||||||
|
// This creates a build step. It will be visible in the `zig build --help` menu, |
||||||
|
// and can be selected like this: `zig build run` |
||||||
|
// This will evaluate the `run` step rather than the default, which is "install". |
||||||
|
const run_step = b.step("run", "Run the app"); |
||||||
|
run_step.dependOn(&run_cmd.step); |
||||||
|
|
||||||
|
const prepare = b.addSystemCommand(&.{ |
||||||
|
"echo", |
||||||
|
"--system command prepare--", |
||||||
|
}); |
||||||
|
run_cmd.step.dependOn(&prepare.step); |
||||||
|
b.getInstallStep().dependOn(&prepare.step); |
||||||
|
return lib; |
||||||
|
|
||||||
|
// Creates a step for unit testing. This only builds the test executable |
||||||
|
// but does not run it. |
||||||
|
//const lib_unit_tests = b.addTest(.{ |
||||||
|
// //.root_source_file = .{ .path = "src/root.zig" }, |
||||||
|
// .target = target, |
||||||
|
// .optimize = optimize, |
||||||
|
//}); |
||||||
|
|
||||||
|
//const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests); |
||||||
|
|
||||||
|
//const exe_unit_tests = b.addTest(.{ |
||||||
|
// .root_source_file = .{ .path = "src/main.zig" }, |
||||||
|
// .target = target, |
||||||
|
// .optimize = optimize, |
||||||
|
//}); |
||||||
|
|
||||||
|
//const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests); |
||||||
|
|
||||||
|
// Similar to creating the run step earlier, this exposes a `test` step to |
||||||
|
// the `zig build --help` menu, providing a way for the user to request |
||||||
|
// running the unit tests. |
||||||
|
//const test_step = b.step("test", "Run unit tests"); |
||||||
|
//test_step.dependOn(&run_lib_unit_tests.step); |
||||||
|
//test_step.dependOn(&run_exe_unit_tests.step); |
||||||
|
} |
||||||
@ -0,0 +1,152 @@ |
|||||||
|
const std = @import("std"); |
||||||
|
const fs = std.fs; |
||||||
|
const builtin = @import("builtin"); |
||||||
|
|
||||||
|
const mkvar_thread_zip_file = "libthread3.0.1.zip"; |
||||||
|
const mkvar_thread_vfs_root = "libthread.vfs"; |
||||||
|
const mkvar_thread_vfs_path = mkvar_thread_vfs_root ++ "/thread_library"; |
||||||
|
|
||||||
|
const mkvar_pkg_lib_file = "tcl9thread301.dll"; |
||||||
|
|
||||||
|
// Although this function looks imperative, note that its job is to |
||||||
|
// declaratively construct a build graph that will be executed by an external |
||||||
|
// runner. |
||||||
|
//pub fn build(b: *std.Build) !void {} |
||||||
|
pub fn build_tclthread(comptime tcldir: []const u8, comptime subdir: []const u8, b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, stublib: *std.Build.Step.Compile) !*std.Build.Step.Compile { |
||||||
|
const wrapfilecmd = b.addExecutable(.{ |
||||||
|
.name = "wrapfiletofile", |
||||||
|
.root_source_file = b.path("tools/wrapfiletofile.zig"), |
||||||
|
.target = b.host, |
||||||
|
}); |
||||||
|
const uuidcmd_step = b.addRunArtifact(wrapfilecmd); |
||||||
|
uuidcmd_step.addArgs(&.{ |
||||||
|
"-prefix", |
||||||
|
"#define THREAD_VERSION_UUID \\", |
||||||
|
"-prefixnl", |
||||||
|
"1", |
||||||
|
"-input", |
||||||
|
}); |
||||||
|
uuidcmd_step.addFileArg(b.path(subdir ++ "/manifest.uuid")); |
||||||
|
uuidcmd_step.addArg("-output"); |
||||||
|
const threaduuid_file = uuidcmd_step.addOutputFileArg("threadUuid.h"); |
||||||
|
|
||||||
|
//var interp: []const []const u8 = undefined; |
||||||
|
////note we determine the interp based on the machine running the build - not the target |
||||||
|
//if (builtin.os.tag == .windows) { |
||||||
|
// interp = &.{ |
||||||
|
// "wrapfiletofile.cmd", |
||||||
|
// }; |
||||||
|
//} else { |
||||||
|
// interp = &.{ |
||||||
|
// "bash", //explicitly use bash. Sometimes sh is linked to some other shell such as zsh, or dash (e.g debian,ubuntu) which don't understand substitution syntax like bash and ordinary posix sh do |
||||||
|
// "wrapfiletofile.cmd", |
||||||
|
// }; |
||||||
|
//} |
||||||
|
//const uuid_cmd = b.addSystemCommand(interp); |
||||||
|
//uuid_cmd.addArgs(&.{ |
||||||
|
// "-prefix", |
||||||
|
// "#define THREAD_VERSION_UUID \\", |
||||||
|
// "-prefixnl", |
||||||
|
// "1", |
||||||
|
// "-input", |
||||||
|
//}); |
||||||
|
////uuid_cmd.addFileArg(.{ .path = b.pathJoin(&.{ b.pathFromRoot(""), "..", "tcl" ++ tcl_version, "manifest.uuid" }) }); |
||||||
|
//uuid_cmd.addFileArg(b.path(subdir ++ "/manifest.Uuid")); |
||||||
|
//uuid_cmd.addArg("-output"); |
||||||
|
//const tcluuid_file1 = uuid_cmd.addOutputFileArg("threadUuid.h"); |
||||||
|
|
||||||
|
//const wf_uuidh = b.addWriteFiles(); |
||||||
|
const wf_uuidh = b.addUpdateSourceFiles(); |
||||||
|
if (target.result.os.tag == .windows) { |
||||||
|
wf_uuidh.addCopyFileToSource(threaduuid_file, b.pathJoin(&.{ subdir, "win", "threadUuid.h" })); |
||||||
|
} else { |
||||||
|
wf_uuidh.addCopyFileToSource(threaduuid_file, b.pathJoin(&.{ subdir, "unix", "threadUuid.h" })); |
||||||
|
} |
||||||
|
|
||||||
|
wf_uuidh.step.dependOn(&uuidcmd_step.step); |
||||||
|
b.getInstallStep().dependOn(&wf_uuidh.step); |
||||||
|
|
||||||
|
const lib = b.addSharedLibrary(.{ |
||||||
|
.name = "tcl9thread301", |
||||||
|
.target = target, |
||||||
|
.optimize = optimize, |
||||||
|
}); |
||||||
|
//lib.step.dependOn(&wf_uuidh.step); |
||||||
|
var flags = std.ArrayList([]const u8).init(b.allocator); |
||||||
|
defer flags.deinit(); |
||||||
|
//try flags.appendSlice(&.{ "-Wall", "-O2", "-fomit-frame-pointer", "-DNDEBUG" }); |
||||||
|
try flags.appendSlice(&.{ "-Wall", "-O3", "-fomit-frame-pointer" }); |
||||||
|
try flags.appendSlice(&.{ |
||||||
|
"-DPACKAGE_NAME=\"thread\"", |
||||||
|
"-DPACKAGE_TARNAME=\"thread\"", |
||||||
|
"-DPACKAGE_VERSION=\"3.0.1\"", |
||||||
|
"-DPACKAGE_STRING=\"thread 3.0.1\"", |
||||||
|
"-DPACKAGE_BUGREPORT=\"\"", |
||||||
|
"-DPACKAGE_URL=\"\"", |
||||||
|
"-DTCL_CFG_OPTIMIZED=1", |
||||||
|
"-DUSE_TCL_STUBS=1", |
||||||
|
"-DZIPFS_BUILD=1", |
||||||
|
"-DTCL_WIDE_INT_TYPE=long long", |
||||||
|
//"-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_FILE_OFFSET_BITS=64", |
||||||
|
//"-DHAVE_STRUCT_STAT64=1", |
||||||
|
//"-DHAVE_LSEEK64=1", |
||||||
|
|
||||||
|
"-static-libgcc", |
||||||
|
}); |
||||||
|
|
||||||
|
//BUILD_<somelibrary> needs to be defined for windows |
||||||
|
if (target.result.os.tag == .windows) { |
||||||
|
try flags.appendSlice(&.{ |
||||||
|
"-DBUILD_thread=/**/", |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
var tclthread_sources = std.ArrayList([]const u8).init(b.allocator); |
||||||
|
try tclthread_sources.append(subdir ++ "/generic/threadNs.c"); |
||||||
|
try tclthread_sources.append(subdir ++ "/generic/threadCmd.c"); |
||||||
|
try tclthread_sources.append(subdir ++ "/generic/threadSvCmd.c"); |
||||||
|
try tclthread_sources.append(subdir ++ "/generic/threadSpCmd.c"); |
||||||
|
try tclthread_sources.append(subdir ++ "/generic/threadPoolCmd.c"); |
||||||
|
try tclthread_sources.append(subdir ++ "/generic/psGdbm.c"); |
||||||
|
try tclthread_sources.append(subdir ++ "/generic/psLmdb.c"); |
||||||
|
try tclthread_sources.append(subdir ++ "/generic/threadSvListCmd.c"); |
||||||
|
try tclthread_sources.append(subdir ++ "/generic/threadSvKeyListCmd.c"); |
||||||
|
try tclthread_sources.append(subdir ++ "/generic/tclXkeylist.c"); |
||||||
|
|
||||||
|
//if (target.result.os.tag == .windows) { |
||||||
|
// lib.linkSystemLibrary("advapi32"); //crypt |
||||||
|
//} |
||||||
|
lib.addIncludePath(b.path(subdir)); |
||||||
|
lib.addIncludePath(b.path(subdir ++ "/generic")); |
||||||
|
//generated threadUuid.h: current thread trunk #includes it (upstream makefiles |
||||||
|
//generate it into their build dir); using the generator's output dir as an include |
||||||
|
//path also gives the compile its dependency on the generation step. |
||||||
|
lib.addIncludePath(threaduuid_file.dirname()); |
||||||
|
lib.addIncludePath(b.path(tcldir ++ "/generic")); //todo - fix |
||||||
|
lib.addCSourceFiles(.{ |
||||||
|
.files = tclthread_sources.items, |
||||||
|
.flags = flags.items, |
||||||
|
}); |
||||||
|
|
||||||
|
lib.linkLibrary(stublib); |
||||||
|
lib.linkLibC(); |
||||||
|
lib.addWin32ResourceFile(.{ |
||||||
|
.file = b.path(subdir ++ "/win/thread.rc"), |
||||||
|
.flags = &.{ |
||||||
|
"-DPACKAGE_MAJOR=3", |
||||||
|
"-DPACKAGE_MINOR=0", |
||||||
|
"-DPACKAGE_VERSION=3.0b2", |
||||||
|
}, |
||||||
|
}); //ignored for non-windows targets |
||||||
|
b.installArtifact(lib); |
||||||
|
|
||||||
|
return lib; |
||||||
|
} |
||||||
@ -0,0 +1,81 @@ |
|||||||
|
const std = @import("std"); |
||||||
|
const fs = std.fs; |
||||||
|
|
||||||
|
const tclvfs_dotversion = "1.4.2"; |
||||||
|
const tclvfs_nodotversion = "142"; |
||||||
|
|
||||||
|
pub fn vfsadd_tclvfs_files(comptime tcldir: []const u8, comptime subdir: []const u8, b: *std.Build, vfswrite: *std.Build.Step.WriteFile) !*std.Build.Step.WriteFile { |
||||||
|
//_ = tcldir; |
||||||
|
//const version = "1.4.2"; |
||||||
|
//recursive copy |
||||||
|
//_ = make_vfs_root.addCopyDirectory(b.path(tcl_source_folder ++ "/../tclvfs/library"), "base/lib/vfs1.4.2", .{}); |
||||||
|
_ = vfswrite.addCopyDirectory(b.path(tcldir ++ "/" ++ subdir ++ "/library"), b.pathJoin(&.{ "base", "lib", "vfs" ++ tclvfs_dotversion }), .{}); |
||||||
|
|
||||||
|
return vfswrite; |
||||||
|
} |
||||||
|
pub fn build_tclvfs(comptime tcldir: []const u8, comptime subdir: []const u8, b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, stublib: *std.Build.Step.Compile) !*std.Build.Step.Compile { |
||||||
|
//review - libname Vfs vs vfs??? |
||||||
|
const lib = b.addSharedLibrary(.{ |
||||||
|
.name = "tcl9vfs142", |
||||||
|
.target = target, |
||||||
|
.optimize = optimize, |
||||||
|
}); |
||||||
|
//_ = stublib; |
||||||
|
var flags = std.ArrayList([]const u8).init(b.allocator); |
||||||
|
defer flags.deinit(); |
||||||
|
//try flags.appendSlice(&.{ "-Wall", "-O3" }); |
||||||
|
try flags.appendSlice(&.{ "-Wall", "-O3", "-fomit-frame-pointer" }); |
||||||
|
try flags.appendSlice(&.{ |
||||||
|
"-DPACKAGE_NAME=\"vfs\"", |
||||||
|
"-DPACKAGE_TARNAME=\"vfs\"", |
||||||
|
"-DPACKAGE_VERSION=\"" ++ tclvfs_dotversion ++ "\"", |
||||||
|
"-DPACKAGE_STRING=\"vfs " ++ tclvfs_dotversion ++ "\"", |
||||||
|
"-DPACKAGE_BUGREPORT=\"\"", |
||||||
|
"-DPACKAGE_URL=\"\"", |
||||||
|
"-DBUILD_VFS=1", |
||||||
|
"-DTCL_CFG_OPTIMIZED=1", |
||||||
|
"-DUSE_TCL_STUBS=1", |
||||||
|
"-DZIPFS_BUILD=1", |
||||||
|
"-DTCL_WIDE_INT_TYPE=long long", |
||||||
|
}); |
||||||
|
if (target.result.os.tag == .windows) { |
||||||
|
try flags.appendSlice(&.{ |
||||||
|
"-static-libgcc", |
||||||
|
}); |
||||||
|
} |
||||||
|
//-DBUILD_VFS only on windows? value? |
||||||
|
|
||||||
|
var sources = std.ArrayList([]const u8).init(b.allocator); |
||||||
|
try sources.append(subdir ++ "/generic/vfs.c"); |
||||||
|
lib.addIncludePath(b.path(subdir)); |
||||||
|
lib.addIncludePath(b.path(subdir ++ "/generic")); |
||||||
|
lib.addIncludePath(b.path(tcldir ++ "/generic")); |
||||||
|
lib.addIncludePath(b.path(tcldir ++ "/generic")); |
||||||
|
if (target.result.os.tag == .windows) { |
||||||
|
lib.addIncludePath(b.path(tcldir ++ "/win")); |
||||||
|
} else { |
||||||
|
lib.addIncludePath(b.path(tcldir ++ "/unix")); |
||||||
|
} |
||||||
|
lib.addCSourceFiles(.{ |
||||||
|
.files = sources.items, |
||||||
|
.flags = flags.items, |
||||||
|
}); |
||||||
|
|
||||||
|
lib.linkLibrary(stublib); |
||||||
|
lib.linkLibC(); |
||||||
|
lib.addWin32ResourceFile(.{ |
||||||
|
.file = b.path(subdir ++ "/win/tclvfs.rc"), |
||||||
|
.flags = &.{ |
||||||
|
"-DPACKAGE_MAJOR=1", |
||||||
|
"-DPACKAGE_MINOR=4", |
||||||
|
"-DPACKAGE_VERSION=" ++ tclvfs_dotversion, |
||||||
|
"-DDOTVERSION=" ++ tclvfs_dotversion, |
||||||
|
"-DCOMMAVERSION=" ++ tclvfs_dotversion, |
||||||
|
"-DVERSION=" ++ tclvfs_nodotversion, |
||||||
|
}, |
||||||
|
}); //ignored for non-windows targets |
||||||
|
// COMMAVERSION??? VERSION??? |
||||||
|
|
||||||
|
b.installArtifact(lib); |
||||||
|
return lib; //static library |
||||||
|
} |
||||||
@ -0,0 +1,76 @@ |
|||||||
|
const std = @import("std"); |
||||||
|
const fs = std.fs; |
||||||
|
|
||||||
|
const tclvfs_dotversion = "1.4.2"; |
||||||
|
const tclvfs_nodotversion = "142"; |
||||||
|
|
||||||
|
pub fn vfsadd_tclvfs_files(comptime tcldir: []const u8, comptime subdir: []const u8, b: *std.Build, vfswrite: *std.Build.Step.WriteFile) !*std.Build.Step.WriteFile { |
||||||
|
//_ = tcldir; |
||||||
|
//const version = "1.4.2"; |
||||||
|
//recursive copy |
||||||
|
//_ = make_vfs_root.addCopyDirectory(b.path(tcl_source_folder ++ "/../tclvfs/library"), "base/lib/vfs1.4.2", .{}); |
||||||
|
_ = vfswrite.addCopyDirectory(b.path(tcldir ++ "/" ++ subdir ++ "/library"), b.pathJoin(&.{ "base", "lib", "vfs" ++ tclvfs_dotversion }), .{}); |
||||||
|
|
||||||
|
return vfswrite; |
||||||
|
} |
||||||
|
pub fn build_tclvfs(comptime tcldir: []const u8, comptime subdir: []const u8, b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, stublib: *std.Build.Step.Compile) !*std.Build.Step.Compile { |
||||||
|
//review - libname Vfs vs vfs??? |
||||||
|
const slib = b.addStaticLibrary(.{ |
||||||
|
.name = "Vfs", |
||||||
|
.target = target, |
||||||
|
.optimize = optimize, |
||||||
|
}); |
||||||
|
|
||||||
|
_ = stublib; |
||||||
|
var flags = std.ArrayList([]const u8).init(b.allocator); |
||||||
|
defer flags.deinit(); |
||||||
|
//try flags.appendSlice(&.{ "-Wall", "-O3" }); |
||||||
|
try flags.appendSlice(&.{ "-Wall", "-O2", "-fomit-frame-pointer" }); |
||||||
|
try flags.appendSlice(&.{ |
||||||
|
"-DPACKAGE_NAME=\"vfs\"", |
||||||
|
"-DPACKAGE_TARNAME=\"vfs\"", |
||||||
|
"-DPACKAGE_VERSION=\"" ++ tclvfs_dotversion ++ "\"", |
||||||
|
"-DPACKAGE_STRING=\"vfs " ++ tclvfs_dotversion ++ "\"", |
||||||
|
"-DPACKAGE_BUGREPORT=\"\"", |
||||||
|
"-DPACKAGE_URL=\"\"", |
||||||
|
"-DBUILD_VFS=1", |
||||||
|
"-DTCL_CFG_OPTIMIZED=1", |
||||||
|
"-DUSE_TCL_STUBS=0", |
||||||
|
"-DZIPFS_BUILD=1", |
||||||
|
"-DTCL_WIDE_INT_TYPE=long long", |
||||||
|
"-DSTATIC_BUILD", |
||||||
|
// ... |
||||||
|
//"-static-libgcc", |
||||||
|
}); |
||||||
|
//-DBUILD_VFS only on windows? value? |
||||||
|
|
||||||
|
var sources = std.ArrayList([]const u8).init(b.allocator); |
||||||
|
try sources.append(subdir ++ "/generic/vfs.c"); |
||||||
|
slib.addIncludePath(b.path(subdir)); |
||||||
|
slib.addIncludePath(b.path(subdir ++ "/generic")); |
||||||
|
slib.addIncludePath(b.path(tcldir ++ "/generic")); |
||||||
|
slib.addIncludePath(b.path(tcldir ++ "/generic")); |
||||||
|
slib.addIncludePath(b.path(tcldir ++ "/win")); |
||||||
|
slib.addCSourceFiles(.{ |
||||||
|
.files = sources.items, |
||||||
|
.flags = flags.items, |
||||||
|
}); |
||||||
|
|
||||||
|
//slib.linkLibrary(stublib); |
||||||
|
slib.linkLibC(); |
||||||
|
slib.addWin32ResourceFile(.{ |
||||||
|
.file = b.path(subdir ++ "/win/tclvfs.rc"), |
||||||
|
.flags = &.{ |
||||||
|
"-DPACKAGE_MAJOR=1", |
||||||
|
"-DPACKAGE_MINOR=4", |
||||||
|
"-DPACKAGE_VERSION=" ++ tclvfs_dotversion, |
||||||
|
"-DDOTVERSION=" ++ tclvfs_dotversion, |
||||||
|
"-DCOMMAVERSION=" ++ tclvfs_dotversion, |
||||||
|
"-DVERSION=" ++ tclvfs_nodotversion, |
||||||
|
}, |
||||||
|
}); //ignored for non-windows targets |
||||||
|
// COMMAVERSION??? VERSION??? |
||||||
|
|
||||||
|
//b.installArtifact(slib); |
||||||
|
return slib; //static library |
||||||
|
} |
||||||
@ -0,0 +1,80 @@ |
|||||||
|
const std = @import("std"); |
||||||
|
const fs = std.fs; |
||||||
|
|
||||||
|
const vqtcl_dotversion = "4.1"; |
||||||
|
const vqtcl_nodotversion = "41"; |
||||||
|
|
||||||
|
pub fn vfsadd_vqtcl_files(comptime tcldir: []const u8, comptime subdir: []const u8, b: *std.Build, vfswrite: *std.Build.Step.WriteFile) !*std.Build.Step.WriteFile { |
||||||
|
//_ = tcldir; |
||||||
|
//recursive copy |
||||||
|
//_ = make_vfs_root.addCopyDirectory(b.path(tcl_source_folder ++ "/../tclvfs/library"), "base/lib/vfs1.4.2", .{}); |
||||||
|
_ = vfswrite.addCopyDirectory(b.path(tcldir ++ "/" ++ subdir ++ "/library"), b.pathJoin(&.{ "base", "lib", "vqtcl" ++ vqtcl_dotversion }), .{}); |
||||||
|
|
||||||
|
return vfswrite; |
||||||
|
} |
||||||
|
pub fn build_vqtcl(comptime tcldir: []const u8, comptime subdir: []const u8, b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, stublib: *std.Build.Step.Compile) !*std.Build.Step.Compile { |
||||||
|
const lib = b.addSharedLibrary(.{ |
||||||
|
.name = "tcl9vlerq" ++ vqtcl_nodotversion, |
||||||
|
.target = target, |
||||||
|
.optimize = optimize, |
||||||
|
}); |
||||||
|
//_ = stublib; |
||||||
|
var flags = std.ArrayList([]const u8).init(b.allocator); |
||||||
|
defer flags.deinit(); |
||||||
|
//try flags.appendSlice(&.{ "-Wall", "-O3" }); |
||||||
|
//try flags.appendSlice(&.{ "-Wall", "-O2", "-fomit-frame-pointer" }); |
||||||
|
try flags.appendSlice(&.{ "-O3", "-fomit-frame-pointer" }); |
||||||
|
try flags.appendSlice(&.{ |
||||||
|
"-DPACKAGE_NAME=\"vfs\"", |
||||||
|
"-DPACKAGE_TARNAME=\"vfs\"", |
||||||
|
"-DPACKAGE_VERSION=\"" ++ vqtcl_dotversion ++ "\"", |
||||||
|
"-DPACKAGE_STRING=\"vfs " ++ vqtcl_dotversion ++ "\"", |
||||||
|
"-DPACKAGE_BUGREPORT=\"\"", |
||||||
|
"-DPACKAGE_URL=\"\"", |
||||||
|
"-DTCL_CFG_OPTIMIZED=1", |
||||||
|
"-DUSE_TCL_STUBS=1", |
||||||
|
"-DZIPFS_BUILD=1", |
||||||
|
"-DTCL_WIDE_INT_TYPE=long long", |
||||||
|
}); |
||||||
|
// "-DTCL_MEM_DEBUG=1", //define for all or none of modules that are linked together |
||||||
|
|
||||||
|
// "-DTCL_MAJOR_VERSION=9", |
||||||
|
//"-static-libgcc", //argument unused - review |
||||||
|
|
||||||
|
var sources = std.ArrayList([]const u8).init(b.allocator); |
||||||
|
try sources.append(subdir ++ "/generic/vlerq.c"); |
||||||
|
lib.addIncludePath(b.path(subdir)); |
||||||
|
lib.addIncludePath(b.path(subdir ++ "/generic")); |
||||||
|
lib.addIncludePath(b.path(subdir ++ "/win")); //header for MSVC only - possibly not needed here - unless zig build can use it? |
||||||
|
lib.addIncludePath(b.path(tcldir ++ "/generic")); |
||||||
|
lib.addIncludePath(b.path(tcldir ++ "/generic")); |
||||||
|
if (target.result.os.tag == .windows) { |
||||||
|
lib.addIncludePath(b.path(tcldir ++ "/win")); |
||||||
|
} else { |
||||||
|
lib.addIncludePath(b.path(tcldir ++ "/unix")); |
||||||
|
} |
||||||
|
lib.addCSourceFiles(.{ |
||||||
|
.files = sources.items, |
||||||
|
.flags = flags.items, |
||||||
|
}); |
||||||
|
|
||||||
|
lib.linkLibrary(stublib); |
||||||
|
lib.linkLibC(); |
||||||
|
|
||||||
|
// no resource file - todo - make one? |
||||||
|
//lib.addWin32ResourceFile(.{ |
||||||
|
// .file = b.path(subdir ++ "/win/tclvfs.rc"), |
||||||
|
// .flags = &.{ |
||||||
|
// "-DPACKAGE_MAJOR=1", |
||||||
|
// "-DPACKAGE_MINOR=4", |
||||||
|
// "-DPACKAGE_VERSION=" ++ vqtcl_dotversion, |
||||||
|
// "-DDOTVERSION=" ++ vqtcl_dotversion, |
||||||
|
// "-DCOMMAVERSION=" ++ vqtcl_dotversion, |
||||||
|
// "-DVERSION=" ++ vqtcl_nodotversion, |
||||||
|
// }, |
||||||
|
//}); //ignored for non-windows targets |
||||||
|
// COMMAVERSION??? VERSION??? |
||||||
|
|
||||||
|
b.installArtifact(lib); |
||||||
|
return lib; //static library |
||||||
|
} |
||||||
@ -0,0 +1,161 @@ |
|||||||
|
const std = @import("std"); |
||||||
|
const fs = std.fs; |
||||||
|
|
||||||
|
pub fn build_zlib(comptime subdir: []const u8, b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) !*std.Build.Step.Compile { |
||||||
|
var statlibname: []const u8 = undefined; |
||||||
|
if (target.result.os.tag == .windows) { |
||||||
|
statlibname = "libz"; |
||||||
|
} else { |
||||||
|
statlibname = "z"; |
||||||
|
} |
||||||
|
|
||||||
|
const statlib = b.addStaticLibrary(.{ |
||||||
|
.name = statlibname, |
||||||
|
.target = target, |
||||||
|
.optimize = optimize, |
||||||
|
}); |
||||||
|
var zlib_flags = std.ArrayList([]const u8).init(b.allocator); |
||||||
|
defer zlib_flags.deinit(); |
||||||
|
//try zlib_flags.appendSlice(&.{ "-Wall", "-static-libgcc", "-Wno-error=implicit-function-declaration", "-O3" }); //DL_info undeclared |
||||||
|
//try zlib_flags.appendSlice(&.{ "-Wall", "-static-libgcc", "-O3" }); //DL_info undeclared |
||||||
|
//try zlib_flags.appendSlice(&.{ "-Wall", "-Wno-error=implicit-function-declaration", "-O3", "-fPIC" }); //seems to work with linux-musl |
||||||
|
//try zlib_flags.appendSlice(&.{ "-Wall", "-Wno-error=implicit-function-declaration", "-O3", "-fPIC", "-fno-omit-frame-pointer", "-fsanitize=undefined" }); |
||||||
|
|
||||||
|
//2024 - seems to work |
||||||
|
try zlib_flags.appendSlice(&.{ "-Wall", "-Wno-error=implicit-function-declaration", "-O3", "-fPIC", "-fno-omit-frame-pointer", "-fno-sanitize=undefined" }); |
||||||
|
|
||||||
|
//2024 trial |
||||||
|
//try zlib_flags.appendSlice(&.{ "-Wall", "-Wno-error=implicit-function-declaration", "-O2", "-fPIC", "-fomit-frame-pointer", "-fno-sanitize=undefined" }); |
||||||
|
//try zlib_flags.appendSlice(&.{ "-Wall", "-Wno-error=implicit-function-declaration", "-fPIC", "-fomit-frame-pointer", "-fno-sanitize=undefined" }); |
||||||
|
|
||||||
|
//try zlib_flags.appendSlice(&.{ "-Wall", "-O3" }); |
||||||
|
//try zlib_flags.appendSlice(&.{"-O"}); //C99 and later do not support implicit function declarations |
||||||
|
//try zlib_flags.appendSlice(&.{ "-O3", "-Wall", "-Wwrite-strings", "-Wpointer-arith", "-Wconversion", "-Wstrict-prototypes", "-Wmissing-prototypes" }); |
||||||
|
|
||||||
|
var zlib_sources = std.ArrayList([]const u8).init(b.allocator); |
||||||
|
{ |
||||||
|
var dir = try fs.cwd().openDir(subdir, .{ .iterate = true }); |
||||||
|
defer dir.close(); |
||||||
|
|
||||||
|
//var walker = try dir.walk(b.allocator); |
||||||
|
//defer walker.deinit(); |
||||||
|
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 zlib_sources.append(b.pathJoin(&.{ |
||||||
|
subdir, |
||||||
|
entry.name, |
||||||
|
})); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
statlib.linkLibC(); |
||||||
|
statlib.addIncludePath(b.path(subdir)); |
||||||
|
statlib.addIncludePath(b.path(subdir ++ "/contrib/minzip")); |
||||||
|
statlib.addCSourceFiles(.{ |
||||||
|
.files = zlib_sources.items, |
||||||
|
.flags = zlib_flags.items, |
||||||
|
}); |
||||||
|
b.installArtifact(statlib); |
||||||
|
var dylib_flags = std.ArrayList([]const u8).init(b.allocator); |
||||||
|
try dylib_flags.appendSlice(zlib_flags.items); |
||||||
|
|
||||||
|
//trial |
||||||
|
//try dylib_flags.appendSlice(&.{ |
||||||
|
// "-DZLIB_DLL", |
||||||
|
//}); |
||||||
|
|
||||||
|
//"-Wl,-with-default-msvcrt=ucrtbase", //no effect - seems to be unnecessary anyway - ldd does show msvcrt as well as ucrtbase, but shims seem to all use ucrtbase.dll |
||||||
|
//"-Wl,-out-implib,libz.dll.a", //seems to have no effect. zig always creates a .lib |
||||||
|
//"-DZLIB_WINAPI", |
||||||
|
//"-Wl,-exclude-libs=ALL", |
||||||
|
std.debug.print("build_zlib.zig flags {s}\n", .{dylib_flags.items}); |
||||||
|
const dylib = b.addSharedLibrary(.{ |
||||||
|
.name = "zlib1", |
||||||
|
.target = target, |
||||||
|
.optimize = optimize, |
||||||
|
}); |
||||||
|
dylib.linkLibC(); |
||||||
|
dylib.addIncludePath(b.path(subdir)); |
||||||
|
dylib.addIncludePath(b.path(subdir ++ "/contrib/minizip")); |
||||||
|
dylib.addCSourceFiles(.{ |
||||||
|
.files = zlib_sources.items, |
||||||
|
.flags = dylib_flags.items, |
||||||
|
}); |
||||||
|
//dylib.addWin32ResourceFile(.{ .file = .{ .path = "zlib/win32/zlib1.rc" } }); //ignored for non-windows targets |
||||||
|
dylib.addWin32ResourceFile(.{ .file = b.path(subdir ++ "/win32/zlib1.rc") }); //ignored for non-windows targets |
||||||
|
b.installArtifact(dylib); |
||||||
|
|
||||||
|
const mgz_exe = b.addExecutable(.{ |
||||||
|
.name = "minigzip", |
||||||
|
.target = target, |
||||||
|
.optimize = optimize, |
||||||
|
}); |
||||||
|
mgz_exe.step.dependOn(&statlib.step); |
||||||
|
mgz_exe.addIncludePath(b.path(subdir)); |
||||||
|
mgz_exe.addCSourceFile(.{ |
||||||
|
.file = b.path(subdir ++ "/test/minigzip.c"), |
||||||
|
.flags = zlib_flags.items, |
||||||
|
}); |
||||||
|
mgz_exe.linkLibC(); |
||||||
|
mgz_exe.linkLibrary(statlib); |
||||||
|
b.installArtifact(mgz_exe); |
||||||
|
|
||||||
|
const eg_exe = b.addExecutable(.{ |
||||||
|
.name = "zlib_example", |
||||||
|
.target = target, |
||||||
|
.optimize = optimize, |
||||||
|
}); |
||||||
|
eg_exe.step.dependOn(&statlib.step); |
||||||
|
eg_exe.addIncludePath(b.path(subdir)); |
||||||
|
eg_exe.addCSourceFile(.{ |
||||||
|
.file = b.path(subdir ++ "/test/example.c"), |
||||||
|
.flags = zlib_flags.items, |
||||||
|
}); |
||||||
|
eg_exe.linkLibC(); |
||||||
|
eg_exe.linkLibrary(statlib); |
||||||
|
b.installArtifact(eg_exe); |
||||||
|
|
||||||
|
const egd_exe = b.addExecutable(.{ |
||||||
|
.name = "zlib_example_d", |
||||||
|
.target = target, |
||||||
|
.optimize = optimize, |
||||||
|
}); |
||||||
|
egd_exe.step.dependOn(&statlib.step); |
||||||
|
egd_exe.addIncludePath(b.path(subdir)); |
||||||
|
egd_exe.addCSourceFile(.{ |
||||||
|
.file = b.path(subdir ++ "/test/example.c"), |
||||||
|
.flags = dylib_flags.items, |
||||||
|
}); |
||||||
|
egd_exe.linkLibrary(dylib); |
||||||
|
egd_exe.root_module.addRPathSpecial("$ORIGIN/../lib"); |
||||||
|
egd_exe.linkLibC(); |
||||||
|
b.installArtifact(egd_exe); |
||||||
|
|
||||||
|
const mgzd_exe = b.addExecutable(.{ |
||||||
|
.name = "minigzip_d", |
||||||
|
.target = target, |
||||||
|
.optimize = optimize, |
||||||
|
}); |
||||||
|
mgzd_exe.step.dependOn(&statlib.step); |
||||||
|
mgzd_exe.addIncludePath(b.path(subdir)); |
||||||
|
mgzd_exe.addCSourceFile(.{ |
||||||
|
.file = b.path(subdir ++ "/test/minigzip.c"), |
||||||
|
.flags = dylib_flags.items, |
||||||
|
}); |
||||||
|
mgzd_exe.root_module.addRPathSpecial("$ORIGIN/../lib"); |
||||||
|
mgzd_exe.linkLibrary(dylib); |
||||||
|
b.installArtifact(mgzd_exe); |
||||||
|
|
||||||
|
return statlib; |
||||||
|
} |
||||||
@ -0,0 +1,41 @@ |
|||||||
|
# Recovered 2024 Tcl source patches (G-096) |
||||||
|
|
||||||
|
Origin: `c:/buildtcl/2024zig/build_tcl90/patch/` (reference snapshot |
||||||
|
`TEMP_REFERENCE/2024zig/build_tcl90/patch/`), written against ~Tcl 9.0b4-era sources |
||||||
|
(Aug 2024; tclZipfs/tclCmdIL Nov 2024). Recovered into tracked form 2026-07-20 - these |
||||||
|
files previously existed only in those two VCS-ignored on-disk copies. |
||||||
|
|
||||||
|
NONE of these are applied by the suite's default build: `suite.tcl build` compiles |
||||||
|
stock upstream sources. Rebasing/applying is per-patch opt-in work. |
||||||
|
|
||||||
|
## tclMain.c.piperepl.patch / tclMain_piperepl.c (the TCLSH_PIPEREPL capability) |
||||||
|
|
||||||
|
`tclMain_piperepl.c` is the full patched file; the `.patch` is its diff against the |
||||||
|
era's stock `tclMain.c`. |
||||||
|
|
||||||
|
Purpose (the G-096 goal capability): allow returning to a standard C-level tcl repl |
||||||
|
after launching from a kit with its own `main.tcl` - not possible with unmodified |
||||||
|
sources. Gated by the `TCLSH_PIPEREPL` env var (unset/`0` = stock behaviour). When |
||||||
|
enabled: |
||||||
|
|
||||||
|
- Publishes `::tclsh(istty)` (unlinked fact) plus linked `::tclsh(dorepl)` and |
||||||
|
`::tclsh(evalinput)` before the startup script runs; a script-arg launch defaults |
||||||
|
`dorepl` to 0 (stock semantics) but the script may set `::tclsh(dorepl) 1` to drop |
||||||
|
into the interactive repl after it completes. |
||||||
|
- Piped (non-tty) input the script did not consume is accumulated into |
||||||
|
`::tclsh(inputbuffer)` rather than evaluated as commands, unless the script opts in |
||||||
|
with `::tclsh(evalinput) 1` - protects arbitrary piped data from accidental eval. |
||||||
|
- On stdin eof with `dorepl` set, stdin is reopened from the console (`CONIN$` on |
||||||
|
windows, `/dev/tty` elsewhere) and installed as the std channel, yielding a live |
||||||
|
standard repl after a pipeline ends. |
||||||
|
|
||||||
|
Status: NOT yet rebased onto current Tcl 9 sources. Note the punkshell-level analogue |
||||||
|
for the punk repl is G-038 (piped-to-interactive session continuity) - this patch is |
||||||
|
the plain-tclsh/kit-runtime counterpart. |
||||||
|
|
||||||
|
## tclZipfs.patch, tclCmdIL.patch |
||||||
|
|
||||||
|
Companion experiment patches from the same era (zipfs behaviour and tclCmdIL tweak), |
||||||
|
recovered for durability; unexamined in detail. See the fossil-era notes in |
||||||
|
`TEMP_REFERENCE/2024zig/build_tcl90/patch/` (doc/, prev/, test_zipfs_patch/) for their |
||||||
|
surrounding experiment context. |
||||||
@ -0,0 +1,13 @@ |
|||||||
|
--- tclCmdIL_orig.c Sat Oct 05 06:09:52 2024
|
||||||
|
+++ tclCmdIL.c Mon Nov 18 13:59:01 2024
|
||||||
|
@@ -3926,6 +3926,10 @@
|
||||||
|
itemPtr = SelectObjFromSublist(listv[i+groupOffset],
|
||||||
|
&sortInfo);
|
||||||
|
Tcl_ListObjAppendElement(interp, listPtr, itemPtr);
|
||||||
|
+ } else if (returnSubindices && (sortInfo.indexc == 0) && (groupSize > 1)) {
|
||||||
|
+ Tcl_BounceRefCount(itemPtr);
|
||||||
|
+ itemPtr = listv[i + groupOffset];
|
||||||
|
+ Tcl_ListObjAppendElement(interp, listPtr, itemPtr);
|
||||||
|
} else if (groupSize > 1) {
|
||||||
|
Tcl_ListObjReplace(interp, listPtr, LIST_MAX, 0,
|
||||||
|
groupSize, &listv[i]);
|
||||||
@ -0,0 +1,233 @@ |
|||||||
|
--- tclMain.c Fri Aug 16 04:10:58 2024
|
||||||
|
+++ tclMain_piperepl.c Mon Aug 19 01:24:03 2024
|
||||||
|
@@ -105,6 +105,22 @@
|
||||||
|
* commands. */
|
||||||
|
} InteractiveState;
|
||||||
|
|
||||||
|
+typedef struct {
|
||||||
|
+ int istty; /* Non-zero means standard input is a
|
||||||
|
+ * terminal-like device
|
||||||
|
+ * Unlike InteractiveState.tty this is
|
||||||
|
+ * unaffected by whether a script path
|
||||||
|
+ * was specified at argv0 */
|
||||||
|
+ int dorepl; /* whether to run the default repl
|
||||||
|
+ * linked to ::tclsh(dorepl)
|
||||||
|
+ * so script file or stdin script
|
||||||
|
+ * can influence */
|
||||||
|
+ int reopened; /* if 1, we are processing from console - not piped input*/
|
||||||
|
+ int evalinput; /* default 0 - whether to evaluate piped input as commands
|
||||||
|
+ * This is input the script (if any) didn't consume
|
||||||
|
+ */
|
||||||
|
+ Tcl_Obj *inputbuffer;
|
||||||
|
+} PipeRepl;
|
||||||
|
/*
|
||||||
|
* Forward declarations for functions defined later in this file.
|
||||||
|
*/
|
||||||
|
@@ -291,6 +307,10 @@
|
||||||
|
Tcl_MainLoopProc *mainLoopProc;
|
||||||
|
Tcl_Channel chan;
|
||||||
|
InteractiveState is;
|
||||||
|
+ PipeRepl piperepl;
|
||||||
|
+ Tcl_Obj *tclInteractive; //JMN
|
||||||
|
+ int ttyAtStart; // Whether we initially had piped data or not
|
||||||
|
+ int inputReopen; // flag for reopening stdin
|
||||||
|
|
||||||
|
TclpSetInitialEncodings();
|
||||||
|
if (argc > 0) {
|
||||||
|
@@ -359,6 +379,37 @@
|
||||||
|
*/
|
||||||
|
|
||||||
|
is.tty = isatty(0);
|
||||||
|
+ ttyAtStart = is.tty; //JMN
|
||||||
|
+ int hasPipeRepl; //flag for whether piperepl and ::tclsh() behaviour enabled
|
||||||
|
+ {
|
||||||
|
+ const char *s;
|
||||||
|
+ Tcl_DString ds;
|
||||||
|
+ s = TclGetEnv("TCLSH_PIPEREPL", &ds);
|
||||||
|
+ hasPipeRepl = ((s != NULL) && strcmp(s, "0"));
|
||||||
|
+ if (s != NULL) {
|
||||||
|
+ Tcl_DStringFree(&ds);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ piperepl.reopened = 0;
|
||||||
|
+ piperepl.dorepl = 0;
|
||||||
|
+ piperepl.evalinput = 0;
|
||||||
|
+ if (hasPipeRepl) {
|
||||||
|
+ TclNewObj(piperepl.inputbuffer);
|
||||||
|
+ piperepl.istty = ttyAtStart;
|
||||||
|
+ piperepl.dorepl = ttyAtStart;
|
||||||
|
+ //unlinked - setting from script should have no effect
|
||||||
|
+ Tcl_SetVar2Ex(interp, "tclsh", "istty",
|
||||||
|
+ Tcl_NewBooleanObj(ttyAtStart), TCL_GLOBAL_ONLY);
|
||||||
|
+ //will be linked so script/stdin can influence
|
||||||
|
+ // if path (script) supplied, but no stdin
|
||||||
|
+ // - will be set 0 to match default 'tclsh <script>' behaviour
|
||||||
|
+ // when ::tclsh(dorepl) not set in the script
|
||||||
|
+ Tcl_SetVar2Ex(interp, "tclsh", "dorepl",
|
||||||
|
+ Tcl_NewBooleanObj(ttyAtStart), TCL_GLOBAL_ONLY);
|
||||||
|
+ Tcl_SetVar2Ex(interp, "tclsh", "evalinput",
|
||||||
|
+ Tcl_NewBooleanObj(piperepl.evalinput), TCL_GLOBAL_ONLY);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
Tcl_SetVar2Ex(interp, "tcl_interactive", NULL,
|
||||||
|
Tcl_NewBooleanObj(!path && is.tty), TCL_GLOBAL_ONLY);
|
||||||
|
|
||||||
|
@@ -397,9 +448,18 @@
|
||||||
|
* Invoke the script specified on the command line, if any. Must fetch it
|
||||||
|
* again, as the appInitProc might have reset it.
|
||||||
|
*/
|
||||||
|
-
|
||||||
|
+ if (hasPipeRepl) {
|
||||||
|
+ //REVIEW - ok to use Tcl_LinkVar on individual array elements? (we don't want to Tcl_LinkArray the whole thing)
|
||||||
|
+ Tcl_LinkVar(interp, "tclsh(dorepl)", &piperepl.dorepl, TCL_LINK_BOOLEAN);
|
||||||
|
+ Tcl_LinkVar(interp, "tclsh(evalinput)", &piperepl.evalinput, TCL_LINK_BOOLEAN);
|
||||||
|
+ Tcl_LinkVar(interp, "tcl_interactive", &is.tty, TCL_LINK_BOOLEAN); // link before script only when TCLSH_PIPEREPL true
|
||||||
|
+ }
|
||||||
|
path = Tcl_GetStartupScript(&encodingName);
|
||||||
|
if (path != NULL) {
|
||||||
|
+ if (hasPipeRepl) {
|
||||||
|
+ piperepl.dorepl = 0; //default to standard behaviour of no repl when script arg present - script can override
|
||||||
|
+ // stdin can only override dorepl, tcl_interactive if evalinput set to true in script
|
||||||
|
+ }
|
||||||
|
Tcl_ResetResult(interp);
|
||||||
|
code = Tcl_FSEvalFileEx(interp, path, encodingName);
|
||||||
|
if (code != TCL_OK) {
|
||||||
|
@@ -419,7 +479,35 @@
|
||||||
|
}
|
||||||
|
exitCode = 1;
|
||||||
|
}
|
||||||
|
- goto done;
|
||||||
|
+ if (hasPipeRepl) {
|
||||||
|
+ if (!(piperepl.dorepl || piperepl.evalinput)) {
|
||||||
|
+ //tty or not - we need some reason to progress
|
||||||
|
+ goto done;
|
||||||
|
+ }
|
||||||
|
+ //evalinput may be specified when tty - but in that case there can be no pipeline input
|
||||||
|
+ //This is for usecase to allow pipeline to set dorepl without modifiying script
|
||||||
|
+ if (piperepl.istty && !piperepl.dorepl) {
|
||||||
|
+ //Launch without pipeline -
|
||||||
|
+ goto done;
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ goto done;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ if (hasPipeRepl) {
|
||||||
|
+ if (path == NULL) {
|
||||||
|
+ piperepl.evalinput = 1; //duplicate standard tclsh behaviour and pass through to repl for eval
|
||||||
|
+ }
|
||||||
|
+ piperepl.inputbuffer = Tcl_NewStringObj("", -1);
|
||||||
|
+ Tcl_IncrRefCount(piperepl.inputbuffer);
|
||||||
|
+ if (piperepl.istty) {
|
||||||
|
+ inputReopen = 0; //no reopen required - eof is from console?
|
||||||
|
+ } else {
|
||||||
|
+ //assume there was some data piped?
|
||||||
|
+ inputReopen = 1;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -444,7 +532,9 @@
|
||||||
|
* Get a new value for tty if anyone writes to ::tcl_interactive
|
||||||
|
*/
|
||||||
|
|
||||||
|
- Tcl_LinkVar(interp, "tcl_interactive", &is.tty, TCL_LINK_BOOLEAN);
|
||||||
|
+ if (!hasPipeRepl) {
|
||||||
|
+ Tcl_LinkVar(interp, "tcl_interactive", &is.tty, TCL_LINK_BOOLEAN);
|
||||||
|
+ }
|
||||||
|
is.input = Tcl_GetStdChannel(TCL_STDIN);
|
||||||
|
while ((is.input != NULL) && !Tcl_InterpDeleted(interp)) {
|
||||||
|
mainLoopProc = TclGetMainLoop();
|
||||||
|
@@ -464,12 +554,34 @@
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- if (Tcl_IsShared(is.commandPtr)) {
|
||||||
|
- Tcl_DecrRefCount(is.commandPtr);
|
||||||
|
- is.commandPtr = Tcl_DuplicateObj(is.commandPtr);
|
||||||
|
- Tcl_IncrRefCount(is.commandPtr);
|
||||||
|
+ if (hasPipeRepl && !piperepl.istty && !piperepl.reopened && !piperepl.evalinput) {
|
||||||
|
+ /* still handling from pipe
|
||||||
|
+ * This is data the script (if any) didn't read
|
||||||
|
+ * We should only evaluate as commands if we were explicitly instructed to (::tclsh(evalinput) == 1)
|
||||||
|
+ * Otherwise a script which processes arbitrary data (but set ::tclsh(dorepl) to 1 to drop into a shell)
|
||||||
|
+ * may cause the arbitrary data to be evaled unexpectedly if it failed to process all the input */
|
||||||
|
+ if (Tcl_IsShared(piperepl.inputbuffer)) {
|
||||||
|
+ Tcl_DecrRefCount(piperepl.inputbuffer);
|
||||||
|
+ piperepl.inputbuffer = Tcl_DuplicateObj(piperepl.inputbuffer);
|
||||||
|
+ Tcl_IncrRefCount(piperepl.inputbuffer);
|
||||||
|
+ }
|
||||||
|
+ length = Tcl_GetsObj(is.input,piperepl.inputbuffer);
|
||||||
|
+ if (length >= 0) {
|
||||||
|
+ if (Tcl_IsShared(piperepl.inputbuffer)) {
|
||||||
|
+ Tcl_DecrRefCount(piperepl.inputbuffer);
|
||||||
|
+ piperepl.inputbuffer = Tcl_DuplicateObj(piperepl.inputbuffer);
|
||||||
|
+ Tcl_IncrRefCount(piperepl.inputbuffer);
|
||||||
|
+ }
|
||||||
|
+ Tcl_AppendToObj(piperepl.inputbuffer, "\n", 1);
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ if (Tcl_IsShared(is.commandPtr)) {
|
||||||
|
+ Tcl_DecrRefCount(is.commandPtr);
|
||||||
|
+ is.commandPtr = Tcl_DuplicateObj(is.commandPtr);
|
||||||
|
+ Tcl_IncrRefCount(is.commandPtr);
|
||||||
|
+ }
|
||||||
|
+ length = Tcl_GetsObj(is.input, is.commandPtr);
|
||||||
|
}
|
||||||
|
- length = Tcl_GetsObj(is.input, is.commandPtr);
|
||||||
|
if (length < 0) {
|
||||||
|
if (Tcl_InputBlocked(is.input)) {
|
||||||
|
/*
|
||||||
|
@@ -487,9 +599,48 @@
|
||||||
|
* Either EOF, or an error on stdin; we're done
|
||||||
|
*/
|
||||||
|
|
||||||
|
- break;
|
||||||
|
+ if (piperepl.dorepl) {
|
||||||
|
+ chan = Tcl_GetStdChannel(TCL_STDOUT);
|
||||||
|
+ inputReopen--;
|
||||||
|
+ if (inputReopen >= 0) {
|
||||||
|
+ Tcl_WriteChars(chan, "? reopen stdin from console \n", -1);
|
||||||
|
+ if (is.input != NULL) {
|
||||||
|
+ //Tcl_UnregisterChannel should close stdin without killing console?
|
||||||
|
+ if (Tcl_UnregisterChannel(interp, is.input) != TCL_OK) {
|
||||||
|
+ Tcl_WriteChars(chan, "?after eof/error on stdin, unregister stdin failed\n", -1);
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ #ifndef _WIN32
|
||||||
|
+ is.input = Tcl_OpenFileChannel(interp,"/dev/tty", "r", 0644);
|
||||||
|
+ #else
|
||||||
|
+ is.input = Tcl_OpenFileChannel(interp, "CONIN$", "r", 0644); //windows specific
|
||||||
|
+ #endif
|
||||||
|
+ //is.input = Tcl_GetStdChannel(TCL_STDIN);
|
||||||
|
+ if (is.input == NULL) {
|
||||||
|
+ Tcl_WriteChars(chan, "?after eof/error on stdin, reopen stdin from console failed\n", -1);
|
||||||
|
+ break;
|
||||||
|
+ } else {
|
||||||
|
+ piperepl.reopened = 1;
|
||||||
|
+ Tcl_SetVar2Ex(interp, "tclsh", "inputbuffer", piperepl.inputbuffer, TCL_GLOBAL_ONLY);
|
||||||
|
+ Tcl_SetChannelOption(interp, is.input, "-blocking", "1");
|
||||||
|
+ Tcl_SetChannelOption(interp, is.input, "-buffering", "line");
|
||||||
|
+ Tcl_SetStdChannel(is.input,TCL_STDIN);
|
||||||
|
+ Tcl_RegisterChannel(interp, is.input);
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ if (hasPipeRepl && !piperepl.istty && !piperepl.reopened && !piperepl.evalinput) {
|
||||||
|
+ /* still handling input from pipe and we are not configured to eval the input
|
||||||
|
+ * keep accumulating in piperepl.inputbuffer*/
|
||||||
|
+ continue;
|
||||||
|
}
|
||||||
|
-
|
||||||
|
/*
|
||||||
|
* Add the newline removed by Tcl_GetsObj back to the string. Have
|
||||||
|
* to add it back before testing completeness, because it can make
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,4 @@ |
|||||||
|
const std = @import("std"); |
||||||
|
|
||||||
|
pub const _start = void; |
||||||
|
pub const WinMainCRTStartup = void; |
||||||
@ -0,0 +1,178 @@ |
|||||||
|
#!/usr/bin/env tclsh |
||||||
|
#suite_tcl90 driver (G-096): stage the tracked zig recipe into ../_build/suite_tcl90, |
||||||
|
#arrange sources, generate the configure-produced files fresh checkouts lack, build, |
||||||
|
#and smoke-test the result. |
||||||
|
# |
||||||
|
#Usage: tclsh suite.tcl build ?options? |
||||||
|
# tclsh suite.tcl clean |
||||||
|
#Options: |
||||||
|
# -zig <path> zig executable (default: $env(PUNK_ZIG), else 'zig' on PATH) |
||||||
|
# -optimize <mode> Debug|ReleaseSafe|ReleaseFast|ReleaseSmall (default ReleaseFast) |
||||||
|
# -tclbranch <branch> tcl branch/tag to open (default core-9-0-branch) |
||||||
|
# -refresh <0|1> fossil update existing source checkouts (default 0) |
||||||
|
# -vqtcl-source <dir> local vqtcl source dir (no public upstream confirmed; |
||||||
|
# default C:/buildtcl/2024zig/vqtcl) |
||||||
|
# -steps <list> zig build steps (default {install install-libraries make-zipfs}) |
||||||
|
# |
||||||
|
#The build area lives entirely under src/buildsuites/_build (VCS-ignored via the |
||||||
|
#existing _build globs). Fossil clones are cached in ~/.fossils; checkouts made here |
||||||
|
#use FOSSIL_HOME=<stage> so the user's global fossil config db records nothing. |
||||||
|
|
||||||
|
proc log {msg} {puts stdout "suite_tcl90: $msg"; flush stdout} |
||||||
|
proc fail {msg} {puts stderr "suite_tcl90 ERROR: $msg"; flush stderr; exit 1} |
||||||
|
|
||||||
|
proc run {args} { |
||||||
|
#stream output; abort on nonzero exit |
||||||
|
log "run: $args" |
||||||
|
if {[catch {exec {*}$args >@stdout 2>@stderr} err opts]} { |
||||||
|
set code [dict get $opts -errorcode] |
||||||
|
if {[lindex $code 0] eq "CHILDSTATUS"} { |
||||||
|
fail "command failed (exit [lindex $code 2]): $args" |
||||||
|
} |
||||||
|
fail "command failed: $args\n$err" |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
set suiteroot [file dirname [file normalize [info script]]] |
||||||
|
set stage [file normalize [file join $suiteroot .. _build suite_tcl90]] |
||||||
|
set fossildir [file normalize [file join $env(HOME) .fossils]] |
||||||
|
|
||||||
|
#-- options --------------------------------------------------------------- |
||||||
|
set action [lindex $argv 0] |
||||||
|
if {$action ni {build clean}} { |
||||||
|
puts stderr "usage: tclsh suite.tcl build|clean ?options? (see header)" |
||||||
|
exit 2 |
||||||
|
} |
||||||
|
array set opt { |
||||||
|
-optimize ReleaseFast |
||||||
|
-tclbranch core-9-0-branch |
||||||
|
-refresh 0 |
||||||
|
-vqtcl-source C:/buildtcl/2024zig/vqtcl |
||||||
|
-steps {install install-libraries make-zipfs} |
||||||
|
} |
||||||
|
set opt(-zig) [expr {[info exists env(PUNK_ZIG)] ? $env(PUNK_ZIG) : "zig"}] |
||||||
|
foreach {k v} [lrange $argv 1 end] { |
||||||
|
if {![info exists opt($k)]} {fail "unknown option '$k'"} |
||||||
|
set opt($k) $v |
||||||
|
} |
||||||
|
|
||||||
|
if {$action eq "clean"} { |
||||||
|
log "removing $stage" |
||||||
|
file delete -force $stage |
||||||
|
exit 0 |
||||||
|
} |
||||||
|
|
||||||
|
#-- fossil environment ---------------------------------------------------- |
||||||
|
#Checkout registrations go to a stage-local config db, not the user's global one |
||||||
|
#(agent-memory: fossil scratchpad registry pollution). Clones are still shared. |
||||||
|
file mkdir $stage |
||||||
|
set env(FOSSIL_HOME) $stage |
||||||
|
file mkdir $fossildir |
||||||
|
|
||||||
|
proc fossil_source {name url branch dir} { |
||||||
|
#ensure ~/.fossils/<name>.fossil exists (clone if needed) and open it at branch in dir |
||||||
|
global fossildir opt |
||||||
|
set repo [file join $fossildir $name.fossil] |
||||||
|
if {![file exists $repo]} { |
||||||
|
log "cloning $url -> $repo" |
||||||
|
run fossil clone $url $repo |
||||||
|
} |
||||||
|
if {![file exists [file join $dir _FOSSIL_]] && ![file exists [file join $dir .fslckout]]} { |
||||||
|
file mkdir $dir |
||||||
|
set savedpwd [pwd] |
||||||
|
cd $dir |
||||||
|
#--nested: the stage lives inside the punkshell checkout tree |
||||||
|
run fossil open $repo $branch --nested |
||||||
|
cd $savedpwd |
||||||
|
} elseif {$opt(-refresh)} { |
||||||
|
set savedpwd [pwd] |
||||||
|
cd $dir |
||||||
|
run fossil update $branch |
||||||
|
cd $savedpwd |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#-- stage the recipe ------------------------------------------------------ |
||||||
|
set builddir [file join $stage build] |
||||||
|
log "staging recipe -> $builddir" |
||||||
|
file delete -force $builddir |
||||||
|
file mkdir $builddir |
||||||
|
foreach item {build905.zig build_libtommath build_zlib build_tclvfs build_vqtcl build_tclthread src tools} { |
||||||
|
file copy [file join $suiteroot $item] $builddir |
||||||
|
} |
||||||
|
|
||||||
|
#-- sources --------------------------------------------------------------- |
||||||
|
fossil_source tcl https://core.tcl-lang.org/tcl $opt(-tclbranch) [file join $stage tcl905] |
||||||
|
fossil_source tclthread https://core.tcl-lang.org/thread trunk [file join $stage tclthread] |
||||||
|
fossil_source tclvfs https://core.tcl-lang.org/tclvfs trunk [file join $stage tclvfs] |
||||||
|
|
||||||
|
#zlib: use the tcl tree's own vendored copy (version-matched; includes contrib/minizip) |
||||||
|
set zlibdir [file join $stage zlib] |
||||||
|
if {![file isdirectory $zlibdir]} { |
||||||
|
log "staging zlib from tcl compat/zlib" |
||||||
|
file copy [file join $stage tcl905 compat zlib] $zlibdir |
||||||
|
} |
||||||
|
#vqtcl: local source only (vlerq 4.1 by jcw - no public upstream confirmed) |
||||||
|
set vqdir [file join $stage vqtcl] |
||||||
|
if {![file isdirectory $vqdir]} { |
||||||
|
if {![file isdirectory $opt(-vqtcl-source)]} { |
||||||
|
fail "vqtcl source not found at '$opt(-vqtcl-source)' (set -vqtcl-source)" |
||||||
|
} |
||||||
|
log "staging vqtcl from $opt(-vqtcl-source)" |
||||||
|
file copy $opt(-vqtcl-source) $vqdir |
||||||
|
} |
||||||
|
|
||||||
|
#-- generated files a fresh tcl checkout lacks (normally configure/prepare products) -- |
||||||
|
set tcldir [file join $stage tcl905] |
||||||
|
#tclUuid.h: '#define TCL_VERSION_UUID \' + manifest.uuid content |
||||||
|
set f [open [file join $tcldir manifest.uuid] r]; set uuid [read $f]; close $f |
||||||
|
set f [open [file join $tcldir win tclUuid.h] w] |
||||||
|
fconfigure $f -translation lf |
||||||
|
puts -nonewline $f "#define TCL_VERSION_UUID \\\n$uuid" |
||||||
|
close $f |
||||||
|
#tclsh.exe.manifest from .in: TCL_WIN_VERSION = TCL_VERSION . releaselevel . patchlevel-stripped |
||||||
|
set f [open [file join $tcldir generic tcl.h] r]; set tclh [read $f]; close $f |
||||||
|
if {![regexp {#\s*define\s+TCL_VERSION\s+"([^"]+)"} $tclh -> tclversion]} {fail "TCL_VERSION not found in tcl.h"} |
||||||
|
if {![regexp {#\s*define\s+TCL_PATCH_LEVEL\s+"([^"]+)"} $tclh -> patchlevel]} {fail "TCL_PATCH_LEVEL not found in tcl.h"} |
||||||
|
set rlevel [expr {[string match *a* $patchlevel] ? 0 : ([string match *b* $patchlevel] ? 1 : 2)}] |
||||||
|
set winver "$tclversion.$rlevel.[string map {a {} b {} . {}} $patchlevel]" |
||||||
|
set f [open [file join $tcldir win tclsh.exe.manifest.in] r]; set manifest [read $f]; close $f |
||||||
|
set manifest [string map [list @TCL_WIN_VERSION@ $winver @MACHINE@ AMD64] $manifest] |
||||||
|
set f [open [file join $tcldir win tclsh.exe.manifest] w] |
||||||
|
fconfigure $f -translation lf |
||||||
|
puts -nonewline $f $manifest |
||||||
|
close $f |
||||||
|
log "generated tclUuid.h + tclsh.exe.manifest (TCL_WIN_VERSION $winver, patchlevel $patchlevel)" |
||||||
|
|
||||||
|
#thread.rc: the zig rc compile does not receive the makefile's include paths; give the |
||||||
|
#version resource script the tcl header it needs (idempotent scripted edit of the |
||||||
|
#staged checkout - the historical recipe carried this as an uncommitted tweak). |
||||||
|
set rcfile [file join $stage tclthread win thread.rc] |
||||||
|
set f [open $rcfile r]; set rc [read $f]; close $f |
||||||
|
if {![string match "*tcl905/generic/tcl.h*" $rc]} { |
||||||
|
set rc [string map [list "#include <winver.h>" "#include <winver.h>\n#include \"../../tcl905/generic/tcl.h\""] $rc] |
||||||
|
set f [open $rcfile w]; fconfigure $f -translation lf; puts -nonewline $f $rc; close $f |
||||||
|
log "thread.rc: inserted tcl.h include for the version resource" |
||||||
|
} |
||||||
|
|
||||||
|
#-- build ----------------------------------------------------------------- |
||||||
|
set zigv [exec $opt(-zig) version] |
||||||
|
log "zig: $opt(-zig) ($zigv)" |
||||||
|
set savedpwd [pwd] |
||||||
|
cd $builddir |
||||||
|
run $opt(-zig) build --build-file build905.zig --prefix [file join $stage out] -Doptimize=$opt(-optimize) {*}$opt(-steps) |
||||||
|
cd $savedpwd |
||||||
|
|
||||||
|
#-- smoke ----------------------------------------------------------------- |
||||||
|
set exe [file join $stage out bin tclsh90s.exe] |
||||||
|
set zexe [file join $stage out bin tclsh90szip.exe] |
||||||
|
foreach {label path script} [list \ |
||||||
|
static $exe {puts [info patchlevel]} \ |
||||||
|
zip $zexe {puts "[info patchlevel] tz=[clock format 0 -gmt 0 -format %Z] auto=[llength [info procs auto_load]]"} \ |
||||||
|
] { |
||||||
|
if {![file exists $path]} {fail "$label shell missing: $path"} |
||||||
|
set out [exec $path << "$script; exit"] |
||||||
|
log "$label shell: $out" |
||||||
|
if {![string match "$patchlevel*" $out]} {fail "$label shell patchlevel mismatch: got '$out' want '$patchlevel'"} |
||||||
|
} |
||||||
|
log "PASS - built $patchlevel (checkout [string range $uuid 0 11]..., zig $zigv) -> $stage/out" |
||||||
@ -0,0 +1,85 @@ |
|||||||
|
const std = @import("std"); |
||||||
|
|
||||||
|
const usage = |
||||||
|
\\Usage: ./wrapfiletofile [options] |
||||||
|
\\ |
||||||
|
\\Options: |
||||||
|
\\ -prefix STRING |
||||||
|
\\ -prefixnl BOOLEAN |
||||||
|
\\ -input INPUTFILENAME |
||||||
|
\\ -outut OUTPUTFILENAME |
||||||
|
; |
||||||
|
|
||||||
|
pub fn main() !void { |
||||||
|
var arena_state = std.heap.ArenaAllocator.init(std.heap.page_allocator); |
||||||
|
defer arena_state.deinit(); |
||||||
|
const arena = arena_state.allocator(); |
||||||
|
|
||||||
|
const args = try std.process.argsAlloc(arena); |
||||||
|
|
||||||
|
var opt_input_file_path: ?[]const u8 = null; |
||||||
|
var opt_output_file_path: ?[]const u8 = null; |
||||||
|
var opt_prefix: ?[]const u8 = null; |
||||||
|
var opt_prefixnl: bool = true; |
||||||
|
|
||||||
|
{ |
||||||
|
var i: usize = 1; |
||||||
|
while (i < args.len) : (i += 1) { |
||||||
|
const arg = args[i]; |
||||||
|
if (std.mem.eql(u8, "-h",arg) or std.mem.eql(u8, "-help",arg)) { |
||||||
|
try std.io.getStdOut().writeAll(usage); |
||||||
|
return std.process.cleanExit(); |
||||||
|
} else if (std.mem.eql(u8,"-prefix",arg)) { |
||||||
|
i += 1; |
||||||
|
if (i > args.len) fatal("expected arg after '{s}'", .{arg}); |
||||||
|
opt_prefix = args[i]; |
||||||
|
} else if (std.mem.eql(u8,"-input",arg)) { |
||||||
|
i += 1; |
||||||
|
if (i > args.len) fatal("expected arg after '{s}'", .{arg}); |
||||||
|
if (opt_input_file_path != null) fatal("duplicated {s} argument", .{arg}); |
||||||
|
opt_input_file_path = args[i]; |
||||||
|
} else if (std.mem.eql(u8,"-output",arg)) { |
||||||
|
i += 1; |
||||||
|
if (i > args.len) fatal("expected arg after '{s}'", .{arg}); |
||||||
|
if (opt_output_file_path != null) fatal("duplicated {s} argument", .{arg}); |
||||||
|
opt_output_file_path = args[i]; |
||||||
|
} else if (std.mem.eql(u8,"-prefixnl",arg)) { |
||||||
|
i+= 1; |
||||||
|
if (i > args.len) fatal("expected arg after '{s}'", .{arg}); |
||||||
|
//cast? review |
||||||
|
if (std.mem.eql(u8,"1",args[i])) { |
||||||
|
opt_prefixnl = true; |
||||||
|
} else { |
||||||
|
opt_prefixnl = false; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const input_file_path = opt_input_file_path orelse fatal("missing -input file", .{}); |
||||||
|
const output_file_path = opt_output_file_path orelse fatal("missing -output file", .{}); |
||||||
|
const prefix = opt_prefix orelse fatal("missing -prefix string",.{}); |
||||||
|
var input_file = std.fs.cwd().openFile(input_file_path,.{ .mode = .read_only}) catch |err| { |
||||||
|
fatal("Unable to open '{s}': {s}",. { input_file_path, @errorName(err) }); |
||||||
|
}; |
||||||
|
defer input_file.close(); |
||||||
|
const input_data = try input_file.readToEndAlloc(arena, std.math.maxInt(usize)); |
||||||
|
defer arena.free(input_data); |
||||||
|
std.debug.print("inputfile - Read {d} octets.\n", .{input_data.len}); |
||||||
|
|
||||||
|
var output_file = std.fs.cwd().createFile(output_file_path, .{}) catch |err| { |
||||||
|
fatal("Unable to open '{s}': {s}", .{ output_file_path, @errorName(err)}); |
||||||
|
}; |
||||||
|
defer output_file.close(); |
||||||
|
_ = try output_file.write(prefix); |
||||||
|
if (opt_prefixnl) { |
||||||
|
_ = try output_file.write("\n"); |
||||||
|
} |
||||||
|
try output_file.writeAll(input_data); |
||||||
|
return std.process.cleanExit(); |
||||||
|
} |
||||||
|
|
||||||
|
fn fatal(comptime format: []const u8, args: anytype) noreturn { |
||||||
|
std.debug.print(format,args); |
||||||
|
std.process.exit(1); |
||||||
|
} |
||||||
@ -0,0 +1,55 @@ |
|||||||
|
#JMN 2024 |
||||||
|
#A simple wrapper to call the 'zipfs mkimg' (tcl::zipfs::mkimg) command via commandline arguments. |
||||||
|
#(avoiding piping commands to tclsh via stdin to make calling simpler, and to provide more specific error messages) |
||||||
|
# |
||||||
|
set script_title "[file tail [info nameofexecutable]] [file tail [info script]]" |
||||||
|
set usage "$script_title -outfile <target_zipfile_path> -indir <folder_to_zip> ?-strip <path_prefix_to_strip>? ?-password <plaintext>? ?-infile <explicit_prepend_file>?" |
||||||
|
set arglist $::argv |
||||||
|
puts stderr "====> '$arglist'" |
||||||
|
#error 42 |
||||||
|
if {![llength $arglist]} { |
||||||
|
puts stderr $usage |
||||||
|
exit 1 |
||||||
|
} |
||||||
|
if {[llength $arglist] %2 != 0} { |
||||||
|
puts stderr "$script_title error: expected an even number of option value pairs. Got [llength $arglist] commandline arguments. '$arglist'" |
||||||
|
puts stderr $usage |
||||||
|
exit 2 |
||||||
|
} |
||||||
|
set known_opts [list -outfile -indir -strip -password -infile] |
||||||
|
dict for {k v} $arglist { |
||||||
|
switch -exact -- $k { |
||||||
|
-outfile - -indir - -strip - -password - -infile {} |
||||||
|
default { |
||||||
|
puts stderr "$script_title error: unrecognised option $k. Known_options $known_opts" |
||||||
|
exit 3 |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
set defaults [dict create\ |
||||||
|
-strip ""\ |
||||||
|
-password ""\ |
||||||
|
] |
||||||
|
|
||||||
|
set opts [dict merge $defaults $arglist] |
||||||
|
if {![dict exists $opts -outfile]} { |
||||||
|
puts stderr "$script_title error: Missing -outfile <zipfilename>" |
||||||
|
exit 4 |
||||||
|
} |
||||||
|
if {![dict exists $opts -indir]} { |
||||||
|
puts stderr "$script_title error: Missing -indir <folder>" |
||||||
|
exit 5 |
||||||
|
} |
||||||
|
set callargs [list [file normalize [dict get $opts -outfile]] [file normalize [dict get $opts -indir]] [file normalize [dict get $opts -strip]] [dict get $opts -password]] |
||||||
|
if {[dict exists $opts -infile]} { |
||||||
|
lappend callargs [file normalize [dict get $opts -infile]] |
||||||
|
} |
||||||
|
puts stderr "$script_title call 'tcl::zipfs::mkimg $callargs'" |
||||||
|
|
||||||
|
if {[catch { |
||||||
|
tcl::zipfs::mkimg {*}$callargs |
||||||
|
} errM]} { |
||||||
|
puts stderr "$script_title error: Failure during call 'tcl::zipfs::mkimg $callargs'\n $errM" |
||||||
|
exit 6 |
||||||
|
} |
||||||
|
exit 0 |
||||||
@ -0,0 +1,65 @@ |
|||||||
|
#JMN 2024 |
||||||
|
#A simple wrapper to call the 'zipfs mkzip' (tcl::zipfs::mkzip) command via commandline arguments. |
||||||
|
#(avoiding piping commands to tclsh via stdin to make calling simpler, and to provide more specific error messages) |
||||||
|
# |
||||||
|
set script_title "[file tail [info nameofexecutable]] [file tail [info script]]" |
||||||
|
set usage "$script_title -outfile <target_zipfile_path> -indir <folder_to_zip> ?-strip <path_prefix_to_strip>? ?-password <plaintext>?" |
||||||
|
set arglist $::argv |
||||||
|
#puts stderr "====> '$arglist'" |
||||||
|
#error 42 |
||||||
|
if {![llength $arglist]} { |
||||||
|
puts stderr $usage |
||||||
|
exit 1 |
||||||
|
} |
||||||
|
if {[llength $arglist] %2 != 0} { |
||||||
|
puts stderr "$script_title error: expected an even number of option value pairs. Got [llength $arglist] commandline arguments. '$arglist'" |
||||||
|
puts stderr $usage |
||||||
|
exit 2 |
||||||
|
} |
||||||
|
set known_opts [list -outfile -indir -strip -password] |
||||||
|
dict for {k v} $arglist { |
||||||
|
switch -exact -- $k { |
||||||
|
-outfile - -indir - -strip - -password {} |
||||||
|
default { |
||||||
|
puts stderr "$script_title error: unrecognised option $k. Known_options $known_opts" |
||||||
|
exit 3 |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
set defaults [dict create\ |
||||||
|
] |
||||||
|
|
||||||
|
set opts [dict merge $defaults $arglist] |
||||||
|
if {![dict exists $opts -outfile]} { |
||||||
|
puts stderr "$script_title error: Missing -outfile <zipfilename>" |
||||||
|
exit 4 |
||||||
|
} |
||||||
|
if {![dict exists $opts -indir]} { |
||||||
|
puts stderr "$script_title error: Missing -indir <folder>" |
||||||
|
exit 5 |
||||||
|
} |
||||||
|
set callargs [list [file normalize [dict get $opts -outfile]] [file normalize [dict get $opts -indir]]] |
||||||
|
if {[dict exists $opts -strip]} { |
||||||
|
set opt_strip [dict get $opts -strip] |
||||||
|
#avoid extraneous underscore(empty path segment?) in zip archive on windows. |
||||||
|
#review - test if trailing slash needed on other platforms |
||||||
|
#if {"windows" eq "$::tcl_platform(platform)" && $opt_strip ne "" && [lindex $opt_strip end] ne "\\"} { |
||||||
|
# append opt_strip \\ |
||||||
|
#} |
||||||
|
lappend callargs [file normalize $opt_strip] |
||||||
|
} |
||||||
|
if {[dict exists $opts -password]} { |
||||||
|
if {![dict exists $opts -strip]} { |
||||||
|
lappend callargs "" |
||||||
|
} |
||||||
|
lappend callargs [dict get $opts -password] |
||||||
|
} |
||||||
|
puts stderr "$script_title call 'tcl::zipfs::mkzip $callargs'" |
||||||
|
|
||||||
|
if {[catch { |
||||||
|
tcl::zipfs::mkzip {*}$callargs |
||||||
|
} errM]} { |
||||||
|
puts stderr "$script_title error: Failure during call 'tcl::zipfs::mkzip $callargs'\n $errM" |
||||||
|
exit 6 |
||||||
|
} |
||||||
|
exit 0 |
||||||
Loading…
Reference in new issue