#!/bin/zsh # Build script for dune on Hammerhead # # illumos patches (readdir d_type, winsize, wait4) applied via [patches] set -e cd "$SRCDIR" # Ensure OCaml is in PATH export PATH="$PREFIX/bin:$PATH" # Force 64-bit compilation export CC="gcc -m64" export CXX="g++ -m64" export CFLAGS="-m64" export CXXFLAGS="-m64" export LDFLAGS="-m64 $LDFLAGS" # libatomic is at /usr/lib (hammerhead BSD layout) export LD_LIBRARY_PATH="/usr/lib:${LD_LIBRARY_PATH:-}" export LIBRARY_PATH="/usr/lib:${LIBRARY_PATH:-}" # Bootstrap dune (creates _boot/dune.exe) ocaml boot/bootstrap.ml # Build dune for release (packager mode) gmake release # Install dune to package directory gmake install PREFIX=$PREFIX DESTDIR="$PKGDIR" --- otherlibs/stdune/src/readdir.c 2026-03-11 20:49:26.711769000 -0500 +++ otherlibs/stdune/src/readdir.c 2026-03-11 20:49:26.713044510 -0500 @@ -1,3 +1,16 @@ +/* + * readdir.c - illumos/Solaris compatible version for dune + * + * This file replaces otherlibs/stdune/dune_filesystem_stubs/readdir.c + * in dune to fix compilation on illumos/Solaris where struct dirent + * does not have d_type field. + * + * Apply by copying this file to: + * dune-X.Y.Z/otherlibs/stdune/dune_filesystem_stubs/readdir.c + * + * For opam's bundled dune-local: + * opam-X.Y.Z/src_ext/dune-local/otherlibs/stdune/dune_filesystem_stubs/readdir.c + */ #include #include @@ -13,12 +26,27 @@ #include #include #include + +/* illumos/Solaris compatibility - d_type not in struct dirent */ +#ifndef DT_UNKNOWN +#define DT_UNKNOWN 0 +#define DT_FIFO 1 +#define DT_CHR 2 +#define DT_DIR 4 +#define DT_BLK 6 +#define DT_REG 8 +#define DT_LNK 10 +#define DT_SOCK 12 +#define DT_WHT 14 +#define ILLUMOS_NO_DTYPE 1 +#endif + typedef struct dirent directory_entry; value val_file_type(int typ) { switch(typ) { -#ifndef __HAIKU__ +#ifndef __HAIKU__ case DT_REG: return Val_int(0); case DT_DIR: @@ -64,10 +92,11 @@ v_filename = caml_copy_string(e->d_name); v_tuple = caml_alloc_small(2, 0); Field(v_tuple, 0) = v_filename; -#ifndef __HAIKU__ - Field(v_tuple, 1) = val_file_type(e->d_type); -#else +#if defined(__HAIKU__) || defined(ILLUMOS_NO_DTYPE) + /* illumos/Solaris don't have d_type, always return unknown */ Field(v_tuple, 1) = Val_int(7); +#else + Field(v_tuple, 1) = val_file_type(e->d_type); #endif CAMLreturn(v_tuple); } --- vendor/notty/src-unix/native/winsize.c 2026-03-11 20:49:26.714264146 -0500 +++ vendor/notty/src-unix/native/winsize.c 2026-03-11 20:49:26.715364983 -0500 @@ -1,44 +1,55 @@ +/* + * winsize.c - illumos/Solaris compatible version for notty (used by dune) + * + * This file replaces vendor/notty/src-unix/native/winsize.c + * in dune to fix compilation on illumos/Solaris where TIOCGWINSZ + * is defined in sys/termios.h rather than sys/ioctl.h. + * + * Apply by copying this file to: + * dune-X.Y.Z/vendor/notty/src-unix/native/winsize.c + * + * For opam's bundled dune-local: + * opam-X.Y.Z/src_ext/dune-local/vendor/notty/src-unix/native/winsize.c + */ + #include +#include +#include -#ifdef _WIN32 -#include +#ifdef __sun +/* illumos/Solaris: struct winsize and TIOCGWINSZ in termios */ +#include +#include #else #include -#include #endif -#ifdef __HAIKU__ -/* On some platforms, ioctl() is declared in . */ #include -#endif - -CAMLprim value caml_notty_winsize (value vfd) { -#ifdef _WIN32 - (void) vfd; - HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - if (hConsole == INVALID_HANDLE_VALUE) return Val_int (0); +#include - CONSOLE_SCREEN_BUFFER_INFO csbi; - if (GetConsoleScreenBufferInfo(hConsole, &csbi)) { - int columns = csbi.srWindow.Right - csbi.srWindow.Left + 1; - int rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; - return Val_int ((columns << 16) + ((rows & 0x7fff) << 1)); - } - return Val_int (0); -#else - int fd = Int_val (vfd); +CAMLprim value caml_notty_winsize (value fd) { +#ifdef TIOCGWINSZ struct winsize w; - if (ioctl (fd, TIOCGWINSZ, &w) >= 0) - return Val_int ((w.ws_col << 16) + ((w.ws_row & 0x7fff) << 1)); - return Val_int (0); + if (ioctl(Int_val(fd), TIOCGWINSZ, &w) == -1) + caml_failwith("ioctl"); + value res = caml_alloc_small(2, 0); + Field(res, 0) = Val_int(w.ws_col); + Field(res, 1) = Val_int(w.ws_row); + return res; +#else + /* Fallback: return default 80x24 */ + value res = caml_alloc_small(2, 0); + Field(res, 0) = Val_int(80); + Field(res, 1) = Val_int(24); + return res; #endif } -CAMLprim value caml_notty_winch_number (value vunit) { - (void) vunit; -#ifdef _WIN32 - return Val_int (0); +/* Return SIGWINCH signal number */ +CAMLprim value caml_notty_winch_number (value unit) { +#ifdef SIGWINCH + return Val_int(SIGWINCH); #else - return Val_int (SIGWINCH); + return Val_int(0); #endif } --- otherlibs/stdune/src/wait4_stubs.c 2026-03-11 20:49:26.716620588 -0500 +++ otherlibs/stdune/src/wait4_stubs.c 2026-03-11 20:49:26.717848047 -0500 @@ -1,83 +1,51 @@ #include - #ifdef _WIN32 #include - -void dune_wait4(value v_pid, value flags) { - (void)flags; - caml_failwith("wait4: not supported on windows"); -} - +void dune_wait4(value v_pid, value flags) { caml_failwith("wait4: not supported"); } #else - #include #include #include #include - #include #include #include #include - +#include +#include #define TAG_WEXITED 0 #define TAG_WSIGNALED 1 #define TAG_WSTOPPED 2 - -CAMLextern int caml_convert_signal_number(int); CAMLextern int caml_rev_convert_signal_number(int); - static value alloc_process_status(int status) { value st; - - if (WIFEXITED(status)) { - st = caml_alloc_small(1, TAG_WEXITED); - Field(st, 0) = Val_int(WEXITSTATUS(status)); - } else if (WIFSTOPPED(status)) { - st = caml_alloc_small(1, TAG_WSTOPPED); - Field(st, 0) = Val_int(caml_rev_convert_signal_number(WSTOPSIG(status))); - } else { - st = caml_alloc_small(1, TAG_WSIGNALED); - Field(st, 0) = Val_int(caml_rev_convert_signal_number(WTERMSIG(status))); - } + if (WIFEXITED(status)) { st = caml_alloc_small(1, TAG_WEXITED); Field(st, 0) = Val_int(WEXITSTATUS(status)); } + else if (WIFSTOPPED(status)) { st = caml_alloc_small(1, TAG_WSTOPPED); Field(st, 0) = Val_int(caml_rev_convert_signal_number(WSTOPSIG(status))); } + else { st = caml_alloc_small(1, TAG_WSIGNALED); Field(st, 0) = Val_int(caml_rev_convert_signal_number(WTERMSIG(status))); } return st; } - static int wait_flag_table[] = {WNOHANG, WUNTRACED}; - -// see https://man7.org/linux/man-pages/man2/waitpid.2.html for a description of -// possible v_pid values -1 is the one we typically use, which means wait for -// any child process value dune_wait4(value v_pid, value flags) { CAMLparam2(v_pid, flags); CAMLlocal2(times, res); - - int status, cv_flags; - struct timeval tp; - cv_flags = caml_convert_flag_list(flags, wait_flag_table); - pid_t pid = Int_val(v_pid); - + int pid, status, cv_flags = caml_convert_flag_list(flags, wait_flag_table); struct rusage ru; - + struct timeval tp; + memset(&ru, 0, sizeof(ru)); caml_enter_blocking_section(); - // returns the pid of the terminated process, or -1 on error - pid = wait4(pid, &status, cv_flags, &ru); + pid = waitpid(Int_val(v_pid), &status, cv_flags); + if (pid > 0) getrusage(RUSAGE_CHILDREN, &ru); gettimeofday(&tp, NULL); caml_leave_blocking_section(); - if (pid == -1) - uerror("wait4", Nothing); - + if (pid == -1) uerror("wait4", Nothing); times = caml_alloc_small(2 * Double_wosize, Double_array_tag); Store_double_field(times, 0, ru.ru_utime.tv_sec + ru.ru_utime.tv_usec / 1e6); Store_double_field(times, 1, ru.ru_stime.tv_sec + ru.ru_stime.tv_usec / 1e6); - res = caml_alloc_tuple(4); Store_field(res, 0, Val_int(pid)); Store_field(res, 1, alloc_process_status(status)); - Store_field(res, 2, - caml_copy_double(((double)tp.tv_sec + (double)tp.tv_usec / 1e6))); + Store_field(res, 2, caml_copy_double(((double)tp.tv_sec + (double)tp.tv_usec / 1e6))); Store_field(res, 3, times); CAMLreturn(res); } - #endif # dune - OCaml build system # https://dune.build/ [package] name = "dune" version = "3.20.2" release = 1 description = "Fast, portable, and opinionated build system for OCaml" url = "https://dune.build/" license = "MIT" maintainer = "Chris Tusa " arch = "x86_64" [dependencies] runtime = ["ocaml"] build = ["ocaml", "make"] [[source]] file = "dune-3.20.2.tar.gz" urls = ["https://github.com/ocaml/dune/archive/refs/tags/3.20.2.tar.gz"] checksum = "579c738f8ca191ba0a9b22dbe78f1377542442c9827cf4939f8964f09f9edb28" [patches] files = ["dune-illumos-compat.patch"] strip = 0 [build] parallel = true /* * readdir.c - illumos/Solaris compatible version for dune * * This file replaces otherlibs/stdune/dune_filesystem_stubs/readdir.c * in dune to fix compilation on illumos/Solaris where struct dirent * does not have d_type field. * * Apply by copying this file to: * dune-X.Y.Z/otherlibs/stdune/dune_filesystem_stubs/readdir.c * * For opam's bundled dune-local: * opam-X.Y.Z/src_ext/dune-local/otherlibs/stdune/dune_filesystem_stubs/readdir.c */ #include #include #include #include #include #ifndef _WIN32 #include #include #include #include /* illumos/Solaris compatibility - d_type not in struct dirent */ #ifndef DT_UNKNOWN #define DT_UNKNOWN 0 #define DT_FIFO 1 #define DT_CHR 2 #define DT_DIR 4 #define DT_BLK 6 #define DT_REG 8 #define DT_LNK 10 #define DT_SOCK 12 #define DT_WHT 14 #define ILLUMOS_NO_DTYPE 1 #endif typedef struct dirent directory_entry; value val_file_type(int typ) { switch(typ) { #ifndef __HAIKU__ case DT_REG: return Val_int(0); case DT_DIR: return Val_int(1); case DT_CHR: return Val_int(2); case DT_BLK: return Val_int(3); case DT_LNK: return Val_int(4); case DT_FIFO: return Val_int(5); case DT_SOCK: return Val_int(6); case DT_UNKNOWN: return Val_int(7); #endif default: return Val_int(7); } } CAMLprim value caml__dune_filesystem_stubs__readdir(value vd) { CAMLparam1(vd); CAMLlocal2(v_filename, v_tuple); DIR * d; directory_entry * e; d = DIR_Val(vd); if (d == (DIR *) NULL) unix_error(EBADF, "readdir", Nothing); caml_enter_blocking_section(); errno = 0; e = readdir((DIR *) d); caml_leave_blocking_section(); if (e == (directory_entry *) NULL) { if(errno == 0) { CAMLreturn(Val_int(0)); } else { uerror("readdir", Nothing); } } v_filename = caml_copy_string(e->d_name); v_tuple = caml_alloc_small(2, 0); Field(v_tuple, 0) = v_filename; #if defined(__HAIKU__) || defined(ILLUMOS_NO_DTYPE) /* illumos/Solaris don't have d_type, always return unknown */ Field(v_tuple, 1) = Val_int(7); #else Field(v_tuple, 1) = val_file_type(e->d_type); #endif CAMLreturn(v_tuple); } #else CAMLprim value caml__dune_filesystem_stubs__readdir(value vd) { unix_error(ENOSYS, "readdir", Nothing); } #endif #include #ifdef _WIN32 #include void dune_wait4(value v_pid, value flags) { caml_failwith("wait4: not supported"); } #else #include #include #include #include #include #include #include #include #include #include #define TAG_WEXITED 0 #define TAG_WSIGNALED 1 #define TAG_WSTOPPED 2 CAMLextern int caml_rev_convert_signal_number(int); static value alloc_process_status(int status) { value st; if (WIFEXITED(status)) { st = caml_alloc_small(1, TAG_WEXITED); Field(st, 0) = Val_int(WEXITSTATUS(status)); } else if (WIFSTOPPED(status)) { st = caml_alloc_small(1, TAG_WSTOPPED); Field(st, 0) = Val_int(caml_rev_convert_signal_number(WSTOPSIG(status))); } else { st = caml_alloc_small(1, TAG_WSIGNALED); Field(st, 0) = Val_int(caml_rev_convert_signal_number(WTERMSIG(status))); } return st; } static int wait_flag_table[] = {WNOHANG, WUNTRACED}; value dune_wait4(value v_pid, value flags) { CAMLparam2(v_pid, flags); CAMLlocal2(times, res); int pid, status, cv_flags = caml_convert_flag_list(flags, wait_flag_table); struct rusage ru; struct timeval tp; memset(&ru, 0, sizeof(ru)); caml_enter_blocking_section(); pid = waitpid(Int_val(v_pid), &status, cv_flags); if (pid > 0) getrusage(RUSAGE_CHILDREN, &ru); gettimeofday(&tp, NULL); caml_leave_blocking_section(); if (pid == -1) uerror("wait4", Nothing); times = caml_alloc_small(2 * Double_wosize, Double_array_tag); Store_double_field(times, 0, ru.ru_utime.tv_sec + ru.ru_utime.tv_usec / 1e6); Store_double_field(times, 1, ru.ru_stime.tv_sec + ru.ru_stime.tv_usec / 1e6); res = caml_alloc_tuple(4); Store_field(res, 0, Val_int(pid)); Store_field(res, 1, alloc_process_status(status)); Store_field(res, 2, caml_copy_double(((double)tp.tv_sec + (double)tp.tv_usec / 1e6))); Store_field(res, 3, times); CAMLreturn(res); } #endif /* * winsize.c - illumos/Solaris compatible version for notty (used by dune) * * This file replaces vendor/notty/src-unix/native/winsize.c * in dune to fix compilation on illumos/Solaris where TIOCGWINSZ * is defined in sys/termios.h rather than sys/ioctl.h. * * Apply by copying this file to: * dune-X.Y.Z/vendor/notty/src-unix/native/winsize.c * * For opam's bundled dune-local: * opam-X.Y.Z/src_ext/dune-local/vendor/notty/src-unix/native/winsize.c */ #include #include #include #ifdef __sun /* illumos/Solaris: struct winsize and TIOCGWINSZ in termios */ #include #include #else #include #endif #include #include CAMLprim value caml_notty_winsize (value fd) { #ifdef TIOCGWINSZ struct winsize w; if (ioctl(Int_val(fd), TIOCGWINSZ, &w) == -1) caml_failwith("ioctl"); value res = caml_alloc_small(2, 0); Field(res, 0) = Val_int(w.ws_col); Field(res, 1) = Val_int(w.ws_row); return res; #else /* Fallback: return default 80x24 */ value res = caml_alloc_small(2, 0); Field(res, 0) = Val_int(80); Field(res, 1) = Val_int(24); return res; #endif } /* Return SIGWINCH signal number */ CAMLprim value caml_notty_winch_number (value unit) { #ifdef SIGWINCH return Val_int(SIGWINCH); #else return Val_int(0); #endif } #!/bin/bash # Build script for menhir on illumos # # menhir is a parser generator used by the Reef compiler set -e cd "$SRCDIR" # Ensure OCaml and dune are in PATH export PATH="$PREFIX/bin:$PATH" # Force 64-bit compilation export CC="gcc -m64" export CXX="g++ -m64" export CFLAGS="-m64" export CXXFLAGS="-m64" export LDFLAGS="-m64 $LDFLAGS" # libatomic is at /usr/lib (hammerhead BSD layout) export LD_LIBRARY_PATH="/usr/lib:${LD_LIBRARY_PATH:-}" export LIBRARY_PATH="/usr/lib:${LIBRARY_PATH:-}" # Build menhir using dune dune build @install # Install dune install --prefix=$PREFIX --destdir="$PKGDIR" # menhir - Parser generator for OCaml # http://gallium.inria.fr/~fpottier/menhir/ [package] name = "menhir" version = "20250912" release = 1 description = "LR(1) parser generator for OCaml" url = "http://gallium.inria.fr/~fpottier/menhir/" license = "GPL-2.0" maintainer = "Chris Tusa " arch = "x86_64" [dependencies] runtime = ["ocaml"] build = ["ocaml", "dune", "make"] [[source]] file = "menhir-20250912.tar.gz" urls = ["https://gitlab.inria.fr/fpottier/menhir/-/archive/20250912/menhir-20250912.tar.gz"] checksum = "26b1f44d6b4ed634631c50866e5535062591308a01a987f415411a9543965c9b" [build] parallel = true #!/bin/bash # Build script for OCaml alcotest library set -e # Find and enter the extracted source directory cd "$SRCDIR" # Ensure OCaml toolchain is in PATH export PATH="$PREFIX/bin:$PATH" # libatomic is at /usr/lib (hammerhead BSD layout) export LD_LIBRARY_PATH="/usr/lib:${LD_LIBRARY_PATH:-}" export LIBRARY_PATH="/usr/lib:${LIBRARY_PATH:-}" # Patch alcotest_stubs.c for illumos (add sys/termios.h for struct winsize) if [[ "$(uname -s)" == "SunOS" || "$(uname -s)" == "Hammerhead" ]]; then sed -i 's|#include |#include \n#include |' src/alcotest/alcotest_stubs.c fi # Build only the alcotest package (skip tests and optional deps) dune build -p alcotest # Install to package directory dune install alcotest --prefix=$PREFIX --destdir="$PKGDIR" # OCaml alcotest - Lightweight testing framework # https://github.com/mirage/alcotest [package] name = "ocaml-alcotest" version = "1.8.0" release = 1 description = "OCaml lightweight and colorful test framework" url = "https://github.com/mirage/alcotest" license = "ISC" maintainer = "Chris Tusa " arch = "x86_64" [dependencies] runtime = ["ocaml", "ocaml-fmt", "ocaml-astring", "ocaml-cmdliner", "ocaml-uutf", "ocaml-re", "ocaml-seq", "ocaml-stdlib-shims", "ocaml-syntax-shims"] build = ["ocaml", "dune", "ocaml-fmt", "ocaml-astring", "ocaml-cmdliner", "ocaml-uutf", "ocaml-re", "ocaml-seq", "ocaml-stdlib-shims", "ocaml-syntax-shims"] [[source]] file = "alcotest-1.8.0.tar.gz" urls = [ "https://github.com/mirage/alcotest/archive/refs/tags/1.8.0.tar.gz" ] checksum = "skip" extract = true [build] parallel = false #!/bin/zsh # Build script for OCaml astring library set -e cd "$SRCDIR" export PATH="$PREFIX/bin:$PATH" export LD_LIBRARY_PATH="/usr/lib:${LD_LIBRARY_PATH:-}" export LIBRARY_PATH="/usr/lib:${LIBRARY_PATH:-}" # Build with topkg ocaml pkg/pkg.ml build # Install from .install file without opam-installer # Parse sections and copy files to appropriate directories install_from_dotinstall() { local installfile="$1" prefix="$2" pkgname="$3" local section="" src dest dir while IFS= read -r line; do # Detect section headers (lib:, bin:, etc.) if [[ "$line" =~ '^([a-z_]+):' ]]; then section="${match[1]}" continue fi [[ -z "$section" || "$line" =~ '^\]' ]] && { [[ "$line" =~ '^\]' ]] && section=""; continue; } # Extract source file path (between first pair of quotes) src="${${line#*\"}%%\"*}" [[ -z "$src" || ! -f "$src" ]] && continue # Extract optional dest name (between braces if present) if [[ "$line" =~ '\{"?([^}"]+)"?\}' ]]; then dest="${match[1]}" else dest="${src:t}" fi # Map section to directory case "$section" in lib|libexec) dir="$prefix/lib/ocaml/$pkgname" ;; bin) dir="$prefix/bin" ;; share) dir="$prefix/share/$pkgname" ;; doc) dir="$prefix/doc/$pkgname" ;; man) dir="$prefix/man" ;; *) continue ;; esac mkdir -p "$dir/$(dirname "$dest")" cp "$src" "$dir/$dest" done < "$installfile" } install_from_dotinstall astring.install "$PKGDIR$PREFIX" astring # OCaml astring - Alternative String module # https://github.com/dbuenzli/astring [package] name = "ocaml-astring" version = "0.8.5" release = 1 description = "OCaml alternative String module" url = "https://github.com/dbuenzli/astring" license = "ISC" maintainer = "Chris Tusa " arch = "x86_64" [dependencies] runtime = ["ocaml"] build = ["ocaml", "ocaml-findlib", "ocaml-ocamlbuild", "ocaml-topkg"] [[source]] file = "astring-0.8.5.tar.gz" urls = [ "https://github.com/dbuenzli/astring/archive/refs/tags/v0.8.5.tar.gz" ] checksum = "skip" extract = true [build] parallel = false #!/bin/zsh # Build script for OCaml cmdliner library set -e cd "$SRCDIR" export PATH="$PREFIX/bin:$PATH" export LD_LIBRARY_PATH="/usr/lib:${LD_LIBRARY_PATH:-}" export LIBRARY_PATH="/usr/lib:${LIBRARY_PATH:-}" # Build mkdir -p _build gmake -j1 all PREFIX=$PREFIX # Manual install — Hammerhead's /usr/sbin/install (SVR4) breaks PATH local B="_build" local LIBDIR="$PKGDIR$PREFIX/lib/ocaml/cmdliner" local DOCDIR="$PKGDIR$PREFIX/doc/cmdliner" mkdir -p "$LIBDIR" mkdir -p "$DOCDIR/odoc-pages" # Common: META, interface files cp pkg/META "$LIBDIR/" cp "$B/cmdliner.mli" "$B/cmdliner.cmi" "$B/cmdliner.cmti" "$LIBDIR/" cp cmdliner.opam "$LIBDIR/opam" # Byte code cp "$B/cmdliner.cma" "$LIBDIR/" # Native cp "$B/cmdliner.cmxa" "$B/cmdliner.a" "$LIBDIR/" for f in "$B"/cmdliner*.cmx; do [ -f "$f" ] && cp "$f" "$LIBDIR/" done # Native dynlink [ -f "$B/cmdliner.cmxs" ] && cp "$B/cmdliner.cmxs" "$LIBDIR/" # Documentation cp CHANGES.md LICENSE.md README.md "$DOCDIR/" cp doc/index.mld doc/cli.mld doc/examples.mld doc/tutorial.mld \ doc/tool_man.mld "$DOCDIR/odoc-pages/" # OCaml cmdliner - Declarative command line interfaces # https://github.com/dbuenzli/cmdliner [package] name = "ocaml-cmdliner" version = "1.3.0" release = 1 description = "OCaml declarative command line interfaces" url = "https://github.com/dbuenzli/cmdliner" license = "ISC" maintainer = "Chris Tusa " arch = "x86_64" [dependencies] runtime = ["ocaml"] build = ["ocaml"] [[source]] file = "cmdliner-1.3.0.tar.gz" urls = [ "https://github.com/dbuenzli/cmdliner/archive/refs/tags/v1.3.0.tar.gz" ] checksum = "skip" extract = true [build] parallel = false #!/bin/zsh # Build script for OCaml findlib library set -e cd "$SRCDIR" export PATH="$PREFIX/bin:$PATH" # libatomic is at /usr/lib (hammerhead BSD layout) export LD_LIBRARY_PATH="/usr/lib:${LD_LIBRARY_PATH:-}" export LIBRARY_PATH="/usr/lib:${LIBRARY_PATH:-}" # Configure findlib ./configure \ -bindir $PREFIX/bin \ -sitelib $PREFIX/lib/ocaml \ -mandir $PREFIX/man \ -config $PREFIX/lib/ocaml/findlib.conf \ -no-custom # Hammerhead's /usr/sbin/install (SVR4) resets PATH internally and breaks. # Override INSTALLDIR and INSTALLFILE with simple alternatives as documented # in findlib's configure output. sed -i 's|^INSTALLDIR = install -d|INSTALLDIR = mkdir -p|' Makefile.config sed -i 's|^INSTALLFILE = install -c|INSTALLFILE = cp|' Makefile.config # Build gmake all gmake opt # Install to staging directory gmake install DESTDIR="$PKGDIR" [package] name = "ocaml-findlib" version = "1.9.8" description = "OCaml library manager and ocamlfind tool" homepage = "http://projects.camlcity.org/projects/findlib.html" license = "MIT" [dependencies] build = ["ocaml"] runtime = ["ocaml"] [[source]] file = "findlib-1.9.8.tar.gz" urls = [ "http://download.camlcity.org/download/findlib-1.9.8.tar.gz" ] checksum = "skip" extract = true #!/bin/zsh # Build script for OCaml fmt library set -e cd "$SRCDIR" export PATH="$PREFIX/bin:$PATH" export LD_LIBRARY_PATH="/usr/lib:${LD_LIBRARY_PATH:-}" export LIBRARY_PATH="/usr/lib:${LIBRARY_PATH:-}" # Build with topkg ocaml pkg/pkg.ml build # Install from .install file without opam-installer install_from_dotinstall() { local installfile="$1" prefix="$2" pkgname="$3" local section="" src dest dir while IFS= read -r line; do if [[ "$line" =~ '^([a-z_]+):' ]]; then section="${match[1]}" continue fi [[ -z "$section" || "$line" =~ '^\]' ]] && { [[ "$line" =~ '^\]' ]] && section=""; continue; } src="${${line#*\"}%%\"*}" [[ -z "$src" || ! -f "$src" ]] && continue if [[ "$line" =~ '\{"?([^}"]+)"?\}' ]]; then dest="${match[1]}" else dest="${src:t}" fi case "$section" in lib|libexec) dir="$prefix/lib/ocaml/$pkgname" ;; bin) dir="$prefix/bin" ;; share) dir="$prefix/share/$pkgname" ;; doc) dir="$prefix/doc/$pkgname" ;; man) dir="$prefix/man" ;; *) continue ;; esac mkdir -p "$dir/$(dirname "$dest")" cp "$src" "$dir/$dest" done < "$installfile" } install_from_dotinstall fmt.install "$PKGDIR$PREFIX" fmt # OCaml fmt - Format pretty-printer combinators # https://github.com/dbuenzli/fmt [package] name = "ocaml-fmt" version = "0.9.0" release = 1 description = "OCaml Format pretty-printer combinators" url = "https://github.com/dbuenzli/fmt" license = "ISC" maintainer = "Chris Tusa " arch = "x86_64" [dependencies] runtime = ["ocaml"] build = ["ocaml", "ocaml-findlib", "ocaml-ocamlbuild", "ocaml-topkg", "ocaml-cmdliner"] [[source]] file = "fmt-0.9.0.tar.gz" urls = [ "https://github.com/dbuenzli/fmt/archive/refs/tags/v0.9.0.tar.gz" ] checksum = "skip" extract = true [build] parallel = false #!/bin/zsh # Build script for OCaml ocamlbuild tool set -e cd "$SRCDIR" export PATH="$PREFIX/bin:$PATH" export LD_LIBRARY_PATH="/usr/lib:${LD_LIBRARY_PATH:-}" export LIBRARY_PATH="/usr/lib:${LIBRARY_PATH:-}" # Configure (generates Makefile.config) gmake -f configure.make all \ OCAMLBUILD_PREFIX=$PREFIX \ OCAMLBUILD_BINDIR=$PREFIX/bin \ OCAMLBUILD_LIBDIR=$PREFIX/lib/ocaml \ OCAMLBUILD_MANDIR=$PREFIX/man # Build core targets only — man page generation (options_man.byte) # crashes on Hammerhead due to OCaml bytecode runtime issue gmake -j1 ocamlbuild.native ocamlbuild.byte # Install manually since gmake install depends on man pages mkdir -p "$PKGDIR$PREFIX/bin" mkdir -p "$PKGDIR$PREFIX/lib/ocaml/ocamlbuild" cp ocamlbuild.native "$PKGDIR$PREFIX/bin/ocamlbuild" cp ocamlbuild.byte "$PKGDIR$PREFIX/bin/ocamlbuild.byte" # Install library files for f in src/ocamlbuildlib.cma src/ocamlbuildlib.cmxa src/ocamlbuildlib.a \ src/ocamlbuild_pack.cmi plugin-lib/ocamlbuild_plugin.cmi \ plugin-lib/ocamlbuild_plugin.cmo plugin-lib/ocamlbuild_plugin.cmx \ plugin-lib/ocamlbuild_plugin.o src/ocamlbuild_executor.cmi \ plugin-lib/ocamlbuild_unix_plugin.cmi plugin-lib/ocamlbuild_unix_plugin.cmo \ plugin-lib/ocamlbuild_unix_plugin.cmx plugin-lib/ocamlbuild_unix_plugin.o; do [ -f "$f" ] && cp "$f" "$PKGDIR$PREFIX/lib/ocaml/ocamlbuild/" done [package] name = "ocaml-ocamlbuild" version = "0.15.0" description = "OCaml build tool" homepage = "https://github.com/ocaml/ocamlbuild" license = "LGPL-2.0" [dependencies] build = ["ocaml"] runtime = ["ocaml"] [[source]] file = "ocamlbuild-0.15.0.tar.gz" urls = [ "https://github.com/ocaml/ocamlbuild/archive/refs/tags/0.15.0.tar.gz" ] checksum = "skip" extract = true #!/bin/bash # Build script for OCaml re library set -e # Find and enter the extracted source directory cd "$SRCDIR" # Ensure OCaml toolchain is in PATH export PATH="$PREFIX/bin:$PATH" # libatomic is at /usr/lib (hammerhead BSD layout) export LD_LIBRARY_PATH="/usr/lib:${LD_LIBRARY_PATH:-}" export LIBRARY_PATH="/usr/lib:${LIBRARY_PATH:-}" # Build only the re package (skip deprecated modules and tests) dune build -p re # Install to package directory dune install re --prefix=$PREFIX --destdir="$PKGDIR" # OCaml re - Regular expression library # https://github.com/ocaml/ocaml-re [package] name = "ocaml-re" version = "1.12.0" release = 1 description = "OCaml regular expression library" url = "https://github.com/ocaml/ocaml-re" license = "LGPL-2.1-or-later" maintainer = "Chris Tusa " arch = "x86_64" [dependencies] runtime = ["ocaml", "ocaml-seq"] build = ["ocaml", "dune", "ocaml-seq"] [[source]] file = "ocaml-re-1.12.0.tar.gz" urls = [ "https://github.com/ocaml/ocaml-re/archive/refs/tags/1.12.0.tar.gz" ] checksum = "skip" extract = true [build] parallel = false #!/bin/bash # Build script for OCaml seq compatibility package # seq is part of OCaml stdlib since 4.07 # This just installs the META file for ocamlfind set -e export PATH="$PREFIX/bin:$PATH" # Create the META file for seq mkdir -p "$PKGDIR$PREFIX/lib/ocaml/seq" cat > "$PKGDIR$PREFIX/lib/ocaml/seq/META" << 'EOF' description = "OCaml Seq iterator type (part of stdlib)" version = "base" requires = "" EOF [package] name = "ocaml-seq" version = "base" description = "OCaml standard iterator type compatibility package" homepage = "https://github.com/ocaml/ocaml" license = "LGPL-2.1" [dependencies] build = ["ocaml"] runtime = ["ocaml"] # seq is part of OCaml stdlib since 4.07, no source needed # This package just installs META file for ocamlfind #!/bin/bash # Build script for OCaml stdlib-shims library set -e cd "$SRCDIR" export PATH="$PREFIX/bin:$PATH" # libatomic is at /usr/lib (hammerhead BSD layout) export LD_LIBRARY_PATH="/usr/lib:${LD_LIBRARY_PATH:-}" export LIBRARY_PATH="/usr/lib:${LIBRARY_PATH:-}" # Build with dune dune build # Install to package directory dune install --prefix=$PREFIX --destdir="$PKGDIR" [package] name = "ocaml-stdlib-shims" version = "0.3.0" description = "Backport newer stdlib features to older OCaml compilers" homepage = "https://github.com/ocaml/stdlib-shims" license = "LGPL-2.1" [dependencies] build = ["ocaml", "dune"] runtime = ["ocaml"] [[source]] file = "stdlib-shims-0.3.0.tar.gz" urls = [ "https://github.com/ocaml/stdlib-shims/archive/refs/tags/0.3.0.tar.gz" ] checksum = "skip" extract = true #!/bin/bash # Build script for OCaml ocaml-syntax-shims library set -e cd "$SRCDIR" export PATH="$PREFIX/bin:$PATH" # libatomic is at /usr/lib (hammerhead BSD layout) export LD_LIBRARY_PATH="/usr/lib:${LD_LIBRARY_PATH:-}" export LIBRARY_PATH="/usr/lib:${LIBRARY_PATH:-}" # Build with dune dune build # Install to package directory dune install --prefix=$PREFIX --destdir="$PKGDIR" [package] name = "ocaml-syntax-shims" version = "1.0.0" description = "Backport newer OCaml syntax features to older compilers" homepage = "https://github.com/ocaml-ppx/ocaml-syntax-shims" license = "MIT" [dependencies] build = ["ocaml", "dune"] runtime = ["ocaml"] [[source]] file = "ocaml-syntax-shims-1.0.0.tar.gz" urls = [ "https://github.com/ocaml-ppx/ocaml-syntax-shims/archive/refs/tags/1.0.0.tar.gz" ] checksum = "skip" extract = true #!/bin/zsh # Build script for OCaml topkg library set -e cd "$SRCDIR" export PATH="$PREFIX/bin:$PATH" export LD_LIBRARY_PATH="/usr/lib:${LD_LIBRARY_PATH:-}" export LIBRARY_PATH="/usr/lib:${LIBRARY_PATH:-}" # Build using the package build script ocaml pkg/pkg.ml build --pkg-name topkg # Install from .install file without opam-installer install_from_dotinstall() { local installfile="$1" prefix="$2" pkgname="$3" local section="" src dest dir while IFS= read -r line; do if [[ "$line" =~ '^([a-z_]+):' ]]; then section="${match[1]}" continue fi [[ -z "$section" || "$line" =~ '^\]' ]] && { [[ "$line" =~ '^\]' ]] && section=""; continue; } src="${${line#*\"}%%\"*}" [[ -z "$src" || ! -f "$src" ]] && continue if [[ "$line" =~ '\{"?([^}"]+)"?\}' ]]; then dest="${match[1]}" else dest="${src:t}" fi case "$section" in lib|libexec) dir="$prefix/lib/ocaml/$pkgname" ;; bin) dir="$prefix/bin" ;; share) dir="$prefix/share/$pkgname" ;; doc) dir="$prefix/doc/$pkgname" ;; man) dir="$prefix/man" ;; *) continue ;; esac mkdir -p "$dir/$(dirname "$dest")" cp "$src" "$dir/$dest" done < "$installfile" } install_from_dotinstall topkg.install "$PKGDIR$PREFIX" topkg [package] name = "ocaml-topkg" version = "1.1.1" description = "OCaml package release helper" homepage = "https://erratique.ch/software/topkg" license = "ISC" [dependencies] build = ["ocaml", "ocaml-findlib", "ocaml-ocamlbuild"] runtime = ["ocaml", "ocaml-findlib", "ocaml-ocamlbuild"] [[source]] file = "topkg-1.1.1.tbz" urls = [ "https://erratique.ch/software/topkg/releases/topkg-1.1.1.tbz" ] checksum = "skip" extract = true #!/bin/zsh # Build script for OCaml uutf library set -e cd "$SRCDIR" export PATH="$PREFIX/bin:$PATH" export LD_LIBRARY_PATH="/usr/lib:${LD_LIBRARY_PATH:-}" export LIBRARY_PATH="/usr/lib:${LIBRARY_PATH:-}" # Build with topkg ocaml pkg/pkg.ml build # Install from .install file without opam-installer install_from_dotinstall() { local installfile="$1" prefix="$2" pkgname="$3" local section="" src dest dir while IFS= read -r line; do if [[ "$line" =~ '^([a-z_]+):' ]]; then section="${match[1]}" continue fi [[ -z "$section" || "$line" =~ '^\]' ]] && { [[ "$line" =~ '^\]' ]] && section=""; continue; } src="${${line#*\"}%%\"*}" [[ -z "$src" || ! -f "$src" ]] && continue if [[ "$line" =~ '\{"?([^}"]+)"?\}' ]]; then dest="${match[1]}" else dest="${src:t}" fi case "$section" in lib|libexec) dir="$prefix/lib/ocaml/$pkgname" ;; bin) dir="$prefix/bin" ;; share) dir="$prefix/share/$pkgname" ;; doc) dir="$prefix/doc/$pkgname" ;; man) dir="$prefix/man" ;; *) continue ;; esac mkdir -p "$dir/$(dirname "$dest")" cp "$src" "$dir/$dest" done < "$installfile" } install_from_dotinstall uutf.install "$PKGDIR$PREFIX" uutf # OCaml uutf - Unicode text decoder/encoder # https://github.com/dbuenzli/uutf [package] name = "ocaml-uutf" version = "1.0.3" release = 1 description = "OCaml Unicode text decoder/encoder" url = "https://github.com/dbuenzli/uutf" license = "ISC" maintainer = "Chris Tusa " arch = "x86_64" [dependencies] runtime = ["ocaml"] build = ["ocaml", "ocaml-findlib", "ocaml-ocamlbuild", "ocaml-topkg"] [[source]] file = "uutf-1.0.3.tar.gz" urls = [ "https://github.com/dbuenzli/uutf/archive/refs/tags/v1.0.3.tar.gz" ] checksum = "skip" extract = true [build] parallel = false #!/bin/zsh # Build script for OCaml on illumos # # OCaml 5.x requires libatomic for atomic operations set -e cd "$SRCDIR" # Force 64-bit compilation on illumos export CC="gcc -m64" export CXX="g++ -m64" export CFLAGS="-m64" export CXXFLAGS="-m64" export LDFLAGS="-m64 $LDFLAGS" export AS="as --64" # libatomic is at /usr/lib (hammerhead BSD layout) export LD_LIBRARY_PATH="/usr/lib:${LD_LIBRARY_PATH:-}" export LIBRARY_PATH="/usr/lib:${LIBRARY_PATH:-}" ./configure --prefix=$PREFIX --build=$BUILD_TRIPLE gmake -j${JOBS:-1} world.opt # Fix INSTALL path for gmake install — OCaml Makefiles use relative # ./build-aux/install-sh which breaks when gmake -C enters subdirectories. # Override with the absolute path. INSTALL_SH="$(pwd)/build-aux/install-sh" gmake install DESTDIR="$PKGDIR" INSTALL="$INSTALL_SH -c" # Create environment script mkdir -p "$PKGDIR/etc/profile.d" cat > "$PKGDIR/etc/profile.d/ocaml.sh" << EOF # OCaml environment export PATH=$PREFIX/bin:\$PATH EOF --- ocaml-5.4.0/configure 2026-03-11 20:48:20.896212520 -0500 +++ ocaml-5.4.0/configure 2026-03-11 20:49:02.433464677 -0500 @@ -6972,7 +6972,7 @@ lt_cv_deplibs_check_method=pass_all ;; -solaris*) +solaris*|hammerhead*) lt_cv_deplibs_check_method=pass_all ;; @@ -7777,7 +7777,7 @@ osf*) symcode='[BCDEGQRST]' ;; -solaris*) +solaris*|hammerhead*) symcode='[BCDRT]' ;; sco3.2v5*) @@ -8409,7 +8409,7 @@ CFLAGS=$SAVE_CFLAGS fi ;; -*-*solaris*) +*-*solaris*|*-*hammerhead*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo 'int i;' > conftest.$ac_ext @@ -8423,7 +8423,7 @@ case $lt_cv_prog_gnu_ld in yes*) case $target in - i?86-*-solaris*|x86_64-*-solaris*) + i?86-*-solaris*|x86_64-*-solaris*|x86_64-*-hammerhead*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) @@ -10296,7 +10296,7 @@ serenity*) ;; - solaris*) + solaris*|hammerhead*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' case $cc_basename in @@ -10948,7 +10948,7 @@ fi ;; - solaris*) + solaris*|hammerhead*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then ld_shlibs=no cat <<_LT_EOF 1>&2 @@ -11744,7 +11744,7 @@ serenity*) ;; - solaris*) + solaris*|hammerhead*) no_undefined_flag=' -z defs' if test yes = "$GCC"; then wlarc='$wl' @@ -12931,7 +12931,7 @@ dynamic_linker='SerenityOS LibELF' ;; -solaris*) +solaris*|hammerhead*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no @@ -13331,7 +13331,7 @@ serenity*) ;; - solaris*) + solaris*|hammerhead*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' case $cc_basename in @@ -18239,7 +18239,7 @@ *) : ;; esac ;; #( - *-*-solaris*) : + *-*-solaris*|*-*-hammerhead*) : sharedlib_cflags="-fPIC" mkdll_flags='-shared' rpath="-Wl,-rpath," @@ -18334,7 +18334,7 @@ natdynlink=true ;; #( powerpc*-*-linux*) : natdynlink=true ;; #( - x86_64-*-solaris*) : + x86_64-*-solaris*|x86_64-*-hammerhead*) : natdynlink=true ;; #( i686-*-kfreebsd*) : natdynlink=true ;; #( @@ -18576,7 +18576,7 @@ has_native_backend=yes; arch=amd64; system=linux ;; #( x86_64-*-dragonfly*) : arch=amd64; system=dragonfly ;; #( - x86_64-*-solaris*) : + x86_64-*-solaris*|x86_64-*-hammerhead*) : has_native_backend=yes; arch=amd64; system=solaris ;; #( x86_64-*-freebsd*) : has_native_backend=yes; arch=amd64; system=freebsd ;; #( @@ -20022,7 +20022,7 @@ fi ;; #( - *-*-solaris*) : + *-*-solaris*|*-*-hammerhead*) : cclibs="$cclibs -lsocket -lnsl" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing socket" >&5 printf %s "checking for library containing socket... " >&6; } @@ -22132,7 +22132,7 @@ ;; - solaris*) + solaris*|hammerhead*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based @@ -22208,7 +22208,7 @@ # correctly enabled case $host_os in - darwin* | hpux* | linux* | osf* | solaris*) + darwin* | hpux* | linux* | osf* | solaris*|hammerhead*) ax_pthread_check_macro="_REENTRANT" ;; @@ -22533,7 +22533,7 @@ else $as_nop ax_cv_PTHREAD_SPECIAL_FLAGS=no case $host_os in - solaris*) + solaris*|hammerhead*) ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" ;; esac @@ -23608,7 +23608,7 @@ printf "%s\n" "#define HAS_NICE 1" >>confdefs.h ;; #( - *-*-solaris*) : + *-*-solaris*|*-*-hammerhead*) : # This is required as otherwise floats are printed # as "Infinity" and "Inf" instead of the expected "inf" printf "%s\n" "#define HAS_BROKEN_PRINTF 1" >>confdefs.h # OCaml - Functional programming language # https://ocaml.org/ [package] name = "ocaml" version = "5.4.0" release = 1 description = "OCaml programming language compiler and runtime" url = "https://ocaml.org/" license = "LGPL-2.1" maintainer = "Chris Tusa " arch = "x86_64" [dependencies] runtime = [] build = ["make"] [[source]] file = "ocaml-5.4.0.tar.gz" urls = ["https://github.com/ocaml/ocaml/archive/refs/tags/5.4.0.tar.gz"] checksum = "4ab55ac30d247e20f35df20a9f7596e5eb5f92fbbd0f8e3e54838bbc3edf931e" [patches] files = ["hammerhead-solaris-compat.patch"] strip = 1 [build] parallel = true #!/bin/bash # Build script for opam on illumos # # opam requires illumos-specific patches for its vendored dune # and also patches for opamUnix.c (terminal handling on illumos) set -e cd "$SRCDIR" # Ensure OCaml is in PATH export PATH="$PREFIX/bin:$PATH" # Force 64-bit compilation export CC="gcc -m64" export CXX="g++ -m64" export CFLAGS="-m64" export CXXFLAGS="-m64" export LDFLAGS="-m64 $LDFLAGS" # libatomic is at /usr/lib (hammerhead BSD layout) export LD_LIBRARY_PATH="/usr/lib:${LD_LIBRARY_PATH:-}" export LIBRARY_PATH="/usr/lib:${LIBRARY_PATH:-}" # PORTDIR may not be set - derive from script location or use default if [[ -z "$PORTDIR" ]]; then PORTDIR="/usr/ports/devel/opam" fi PATCHDIR="$PORTDIR/patches" # Apply opamUnix.c patch for illumos terminal handling if [[ -f "src/core/opamUnix.c" ]] && [[ -f "$PATCHDIR/opamUnix.c.patch" ]]; then echo "Applying opamUnix.c patch..." patch -p1 < "$PATCHDIR/opamUnix.c.patch" fi # Configure without mccs solver (C++ compat issues on illumos) ./configure --prefix=$PREFIX --with-vendored-deps --without-mccs # Build external dependencies gmake lib-ext # Apply illumos file replacements to vendored dune echo "Applying illumos file replacements to vendored dune..." # Find and replace readdir.c DUNE_READDIR="" for path in \ "src_ext/dune-local/otherlibs/stdune/src/readdir.c" \ "src_ext/dune-local/otherlibs/stdune/dune_filesystem_stubs/readdir.c" \ "src_ext/dune/otherlibs/stdune/dune_filesystem_stubs/readdir.c" \ "vendor/dune-local/otherlibs/stdune/dune_filesystem_stubs/readdir.c"; do if [[ -f "$path" ]]; then DUNE_READDIR="$path" break fi done if [[ -n "$DUNE_READDIR" ]] && [[ -f "$PATCHDIR/readdir.c" ]]; then cp "$PATCHDIR/readdir.c" "$DUNE_READDIR" echo " - Replaced readdir.c" fi # Find and replace winsize.c WINSIZE_FILE="" for path in \ "src_ext/dune-local/vendor/notty/src-unix/native/winsize.c" \ "src_ext/dune/vendor/notty/src-unix/native/winsize.c"; do if [[ -f "$path" ]]; then WINSIZE_FILE="$path" break fi done if [[ -n "$WINSIZE_FILE" ]] && [[ -f "$PATCHDIR/winsize.c" ]]; then cp "$PATCHDIR/winsize.c" "$WINSIZE_FILE" echo " - Replaced winsize.c" fi # Find and replace wait4_stubs.c WAIT4_FILE="" for path in \ "src_ext/dune-local/otherlibs/stdune/src/wait4_stubs.c"; do if [[ -f "$path" ]]; then WAIT4_FILE="$path" break fi done if [[ -n "$WAIT4_FILE" ]] && [[ -f "$PATCHDIR/wait4_stubs.c" ]]; then cp "$PATCHDIR/wait4_stubs.c" "$WAIT4_FILE" echo " - Replaced wait4_stubs.c" fi # Build opam gmake -j${JOBS:-1} gmake install DESTDIR="$PKGDIR" # opam - OCaml package manager # https://opam.ocaml.org/ [package] name = "opam" version = "2.5.0" release = 1 description = "OCaml package manager" url = "https://opam.ocaml.org/" license = "LGPL-2.1" maintainer = "Chris Tusa " arch = "x86_64" [dependencies] runtime = ["ocaml"] build = ["ocaml", "make", "curl"] [[source]] file = "opam-2.5.0.tar.gz" urls = ["https://github.com/ocaml/opam/archive/refs/tags/2.5.0.tar.gz"] checksum = "8c5afec91db80f5c0a34b32e5186ea6349933ee65c3ebb48b15fd317464ddbfc" # Note: Patches are handled in build.sh due to path complexity [build] parallel = true --- a/src/core/opamUnix.c +++ b/src/core/opamUnix.c @@ -8,6 +8,12 @@ /* */ /**************************************************************************/ +#ifdef __sun +/* illumos/Solaris: struct winsize and TIOCGWINSZ in termios */ +#include +#include +#endif + #include CAMLprim value opam_stdout_ws_col(value _unit) { /* * readdir.c - illumos/Solaris compatible version for dune * * This file replaces otherlibs/stdune/dune_filesystem_stubs/readdir.c * in dune to fix compilation on illumos/Solaris where struct dirent * does not have d_type field. * * Apply by copying this file to: * dune-X.Y.Z/otherlibs/stdune/dune_filesystem_stubs/readdir.c * * For opam's bundled dune-local: * opam-X.Y.Z/src_ext/dune-local/otherlibs/stdune/dune_filesystem_stubs/readdir.c */ #include #include #include #include #include #ifndef _WIN32 #include #include #include #include /* illumos/Solaris compatibility - d_type not in struct dirent */ #ifndef DT_UNKNOWN #define DT_UNKNOWN 0 #define DT_FIFO 1 #define DT_CHR 2 #define DT_DIR 4 #define DT_BLK 6 #define DT_REG 8 #define DT_LNK 10 #define DT_SOCK 12 #define DT_WHT 14 #define ILLUMOS_NO_DTYPE 1 #endif typedef struct dirent directory_entry; value val_file_type(int typ) { switch(typ) { #ifndef __HAIKU__ case DT_REG: return Val_int(0); case DT_DIR: return Val_int(1); case DT_CHR: return Val_int(2); case DT_BLK: return Val_int(3); case DT_LNK: return Val_int(4); case DT_FIFO: return Val_int(5); case DT_SOCK: return Val_int(6); case DT_UNKNOWN: return Val_int(7); #endif default: return Val_int(7); } } CAMLprim value caml__dune_filesystem_stubs__readdir(value vd) { CAMLparam1(vd); CAMLlocal2(v_filename, v_tuple); DIR * d; directory_entry * e; d = DIR_Val(vd); if (d == (DIR *) NULL) unix_error(EBADF, "readdir", Nothing); caml_enter_blocking_section(); errno = 0; e = readdir((DIR *) d); caml_leave_blocking_section(); if (e == (directory_entry *) NULL) { if(errno == 0) { CAMLreturn(Val_int(0)); } else { uerror("readdir", Nothing); } } v_filename = caml_copy_string(e->d_name); v_tuple = caml_alloc_small(2, 0); Field(v_tuple, 0) = v_filename; #if defined(__HAIKU__) || defined(ILLUMOS_NO_DTYPE) /* illumos/Solaris don't have d_type, always return unknown */ Field(v_tuple, 1) = Val_int(7); #else Field(v_tuple, 1) = val_file_type(e->d_type); #endif CAMLreturn(v_tuple); } #else CAMLprim value caml__dune_filesystem_stubs__readdir(value vd) { unix_error(ENOSYS, "readdir", Nothing); } #endif #include #ifdef _WIN32 #include void dune_wait4(value v_pid, value flags) { caml_failwith("wait4: not supported"); } #else #include #include #include #include #include #include #include #include #include #include #define TAG_WEXITED 0 #define TAG_WSIGNALED 1 #define TAG_WSTOPPED 2 CAMLextern int caml_rev_convert_signal_number(int); static value alloc_process_status(int status) { value st; if (WIFEXITED(status)) { st = caml_alloc_small(1, TAG_WEXITED); Field(st, 0) = Val_int(WEXITSTATUS(status)); } else if (WIFSTOPPED(status)) { st = caml_alloc_small(1, TAG_WSTOPPED); Field(st, 0) = Val_int(caml_rev_convert_signal_number(WSTOPSIG(status))); } else { st = caml_alloc_small(1, TAG_WSIGNALED); Field(st, 0) = Val_int(caml_rev_convert_signal_number(WTERMSIG(status))); } return st; } static int wait_flag_table[] = {WNOHANG, WUNTRACED}; value dune_wait4(value v_pid, value flags) { CAMLparam2(v_pid, flags); CAMLlocal2(times, res); int pid, status, cv_flags = caml_convert_flag_list(flags, wait_flag_table); struct rusage ru; struct timeval tp; memset(&ru, 0, sizeof(ru)); caml_enter_blocking_section(); pid = waitpid(Int_val(v_pid), &status, cv_flags); if (pid > 0) getrusage(RUSAGE_CHILDREN, &ru); gettimeofday(&tp, NULL); caml_leave_blocking_section(); if (pid == -1) uerror("wait4", Nothing); times = caml_alloc_small(2 * Double_wosize, Double_array_tag); Store_double_field(times, 0, ru.ru_utime.tv_sec + ru.ru_utime.tv_usec / 1e6); Store_double_field(times, 1, ru.ru_stime.tv_sec + ru.ru_stime.tv_usec / 1e6); res = caml_alloc_tuple(4); Store_field(res, 0, Val_int(pid)); Store_field(res, 1, alloc_process_status(status)); Store_field(res, 2, caml_copy_double(((double)tp.tv_sec + (double)tp.tv_usec / 1e6))); Store_field(res, 3, times); CAMLreturn(res); } #endif /* * winsize.c - illumos/Solaris compatible version for notty (used by dune) * * This file replaces vendor/notty/src-unix/native/winsize.c * in dune to fix compilation on illumos/Solaris where TIOCGWINSZ * is defined in sys/termios.h rather than sys/ioctl.h. * * Apply by copying this file to: * dune-X.Y.Z/vendor/notty/src-unix/native/winsize.c * * For opam's bundled dune-local: * opam-X.Y.Z/src_ext/dune-local/vendor/notty/src-unix/native/winsize.c */ #include #include #include #ifdef __sun /* illumos/Solaris: struct winsize and TIOCGWINSZ in termios */ #include #include #else #include #endif #include #include CAMLprim value caml_notty_winsize (value fd) { #ifdef TIOCGWINSZ struct winsize w; if (ioctl(Int_val(fd), TIOCGWINSZ, &w) == -1) caml_failwith("ioctl"); value res = caml_alloc_small(2, 0); Field(res, 0) = Val_int(w.ws_col); Field(res, 1) = Val_int(w.ws_row); return res; #else /* Fallback: return default 80x24 */ value res = caml_alloc_small(2, 0); Field(res, 0) = Val_int(80); Field(res, 1) = Val_int(24); return res; #endif } /* Return SIGWINCH signal number */ CAMLprim value caml_notty_winch_number (value unit) { #ifdef SIGWINCH return Val_int(SIGWINCH); #else return Val_int(0); #endif } #!/bin/bash # Build script for perl set -e cd "$SRCDIR" # Perl uses its own Configure script (note the capital C) ./Configure -des \ -Dprefix=$PREFIX \ -Dvendorprefix=$PREFIX \ -Dprivlib=$PREFIX/lib/perl5/5.40/core_perl \ -Darchlib=$PREFIX/lib/perl5/5.40/core_perl \ -Dsitelib=$PREFIX/lib/perl5/5.40/site_perl \ -Dsitearch=$PREFIX/lib/perl5/5.40/site_perl \ -Dvendorlib=$PREFIX/lib/perl5/5.40/vendor_perl \ -Dvendorarch=$PREFIX/lib/perl5/5.40/vendor_perl \ -Dman1dir=$PREFIX/share/man/man1 \ -Dman3dir=$PREFIX/share/man/man3 \ -Dusethreads \ -Duseshrplib \ -Doptimize="${CFLAGS:--O2}" gmake -j${JOBS:-1} gmake install DESTDIR="$PKGDIR" # Perl - Practical Extraction and Report Language # https://www.perl.org/ [package] name = "perl" version = "5.40.1" release = 1 description = "Practical Extraction and Report Language" url = "https://www.perl.org/" license = "Artistic-1.0 OR GPL-1.0" maintainer = "Chris Tusa " arch = "x86_64" [dependencies] runtime = ["zlib"] build = ["zlib"] [[source]] file = "perl-5.40.1.tar.xz" urls = [ "https://www.cpan.org/src/5.0/perl-5.40.1.tar.xz", "https://cpan.metacpan.org/authors/id/P/PE/PEVANS/perl-5.40.1.tar.xz" ] checksum = "02a4a4f273590fe00a63cb1d6a23ba85e27f7de5bce0c74a049e9eb6bb783b52" [build] parallel = true #!/bin/bash # Build script for CPython 3.13. # # Links the OS-provided OpenSSL 3.5 (base, in /usr) — so _ssl/_hashlib build # stock with no LibreSSL patches, and pip + HTTPS work out of the box. zlib # and libffi also come from the base system. set -e cd "$SRCDIR" # Hammerhead is illumos with a renamed sysname. CPython's configure derives its # platform logic (LDSHARED, Py_SUNOS_VERSION, dynamic loading, ...) from # `uname -s`, which returns "Hammerhead" — so NONE of the SunOS/Solaris branches # fire. Symptoms: LDSHARED defaults to bare `ld` (extension .so links fail with # "cannot find entry symbol _start" + undefined Py symbols), and socketmodule.c # re-declares sethostname() (Py_SUNOS_VERSION undefined, i.e. <= 510), clashing # with illumos . Map Hammerhead -> SunOS in configure so the correct # SunOS/5.x + GCC branches activate: LDSHARED becomes '$(CC) -shared' (GNU-ld # friendly) and Py_SUNOS_VERSION becomes 511. Same approach as the other ports' # hammerhead-solaris-compat patches; done as a string-keyed sed so it survives # Python patch-version bumps. sed -i 's/ac_sys_system=`uname -s`/&; if test "$ac_sys_system" = Hammerhead; then ac_sys_system=SunOS; fi/' configure export CFLAGS="${CFLAGS:--O2} -fPIC" export CPPFLAGS="-I$PREFIX/include" # rpath: libpython3.13.so + any zport deps live at $PREFIX/lib; the base # OpenSSL/ffi/z live at /usr/lib. Bake both so nothing needs LD_LIBRARY_PATH. export LDFLAGS="-L$PREFIX/lib -R$PREFIX/lib -R/usr/lib" # illumos: the _socket module calls hstrerror(), which lives in libresolv # (not libc/libnsl as on Linux). Without this _socket fails to import with # "symbol hstrerror: referenced symbol not found". export LIBS="-lresolv" ./configure \ --build=$BUILD_TRIPLE \ --host=$BUILD_TRIPLE \ --prefix=$PREFIX \ --enable-shared \ --with-system-ffi \ --with-openssl=/usr \ --with-ensurepip=install gmake -j${JOBS:-1} gmake install DESTDIR="$PKGDIR" # convenience symlinks (setup.py install names the binary python3.13) ln -sf python3.13 "$PKGDIR$PREFIX/bin/python3" ln -sf python3 "$PKGDIR$PREFIX/bin/python" ln -sf pip3.13 "$PKGDIR$PREFIX/bin/pip3" 2>/dev/null || true ln -sf pip3 "$PKGDIR$PREFIX/bin/pip" 2>/dev/null || true # Python - CPython interpreter (links the OS-provided OpenSSL 3.5) # https://www.python.org/ [package] name = "python" version = "3.13.2" release = 1 description = "Python programming language interpreter (CPython)" url = "https://www.python.org/" license = "PSF-2.0" maintainer = "Chris Tusa " arch = "x86_64" [dependencies] # openssl, zlib, libffi are provided by the base system (/usr/lib). runtime = [] build = [] [[source]] file = "Python-3.13.2.tar.xz" urls = ["https://www.python.org/ftp/python/3.13.2/Python-3.13.2.tar.xz"] checksum = "d984bcc57cd67caab26f7def42e523b1c015bbc5dc07836cf4f0b63fa159eb56" extract = true [build] parallel = true #!/bin/zsh # Build script for Reef programming language set -e cd "$SRCDIR" export PATH="$PREFIX/bin:$PATH" # dune-installed libs live in $PREFIX/lib, not $PREFIX/lib/ocaml export OCAMLPATH="$PREFIX/lib:${OCAMLPATH:-}" # Force 64-bit compilation for the runtime export CC="gcc -m64" export CXX="g++ -m64" export CFLAGS="-m64 -O2" export CXXFLAGS="-m64 -O2" export LDFLAGS="-m64 $LDFLAGS" # Library paths (hammerhead BSD layout) export LD_LIBRARY_PATH="/usr/lib:${LD_LIBRARY_PATH:-}" export LIBRARY_PATH="/usr/lib:${LIBRARY_PATH:-}" # Build sequentially — runtime then compiler — to avoid OOM on small VMs # (gmake all would build both in parallel via -j flag) echo "Building Reef runtime..." gmake -j1 runtime echo "Building Reef compiler..." gmake -j1 compiler # Manual install — Hammerhead's /usr/sbin/install (SVR4) breaks PATH local COMPILER_DIR="$SRCDIR/reef-compiler" local RUNTIME_DIR="$SRCDIR/reef-runtime" local RUNTIME_BUILD="$RUNTIME_DIR/build" local STDLIB_DIR="$SRCDIR/reef-stdlib" local D="$PKGDIR$PREFIX" # Compiler binary mkdir -p "$D/bin" cp "$COMPILER_DIR/_build/default/bin/reefc.exe" "$D/bin/reefc" chmod 755 "$D/bin/reefc" # Runtime headers mkdir -p "$D/lib/reef/runtime/include" cp "$RUNTIME_DIR"/include/*.h "$D/lib/reef/runtime/include/" # Runtime libraries mkdir -p "$D/lib/reef/runtime/lib" cp "$RUNTIME_BUILD/libreef_runtime.a" "$D/lib/reef/runtime/lib/" for lib in libreef_x11.a libreef_tls.a libcrypto.a libssl.a libtls.a; do [ -f "$RUNTIME_BUILD/$lib" ] && cp "$RUNTIME_BUILD/$lib" "$D/lib/reef/runtime/lib/" done # Standard library mkdir -p "$D/lib/reef/stdlib" cp -r "$STDLIB_DIR"/* "$D/lib/reef/stdlib/" rm -rf "$D/lib/reef/stdlib/docs" 2>/dev/null || true chmod -R a+rX "$D/lib/reef" # Config file — substitute @PREFIX@ with actual prefix mkdir -p "$PKGDIR$SYSCONFDIR/reef" sed "s|@PREFIX@|$PREFIX|g" "$SRCDIR/etc/reefc.conf.in" > "$PKGDIR$SYSCONFDIR/reef/reefc.conf" chmod 644 "$PKGDIR$SYSCONFDIR/reef/reefc.conf" # Reef - Programming language for system programming # https://reef-lang.org [package] name = "reef" version = "0.7.7" release = 1 description = "Reef programming language compiler and runtime" url = "https://reef-lang.org" license = "BSD-2-Clause" maintainer = "Chris Tusa " arch = "x86_64" [dependencies] runtime = [] build = ["ocaml", "dune", "menhir", "ocaml-alcotest"] [[source]] file = "reef-lang-0.7.7-source.tar.gz" urls = ["reef-lang-0.7.7-source.tar.gz"] checksum = "d27b526aa7f7e61c72c0b16a9fd8a3ef37e39676a2d0d14257a244b678cd3516" extract = true [build] parallel = false