I need to do some computation when compiling a file and have the
result of the computation available when loading the compiled file.
something like
=============== foo.lisp
(defparameter *foo*
(eval-when (compile)
(some-intricate-function-with-important-side-effects-
returning-42))
=============== foo.lisp
so that when I load foo.lisp, *foo* will have value nil,
while if I load (compile-file "foo.lisp"), *foo* will have value 42.
(yes, I know that this eval-when is not top-level, so it should never
be evaluated by an ANSI CL; you can assume that in this case it is
evaluated, if it helps).
basically, I want the compiled file to contain the result of
compilation of the form
(defparameter *foo* 42)
thanks.
sds <···@gnu.org> writes:
> I need to do some computation when compiling a file and have the
> result of the computation available when loading the compiled file.
> something like
> =============== foo.lisp
> (defparameter *foo*
> (eval-when (compile)
> (some-intricate-function-with-important-side-effects-
> returning-42))
> =============== foo.lisp
> so that when I load foo.lisp, *foo* will have value nil,
> while if I load (compile-file "foo.lisp"), *foo* will have value 42.
> (yes, I know that this eval-when is not top-level, so it should never
> be evaluated by an ANSI CL; you can assume that in this case it is
> evaluated, if it helps).
>
> basically, I want the compiled file to contain the result of
> compilation of the form
> (defparameter *foo* 42)
Does the following do what you want?
(defparameter *foo* nil)
(eval-when (:compile-toplevel)
(defparameter *foo* (some-intricate-function...)))
--
Thomas A. Russ, USC/Information Sciences Institute
On Feb 7, 2:11 pm, ····@sevak.isi.edu (Thomas A. Russ) wrote:
> (defparameter *foo* nil)
> (eval-when (:compile-toplevel)
> (defparameter *foo* (some-intricate-function...)))
I guess I should have been more explicit.
I have a function (some-intricate-function-with-important-side-
effects)
which lives in file f1.lisp.
I want to define a macro deffoo in the same file f1.lisp so that when
I say
(deffoo foo ...)
(deffoo bar ...)
in a different file f2.lisp, the following conditions are fulfilled:
1. when f2 is compiled, (some-intricate-function-with-important-side-
effects) is called for each deffoo _once_
2. when f2.lisp is loaded, (some-intricate-function-with-important-
side-effects) is not called
3. when (compile-file-pathname "f2.lisp") is loaded, foo (and bar &c)
have the value which the intricate function returned when it was
called at compile time.
i.e., I want to be able to save the results of my compile-time
computations in the FASL file.
ideally, a compile-time-value macro would be ideal...
···@sevak.isi.edu (Thomas A. Russ) writes:
> sds <···@gnu.org> writes:
>
> > I need to do some computation when compiling a file and have the
> > result of the computation available when loading the compiled file.
> > something like
> > =============== foo.lisp
> > (defparameter *foo*
> > (eval-when (compile)
> > (some-intricate-function-with-important-side-effects-
> > returning-42))
> > =============== foo.lisp
> > so that when I load foo.lisp, *foo* will have value nil,
> > while if I load (compile-file "foo.lisp"), *foo* will have value 42.
> > (yes, I know that this eval-when is not top-level, so it should never
> > be evaluated by an ANSI CL; you can assume that in this case it is
> > evaluated, if it helps).
> >
> > basically, I want the compiled file to contain the result of
> > compilation of the form
> > (defparameter *foo* 42)
>
> Does the following do what you want?
>
> (defparameter *foo* nil)
> (eval-when (:compile-toplevel)
> (defparameter *foo* (some-intricate-function...)))
Never mind, this won't work.
The problem is that the second defparameter will only take effect in the
compile-time environment and not actually happen when the file is
loaded.
What is needed is a solution like Pascal's, where you arrange the
compile-time environment in such a way that the result gets stored in
the resulting compiled file and persists through to load time.
--
Thomas A. Russ, USC/Information Sciences Institute
In article
<····································@e6g2000prf.googlegroups.com>,
sds <···@gnu.org> wrote:
> I need to do some computation when compiling a file and have the
> result of the computation available when loading the compiled file.
> something like
> =============== foo.lisp
> (defparameter *foo*
> (eval-when (compile)
> (some-intricate-function-with-important-side-effects-
> returning-42))
> =============== foo.lisp
> so that when I load foo.lisp, *foo* will have value nil,
> while if I load (compile-file "foo.lisp"), *foo* will have value 42.
> (yes, I know that this eval-when is not top-level, so it should never
> be evaluated by an ANSI CL; you can assume that in this case it is
> evaluated, if it helps).
>
> basically, I want the compiled file to contain the result of
> compilation of the form
> (defparameter *foo* 42)
>
> thanks.
Does it have to be "compile-time"? How about "read-time":
(defparameter *foo* #.(progn (print 'read-time) (sin 17)))
On Feb 7, 12:52 pm, Rainer Joswig <······@lisp.de> wrote:
> In article
> <····································@e6g2000prf.googlegroups.com>,
>
>
>
> sds <····@gnu.org> wrote:
> > I need to do some computation when compiling a file and have the
> > result of the computation available when loading the compiled file.
> > something like
> > =============== foo.lisp
> > (defparameter *foo*
> > (eval-when (compile)
> > (some-intricate-function-with-important-side-effects-
> > returning-42))
> > =============== foo.lisp
> > so that when I load foo.lisp, *foo* will have value nil,
> > while if I load (compile-file "foo.lisp"), *foo* will have value 42.
> > (yes, I know that this eval-when is not top-level, so it should never
> > be evaluated by an ANSI CL; you can assume that in this case it is
> > evaluated, if it helps).
>
> > basically, I want the compiled file to contain the result of
> > compilation of the form
> > (defparameter *foo* 42)
>
> > thanks.
>
> Does it have to be "compile-time"? How about "read-time":
>
> (defparameter *foo* #.(progn (print 'read-time) (sin 17)))
Yes, it does have to be _compile_ time and _only_ compile time.
No, read time is NOT what I want.
Note that your code produces the same result whether loaded compiled
or not.
(this separation is not a whim, it does matter in my case).
In article
<····································@s13g2000prd.googlegroups.com>,
sds <···@gnu.org> wrote:
> On Feb 7, 12:52 pm, Rainer Joswig <······@lisp.de> wrote:
> > In article
> > <····································@e6g2000prf.googlegroups.com>,
> >
> >
> >
> > sds <····@gnu.org> wrote:
> > > I need to do some computation when compiling a file and have the
> > > result of the computation available when loading the compiled file.
> > > something like
> > > =============== foo.lisp
> > > (defparameter *foo*
> > > (eval-when (compile)
> > > (some-intricate-function-with-important-side-effects-
> > > returning-42))
> > > =============== foo.lisp
> > > so that when I load foo.lisp, *foo* will have value nil,
> > > while if I load (compile-file "foo.lisp"), *foo* will have value 42.
> > > (yes, I know that this eval-when is not top-level, so it should never
> > > be evaluated by an ANSI CL; you can assume that in this case it is
> > > evaluated, if it helps).
> >
> > > basically, I want the compiled file to contain the result of
> > > compilation of the form
> > > (defparameter *foo* 42)
> >
> > > thanks.
> >
> > Does it have to be "compile-time"? How about "read-time":
> >
> > (defparameter *foo* #.(progn (print 'read-time) (sin 17)))
>
> Yes, it does have to be _compile_ time and _only_ compile time.
> No, read time is NOT what I want.
> Note that your code produces the same result whether loaded compiled
> or not.
> (this separation is not a whim, it does matter in my case).
Sketch:
(defparameter *foo* nil)
(eval-when (:compile-toplevel)
(setf *foo* 42))
(defmacro foo ()
(when *foo*
(expt *foo* 2)))
(defparameter *bar* (foo))
On Feb 7, 1:57 pm, Rainer Joswig <······@lisp.de> wrote:
> In article
> <····································@s13g2000prd.googlegroups.com>,
>
>
>
> sds <····@gnu.org> wrote:
> > On Feb 7, 12:52 pm, Rainer Joswig <······@lisp.de> wrote:
> > > In article
> > > <····································@e6g2000prf.googlegroups.com>,
>
> > > sds <····@gnu.org> wrote:
> > > > I need to do some computation when compiling a file and have the
> > > > result of the computation available when loading the compiled file.
> > > > something like
> > > > =============== foo.lisp
> > > > (defparameter *foo*
> > > > (eval-when (compile)
> > > > (some-intricate-function-with-important-side-effects-
> > > > returning-42))
> > > > =============== foo.lisp
> > > > so that when I load foo.lisp, *foo* will have value nil,
> > > > while if I load (compile-file "foo.lisp"), *foo* will have value 42.
> > > > (yes, I know that this eval-when is not top-level, so it should never
> > > > be evaluated by an ANSI CL; you can assume that in this case it is
> > > > evaluated, if it helps).
>
> > > > basically, I want the compiled file to contain the result of
> > > > compilation of the form
> > > > (defparameter *foo* 42)
>
> > > > thanks.
>
> > > Does it have to be "compile-time"? How about "read-time":
>
> > > (defparameter *foo* #.(progn (print 'read-time) (sin 17)))
>
> > Yes, it does have to be _compile_ time and _only_ compile time.
> > No, read time is NOT what I want.
> > Note that your code produces the same result whether loaded compiled
> > or not.
> > (this separation is not a whim, it does matter in my case).
>
> Sketch:
>
> (defparameter *foo* nil)
>
> (eval-when (:compile-toplevel)
> (setf *foo* 42))
>
> (defmacro foo ()
> (when *foo*
> (expt *foo* 2)))
>
> (defparameter *bar* (foo))
yes, this is what I originally tried:
====================================================
(eval-when (compile load eval)
(defun note (n v) (format nil "~S-~S" n v)))
(defmacro defcon (n v)
`(let (s)
(eval-when (compile)
(setq s (print (note ',n ',v))))
(defparameter ,n s)))
(defcon z foo)
(print z)
====================================================
when I compile this file, "Z-FOO" is duly printed,
but when I load either compiled or the source file,
(Z NIL) is printed.
I expect (Z NIL) to be printed for the source file and
(Z "Z-FOO") for the compiled file
sds <···@gnu.org> writes:
> I need to do some computation when compiling a file and have the
> result of the computation available when loading the compiled file.
> something like
> =============== foo.lisp
> (defparameter *foo*
> (eval-when (compile)
> (some-intricate-function-with-important-side-effects-
> returning-42))
> =============== foo.lisp
> so that when I load foo.lisp, *foo* will have value nil,
> while if I load (compile-file "foo.lisp"), *foo* will have value 42.
> (yes, I know that this eval-when is not top-level, so it should never
> be evaluated by an ANSI CL; you can assume that in this case it is
> evaluated, if it helps).
>
> basically, I want the compiled file to contain the result of
> compilation of the form
> (defparameter *foo* 42)
>
C/USER[13]> (cat "compile-load-time.lisp")
(eval-when (:compile-toplevel)
(defmacro compile-time-value (expression)
(eval expression)))
(eval-when (:compile-toplevel)
(defparameter *item* 42))
(eval-when (:load-toplevel :execute)
(defparameter *item* 0))
(defparameter *foo* (compile-time-value *item*))
(defun result ()
*foo*)
C/USER[14]> (load(compile-file "compile-load-time.lisp"))
;; Compiling file /home/pjb/src/lisp/encours/compile-load-time.lisp ...
;; Wrote file /home/pjb/src/lisp/encours/compile-load-time.fas
0 errors, 0 warnings
;; Loading file /home/pjb/src/lisp/encours/compile-load-time.fas ...
;; Loaded file /home/pjb/src/lisp/encours/compile-load-time.fas
T
C/USER[15]> (result)
42
C/USER[16]> (load "compile-load-time.lisp")
;; Loading file compile-load-time.lisp ...
;; Loaded file compile-load-time.lisp
T
C/USER[17]> (result)
0
C/USER[18]> (cat "compile-load-time.fas")
(|SYSTEM|::|VERSION| '(20060802.))
#0Y |CHARSET|::|UTF-8|
#Y(#:|8 9 (EVAL-WHEN (:LOAD-TOPLEVEL :EXECUTE) (DEFPARAMETER *ITEM* 0))-3|
#20Y(00 00 00 00 00 00 00 00 00 01 DA 31 5A DB DC 31 52 C6 19 01)
((|COMMON-LISP|::|SPECIAL| |COMMON-LISP-USER|::|*ITEM*|)
|COMMON-LISP-USER|::|*ITEM*| 0.)
(|COMMON-LISP|::|T| |COMMON-LISP|::|T| |COMMON-LISP|::|T|))
#Y(#:|12 12 (DEFPARAMETER *FOO* (COMPILE-TIME-VALUE *ITEM*))-4|
#20Y(00 00 00 00 00 00 00 00 00 01 DA 31 5A DB DC 31 52 C6 19 01)
((|COMMON-LISP|::|SPECIAL| |COMMON-LISP-USER|::|*FOO*|)
|COMMON-LISP-USER|::|*FOO*| 42.) ; <-- 42, not *item*!
(|COMMON-LISP|::|T| |COMMON-LISP|::|T| |COMMON-LISP|::|T|))
#Y(#:|14 15 (DEFUN RESULT NIL ...)-5|
#20Y(00 00 00 00 00 00 00 00 00 01 DA 2F 01 DA DC 32 83 C5 19 01)
(|COMMON-LISP-USER|::|RESULT| |SYSTEM|::|REMOVE-OLD-DEFINITIONS|
#Y(|COMMON-LISP-USER|::|RESULT|
#14Y(00 00 00 00 00 00 00 00 06 01 0E 00 19 01)
(|COMMON-LISP-USER|::|*FOO*|)
(|COMMON-LISP|::|T| |COMMON-LISP|::|NIL| |COMMON-LISP|::|NIL|) ()
|COMMON-LISP|::|NIL|))
(|COMMON-LISP|::|T| |COMMON-LISP|::|T| |COMMON-LISP|::|T|))
--
__Pascal Bourguignon__ http://www.informatimago.com/
You never feed me.
Perhaps I'll sleep on your face.
That will sure show you.
On Feb 7, 2:14 pm, Pascal Bourguignon <····@informatimago.com> wrote:
>
> (eval-when (:compile-toplevel)
> (defmacro compile-time-value (expression)
> (eval expression)))
yes, compile-time-value is what I want.
I tried this:
(defmacro compile-time-value (expression)
(let ((var (gensym "COMPILE-TIME-VALUE-")))
`(let ((,var nil))
(eval-when (compile) (setq ,var (eval ,expression)))
,var)))
alas, this code does not cut it.
I need to define the macro in one file and use it in another file.
sds <···@gnu.org> writes:
> On Feb 7, 2:14 pm, Pascal Bourguignon <····@informatimago.com> wrote:
>>
>> (eval-when (:compile-toplevel)
>> (defmacro compile-time-value (expression)
>> (eval expression)))
>
> yes, compile-time-value is what I want.
> I tried this:
> (defmacro compile-time-value (expression)
> (let ((var (gensym "COMPILE-TIME-VALUE-")))
> `(let ((,var nil))
> (eval-when (compile) (setq ,var (eval ,expression)))
> ,var)))
> alas, this code does not cut it.
> I need to define the macro in one file and use it in another file.
Of course, because your macro doesn't do what mine does. Mine
evaluates the expression at macro expansion time. Your does all it can
to have expression evaluated at run-time. How could it do what you
want then?
Well my macro has a little defect. Perhaps you don't want to have the
result of expression evaluated once more as result of the macro call
(but this is exactly what you explicitely do in your macro, so I may
be wrong here...) Anyways, here is a better version. And of course,
you can put it in a different file, but you must ensure that macro is
defined at compilation time, that is, you must load that file at
compilation time at least.
C/USER[36]> (cat "compile-time-value.lisp")
(eval-when (:compile-toplevel)
(defmacro compile-time-value (expression)
(let ((result (eval expression)))
`',result)))
C/USER[37]> (cat "compile-load-time.lisp")
(eval-when (:compile-toplevel)
(load "compile-time-value.lisp"))
(eval-when (:compile-toplevel)
(defparameter *item* 42))
(eval-when (:load-toplevel :execute)
(defparameter *item* 0))
(defparameter *foo* (compile-time-value `(+ 1 ,*item*)))
(defparameter *bar* (compile-time-value (+ 1 *item*)))
(defun result ()
(list *foo* *bar*))
C/USER[38]> (load (compile-file "compile-load-time.lisp"))
;; Compiling file /home/pjb/src/lisp/encours/compile-load-time.lisp ...
;; Wrote file /home/pjb/src/lisp/encours/compile-load-time.fas
0 errors, 0 warnings
;; Loading file /home/pjb/src/lisp/encours/compile-load-time.fas ...
;; Loading file compile-time-value.lisp ...
;; Loaded file compile-time-value.lisp
;; Loaded file /home/pjb/src/lisp/encours/compile-load-time.fas
T
C/USER[39]> (result)
((+ 1 42) 43)
C/USER[40]> (load "compile-load-time.lisp")
;; Loading file compile-load-time.lisp ...
;; Loading file compile-time-value.lisp ...
;; Loaded file compile-time-value.lisp
;; Loaded file compile-load-time.lisp
T
C/USER[41]> (result)
((+ 1 0) 1)
C/USER[42]>
--
__Pascal Bourguignon__ http://www.informatimago.com/
"Do not adjust your mind, there is a fault in reality"
-- on a wall many years ago in Oxford.
On Feb 7, 5:33 pm, Pascal Bourguignon <····@informatimago.com> wrote:
thanks, now I see the light.
From: Maciej Katafiasz
Subject: Re: passing values from compile-time to load-time
Date:
Message-ID: <fog8vf$7jf$2@news.net.uni-c.dk>
Den Thu, 07 Feb 2008 23:33:15 +0100 skrev Pascal Bourguignon:
> C/USER[38]> (load (compile-file "compile-load-time.lisp"))
The function compile-time-value is undefined.
[Condition of type undefined-function]
That's what I get on SBCL 1.0.10
Cheers,
Maciej
Maciej Katafiasz <········@gmail.com> writes:
> Den Thu, 07 Feb 2008 23:33:15 +0100 skrev Pascal Bourguignon:
>
>> C/USER[38]> (load (compile-file "compile-load-time.lisp"))
>
> The function compile-time-value is undefined.
> [Condition of type undefined-function]
>
> That's what I get on SBCL 1.0.10
That's right. We need to define and load compile-time-value also in
the other situations. Adding them, it works also on implementations
with better separation of the various environments:
S/CL-USER[15]> (cat "compile-time-value.lisp")
(eval-when (:compile-toplevel :load-toplevel :execute)
(defmacro compile-time-value (expression)
(let ((result (eval expression)))
`',result)))
S/CL-USER[16]> (cat "compile-load-time.lisp")
(eval-when (:compile-toplevel :load-toplevel :execute)
(load "compile-time-value.lisp"))
(eval-when (:compile-toplevel)
(defparameter *item* 42))
(eval-when (:load-toplevel :execute)
(defparameter *item* 0))
(defparameter *foo* (compile-time-value `(+ 1 ,*item*)))
(defparameter *bar* (compile-time-value (+ 1 *item*)))
(defun result ()
(list *foo* *bar*))
S/CL-USER[17]> (load"compile-load-time.lisp")
STYLE-WARNING: redefining RESULT in DEFUN
T
S/CL-USER[18]> (result)
((+ 1 0) 1)
S/CL-USER[19]> (load(compile-file "compile-load-time.lisp"))
; compiling file "/home/pjb/src/lisp/encours/compile-load-time.lisp" (written 09 FEB 2008 01:21:04 PM):
; compiling (LOAD "compile-time-value.lisp")
; compiling (DEFPARAMETER *ITEM* ...)
; compiling (DEFPARAMETER *FOO* ...)
; compiling (DEFPARAMETER *BAR* ...)
; compiling (DEFUN RESULT ...)
; /home/pjb/src/lisp/encours/compile-load-time.fasl written
; compilation finished in 0:00:00
STYLE-WARNING: redefining RESULT in DEFUN
T
S/CL-USER[20]> (result)
((+ 1 42) 43)
S/CL-USER[21]>
--
__Pascal Bourguignon__ http://www.informatimago.com/
THIS IS A 100% MATTER PRODUCT: In the unlikely event that this
merchandise should contact antimatter in any form, a catastrophic
explosion will result.
while your code works, it does not do what was originally asked for
because the evaluation of + and ` is done at load time, not at compile/
macroexpand time.
I have an expensive function ABAZONK which returns non-trivial
results.
the request was for a file foo.lisp, so that after foo is compiled and
loaded,
the macro deffoo is defined so that if I put (deffoo bar) in file
bar.lisp,
then the following behavior is exhibited:
(load "bar.lisp")
==> bar is NIL
(compile-file "bar.lisp")
==> ABAZONK is called and the result value V is stored in the
compiled file
(load (compiled-file-filename "bar.lisp"))
==> bar is V, ABAZONK is NOT called.
again:
1. bar.lisp contains only (deffoo bar)
2. foo.lisp is compiled and loaded at all times.
3. ABAZONK is called by (compile-file "bar.lisp")
4. ABAZONK is NOT called by (load (compiled-file-filename "bar.lisp"))
On Feb 9, 7:22 am, Pascal Bourguignon <····@informatimago.com> wrote:
> Maciej Katafiasz <········@gmail.com> writes:
> > Den Thu, 07 Feb 2008 23:33:15 +0100 skrev Pascal Bourguignon:
>
> >> C/USER[38]> (load (compile-file "compile-load-time.lisp"))
>
> > The function compile-time-value is undefined.
> > [Condition of type undefined-function]
>
> > That's what I get on SBCL 1.0.10
>
> That's right. We need to define and load compile-time-value also in
> the other situations. Adding them, it works also on implementations
> with better separation of the various environments:
>
> S/CL-USER[15]> (cat "compile-time-value.lisp")
> (eval-when (:compile-toplevel :load-toplevel :execute)
> (defmacro compile-time-value (expression)
> (let ((result (eval expression)))
> `',result)))
>
> S/CL-USER[16]> (cat "compile-load-time.lisp")
> (eval-when (:compile-toplevel :load-toplevel :execute)
> (load "compile-time-value.lisp"))
>
> (eval-when (:compile-toplevel)
> (defparameter *item* 42))
> (eval-when (:load-toplevel :execute)
> (defparameter *item* 0))
>
> (defparameter *foo* (compile-time-value `(+ 1 ,*item*)))
> (defparameter *bar* (compile-time-value (+ 1 *item*)))
>
> (defun result ()
> (list *foo* *bar*))
>
> S/CL-USER[17]> (load"compile-load-time.lisp")
> STYLE-WARNING: redefining RESULT in DEFUN
>
> T
>
> S/CL-USER[18]> (result)
>
> ((+ 1 0) 1)
* sds Wrote on Fri, 15 Feb 2008 07:39:06 -0800 (PST):
| I have an expensive function ABAZONK which returns non-trivial
| results. the request was for a file foo.lisp, so that after foo is
| compiled and loaded, the macro deffoo is defined so that if I put
| (deffoo bar) in file bar.lisp, then the following behavior is
| exhibited:
|
| (load "bar.lisp")
| ==> bar is NIL
| (compile-file "bar.lisp")
| ==> ABAZONK is called and the result value V is stored in the
| compiled file
| (load (compiled-file-filename "bar.lisp"))
| ==> bar is V, ABAZONK is NOT called.
|
| again:
| 1. bar.lisp contains only (deffoo bar)
| 2. foo.lisp is compiled and loaded at all times.
| 3. ABAZONK is called by (compile-file "bar.lisp")
| 4. ABAZONK is NOT called by (load (compiled-file-filename "bar.lisp"))
You missed out a case but from your example. I understand
5. ABAZONK is NOT called by (load "bar.lisp") bar is NIL.
Now the problem is you have two conflicting requirements:
1. you want to put literal data into the fasl file.
2. you want the literal data to be evaluated ONLY when the fasl file is
generated.
However as you are not averse to EVAL, And Pascal B. has already
outlined how to wrap it up. It is just a matter of getting it correct,
here is one way of doing it, (only lightly tested) --
$ cat foo.lisp
(defvar *compile-time-value-definer* nil)
(defmacro deffoo (var expr)
`(progn
(defvar ,var nil)
(setq *compile-time-value-definer* nil)
(eval-when (:compile-toplevel)
(setq *compile-time-value-definer*
`(setq ,',var ',(eval ',expr))))
(eval-when (:compile-toplevel :load-toplevel :execute)
(macrolet ((define-compile-time-value ()
*compile-time-value-definer*))
(eval-when (:load-toplevel :execute)
(define-compile-time-value))))))
$ cat bar.lisp
(deffoo *foo* (abazonk))
Doesnt this not meet the requirements above ?
--
Madhu
PS: it is much easier to get the effect you desire if you de-conflate
the issue with CL's load eval compile and macroexpansion times
On Feb 16, 11:14 am, Madhu <·······@meer.net> wrote:
> *sdsWrote on Fri, 15 Feb 2008 07:39:06 -0800 (PST):
>
> | I have an expensive function ABAZONK which returns non-trivial
> | results. the request was for a file foo.lisp, so that after foo is
> | compiled and loaded, the macro deffoo is defined so that if I put
> | (deffoo bar) in file bar.lisp, then the following behavior is
> | exhibited:
> |
> | (load "bar.lisp")
> | ==> bar is NIL
> | (compile-file "bar.lisp")
> | ==> ABAZONK is called and the result value V is stored in the
> | compiled file
> | (load (compiled-file-filename "bar.lisp"))
> | ==> bar is V, ABAZONK is NOT called.
> |
> | again:
> | 1. bar.lisp contains only (deffoo bar)
> | 2. foo.lisp is compiled and loaded at all times.
> | 3. ABAZONK is called by (compile-file "bar.lisp")
> | 4. ABAZONK is NOT called by (load (compiled-file-filename "bar.lisp"))
>
> You missed out a case but from your example. I understand
>
> 5. ABAZONK is NOT called by (load "bar.lisp") bar is NIL.
yes.
> Now the problem is you have two conflicting requirements:
>
> 1. you want to put literal data into the fasl file.
> 2. you want the literal data to be evaluated ONLY when the fasl file is
> generated.
where is the conflict?
I do want literal data in the fasl file,
but I don't care when the literal data is evaluated (to itself).
the main requirement is that abazonk is NOT called during bar.lisp
loading.
> $ cat foo.lisp
>
> (defvar *compile-time-value-definer* nil)
> (defmacro deffoo (var expr)
> `(progn
> (defvar ,var nil)
> (setq *compile-time-value-definer* nil)
> (eval-when (:compile-toplevel)
> (setq *compile-time-value-definer*
> `(setq ,',var ',(eval ',expr))))
> (eval-when (:compile-toplevel :load-toplevel :execute)
> (macrolet ((define-compile-time-value ()
> *compile-time-value-definer*))
> (eval-when (:load-toplevel :execute)
> (define-compile-time-value))))))
>
> $ cat bar.lisp
> (deffoo *foo* (abazonk))
>
> Doesnt this not meet the requirements above ?
yes, this appears to work.
thanks.
I don't like the global variable though,
so I think I will be using the following:
(defmacro compile-time-value (expression)
(let ((result (gensym "COMPILE-TIME-VALUE-")))
`(let ((,result nil))
(declare (special ,result))
(eval-when (compile)
(setq ,result `',(eval ',expression)))
(eval-when (compile load eval)
(macrolet ((ctv () ,result))
(eval-when (load eval) (ctv)))))))
(this works in clisp, see http://clisp.cons.org/impnotes/eval-comp.html#eval-when)
sds <···@gnu.org> writes:
> while your code works, it does not do what was originally asked for
> because the evaluation of + and ` is done at load time, not at compile/
> macroexpand time.
>
> I have an expensive function ABAZONK which returns non-trivial
> results.
> the request was for a file foo.lisp, so that after foo is compiled and
> loaded,
> the macro deffoo is defined so that if I put (deffoo bar) in file
> bar.lisp,
> then the following behavior is exhibited:
>
> (load "bar.lisp")
> ==> bar is NIL
> (compile-file "bar.lisp")
> ==> ABAZONK is called and the result value V is stored in the
> compiled file
> (load (compiled-file-filename "bar.lisp"))
> ==> bar is V, ABAZONK is NOT called.
Well, I'm beginning to think that what you're asking is impossible, in
portable Common Lisp. ( But read on ;-) )
When a macro is executing, the situation is :EXECUTE.
If some file is being LOADed, *LOAD-PATHNAME* is true.
If some file is begin COMPILE-FILEd, *COMPILE-FILE-PATHNAME* is true.
But both may be true at the same time when the macro is :EXECUTEing.
For example, with a macro such as the following, in a file named
compile-time-value.lisp:
(defmacro compile-time-value (expression)
(declare (ignorable expression))
(eval-when (:load-toplevel) (print :load-toplevel))
(eval-when (:compile-toplevel) (print :compile-toplevel))
(eval-when (:execute) (print :execute))
(print '(|#.*LOAD-PATHNAME*| #.*LOAD-PATHNAME*))
(print '(|#.*COMPILE-FILE-PATHNAME*| #.*COMPILE-FILE-PATHNAME*))
(print `(*LOAD-PATHNAME* ,*LOAD-PATHNAME*))
(print `(*COMPILE-FILE-PATHNAME* ,*COMPILE-FILE-PATHNAME*))
'nil)
you may get this:
:EXECUTE
(|#.*LOAD-PATHNAME*| NIL)
(|#.*COMPILE-FILE-PATHNAME*| #P"/home/pjb/src/lisp/encours/compile-time-value/compile-time-value.lisp")
(*LOAD-PATHNAME* #P"/home/pjb/src/lisp/encours/compile-time-value/bar.lisp")
(*COMPILE-FILE-PATHNAME* #P"/home/pjb/src/lisp/encours/compile-time-value/foo.lisp")
The question here is: are we loading bar.lisp while compiling
foo.lisp, or are we compiling foo.lisp while loading bar.lisp?
What time is it?
There are five different times in Common Lisp, but the point here is
that they can mix indiscriminately: you can load while you compile
while you read while you macroexpand while you run a program, etc.
To know, we would have to scan the backtrace, and this is
implementation dependant.
With EVAL-WHEN, you can write:
(eval-when (:compile-toplevel)
(defparameter *bar* (abazonk)))
(eval-when (:load-toplevel :execute)
(defparameter *bar* nil))
but of course it's not possible this way to magically have the value
returned by ABAZONK assigned to the _other_ *BAR*, which will live in
the run-time environment. And of course, EVAL-WHEN :COMPILE-TOPLEVEL
doesn't work when it's not a top-level form.
You could write something like:
(defvar *bar*)
(eval-when (:compile-toplevel)
(let ((big-data (abazonk)))
(with-open-file (out "big.data" :direction :output)
(print big-data out)))
(setf *bar* nil))
(eval-when (:load-toplevel :execute)
(setf *bar* (with-open-file (inp "big.data")
(read inp))))
but I feel that we're mixing two different time orders: the various
lisp times, and your own time. You may want to pre-compute this data,
at some specific date, while using it later, when executing some other
lisp program. It does not really matter that this data is precomputed
at :COMPILE-TIME or at :EXECUTE time.
Just use two programs:
---(precompute.lisp)------------------------------
(let ((big-data (abazonk)))
(with-open-file (out "big.data" :direction :output)
(print big-data out)))
--------------------------------------------------
and:
---(use.lisp)-------------------------------------
(defparameter *bar* (with-open-file (inp "big.data")
(read inp)))
--------------------------------------------------
or, if you want to copy the data into the compiled file:
---(use.lisp)-------------------------------------
(defparameter *bar* '#.(with-open-file (inp "big.data")
(read inp)))
--------------------------------------------------
Note that the data is actually loaded at read time, which is included
in load time: *bar* will take its value when you (load "use.lisp")
too.
If you insist on a solution with a macro, then you should accept to
compute the value when loading the source:
---(bar.lisp)-------------------------------------
(defmacro define-variable-with-macroexpansion-time-value
(name expression &optional docstring)
`(defparameter ,name ',(eval expression) ,docstring))
(define-variable-with-macroexpansion-time-value *bar*
(abazonk)
"The value of this variable is computed at compilation time.")
--------------------------------------------------
C/USER[89]> (load"bar.lisp")
;; Loading file bar.lisp ...
(COMPUTING ABAZONK)
(COMPLETED ABAZONK)
;; Loaded file bar.lisp
T
C/USER[90]> (compile-file"bar.lisp")
;; Compiling file /home/pjb/src/lisp/encours/compile-time-value/bar.lisp ...
(COMPUTING ABAZONK)
(COMPLETED ABAZONK)
;; Wrote file /home/pjb/src/lisp/encours/compile-time-value/bar.fas
0 errors, 0 warnings
#P"/home/pjb/src/lisp/encours/compile-time-value/bar.fas" ;
NIL ;
NIL
C/USER[91]> (load"bar.fas")
;; Loading file bar.fas ...
;; Loaded file bar.fas
T
C/USER[92]> *bar*
V
C/USER[93]>
The point here is that CL tries as much as it can to enforce the same
semantics on interpreted code as on compiled code. Time of execution
is only a side effect that is irrelevant here.
You can just avoid to (load "bar.lisp"), or use an implementation that
always compiles, like sbcl.
Finally, with a file such as:
----(bar.lisp)------------------------------------
(defparameter *bar* (quote #.(when *compile-file-pathname*
(abazonk))))
--------------------------------------------------
it appears to work as you want:
C/USER[107]> (load "bar.lisp")
;; Loading file bar.lisp ...
;; Loaded file bar.lisp
T
C/USER[108]> *bar*
NIL
C/USER[109]> (compile-file "bar.lisp")
;; Compiling file /home/pjb/src/lisp/encours/compile-time-value/bar.lisp ...
(COMPUTING ABAZONK)
(COMPLETED ABAZONK)
;; Wrote file /home/pjb/src/lisp/encours/compile-time-value/bar.fas
0 errors, 0 warnings
#P"/home/pjb/src/lisp/encours/compile-time-value/bar.fas" ;
NIL ;
NIL
C/USER[110]> *bar*
NIL
C/USER[111]> (load "bar.fas")
;; Loading file bar.fas ...
;; Loaded file bar.fas
T
C/USER[112]> *bar*
V
C/USER[113]>
But of course, you'll be surprized when you LOAD this file:
---(foo.lisp)-------------------------------------
(compile-file "bar.lisp")
--------------------------------------------------
and even more, when you COMPILE-FILE this one:
---(baz.lisp)-------------------------------------
(eval-when (:compile-toplevel)
(load "bar.lisp"))
--------------------------------------------------
--
__Pascal Bourguignon__ http://www.informatimago.com/
"Logiciels libres : nourris au code source sans farine animale."
On Feb 7, 6:21 pm, sds <····@gnu.org> wrote:
> basically, I want the compiled file to contain the result of
> compilation of the form
> (defparameter *foo* 42)
>
> thanks.
Macro-expansion time is a very close approximation of compile-time.
Have a macro expand to the literal value you want, eg:
(defmacro value-from-db-at-compile-time ()
(with-db-connection ()
(let ((value (some-query)))
`(quote ,value))))
(defparameter *foo* (value-from-db-at-compile-time))