Hi Paulo, Some of your problems come from working with filesystem paths, instead of module paths. That's a problem because the deployment filesystem isn't necessarily anything like the build filesystem, and you have to do work to manage the difference. The simplest solution is to write things in terms of module paths, instead, using `define-runtime-module-path-index`:
driver.rkt ---------------------------------------- #lang racket (require racket/runtime-path) (unless (getenv "ARCH") (raise-user-error 'driver "Please define ARCH with suitable path")) (define-runtime-module-path-index arm-name "archs/arm/name.rkt") (define-runtime-module-path-index intel-name "archs/intel/name.rkt") (define arch-path (getenv "ARCH")) (define arch-name-path (case arch-path [("archs/arm") arm-name] [("archs/intel") intel-name] [else (error 'driver "unknown ~s" arch-path)])) (module+ main (define arch-proc (dynamic-require arch-name-path 'get-arch)) (printf "loading arch ~a~n" (arch-proc))) ---------------------------------------- To include only support for a module specified at build time: driver.rkt ---------------------------------------- #lang racket (require racket/runtime-path) (define-runtime-module-path-index arch-name-path (case (getenv "ARCH") [(#f) (raise-user-error 'driver "Please define ARCH with suitable path")] [("archs/arm") "archs/arm/name.rkt"] [("archs/intel") "archs/intel/name.rkt"] [else (error 'driver "unknown")])) (module+ main (define arch-proc (dynamic-require arch-name-path 'get-arch)) (printf "loading arch ~a~n" (arch-proc))) ---------------------------------------- That second strategy still expects "ARCH" to be defined at run time, and it only work if the definition is the same at both times. As you say, you could have a macro expand to the result of `(getenv "ARCH")` to pin it down at compile time, but you'll need to import that macro into two phases, since the right-hand side of `define-runtime-module-path-index` is implicitly used at two phases. Or just use the first strategy if you don't mind including support for all architectures in all builds. With either of these "driver.rkt" variants, you should drop the "archs/X/name.rkt" items from the `#:modules` argument of `create-embedding-executable`, because using `define-runtime-module-path-index` makes the dependency visible to the embedder. In fact, leaving them in `#:modules` creates a problem: #:modules (list (list #f '(file "driver.rkt")) ;; module name is 'name: (list #f '(file "archs/intel/name.rkt")) ;; module name is also 'name: (list #f '(file "archs/arm/name.rkt"))) Unfortunately, the embedder doesn't currently notice that you have asked for two modules that will both be called 'name, so it effectively picks one at random. That answers your question about prefixing: you could use different prefixes to give the modules different names. But using `define-runtime-module-path-index` saves you from this problem (and, as it happens, some other problems). Meanwhile, running `bin/prog` doesn't do anything, because your `create-embedding-executable` uses `namespace-require` to start the module "driver.rkt", but your program starts through the `main` submodule of "driver.rkt". Unlike specifying a module path on the command line of `racket`, giving a module path to `namespace-require` does not automatically do anything with the `main` submodule. So, you need to embed the `main` submodule and explicitly require it: ;; in "build.rkt": (create-embedding-executable "prog" #:verbose? #t #:modules (list (list #f "driver.rkt" '(main))) ; <<< #:configure-via-first-module? #t #:literal-expression (parameterize ([current-namespace (make-base-namespace)]) (compile `(begin (namespace-require '(submod 'driver main))))) ; <<<< #:cmdline (list "-U" "--")) Finally, you ask about that `#:literal-expression` argument. Note that the namespace is created at build time to get the argument for `literal-expression`, not at run time for the generated executable. That build-time namespace is used to compile the `namespace-require` form to bytecode, so that no macro expansion and compilation needs to happen at run time to get your program running. Compiled to using `require`, using `namespace-require` compiles to lighter code with fewer dependencies. Matthew At Wed, 12 Sep 2018 10:46:23 +0200, "'Paulo Matos' via Racket Users" wrote: > Hi, > > I am trying to create racket distribution for my application, except I > am tripping on my first few steps - that of generating the binary. > > First, the architecture of the application. There is a driver program > that is configured with a backend at run-time (although one can argue > this should be a compile time configuration - happy to change that). > > The configuration that matches the driver to the backend is an > environment relative path - which is then used to dynamic-require the > backend. > > The tree looks like: > > `|- info.rkt > |- driver.rkt > |- build.rkt > | > `-archs > |- intel > | `- name.rkt > `- arm > `- name.rkt > > info.rkt: > #lang info > > (define collection 'multi) > ;------------------------ > > > driver.rkt: > > #lang racket > > (unless (getenv "ARCH") > (raise-user-error 'driver "Please define ARCH with suitable path")) > > (define arch-path (getenv "ARCH")) > (define arch-name-path > (build-path arch-path "name.rkt")) > > (module+ main > > (define arch-proc > (dynamic-require arch-name-path > 'get-arch)) > (printf "loading arch ~a~n" (arch-proc))) > ;------------------------ > > archs/intel/name.rkt > > #lang racket > > (provide get-arch) > > (define (get-arch) > (if (fixnum? (expt 2 32)) > 'x86_64 > 'i386)) > ;------------------------ > > archs/arm/name.rkt > > > #lang racket > > (provide get-arch) > > ;; Support for 32bits arm only > (define (get-arch) > 'arm32) > > > So far so good. > $ raco pkg install --link --auto > $ ARCH=archs/intel racket driver.rkt > loading arch x86_64 > $ ARCH=archs/arm racket driver.rkt > loading arch arm32 > > Not, I try to create an executable using raco exe: > $ mkdir bin > $ raco exe ++lib archs/intel/name.rkt ++lib archs/arm/name.rkt -o > bin/r-prog driver.rkt > $ ARCH=archs/intel bin/r-prog > loading arch x86_64 > $ cd bin > $ ARCH=archs/intel ./r-prog > open-input-file: cannot open module file > module path: /home/pmatos/tmp/racket-distro/bin/archs/intel/name.rkt > > This doesn't work but it's understandable. However, if only I could > replicate this behaviour in a build script using > create-embedding-executable: > > build.rkt: > > #lang racket > > (require compiler/embed) > > (create-embedding-executable > "prog" > #:verbose? #t > #:modules (list (list #f '(file "driver.rkt")) > (list #f '(file "archs/intel/name.rkt")) > (list #f '(file "archs/arm/name.rkt"))) > #:configure-via-first-module? #t > #:literal-expression > (parameterize ([current-namespace (make-base-namespace)]) > (compile > `(begin > (namespace-require ''driver)))) > #:cmdline (list "-U" "--")) > > (make-directory* "bin") > (delete-directory/files "bin/prog" #:must-exist? #f) > (copy-directory/files "prog" "bin/prog") > (delete-directory/files "prog") > > > $ ARCH=archs/intel bin/prog > > This finishes successfully and returns nothing which makes me think that > nothing is being executed. This is slightly different from the error I > initially had but I am quite lost with the inner workings of > create-embedding-executable and am using examples online to guide me > which are few and don't really deal exactly with the kind of program I > am trying to compile. > > At this point I have a few questions: > 1. It is still not clear what the first element in each sublist in > #:modules exactly represents. I understand that it is related to a > module prefix but I don't understand how any value besides #f is useful. > The example in the docs has #f so I used that. Can someone clarify the > usefulness of having a prefix or #t? > 2. All examples I have seen create a new namespace in literal-expression > and then use namespace-require. Why can't I just do (require ...) in the > literal-expression? > 3. I will have some problems once I got the basics to work with paths. I > assume the solution is define-runtime-path. > > I tried > (define-runtime-path arch-path (getenv "ARCH")) > > but this will, I think, evaluate the value at both compile time and > runtime which means I will potentially get two different values for > arch-path depending if I am compiling or executing. This also means I am > moving the backend configuration to compile time which is ok but how can > I get the variable at compile time, and then cache that for use at runtime? > > I tried > (define-for-syntax foo (getenv "FOO")) > (define-runtime-path p (build-path foo "name.rkt")) > > but this will tell me foo is not available at runtime, so I sort of need > to move the compile-time value to runtime. Maybe I am over-complicating > this though so I am happy to hear some comments on this. > > Kind regards, > > -- > Paulo Matos -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.