From 488951f298141036a615b9f3a55069834dbae402 Mon Sep 17 00:00:00 2001 From: Brandon Payton Date: Fri, 10 Jul 2026 23:39:56 -0400 Subject: [PATCH 1/3] make: add GNU build automation formula --- Formula/make.rb | 111 ++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 3 +- 2 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 Formula/make.rb diff --git a/Formula/make.rb b/Formula/make.rb new file mode 100644 index 0000000..ee841c7 --- /dev/null +++ b/Formula/make.rb @@ -0,0 +1,111 @@ +require_relative "../Kandelo/formula_support/kandelo_formula_support" + +class Make < Formula + include KandeloFormulaSupport + + desc "GNU build automation tool for Kandelo" + homepage "https://www.gnu.org/software/make/" + url "https://ftpmirror.gnu.org/gnu/make/make-4.4.1.tar.gz" + mirror "https://ftp.gnu.org/gnu/make/make-4.4.1.tar.gz" + sha256 "dd16fb1d67bfab79a72f5e8390735c49e3e8e70b4945a15ab1f81ddb78658fb3" + license "GPL-3.0-or-later" + + depends_on "automattic/kandelo-homebrew/dash" + + skip_clean "bin/make" + patch :DATA + + def install + kandelo_require_arch!("wasm32") + + kandelo_wasm_build do + # These runtime probes are package-specific; target facts stay in the SDK site file. + ENV["gl_cv_func_strerror_0_works"] = "yes" + ENV["make_cv_synchronous_posix_spawn"] = "yes" + + system kandelo_configure, *kandelo_std_configure_args, + "--disable-nls", + "--disable-load", + "--disable-dependency-tracking" + system "make", "-j#{ENV.make_jobs}" + end + + kandelo_install_bin(buildpath, "make", "make") + end + + test do + assert_match(/^GNU Make 4\.4\.1$/, + kandelo_run_wasm(bin/"make", ["--version"])) + + dash = testpath/"dash" + dash.binwrite((formula_opt_bin("automattic/kandelo-homebrew/dash")/"dash").binread) + dash.chmod 0755 + recursive_make = testpath/"make" + recursive_make.binwrite((bin/"make").binread) + recursive_make.chmod 0755 + + (testpath/"alpha.txt").write "alpha\n" + (testpath/"beta.txt").write "beta\n" + (testpath/"Makefile").write <<~MAKEFILE + SHELL := dash + .PHONY: all + all: report.txt recursive.txt + + report.txt: alpha.txt beta.txt + \t@printf 'name=%s inputs=%s\\n' '$(NAME)' '$^' > $@ + + recursive.txt: + \t@make --no-print-directory -f child.mk CHILD='$(NAME)' + MAKEFILE + (testpath/"child.mk").write <<~MAKEFILE + SHELL := dash + all: + \t@printf 'child=%s\\n' '$(CHILD)' > recursive.txt + MAKEFILE + + env = { "KERNEL_CWD" => testpath, "KERNEL_PATH" => testpath } + assert_empty kandelo_run_wasm(bin/"make", ["-j2", "NAME=Kandelo", "all"], env: env) + assert_equal "name=Kandelo inputs=alpha.txt beta.txt\n", (testpath/"report.txt").read + assert_equal "child=Kandelo\n", (testpath/"recursive.txt").read + up_to_date = kandelo_run_wasm(bin/"make", ["NAME=Kandelo", "all"], env: env) + assert_match(/\Amake(?:\.wasm)?: Nothing to be done for 'all'\.\n\z/, up_to_date) + + (testpath/"failure.mk").write <<~MAKEFILE + failure: + \t@missing-kandelo-command + MAKEFILE + failure = kandelo_run_wasm( + bin/"make", ["-f", "failure.mk", "failure"], env: env, merge_stderr: true, expected_status: 2 + ) + assert_match(/missing-kandelo-command.*No such file or directory/, failure) + end +end + +__END__ +diff --git a/src/main.c b/src/main.c +index af01f36..b669875 100644 +--- a/src/main.c ++++ b/src/main.c +@@ -1160,11 +1160,11 @@ temp_stdin_unlink () + } + } + +-#ifdef MK_OS_ZOS ++#if defined(MK_OS_ZOS) || defined(__wasm__) + extern char **environ; + #endif + +-#if defined(_AMIGA) || defined(MK_OS_ZOS) ++#if defined(_AMIGA) || defined(MK_OS_ZOS) || defined(__wasm__) + int + main (int argc, char **argv) + #else +@@ -1482,7 +1482,7 @@ main (int argc, char **argv, char **envp) + done before $(MAKE) is figured out so its definitions will not be + from the environment. */ + +-#ifdef MK_OS_ZOS ++#if defined(MK_OS_ZOS) || defined(__wasm__) + char **envp = environ; + #endif + diff --git a/README.md b/README.md index f9e5016..08b0ded 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,8 @@ Current migration controls and pilots include: - `gzip`, the GNU compression CLI with native gunzip and zcat aliases; - `grep`, GNU regular-expression and file search for the leaf CLI wave; - `pcre2`, the Unicode-capable regex library, POSIX wrapper, and upstream CLI tools; -- `dash`, the dependency-free POSIX shell with instrumented subprocess support. +- `dash`, the dependency-free POSIX shell with instrumented subprocess support; +- `make`, GNU dependency-driven build automation using the tap's POSIX shell. The SDK is not yet a Homebrew dependency. Trusted builds supply an `HOMEBREW_KANDELO_ROOT` checkout containing the SDK, sysroot, kernel, and Node From b3f2e841a9c2fe33f32508381a142373141442c2 Mon Sep 17 00:00:00 2001 From: Brandon Payton Date: Sat, 11 Jul 2026 00:39:02 -0400 Subject: [PATCH 2/3] make: enable loadable object support GNU Make's loadable-object API was disabled even though Kandelo supports Wasm side modules. Install the public header, mark the documented gmk API as visible, and exercise a compiled module that registers and runs a custom Make function. The runtime path depends on the SDK's explicit -ldl configure fact and the host's main-program handle support, so the tap PR remains gated on Automattic/kandelo#874 and #879. --- Formula/make.rb | 68 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 59 insertions(+), 9 deletions(-) diff --git a/Formula/make.rb b/Formula/make.rb index ee841c7..138afa2 100644 --- a/Formula/make.rb +++ b/Formula/make.rb @@ -25,18 +25,48 @@ def install system kandelo_configure, *kandelo_std_configure_args, "--disable-nls", - "--disable-load", "--disable-dependency-tracking" system "make", "-j#{ENV.make_jobs}" + system "make", "install" end - - kandelo_install_bin(buildpath, "make", "make") end test do assert_match(/^GNU Make 4\.4\.1$/, kandelo_run_wasm(bin/"make", ["--version"])) + root = kandelo_activate_sdk! + kandelo_activate_sysroot!(root) + (testpath/"kandelo_plugin.c").write <<~C + #include + + int plugin_is_GPL_compatible; + + static char *kandelo_plugin(const char *name, unsigned int argc, char **argv) { + const char prefix[] = "plugin="; + const char *value = argc == 0 ? "" : argv[0]; + unsigned int prefix_len = sizeof(prefix) - 1; + unsigned int value_len = 0; + while (value[value_len] != '\\0') + ++value_len; + + char *result = gmk_alloc(prefix_len + value_len + 1); + for (unsigned int i = 0; i < prefix_len; ++i) + result[i] = prefix[i]; + for (unsigned int i = 0; i < value_len; ++i) + result[prefix_len + i] = value[i]; + result[prefix_len + value_len] = '\\0'; + return result; + } + + int kandelo_plugin_gmk_setup(const gmk_floc *floc) { + gmk_add_function("kandelo-plugin", kandelo_plugin, 1, 1, GMK_FUNC_DEFAULT); + return 1; + } + C + system kandelo_cc(root), "-shared", "-fPIC", "-I#{include}", + testpath/"kandelo_plugin.c", "-o", testpath/"kandelo_plugin.so" + dash = testpath/"dash" dash.binwrite((formula_opt_bin("automattic/kandelo-homebrew/dash")/"dash").binread) dash.chmod 0755 @@ -49,13 +79,17 @@ def install (testpath/"Makefile").write <<~MAKEFILE SHELL := dash .PHONY: all - all: report.txt recursive.txt + load kandelo_plugin.so(kandelo_plugin_gmk_setup) + all: report.txt recursive.txt plugin.txt report.txt: alpha.txt beta.txt \t@printf 'name=%s inputs=%s\\n' '$(NAME)' '$^' > $@ recursive.txt: \t@make --no-print-directory -f child.mk CHILD='$(NAME)' + + plugin.txt: + \t@printf '%s\\n' '$(kandelo-plugin $(NAME))' > $@ MAKEFILE (testpath/"child.mk").write <<~MAKEFILE SHELL := dash @@ -67,6 +101,7 @@ def install assert_empty kandelo_run_wasm(bin/"make", ["-j2", "NAME=Kandelo", "all"], env: env) assert_equal "name=Kandelo inputs=alpha.txt beta.txt\n", (testpath/"report.txt").read assert_equal "child=Kandelo\n", (testpath/"recursive.txt").read + assert_equal "plugin=Kandelo\n", (testpath/"plugin.txt").read up_to_date = kandelo_run_wasm(bin/"make", ["NAME=Kandelo", "all"], env: env) assert_match(/\Amake(?:\.wasm)?: Nothing to be done for 'all'\.\n\z/, up_to_date) @@ -82,6 +117,19 @@ def install end __END__ +diff --git a/src/gnumake.h b/src/gnumake.h +--- a/src/gnumake.h ++++ b/src/gnumake.h +@@ -35,6 +35,8 @@ typedef char *(*gmk_func_ptr)(const char *nm, unsigned int argc, char **argv); + # else + # define GMK_EXPORT __declspec(dllimport) + # endif ++#elif defined(__wasm__) ++# define GMK_EXPORT __attribute__((visibility("default"))) + #else + # define GMK_EXPORT + #endif + diff --git a/src/main.c b/src/main.c index af01f36..b669875 100644 --- a/src/main.c @@ -89,23 +137,25 @@ def install @@ -1160,11 +1160,11 @@ temp_stdin_unlink () } } - +- ++ -#ifdef MK_OS_ZOS +#if defined(MK_OS_ZOS) || defined(__wasm__) extern char **environ; #endif - +- ++ -#if defined(_AMIGA) || defined(MK_OS_ZOS) +#if defined(_AMIGA) || defined(MK_OS_ZOS) || defined(__wasm__) int main (int argc, char **argv) #else -@@ -1482,7 +1482,7 @@ main (int argc, char **argv, char **envp) +@@ -1482,6 +1482,6 @@ main (int argc, char **argv, char **envp) done before $(MAKE) is figured out so its definitions will not be from the environment. */ - +- ++ -#ifdef MK_OS_ZOS +#if defined(MK_OS_ZOS) || defined(__wasm__) char **envp = environ; #endif - From d338c75953b8181b62793f1822ebb1012c0101b2 Mon Sep 17 00:00:00 2001 From: Brandon Payton Date: Sat, 11 Jul 2026 21:13:53 -0400 Subject: [PATCH 3/3] make: load support from the installed tap --- Formula/make.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Formula/make.rb b/Formula/make.rb index 138afa2..728a3ef 100644 --- a/Formula/make.rb +++ b/Formula/make.rb @@ -1,4 +1,4 @@ -require_relative "../Kandelo/formula_support/kandelo_formula_support" +require (Tap.fetch("automattic", "kandelo-homebrew").path/"Kandelo/formula_support/kandelo_formula_support").to_s class Make < Formula include KandeloFormulaSupport