Compilation of a file as if its contents were in specified package - compilation

I've written a sort of DSL on top of Common Lisp. The domain is quite strange and my language looks quite different from Common Lisp itself. I've put all interface into a package foo:
(defpackage :foo
(:use :common-lisp
:internal-machinery)
(:shadow :in-package
:*packages*))
Switching between packages is beyond of the language concept, so I've disabled this ability by shadowing symbols in-package and *package*. Now user (programmer) of my language will be unable to switch packages. Fine.
Obviously, I want to use Common Lisp compiler to compile programs written in this language. Function compile-file looks OK for me. But there are difficulties.
I want to compile a file as if its contents were inside of my foo package. Putting (in-package :foo) on top of every program in my prototypical language is an undesirable option.
To make things even worse, I have to compile a file inside of a function:
(in-package :internal-machinery)
(defun compile-stuff (filename)
(in-package :foo) ; it will have no effect, because
; this macro must be top level form
(compile-file filename) ; other options are omitted
(in-package :internal-machinery)) ; no way, even if it were top level
; form, in-package is shadowed
I have no idea if it's possible or not, so any help would be appreciated.

How about
(defun compile-stuff (filename)
(let ((*package* (find-package '#:foo)))
(compile-file filename)))
PS. As Rainer mentioned in a comment, if you offer REPL to the user, you are not safe from the user changing the package with (cl:in-package "CL-USER").

Related

How to compile multiple Chicken Scheme files?

I need to compile a Chicken Scheme project containing multiple source files, but I'm getting errors.
According to the manual and this SO answer, I need to put (declare)s in my sources. Why the compiler can't just see that I'm importing the other source is beyond me, but meh.
The problem is, even if I put the (declare)s in, the compiler complains about the (import)s and (use)s.
infinity.filesystem.scm:
(use bindings filepath posix)
(declare (uses infinity.general.scm))
(load-relative "infinity.general.scm")
(module infinity.filesystem (with-open-file make-absolute-path with-temporary-directory with-chdir)
(import scheme filepath posix infinity.general)
(begin-for-syntax
(use bindings chicken)
(import infinity.general))
...etc...
infinity.general.scm:
(declare (unit infinity.general.scm))
(require-extension srfi-1 srfi-13 format data-structures ansi-escape-sequences basic-sequences)
(module infinity.general (bind+ format-ansi repeat-string join-strings pop-chars! inc! dec!
take* drop* take-right* drop-right* ends-with? take-where)
(import scheme chicken srfi-1 srfi-13 data-structures ansi-escape-sequences basic-sequences bindings ports format)
...etc...
Command:
$ csc -uses bindings.o -uses infinity.general.o -c infinity.filesystem.scm -o infinity.filesystem.o
Compiler says:
Syntax error (import): cannot import from undefined module
and
unbound variable: use
If I just remove the import and use declarations for "infinity.general", the file compiles. However, I have two problems with this:
Will the resulting .o file actually work, in the absence of import and use clauses? Or will it complain about missing code at runtime?
csi requires that my code contains (import) and (use) declarations, whereas csc requires that it does not. I, however, require that my code works in both csi and csc!
How can I solve this, please?
Why the compiler can't just see that I'm importing the other source is beyond me, but meh.
Declares are used to determine dependencies: the compiler needs to know in what order (and if at all) to invoke a particular toplevel, to ensure the right code is initialized before any of the globals from that unit can be used. When everything is being compiled separately, the compiler wouldn't know when to insert calls to toplevels. The -uses switch you pass to csc is redundant: csc -uses foo is equivalent to putting (declare (uses foo)) in the source code. Passing -uses foo.o doesn't do anything with the file foo.o as far as I can tell.
In your code snippet, you're using load, which is not the correct way to include code at compile-time: load will read and evaluate the target file at run time. Instead, you should omit the load completely: the declare already takes care of the dependency; you just need to link them together.
Also, it's not very common to use filenames as module/unit names, though it should work.
If I just remove the import and use declarations for "infinity.general", the file compiles. However, I have two problems with this:
1) Will the resulting .o file actually work, in the absence of import and use clauses? Or will it complain about missing code at runtime?
You'll need to keep the import expressions, or the program shouldn't compile. If it does compile, there's something strange going on. You don't need use when you link everything together statically. If you're using dynamic linking, you will get a runtime error.
The error you get about unbound variable: use is because you're using use in a begin-for-syntax block. You'll probably just need to (import-for-syntax chicken), as per your other SO question.
2) csi requires that my code contains (import) and (use) declarations, whereas csc requires that it does not. I, however, require that my code works in both csi and csc!
It looks like you're approaching this too quickly: You are writing a complete program and at the same time trying to make it run compiled and interpreted, without first building an understanding of how the system works.
At this point, it's probably a good idea to experiment first with a tiny project consisting of two files. Then you can figure out how to compile an executable that works from code that also works in the interpreter. Then, use this knowledge to build the actual program. If at any point something breaks, you can always go back to the minimal case and figure out what you're doing differently.
This will also help in getting support, as you would be able to present a complete, but minimal set of files, and people will be able to tell you much quicker where you went wrong, or whether you've found a bug.

#ifndef in Common Lisp

In C, to make sure we don't re-include headers that are included we use the following structure:
#ifndef UTILS
#define UTILS
#include "my_utils.h"
#endif
I've broken my Lisp program into separate files; multiple files sometimes use the same file (e.g., my_utilities is used by multiple files). When I run the program, I get warnings that I am redefining things (calling load of the same file multiple times).
This would be fixed by doing something similar to #ifndef in C. What is the Common Lisp equivalent or standard method of doing this?
I am fairly new to Lisp. Let me know if there are best practices (perhaps, a different method of structuring my programs?) that I am missing.
The question you asked
The direct analogue of preprocessor conditions like #if in C is the
#+ read-time conditionalization facility.
The question you wanted to ask
To avoid multiple loading of a file, you can either use the standard
(but deprecated)
provide/require facility,
or an add-on system like ASDF.
For Common Lisp applications and libraries it is preferred to use a system management tool. Like ASDF or whatever your implementation may provide. A system is a collection of files with dependencies and various actions (load, compile, ...).
You can always check the state of the runtime and do something.
Example:
(unless (fboundp 'foobar)
(require "foo")
(load "bar"))
(unless (find-package 'foobar)
(require "foo")
(load "bar"))
PROVIDE and REQUIRE are built-in functions for exactly that. If you require a module it will be loaded, unless already provided. Unfortunately this functionality is underspecified in the standard, but implementations may provide useful functionality.
Common Lisp runtimes have a list of features on the list *features*. You can use that to advertise and check functionality.
Example:
In your library:
(push :cool-new-graphics-library cl:*features*)
In your application code:
(when (member :cool-new-graphics-library cl:*features*)
(funcall (find-symbol "DRAW-SPACE-SHIP" "CNGL")
:death-star))
Common Lisp provides a way to conditionalize that a read time. The following code will only be read when the :cool-new-graphics-library feature is present, and thus it only then will be executed later:
#+cool-new-graphics-library(cngl:draw-space-ship :death-star)
Common Lisp also allows you to express some logic:
#+(and lispworks cool-new-graphics-library)
(cngl:draw-space-ship :enterprise)
#-cool-new-graphics-library(warn "no cool graphics library available")
Note that you can force Lisp to execute code at compile-time:
(eval-when (:load-toplevel :compile-toplevel :execute)
#+(and lispworks cool-new-graphics-library)
(cngl:draw-space-ship :enterprise)
#-cool-new-graphics-library(warn "no cool graphics library available")
)
For this to work the EVAL-WHEN has to be at the toplevel in a file. That means it will not work deep in nested forms. It does work inside a toplevel PROGN,LOCALLY, MACROLET and SYMBOL-MACROLET, though.
Thus EVAL-WHEN allows you to run code which is part of the file which is currently compiled. This code than can look for loaded systems, provided modules, available functions, and more.

Create a library accessible from csi

Let's say I have a library foo in foo.scm like so:
(module foo (bar)
(import scheme)
(define (bar arg)
(+ 5 arg)))
And I have a program program.scm:
(use foo)
(display (bar 2))
Now, I compile foo and generate the import library using csc -J -library foo.scm, and then compile program with csc program.scm. Running program displays "7", as expected and everything is dandy. However, I want to load program interactively in the interpreter (csi), but now for some reason each call to a function in foo has to be prefixed with foo#, i.e. in the interpreter (foo#bar 2) works, but (bar 2) doesn't even though it works when used in a source file.
Why is this? Not only is this slightly annoying, I'm also afraid that I may have a misunderstanding of how the module system works in Chicken, so any clarification would be much appreciated.
I'm not sure what you mean by "load the program into the interpreter", but usually (use foo) should load and import the library, so performing (load "program.scm") should do just that, and all the things exported by foo should be available at toplevel.
It sounds like you somehow ended up with a situation where the library has been loaded into the running system, but hasn't been imported for use at toplevel. Just typing (use foo) (or even (import foo)) at the REPL should fix this problem.
CHICKEN's module system has been designed to allow for separate compilation, which makes cross-compilation possible. To make this work, the import library and actual implementation have been separated, but this complicates things a little, as you've discovered. This is needed because the import library may define macros that are needed at compile-time, so it needs to run on the cross-compiling host, whereas the library itself will need to be available in the cross-compilation target's architecture. We're discussing on how to simplify this for CHICKEN 5, as this is something that confuses many beginners (and sometimes advanced users, too).

Eval-when uses?

After reading a lot of documentation regarding Lisp eval-when operator I still can't understand its uses, I know with this operator I can control the evaluation time of my expressions but I can't figure out any example where this may be applicable ?
Best Regards,
utxeee.
Compilation of a Lisp file
Take for example the compilation of a Lisp file. The Lisp compiler processes the top-level forms. These can be arbitrary Lisp forms, DEFUNs, DEFMACROS, DEFCLASS, function calls,...
The whole story how the file compiler works is too complex to explain here, but a few things:
the file compiler generates code for a (DEFUN foo () ) form. But it does not execute the defun form. Thus during compilation it is known that there is a function FOO, but the code of ˋFOOˋ is not available during the compilation. The compiler generates the code for the compiled file, but does not keep it in memory. You can't call such a function at compile time.
for macros this works slightly different: (DEFMACRO BAZ ...). The file compiler will not only compile the macro and note that it is there, but it will also make the macro available at compilation time. It is loaded into the compiler environment.
Thus imagine the sequence of forms in a file:
(defmacro baz ...)
(defun foo () (baz ...))
This works because the file compiler knows the macro BAZ and when it compiles the code for FOO, then it can expand the macro form.
Now let's look at the following example:
(defun bar (form) ...)
(defmacro baz (form) (bar form))
(defun foo () (baz ...))
Above will not work. Now the macro BAZ uses the function BAR by calling it. When the compiler tries to compile the function FOO, it can't expand the BAZ macro, because BAR can't be called, because the code of BAR is not loaded into the compile-time environment.
There are two solutions to this:
compile and load BAR earlier using a separate file.
Use EVAL-WHEN
Example for EVAL-WHEN:
(eval-when (:compile-toplevel :execute :load-toplevel)
(defun bar (form) ...)
)
(defmacro baz (form) (bar form))
(defun foo () (baz ...))
Now the EVAL-WHEN instructs the file compiler to actually run the DEFUN form during compilation. The effect of this is: the file compiler now knows the definition of BAR at compile time. Thus it is available later, when the file compiler need to call BAR during macro expansion of the usage of BAZ.
One could use only :compile-toplevel, when the function would not be needed after the compilation of the file. If it is used later, then we need to make sure that it gets loaded.
So EVAL-WHEN allows to specify if a particular piece of code should be run
during compilation of a file
during loading of a file
during execution
EVAL-WHEN is not used that often in user code. If you use it, then you should ask yourself if you really need it.

Including files from within racket/scheme

I'm trying to use drracket to work thru the exercises in "How To
Design Programs 2nd Ed".
A number of the exercises in this build up on the answers to previous
questions, so I would like to include the source files from the
answered questions so that I don't have to copy and paste the the body
of the old answer each time.
My main question is: How do I do this?
I have looked thru the documentation and found a method called
include that seems to do what I want, but I cant work out how to use
it correctly.
eg - I have two files:
test.rkt - this compiles and runs fine and contains one function:
(define (test) 1)
(test)
newtest.rkt - I would like this file to to be able to use the function defined in test.rkt.
(require racket/include)
(include "test.rkt")
(define (newtest) (* test 2))
When I try to compile this I get the following error:
module: this function is not defined
(Not very informative, but that's all the information I'm given...)
How do I get this first file to include without getting this error? Is include
even the right function for this, or is my approach completely wrong?
The include form isn't working because when the language is set to "Beginning Student" or one of the other teaching languages, DrRacket actually wraps your program in a module. You can see this if you open "test.rkt" in a regular text editor. The #reader.... bit is what generates the module. But when that gets included into the other file, it doesn't make sense. Thus the error complaining about module.
Unfortunately, as far as I can tell, the HtDP languages still don't have provide, which is what you need to make this work right.
If you really want to get this working, here's a way to hack around it:
Create a new file called "provide.rkt" in the same directory as your other files. While you're editing this file (and only this file), set the Language in DrRacket to "Determine language from source". Put the following two lines in "provide.rkt":
#lang racket
(provide provide)
(That declares a module using the full Racket language that provides only the built-in special form provide.)
Add the following lines to your "test.rkt" program. (Make sure DrRacket's Language is set back to "Beginning Student" or whichever teaching language you're using for this.)
(require "provide.rkt")
(provide test)
Now "test.rkt" is a module that exports your test function. (It was always a module, it just didn't have any exports before, so it wasn't very useful.)
Add the following lines to your "newtest.rkt" program:
(require "test.rkt")
That imports everything provided by "test.rkt": currently just test, but you can add other things to, you just have to provide them.

Resources