有四個方面的問題在這裏(!):
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
,這將在運行時需要庫。這意味着加載和導入由動態鏈接庫定義的模塊。
因此,要解決這個問題,你可以做這樣的:
測試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)
測試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添加一個FAQ,因爲這真的不是很明顯,有點常見問題解答。
您鏈接的手冊頁長時間未更改:例如,它完全忽略了模塊的存在。這就是爲什麼你不能編譯它,-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)
謝謝,這是非常有用的。但我可以問一個後續問題嗎?爲什麼我會收到像'未定義的引用blah_toplevel'的錯誤?我生成了導入文件,並且鏈接了.o文件。無可否認,我正在編譯的文件比示例稍微複雜一些。 –
'blah_toplevel'是一個單元的「主要」入口點。它不是實際的C main(),但是它被所有使用'blah'的單元調用來初始化該單元。如果它丟失了,也許你在一些源文件中有'(聲明(使用blah))',但是你忘了實際上將它鏈接到'blah'?另一種可能的解釋是,你在源文件中有'(declare(unit blah2))'blah,所以它不會聲明與其他人期望的相同的單元名稱。如果沒有真正看到源代碼,確切原因很難說清楚。 – sjamaan
我試圖邀請你去聊天,但我不認爲它有效。如果我給你我的項目文件,你能告訴我爲什麼我會得到一個奇怪的錯誤嗎? –