Как мне получить этот код Chicken Scheme для компиляции?

Очевидно, мой предыдущий вопрос был слишком общим. Итак, вот еще раз вопрос, упрощенный, и с примером исходного кода.

Я пытаюсь скомпилировать проект 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")))))

Согласно официальному руководству, я должен сделать это так:

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, я могу сделать эту компиляцию?


person Sod Almighty    schedule 17.08.2016    source источник


Ответы (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, для которого потребуется библиотека во время выполнения. Это предназначено для загрузки и импорта модулей, определенных динамически подключаемыми библиотеками.

Итак, чтобы решить эту проблему, вы можете сделать это следующим образом:

тест-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, и мы также собираемся добавить FAQ на вики, потому что это действительно не очевидно и немного похоже на 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)
person sjamaan    schedule 17.08.2016
comment
Спасибо, это очень полезно. Но можно вопрос вдогонку? Почему я получаю такие ошибки, как undefined reference to blah_toplevel? Я создал файлы импорта и связываю файлы .o. Правда, файлы, которые я компилирую, немного сложнее, чем в примере. - person Sod Almighty; 18.08.2016
comment
blah_toplevel — главный вход в объект. Это не настоящий C main(), но он вызывается всеми модулями, которые используют blah для инициализации этого модуля. Если он отсутствует, возможно, у вас есть (declare (uses blah)) в каком-то исходном файле, но вы забыли связать его с blah? Другое возможное объяснение состоит в том, что у вас есть (declare (unit blah2)) внутри исходного файла для blah, так что он не объявляет то же имя модуля, которое ожидают другие. Точную причину трудно сказать, не видя исходный код. - person sjamaan; 18.08.2016
comment
Я пытался пригласить вас в чат SO, но я не думаю, что это сработало. Если я дам вам файлы моего проекта, не могли бы вы сказать мне, почему я получаю странную ошибку, пожалуйста? - person Sod Almighty; 19.08.2016
comment
Меня в то время не было в сети. Может быть, вы можете положить их на pastebin? В качестве альтернативы попробуйте отправить файлы (если они не слишком велики!) в список рассылки chicken-users и попросить там помощи. Я также читал этот список, поэтому, если кто-то не опередит меня, я смогу ответить там. - person sjamaan; 20.08.2016