【问题标题】:How do I get this Chicken Scheme code to compile?如何编译这个 Chicken Scheme 代码?
【发布时间】:2016-08-17 01:48:50
【问题描述】:

显然我的previous question 太宽泛了。所以这里又是一个问题,简化了,并带有示例源代码。

我正在尝试编译一个包含多个文件的 Chicken Scheme 项目:

test-a.scm:

#!/usr/bin/csi -script

(declare (unit test-a))
(declare (uses test-b))

(load "test-b.scm")
(use 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")))))

根据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 的兼容性的情况下,进行编译?

【问题讨论】:

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


    【解决方案1】:

    这里有四个(!)问题:

    • test-a.scm 包含一个单元声明。这是不正确的;总有一个文件需要编译为具有main() C 函数。那是没有单元声明的文件。如果您仔细研究您链接的手册页,它会说“在这种情况下,foo.scm 是主模块,因为它没有单元声明”。
    • 既然你决定使用模块,你需要编译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,它将在运行时需要该库。这用于加载和导入由动态链接库定义的模块。

    所以,要解决这个问题,你可以这样做:

    test-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

    test-a.scm

    #!/usr/bin/csi -script
    (cond-expand
      (compiling (declare (uses test-b)))
      (else (load "test-b.scm")))
    
    (import test-b)
    
    (test-syntax)
    

    【讨论】:

    • 谢谢,这很有用。但是我可以问一个后续问题吗?为什么会出现undefined reference to blah_toplevel 之类的错误?我已经生成了导入文件,并且正在链接 .o 文件。不可否认,我正在编译的文件比示例要复杂一些。
    • blah_toplevel 是一个单元的“主要”入口点。它不是实际的 C main(),但它被所有使用 blah 初始化该单元的单元调用。如果它丢失,也许您在某个源文件中有(declare (uses blah)),但您忘记将它实际链接到blah?另一种可能的解释是,您在 blah 的源文件中有 (declare (unit blah2)),因此它不会声明其他人期望的相同单位名称。如果不实际查看源代码,则很难说出确切的原因。
    • 我试图邀请你加入 SO 聊天,但我认为它不起作用。如果我给你我的项目文件,你能告诉我为什么会出现奇怪的错误吗?
    • 我当时不在线。也许你可以把它们放在一个pastebin上?或者,尝试将文件(如果它们不是太大!)发送到chicken-users 邮件列表并在那里寻求帮助。我也阅读了该列表,因此除非有人击败我,否则我将能够在那里做出回应。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多