From b545ce5630fc43a88fac0f7973385795eb709ec2 Mon Sep 17 00:00:00 2001 From: jrtxio Date: Wed, 16 Sep 2026 09:08:19 +0800 Subject: [PATCH] =?UTF-8?q?build-app:=20run=20the=20user=20entry's=20main?= =?UTF-8?q?=20submodule=20=E2=80=94=20packaged=20apps=20did=20nothing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The generated entry wrapper required the user's main as a plain library. Under `racket main.rkt` the (module+ main) submodule runs because the file is the program's top module; loaded via require from a wrapper, that submodule is never instantiated — so build-app's launcher exited 0 immediately without executing any user code (no output for --version, no usage error for unknown flags; the program body never started). The wrapper now mirrors the interpreter: it keeps the static require (so raco exe embeds the full dependency closure — dynamic-requires are invisible to it) and then explicitly instantiates (submod "main.rkt" main) when declared, falling back to the module body for top-level-style apps. Verified on Racket 9.3 CS / macOS arm64 with a real app using module+ main (window opens, server serves, SSE streams), a top-level-style script, and --version/--bogus flag semantics. glaze-test: 216 passed. Fixes #1 --- glaze/build.rkt | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/glaze/build.rkt b/glaze/build.rkt index 77d4c45..0dd26ea 100644 --- a/glaze/build.rkt +++ b/glaze/build.rkt @@ -396,6 +396,13 @@ NSI ;; executable's own directory first, then falls back to the original CWD if ;; that directory does not contain a public/ (covering launchers that report ;; a wrapper path). +;; +;; Running the user program must mirror `racket main.rkt`: instantiate the +;; (module+ main) submodule when the user entry declares one, otherwise the +;; module body itself. A static (require "main.rkt") here loads the module +;; as a plain library — its main submodule would never run and the packaged +;; app would exit 0 without executing anything (the entry wrapper itself has +;; no main submodule either). (define (entry-module-source user-entry) (define entry-filename (let ([p (if (complete-path? user-entry) @@ -416,7 +423,16 @@ NSI " (and c (directory-exists? (build-path c \"public\")) c))])\n" " (when (and pick (not (directory-exists? (build-path (current-directory) \"public\"))))\n" " (current-directory pick)))\n" - (format "(require \"~a\")\n" entry-filename))) + ;; Static require: embeds the user module and its full dependency closure + ;; (raco exe cannot see dynamic-requires), and runs top-level code once. + (format "(require \"~a\")\n" entry-filename) + ";; Run the user entry the way `racket main.rkt` would: the (module+ main)\n" + ";; submodule when declared, else the module body. The static require above\n" + ";; embeds the full dependency closure and runs top-level code once; the\n" + ";; main submodule itself is only instantiated for the program's top module,\n" + ";; which is this wrapper — so run it explicitly here.\n" + "(when (module-declared? '(submod \"" entry-filename "\" main) #t)\n" + " (dynamic-require '(submod \"" entry-filename "\" main) 0))\n")) ;; Assemble a canonical macOS .app bundle from whatever `raco distribute` ;; produced. Current versions lay out /bin/ + /lib/; older