Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

  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?
  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!

How can I solve this, please?

like image 826
Sod Almighty Avatar asked Oct 18 '22 03:10

Sod Almighty


1 Answers

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.

like image 183
sjamaan Avatar answered Oct 21 '22 03:10

sjamaan