M gnu/packages/hare.scm => gnu/packages/hare.scm +67 -0
@@ 105,3 105,70 @@
programming language. For general Hare programming, see the @code{hare}
package.")
(license license:gpl3)))
+
+(define-public hare
+ (package
+ (name "hare")
+ (version "0.25.2")
+ (source (origin
+ (method git-fetch)
+ (uri (git-reference
+ (url "https://git.sr.ht/~sircmpwn/hare")
+ (commit version)))
+ (file-name (git-file-name name version))
+ (patches (search-patches "hare-fallback-cache.patch"
+ "hare-toolpath.patch"))
+ (sha256
+ (base32
+ "1kfvf1xk36w49dnqrkcahh35xdgilhgdn3q84r2101rz2iy4pbba"))))
+ (build-system gnu-build-system)
+ (arguments
+ (list #:modules `((ice-9 format) ,@%default-gnu-modules)
+ #:make-flags #~(list (string-append "PREFIX=" #$output)
+ (string-append "VERSION=" #$version))
+ #:phases
+ #~(modify-phases %standard-phases
+ ;; technically hare does programmatically generate some
+ ;; makefiles as part of a bootstrap phase. however, regenning
+ ;; these files requires an installation of hare in the first
+ ;; place. seeing as the files are pretty short and
+ ;; human-readable, I think it's fine to leave them as-is.
+ (replace 'configure
+ (lambda* (#:key inputs #:allow-other-keys)
+ (copy-file #$hare-config "config.mk")
+ ;; need to unhardcode some shit manually
+ (let ((file (lambda (s) (search-input-file inputs s)))
+ (dir (lambda (s) (search-input-directory inputs s))))
+ (substitute* "cmd/hare/build.ha"
+ (("\"harec\"") (format #f "\"~a\"" (file "bin/harec")))
+ (("\"qbe\"") (format #f "\"~a\"" (file "bin/qbe"))))
+ (substitute* "cmd/haredoc/main.ha"
+ (("\"less\"") (format #f "\"~a\"" (file "bin/less"))))
+ (substitute* "wordexp/wordexp.ha"
+ (("/bin/sh") (file "bin/sh")))
+ (substitute* "time/chrono/+linux.ha"
+ (("/usr/share/zoneinfo/leap-seconds.list")
+ (file "share/zoneinfo/leap-seconds.list")))
+ (substitute* "time/date/+linux.ha"
+ (("/usr/share/zoneinfo") (dir "share/zoneinfo")))))))))
+ (inputs
+ (let ((tc (lambda (t) (and (cross-target? t) (cross-gcc-toolchain t)))))
+ (filter ->bool (list gcc-toolchain less tzdata/leap-seconds harec qbe
+ ;; provide cross toolchains for all
+ ;; non-native possible targets
+ (tc "aarch64-linux-gnu")
+ (tc "riscv64-linux-gnu")
+ (tc "x86_64-linux-gnu")))))
+ (native-inputs (list harec qbe scdoc))
+ (supported-systems hare-supported-systems)
+ (search-paths (list (search-path-specification
+ (variable "HAREPATH")
+ (files '("share/hare")))))
+ (native-search-paths (list (search-path-specification
+ (variable "HARE_TOOLPATH")
+ (files '("libexec/hare")))))
+ (home-page "https://harelang.org")
+ (synopsis "Harelang compiler tooling and stdlib")
+ (description "Hare is a simple systems programming language, featuring
+static typing, manual memory management, and a minimal runtime.")
+ (license (list license:gpl3 license:mpl2.0))))
A gnu/packages/patches/hare-fallback-cache.patch => gnu/packages/patches/hare-fallback-cache.patch +33 -0
@@ 0,0 1,33 @@
+From 04fb25e334492432c0c1a09e1abb4c506fb1e710 Mon Sep 17 00:00:00 2001
+Message-ID: <04fb25e334492432c0c1a09e1abb4c506fb1e710.1754429792.git.lilah@lunabee.space>
+From: Lilah Tascheter <lilah@lunabee.space>
+Date: Tue, 5 Aug 2025 16:35:24 -0500
+Subject: [PATCH] dirs::xdg: Fallback to cwd.
+
+Guix builds take place without a valid HOME, which will immediately prevent hare
+from functioning. Provide a usable, if unfortunate, default.
+---
+ dirs/xdg.ha | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/dirs/xdg.ha b/dirs/xdg.ha
+index 9dc6c3b9..65eb92db 100644
+--- a/dirs/xdg.ha
++++ b/dirs/xdg.ha
+@@ -29,7 +29,12 @@ fn lookup(prog: str, var: str, default: str) str = {
+ case void => void;
+ };
+
+- const home = os::getenv("HOME") as str;
++ let home = os::getenv("HOME") as str;
++ if(match(os::stat(home)) {
++ case let err: fs::error => yield true;
++ case let st: fs::filestat => yield !fs::isdir(st.mode);
++ }){ home = "."; };
++
+ const path = path::set(&buf, home, default, prog)!;
+ match (os::mkdirs(path, 0o755)) {
+ case let err: fs::error =>
+--
+2.50.0
+
A gnu/packages/patches/hare-toolpath.patch => gnu/packages/patches/hare-toolpath.patch +72 -0
@@ 0,0 1,72 @@
+From 98677305eba7acd487803b6670a1bd67e1fc2796 Mon Sep 17 00:00:00 2001
+Message-ID: <98677305eba7acd487803b6670a1bd67e1fc2796.1754431105.git.lilah@lunabee.space>
+From: Lilah Tascheter <lilah@lunabee.space>
+Date: Tue, 5 Aug 2025 16:42:50 -0500
+Subject: [PATCH] cmd::hare::tool: Use HARE_TOOLPATH when available.
+
+Some distros, like Guix, do not have set search paths, and instead rely on
+environment variables. Allow tools to be specified through a new variable,
+HARE_TOOLPATH.
+---
+ cmd/hare/tool.ha | 35 +++++++++++++++++++++--------------
+ 1 file changed, 21 insertions(+), 14 deletions(-)
+
+diff --git a/cmd/hare/tool.ha b/cmd/hare/tool.ha
+index b14250fc..b7e4e2ff 100644
+--- a/cmd/hare/tool.ha
++++ b/cmd/hare/tool.ha
+@@ -7,6 +7,7 @@ use getopt;
+ use os;
+ use os::exec;
+ use path;
++use strings;
+
+ fn tool(name: str, cmd: *getopt::command) (void | error) = {
+ if (len(cmd.args) < 1) {
+@@ -19,23 +20,29 @@ fn tool(name: str, cmd: *getopt::command) (void | error) = {
+ args = cmd.args[1..];
+ };
+
+- const path = path::init(TOOLDIR)?;
++ const paths = strings::tokenize(os::tryenv("HARE_TOOLPATH", TOOLDIR), ":");
+ const tool = cmd.args[0];
+ const name = fmt::asprintf("hare-{}", tool)!;
+ defer free(name);
+- path::push(&path, name)?;
+-
+- const cmd = match (exec::cmd(path::string(&path), args...)) {
+- case let cmd: exec::command =>
+- yield cmd;
+- case errors::noentry =>
+- fmt::fatalf("hare tool {}: tool not found", tool);
+- case let err: exec::error =>
+- return err;
++
++ for(const segment => strings::next_token(&paths)) {
++ const path = path::init(segment)?;
++ path::push(&path, name)?;
++
++ const cmd = match (exec::cmd(path::string(&path), args...)) {
++ case let cmd: exec::command =>
++ yield cmd;
++ case errors::noentry =>
++ continue;
++ case let err: exec::error =>
++ return err;
++ };
++
++ const argv0 = fmt::asprintf("hare tool {}", tool)!;
++ exec::setname(&cmd, argv0)!;
++ const err = exec::exec(&cmd);
++ fmt::fatalf("exec {}: {}", path::string(&path), exec::strerror(err));
+ };
+
+- const argv0 = fmt::asprintf("hare tool {}", tool)!;
+- exec::setname(&cmd, argv0)!;
+- const err = exec::exec(&cmd);
+- fmt::fatalf("exec {}: {}", path::string(&path), exec::strerror(err));
++ fmt::fatalf("hare tool {}: tool not found", tool);
+ };
+--
+2.50.0
+