Compiled code can't evaluate variables in a different environment.
Evaluating variables in a different environment only works in interpreter mode. Compiled code can't evaluate variables in a different environment using eval.
Can you give an example of what you mean? See https://cisco.github.io/ChezScheme/csug9.5/system.html#./system:s38 for details on Chez Scheme's eval function that takes an optional environment argument.

This is what happens when trying to build a boot file:

This isn't the same error I've had working with Chez. The error I've encountered is eval will throw an unbound variable exception. This is how I'm building:
(generate-wpo-files #t)
(compile-imported-libraries #t)
(compile-program "hello.ss")
(compile-whole-program "hello.wpo" "hello.cwp")
(strip-fasl-file "hello.cwp" "hello.cwp"
(fasl-strip-options inspector-source
source-annotations
profile-source))
(make-boot-file "hello.boot" '("scheme" "petite") "hello.cwp")
Try adding (expand '(import (n))) to hello.ss before calling eval. This will load the compile-time information for library (n).
If you do (eval '(import (n)), then the variable binding will be available in the interaction environment, and you can use (eval 'var).
I tried expand but eval still can't find the library. I'm not sure under what conditions eval will throw an exception but, I think I still have code that will produce this in Chez in my archive and, if I can find it I'll try to see how I did that.
There's also Chez specific procedures for working with env which also share similar problems. https://cisco.github.io/ChezScheme/csug9.5/binding.html#./binding:h5
I had a look at the code that produced the unbound variable exception and, it doesn't do this in newer versions of Chez. It gives a similar "library not found" exception.
Would you please zip up all the files you've used to demonstrate the trouble and attach to this issue so that I can reproduce the behavior?
Thanks for sharing the zip @swatson555, there are actually a few issues you're running into here.
-
compile-whole-programdoes not preserve the library entry points like(n)unless you specifylibs-visible?as#tin the(compile-whole-program input-filename output-filename libs-visible?)version of the call. Generally, this information is not needed at run time, unless you want to use the library explicitly ineval(as in your example) orenvironment. You can read more about that in Section 12.4 of the Chez Scheme User's Guide. - When
hello.ssis compiled,(n)is not identified as a dependency because it is not imported and nothing in the library is referenced. You can see this actually, when you runbuild.ssbecause it never even tries to compile(n)whencompile-programis invoked, even though thecompile-imported-librariesparameter is set to#t. When the output is executed theevalwill cause scheme to look for your library (and compile it if necessary, which in this case it is). You can see this by enablingimport-notifyand usingload-programto load thehello.cwpprogram file:
% scheme
Chez Scheme Version 9.5.5
Copyright 1984-2020 Cisco Systems, Inc.
> (import-notify #t)
> (load-program "hello.cwp")
import: did not find source file "n.chezscheme.sls"
import: did not find source file "n.ss"
import: did not find source file "n.sls"
import: did not find source file "n.scm"
import: did not find source file "n.sch"
import: did not find object file "n.chezscheme.so"
import: did not find object file "n.so"
Exception in environment: library (n) not found
Type (debug) to enter the debugger.
>
If we extend the library-directories to include lib, it will find the file, and run the program correctly (though not the boot file---perhaps @burgerrg has some insight on that part).
[akeep@hawkeye hello-2]% scheme
Chez Scheme Version 9.5.5
Copyright 1984-2020 Cisco Systems, Inc.
> (import-notify #t)
> (library-directories (cons "lib" (library-directories)))
> (load-program "hello.cwp")
import: did not find source file "lib/n.chezscheme.sls"
import: did not find source file "lib/n.ss"
import: found source file "lib/n.sls"
import: did not find corresponding object file "lib/n.so"
import: loading source file "lib/n.sls"
Hello, World!
>
- Even if
(n)were imported, thehello.ssprogram would not record that(n)is necessary for it building, because only code that is compiled is used to determine the imports, and the code inevalis not evaluated until run time.
So, here are a few changes that can build a hello.boot that will contain (n) (recognizing that this is a little different from your original intention).
Changes to hello.ss (comments inline):
(import (chezscheme) (n)) ;; 1. add the import for (n)
(define foo var) ;; 2. reference something from (n)
(display
(eval 'var (environment '(n))))
(newline)
and changes to build.ss (comments inline):
#!/usr/bin/env scheme --script
(generate-wpo-files #t)
(compile-imported-libraries #t)
(library-directories (cons "lib" (library-directories))) ;; 1. add the "lib" directory to library-directories
(compile-program "hello.ss")
(compile-whole-program "hello.wpo" "hello.cwp" #t) ;; 2. add the _libs-visible?_ #t argument.
(strip-fasl-file "hello.cwp" "hello.cwp"
(fasl-strip-options inspector-source
source-annotations
profile-source))
(make-boot-file "hello.boot" '("scheme" "petite") "hello.cwp")
With these changes, I was able to get the following to work:
% ./build.ss
compiling hello.ss with output to hello.so
compiling lib/n.sls with output to lib/n.so
[akeep@hawkeye hello]% scheme --boot hello.boot
Hello, World!
Chez Scheme Version 9.5.5
Copyright 1984-2020 Cisco Systems, Inc.
>
Incidentally, Chez cannot compile the arguments to eval or environment in general because they can be constructed at run time.
This isn't viable work around because in the case where the name var exists in the current environment the compiler will throw an exception that there are multiple definitions of the same name.
Fortunately, naming is an easy problem to work around because R6RS allows you to rename and limit imports, so you can do something like:
(import (chezscheme) (rename (only (n) var) (var something-else)))
(define foo something-else)
And if this is being generated as the output of a macro something-else could just be a gensym (actually you could even generate a gensym and use that directly:
% scheme
Chez Scheme Version 9.5.5
Copyright 1984-2020 Cisco Systems, Inc.
> (gensym)
#{g0 mpf482drvcnazscbdytjja3wj-0}
Then rewrite to:
#!chezscheme
(import (chezscheme) (rename (only (n) var) (var #{g0 mpf482drvcnazscbdytjja3wj-
(define foo #{g0 mpf482drvcnazscbdytjja3wj-0})
The #!chezscheme is necessary to inform the reader to accept extended Chez Scheme syntax.
However, it is worth noting that you are not really getting any benefit from compile-whole-program with regards to the (n) library, since, compile-whole-program cannot inline a library you are not really using. (In your use case, if you have libraries you are using directly, you will still get the benefits of those of course.)
Since you are building a boot file, you can simply include other libraries with the program. The way to do this is to compile lib/n.sls separately (since compiling hello.ss will not cause it to be compiled otherwise), and then include it in the boot file call:
#!/usr/bin/env scheme --script
(generate-wpo-files #t)
(compile-imported-libraries #t)
(compile-program "hello.ss")
(compile-whole-program "hello.wpo" "hello.cwp")
(compile-library "lib/n.sls" "lib/n.so") ;; 1. compile any additional libraries
(strip-fasl-file "hello.cwp" "hello.cwp"
(fasl-strip-options inspector-source
source-annotations
profile-source))
;; 2. add the libraries before the program, so that they will be loaded and available in the boot file.
(make-boot-file "hello.boot" '("scheme" "petite") "lib/n.so" "hello.cwp")
This approach will work without needing to change the hello.ss code.