Matthew, Many thanks! Your code works perfectly for my program.
Now I would like to describe my tries to make a standalone executable out of my program. Most obvious way fails: $ raco exe slon-main.rkt $ ./slon-main standard-module-name-resolver: collection not found collection: "slon" in collection directories: context...: standard-module-name-resolver Not surprising, as the "slon" collection is not mentioned in the slon-main.rkt itself, but is required dynamically. So my second thought was that maybe ++lib would help. It did not. (Did I use the flag incorrectly?) $ raco exe ++lib slon/slon-language slon-main.rkt $ ./slon-main <same error message> Seeking for the solution, I upgraded from raco to the Racket level: #lang racket (require compiler/embed) (create-embedding-executable "slon-main" #:modules '((#f slon/slon-main) (#f slon/slon-language)) #:literal-expression (parameterize ([current-namespace (make-base-namespace)]) (compile `(namespace-require 'slon/slon-main))) #:configure-via-first-module? #t #:verbose? #t) That worked great. "slon-main" was able to run independently of its own location in the file system, and indenendeltly of the presence of the original files in the slon/ collection on disk. But there was another thing. In my implementation, I have some binary data files that are loaded via (define-runtime-path eop.era "../eop/eop.era") The resulting program depended on those files. When I renamed one of them, I got an error message: $ ./slon-main with-input-from-file: cannot open input file path: /home/dpavlov/era/slon/../eop/eop.era "OK", I thought, "raco distribute is supposed to fix that". $ raco distribute slon-distr slon-main $ ls ./slon-distr/lib/plt/slon-main/exts/ert/home/dpavlov/era/eop/ eop.era $ ./slon-distr/bin/slon-main standard-module-name-resolver: collection not found collection: "slon" in collection directories: /home/dpavlov/.racket/5.3.4/collects /home/dpavlov/era/slon/slon-distr/lib/plt/slon-main/collects The executable "slon-main" produced by raco distrubute is different from the original one (although the size is the same). I guess, raco distribute have eliminated the dependency of the binary files with absolute paths, but it reintroduced the dependency on the "slon" collection, which I previously got rid of with the help of (create-embedding-executable)! And here I am stuck, asking for help. Regards, Dmitry On 09/13/2013 05:33 AM, Matthew Flatt wrote:
I'm not sure I understand what you want, but here are some ideas about evaluating a text that would a module if only a "#lang" line were added. To start, here's a function to `require` an input port that contains a module's source. It uses the current namespace, and it gensyms a name for the module if you don't provide one. The part that I think is least obvious is using `current-module-declare-name` to set the name of the module to that it can be found by `dynamic-require`: (require syntax/modread) (define (require-input-port p [name (gensym)]) (define module-name (make-resolved-module-path name)) (parameterize ([current-module-declare-name module-name]) (eval-syntax (check-module-form ; ensures that `module` is bound (with-module-reading-parameterization (lambda () (read-syntax (object-name p) p))) 'ignored #f))) (dynamic-require module-name #f)) The `require-input-port` function assumes that the source starts with "#lang". You could use `input-port-append`, as others have suggested, to add a "#lang" line: (define p (input-port-append #t (open-input-string "#lang racket/base\n") (open-input-file "body.rktd"))) (port-count-lines! p) (require-input-port p) A problem with `input-port-append` is that line numbers are off by one for error reporting, and positions are off by the length of the first line. That's an annoyingly difficult problem to fix, but `prefix-input-port` below is my attempt (and maybe `input-port-append` should just work better along similar lines). (define p (prefix-input-port #"#lang racket/base\n" (open-input-file "body.rktd"))) (port-count-lines! p) (require-input-port p) ---------------------------------------- ;; prefix-input-port : bytes input-port -> input-port ;; Directs position requests to the given port after the ;; prefix is read. ;; Closes the given input port when the result port is closed. (define (prefix-input-port prefix base-p) (define-values (prefix-i prefix-o) (make-pipe)) (write-bytes prefix prefix-o) (close-output-port prefix-o) (define (prefix-done?) (zero? (pipe-content-length prefix-i))) (make-input-port (object-name base-p) ;; read (lambda (bstr) (define n (read-bytes-avail!* bstr (if (prefix-done?) base-p prefix-i))) (if (equal? n 0) (wrap-evt base-p (lambda (v) 0)) n)) ;; peek (lambda (bstr offset evt) (define pre-n (pipe-content-length prefix-i)) (define n (if (offset . >= . pre-n) (peek-bytes-avail!* bstr (- offset pre-n) #f base-p) (peek-bytes-avail!* bstr offset #f prefix-i))) (if (equal? n 0) (wrap-evt base-p (lambda (v) 0)) n)) ;; close (lambda () (close-input-port base-p)) ;; get-progress-evt ;; Difficult (impossible?) to support at the ;; prefix--base boundary. #f ;; commit #f ;; get-location (lambda () (if (prefix-done?) (port-next-location base-p) (port-next-location prefix-i))) ;; count-lines! (lambda () (port-count-lines! prefix-i) (port-count-lines! base-p))))
____________________ Racket Users list: http://lists.racket-lang.org/users