My aggregated monorepo of OCaml code, automaintained
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add per-package JTW generation

For each package with findlib libraries, runs jtw opam in a container
with the build layer stacked and jtw/js_of_ocaml binaries bind-mounted.
Produces .cma.js, .cmi, META, and dynamic_cmis.json.

build_and_run builds tools then generates artifacts in one call.
Per-compiler tool selection matches the doc generation pattern.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+144 -9
+2 -2
day11/bin/cmd_batch.ml
··· 366 366 (* JTW *) 367 367 (match jtw_repo with 368 368 | Some dir -> 369 - Day11_jtw.Build_tools.build_per_compiler env benv ~np 369 + Day11_jtw.Build_tools.build_and_run env benv ~np ~os_dir 370 370 ~packages:git_packages ~opam_env ~mounts:[repo_mount] 371 - ~repo_dir:dir ~solutions 371 + ~repo_dir:dir ~nodes ~solutions 372 372 | None -> ()); 373 373 0 374 374 end
+17 -4
day11/jtw/build_tools.ml
··· 3 3 Printf.printf "\nBuilding JTW tools from %s...\n%!" repo_dir; 4 4 let compiler_versions = 5 5 Day11_doc.Generate.unique_compilers solutions in 6 - List.iter (fun compiler_v -> 6 + List.filter_map (fun compiler_v -> 7 7 Printf.printf "Building JTW for %s...\n%!" 8 8 (OpamPackage.to_string compiler_v); 9 9 match Day11_build.Tools.build_tool_from_repo env benv ~np 10 10 ~packages ~env:opam_env ~ocaml_version:compiler_v 11 11 ~mounts ~repo_dir 12 12 ~target_name:Tool_layer.tool_target () with 13 - | Ok _tool -> 13 + | Ok tool -> 14 14 Printf.printf "JTW tools for %s: OK\n%!" 15 - (OpamPackage.to_string compiler_v) 15 + (OpamPackage.to_string compiler_v); 16 + Some (compiler_v, tool) 16 17 | Error (`Msg e) -> 17 18 Printf.printf "JTW tools for %s failed: %s\n%!" 18 - (OpamPackage.to_string compiler_v) e 19 + (OpamPackage.to_string compiler_v) e; 20 + None 19 21 ) compiler_versions 22 + 23 + let build_and_run env benv ~np ~os_dir ~packages ~opam_env ~mounts 24 + ~repo_dir ~nodes ~solutions = 25 + let jtw_tools = build_per_compiler env benv ~np ~packages ~opam_env 26 + ~mounts ~repo_dir ~solutions in 27 + if jtw_tools = [] then 28 + Printf.printf "No JTW tools built, skipping generation\n%!" 29 + else begin 30 + let count = Generate.run env benv ~os_dir ~jtw_tools ~nodes ~solutions in 31 + Printf.printf "\n=== JTW: %d packages processed ===\n%!" count 32 + end
+18 -3
day11/jtw/build_tools.mli
··· 1 - (** Build JTW tools from a local source checkout. 1 + (** Build JTW tools and generate per-package artifacts. 2 2 3 - Builds [js_top_worker-bin] for each unique compiler version in 4 - the batch solutions, using {!Day11_build.Tools.build_tool_from_repo}. *) 3 + Builds [js_top_worker-bin] from a local checkout for each unique 4 + compiler version, then runs per-package JTW generation. *) 5 5 6 6 val build_per_compiler : 7 7 Eio_unix.Stdenv.base -> ··· 12 12 mounts:Day11_container.Mount.t list -> 13 13 repo_dir:string -> 14 14 solutions:(OpamPackage.t * Day11_graph.Graph.solution) list -> 15 + (OpamPackage.t * Day11_layer.Layer_type.tool) list 16 + (** Build JTW tools for each compiler version. Returns the built tools. *) 17 + 18 + val build_and_run : 19 + Eio_unix.Stdenv.base -> 20 + Day11_build.Types.build_env -> 21 + np:int -> 22 + os_dir:Fpath.t -> 23 + packages:Day11_solver.Git_packages.t -> 24 + opam_env:(string -> OpamVariable.variable_contents option) -> 25 + mounts:Day11_container.Mount.t list -> 26 + repo_dir:string -> 27 + nodes:Day11_layer.Layer_type.build list -> 28 + solutions:(OpamPackage.t * Day11_graph.Graph.solution) list -> 15 29 unit 30 + (** Build JTW tools then generate per-package artifacts for all nodes. *)
+84
day11/jtw/generate.ml
··· 1 + open Day11_layer.Layer_type 2 + 3 + let extract_bin ~os_dir tool_builds name = 4 + let switch = Day11_build.Types.switch in 5 + List.find_map (fun (bl : build) -> 6 + let bin = Fpath.(build_dir ~os_dir bl / "fs" / "home" / "opam" 7 + / ".opam" / switch / "bin" / name) in 8 + if Bos.OS.File.exists bin |> Result.get_ok then Some bin 9 + else None 10 + ) tool_builds 11 + 12 + let make_jtw_mounts ~os_dir ~(jtw_tool : tool) = 13 + let find name = 14 + match extract_bin ~os_dir jtw_tool.builds name with 15 + | Some p -> p 16 + | None -> failwith (Printf.sprintf "JTW binary %s not found" name) 17 + in 18 + let mount src dst = Day11_container.Mount.bind_ro 19 + ~src:(Fpath.to_string src) dst in 20 + [ mount (find "jtw") "/home/opam/jtw-tools/bin/jtw"; 21 + mount (find "js_of_ocaml") "/home/opam/jtw-tools/bin/js_of_ocaml" ] 22 + 23 + let jtw_cleanup _env upper = 24 + ignore (Day11_exec.Sudo.rm_rf _env 25 + Fpath.(upper / "home" / "opam" / "jtw-tools")) 26 + 27 + let generate_package env benv ~os_dir ~jtw_tool (node : build) = 28 + let pkg_dir = build_dir ~os_dir node in 29 + let installed_libs = Day11_layer.Installed_files.scan_libs 30 + ~layer_dir:pkg_dir in 31 + if installed_libs = [] then None 32 + else 33 + let findlib_names = Gen.findlib_names_of_installed_libs installed_libs in 34 + if findlib_names = [] then None 35 + else begin 36 + let jtw_mounts = make_jtw_mounts ~os_dir ~jtw_tool in 37 + let cmd = 38 + "export PATH=/home/opam/jtw-tools/bin:$PATH && " ^ 39 + Gen.container_script ~pkg:node.pkg ~installed_libs in 40 + let hash = Gen.compute_layer_hash 41 + ~build_hash:node.hash ~tools_hash:jtw_tool.hash in 42 + let jtw_node : build = 43 + { hash; pkg = node.pkg; deps = [ node ] } in 44 + match Day11_build.Build_layer.build env benv 45 + ~mounts:jtw_mounts jtw_node 46 + ~strategy:{ cmd; cleanup = jtw_cleanup } () with 47 + | Day11_build.Types.Success bl -> 48 + Printf.printf " %s: OK\n%!" (OpamPackage.to_string node.pkg); 49 + Some bl 50 + | _ -> 51 + Printf.printf " %s: FAILED\n%!" (OpamPackage.to_string node.pkg); 52 + None 53 + end 54 + 55 + let run env benv ~os_dir ~jtw_tools ~nodes ~solutions = 56 + let pkg_compiler = Hashtbl.create 64 in 57 + List.iter (fun (_target, solution) -> 58 + match Day11_doc.Generate.find_compiler solution with 59 + | None -> () 60 + | Some compiler -> 61 + OpamPackage.Map.iter (fun pkg _deps -> 62 + Hashtbl.replace pkg_compiler pkg compiler 63 + ) solution 64 + ) solutions; 65 + let find_jtw_tool pkg = 66 + match Hashtbl.find_opt pkg_compiler pkg with 67 + | None -> None 68 + | Some compiler -> 69 + List.find_opt (fun (c, _) -> 70 + OpamPackage.equal c compiler) jtw_tools 71 + |> Option.map snd 72 + in 73 + Printf.printf " JTW generation (%d packages)...\n%!" (List.length nodes); 74 + let count = ref 0 in 75 + List.iter (fun (node : build) -> 76 + match find_jtw_tool node.pkg with 77 + | None -> () 78 + | Some jtw_tool -> 79 + match generate_package env benv ~os_dir ~jtw_tool node with 80 + | Some _ -> incr count 81 + | None -> () 82 + ) nodes; 83 + Printf.printf " JTW: %d packages processed\n%!" !count; 84 + !count
+23
day11/jtw/generate.mli
··· 1 + (** Per-package JTW artifact generation. 2 + 3 + For each package with findlib libraries, runs [jtw opam --path <pkg> 4 + --no-worker] in a container with the package's build layer. Produces 5 + [.cma.js] files, copies [.cmi] and [META], generates 6 + [dynamic_cmis.json]. 7 + 8 + JTW tool binaries ([jtw], [js_of_ocaml]) are bind-mounted from the 9 + tool layer at [/home/opam/jtw-tools/bin/]. The per-compiler JTW tool 10 + is selected based on which compiler appears in each package's 11 + solution. *) 12 + 13 + val run : 14 + Eio_unix.Stdenv.base -> 15 + Day11_build.Types.build_env -> 16 + os_dir:Fpath.t -> 17 + jtw_tools:(OpamPackage.t * Day11_layer.Layer_type.tool) list -> 18 + nodes:Day11_layer.Layer_type.build list -> 19 + solutions:(OpamPackage.t * Day11_graph.Graph.solution) list -> 20 + int 21 + (** [run env benv ~os_dir ~jtw_tools ~nodes ~solutions] generates JTW 22 + artifacts for all packages in [nodes] that have findlib libraries. 23 + Returns the number of packages processed. *)