如何编译多个Chicken Scheme文件?

5
我需要编译一个包含多个源文件的 Chicken Scheme 项目,但是我遇到了错误。
根据手册这个 SO 回答,我需要在我的源代码中放置 (declare)。为什么编译器无法直接“看到”我正在导入其他源代码,这超出了我的理解,但也无所谓。
问题是,即使我已经添加了 (declare),编译器仍会抱怨 (import)(use)
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...

命令:

$ csc -uses bindings.o -uses infinity.general.o -c infinity.filesystem.scm -o infinity.filesystem.o

编译器报错:

语法错误(import):无法从未定义的模块导入

以及

未绑定的变量:use

如果我只是删除“infinity.general”的importuse声明,文件就可以编译。但是,我有两个问题:

  1. 在缺少importuse子句的情况下,生成的.o文件是否实际可用?还是会在运行时抱怨缺少代码?
  2. csi要求我的代码包含(import)(use)声明,而csc则要求不包含。 然而,我需要我的代码在csicsc中都能正常工作!

请问我该如何解决这个问题?

1个回答

3
声明用于确定依赖项:编译器需要知道按什么顺序(如果需要)调用特定的顶级来确保在使用该单元的任何全局变量之前初始化正确的代码。当每个文件都被单独编译时,编译器不知道何时插入对顶层的调用。你传递给的-uses开关是多余的:csc -uses foo等同于将(declare (uses foo))放在源代码中。我所知道的是,传递-uses foo.ofoo.o文件无关。

在您的代码片段中,您正在使用load,这不是在编译时包含代码的正确方法:load将在运行时读取和评估目标文件。相反,您应完全省略load:声明已经处理了依赖项;你只需要将它们链接在一起即可。

此外,使用文件名作为模块/单元名称并不常见,但它应该可以工作。
如果我仅删除"infinity.general"的import和use声明,该文件将编译。但是,我有两个问题:
1)在缺少import和use子句的情况下,生成的.o文件是否实际上可用?还是会在运行时抱怨缺少代码?
您需要保留import表达式,否则程序不应该编译。如果它确实编译了,那么就有一些奇怪的事情发生了。在静态链接所有内容时,您不需要使用use。如果使用动态链接,您将获得运行时错误。
关于"未绑定变量:use"的错误,是因为您在begin-for-syntax块中使用了use。你可能只需要像你的其他SO问题中一样"(import-for-syntax chicken)"。

2) CSI要求我的代码包含(import)和(use)声明,而CSC则要求不需要。然而,我需要我的代码在CSI和CSC中都能运行!

看起来你处理得太快了:你正在编写一个完整的程序,并同时尝试使其在编译和解释器中运行,而没有先建立对系统工作原理的理解。

此时,最好先用两个文件组成的微型项目进行实验。然后,您可以找出如何编译可执行文件,该文件可以从也适用于解释器的代码中工作。然后,使用这些知识构建实际程序。如果任何时候出现问题,您始终可以返回到最小情况并找出您所做的不同之处。

这也有助于获得支持,因为您将能够呈现完整但最小的文件集,并且人们将能够更快地告诉您哪里出了问题,或者您是否发现了错误。


但是如果我省略了 load,解释器怎么知道在哪里找到我的包含文件呢? - Sod Almighty
FYI,使用文件名作为单元名称是我的笔误。我本意是使用“infinity.general”等名称。 - Sod Almighty
1
你可以使用 include 而不是 load,它会在另一个文件的位置文本地包含源文件。它适用于解释器和编译器。但我不确定你是否想这样做,因为这基本上与在 C 文件中使用 #include "other-file.c" 相同。另一个选项是使用 cond-expand,只有在解释器中运行时才进行 load,否则将编译对象链接在一起。 - sjamaan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接