如何编译这个Chicken Scheme代码?

时间:2016-08-17 01:48:50

标签: compilation compiler-errors include scheme chicken-scheme

显然我的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

我真正得到的是:

  

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

注意事项:

  • 我正在呼唤一个宏。
  • 我有(declare (uses条款,但csc找不到我的来源。
  • csc test-a.scm test-b.o -o test也不起作用。
  • 如果我删除load,该程序将无法在csi中使用。
  • 如果我删除use,该程序将无法在csi中使用。
  • 我需要该程序在csi中工作。

如何,在不破坏与csi 的兼容性的情况下,我可以进行此编译吗?

1 个答案:

答案 0 :(得分:1)

这里有四个(!)问题:

  • test-a.scm包含单位声明。这是不正确的;总有一个文件需要编译成具有main() C函数。这是没有单位声明的文件。如果您研究的是您更密切联系的手册页,它会说"在这种情况下,foo.scm是主要模块,因为它没有单位声明"。
  • 由于您决定使用模块,因此您需要按如下方式编译test-b.scmcsc -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

我意识到这是很多要知道的东西,也很棘手,而useregister-feature!之类的东西根本没有多大意义。我们试图在CHICKEN 5中不那么繁琐,我们也会在维基上添加常见问题解答,因为这真的不是很明显,而且有点像常见问题解答。

您链接的手册页在很长一段时间内未被更改:例如,它完全忽略了模块的存在。这就是为什么你无法编译它,-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)