我如何让这个 Chicken Scheme 代码编译?
How do I get this Chicken Scheme code to compile?
显然我的 previous question 太宽泛了。所以这又是一个问题,经过简化,并带有示例源代码。
我正在尝试编译包含多个文件的 Chicken Scheme 项目:
测试-a.scm:
#!/usr/bin/csi -script
(declare (unit test-a))
(declare (uses test-b))
(load "test-b.scm")
(use test-b)
(test-syntax)
测试-b.scm:
(declare (unit test-b))
(module test-b *
(import scheme chicken)
(define-syntax test-syntax
(syntax-rules ()
((_)
(print "In test-syntax")))))
根据official manual,我应该这样做:
csc -c test-b.scm
csc -c test-a.scm
csc test-a.o test-b.o -o test
我实际得到的是这样的:
Syntax error (import): cannot import from undefined module
注意事项:
- 我在调用宏
- 我有一个
(declare (uses
子句,但 csc 找不到我的来源。
csc test-a.scm test-b.o -o test
也不行。
- 如果我删除
load
,该程序将无法在 csi 中运行。
- 如果我删除
use
,该程序将无法在 csi 中运行。
- 我需要程序在 csi 中工作。
如何,在不破坏与 csi 的兼容性的情况下,我可以进行编译吗?
这里有四个(!)问题:
test-a.scm
包含一个单元声明。这是不正确的;总有一个文件需要编译以具有 main()
C 函数。那是没有单位声明的文件。如果您仔细研究链接的手册页,它会显示 "In this case foo.scm
is the main module, because it doesn't have a unit declaration"。
- 由于您决定使用模块,因此需要按如下方式编译
test-b.scm
:csc -c -j test-b test-b.scm
。 -j
开关将导致编译器发出模块库 test-b.import.scm
,这是编译器在编译 test-a.scm
时要查找的内容。当缺少导入库时,它会抱怨模块未定义。在解释器中,这没问题,因为您 load
在导入它定义的模块之前的文件。
- 您正在使用
load
,即使是在程序的编译版本中。这意味着它将在任何情况下读取和评估 test-b.scm
文件(如果丢失则抱怨)。
- 您正在使用
use
,这将在运行时需要该库。这意味着加载和导入由动态链接库定义的模块。
所以,要解决这个问题,您可以这样做:
测试-a.scm
#!/usr/bin/csi -script
;; Declare that this uses test-b, so that its toplevel is initialised
(declare (uses test-b))
;; No (declare (unit test-a)) because this file should generate main().
;; Because we tell the compiler what to link together and we want to
;; avoid passing all the .scm files on the csi command line, we can load
;; the test-b.scm file here, but only when interpreting:
(cond-expand
((not compiling) (load "test-b.scm"))
(else))
;; Only import the module; we take care of loading the code above,
;; or in the linking step when compiling. If we had (use test-b),
;; the library would be searched for at runtime.
;; Alternatively, (use test-b) here, but add (register-feature! 'test-b)
;; to test-b.scm, which prevents the runtime from attempting to load test-b.
(import test-b)
(test-syntax)
test-b.scm (不变)
(declare (unit test-b))
(module test-b *
(import scheme chicken)
(define-syntax test-syntax
(syntax-rules ()
((_)
(print "In test-syntax")))))
并且,编译它:
csc -c -j test-b test-b.scm
csc -c test-a.scm
csc test-a.o test-b.o -o test
我意识到这需要知道的东西很多,而且也很棘手,有些东西比如 use
加上 register-feature!
根本就没有多大意义。我们正试图在 CHICKEN 5 中使它变得不那么繁琐,我们还将向 wiki 添加一个常见问题解答,因为这真的不是很明显而且有点常见问题解答。
您链接的手册页已经很长时间没有更改了:例如,它完全忽略了模块的存在。这就是为什么你无法编译它,缺少 -j
开关,因为手册页中的示例文件没有定义模块。
编辑:
这可以稍微清理一下,因为 declare
无论如何只被编译器接受。所以我们也可以将其移动到 cond-expand
中:
测试-a.scm
#!/usr/bin/csi -script
(cond-expand
(compiling (declare (uses test-b)))
(else (load "test-b.scm")))
(import test-b)
(test-syntax)
显然我的 previous question 太宽泛了。所以这又是一个问题,经过简化,并带有示例源代码。
我正在尝试编译包含多个文件的 Chicken Scheme 项目:
测试-a.scm:
#!/usr/bin/csi -script
(declare (unit test-a))
(declare (uses test-b))
(load "test-b.scm")
(use test-b)
(test-syntax)
测试-b.scm:
(declare (unit test-b))
(module test-b *
(import scheme chicken)
(define-syntax test-syntax
(syntax-rules ()
((_)
(print "In test-syntax")))))
根据official manual,我应该这样做:
csc -c test-b.scm
csc -c test-a.scm
csc test-a.o test-b.o -o test
我实际得到的是这样的:
Syntax error (import): cannot import from undefined module
注意事项:
- 我在调用宏
- 我有一个
(declare (uses
子句,但 csc 找不到我的来源。 csc test-a.scm test-b.o -o test
也不行。- 如果我删除
load
,该程序将无法在 csi 中运行。 - 如果我删除
use
,该程序将无法在 csi 中运行。 - 我需要程序在 csi 中工作。
如何,在不破坏与 csi 的兼容性的情况下,我可以进行编译吗?
这里有四个(!)问题:
test-a.scm
包含一个单元声明。这是不正确的;总有一个文件需要编译以具有main()
C 函数。那是没有单位声明的文件。如果您仔细研究链接的手册页,它会显示 "In this casefoo.scm
is the main module, because it doesn't have a unit declaration"。- 由于您决定使用模块,因此需要按如下方式编译
test-b.scm
:csc -c -j test-b test-b.scm
。-j
开关将导致编译器发出模块库test-b.import.scm
,这是编译器在编译test-a.scm
时要查找的内容。当缺少导入库时,它会抱怨模块未定义。在解释器中,这没问题,因为您load
在导入它定义的模块之前的文件。 - 您正在使用
load
,即使是在程序的编译版本中。这意味着它将在任何情况下读取和评估test-b.scm
文件(如果丢失则抱怨)。 - 您正在使用
use
,这将在运行时需要该库。这意味着加载和导入由动态链接库定义的模块。
所以,要解决这个问题,您可以这样做:
测试-a.scm
#!/usr/bin/csi -script
;; Declare that this uses test-b, so that its toplevel is initialised
(declare (uses test-b))
;; No (declare (unit test-a)) because this file should generate main().
;; Because we tell the compiler what to link together and we want to
;; avoid passing all the .scm files on the csi command line, we can load
;; the test-b.scm file here, but only when interpreting:
(cond-expand
((not compiling) (load "test-b.scm"))
(else))
;; Only import the module; we take care of loading the code above,
;; or in the linking step when compiling. If we had (use test-b),
;; the library would be searched for at runtime.
;; Alternatively, (use test-b) here, but add (register-feature! 'test-b)
;; to test-b.scm, which prevents the runtime from attempting to load test-b.
(import test-b)
(test-syntax)
test-b.scm (不变)
(declare (unit test-b))
(module test-b *
(import scheme chicken)
(define-syntax test-syntax
(syntax-rules ()
((_)
(print "In test-syntax")))))
并且,编译它:
csc -c -j test-b test-b.scm
csc -c test-a.scm
csc test-a.o test-b.o -o test
我意识到这需要知道的东西很多,而且也很棘手,有些东西比如 use
加上 register-feature!
根本就没有多大意义。我们正试图在 CHICKEN 5 中使它变得不那么繁琐,我们还将向 wiki 添加一个常见问题解答,因为这真的不是很明显而且有点常见问题解答。
您链接的手册页已经很长时间没有更改了:例如,它完全忽略了模块的存在。这就是为什么你无法编译它,缺少 -j
开关,因为手册页中的示例文件没有定义模块。
编辑:
这可以稍微清理一下,因为 declare
无论如何只被编译器接受。所以我们也可以将其移动到 cond-expand
中:
测试-a.scm
#!/usr/bin/csi -script
(cond-expand
(compiling (declare (uses test-b)))
(else (load "test-b.scm")))
(import test-b)
(test-syntax)