(решено, смотрите комментарии)
Недавно я работал над API, который должен взаимодействовать с уже существующей службой. Кажется, все работает довольно хорошо, и мой проект только начинает становиться достаточно большим, чтобы я увидел некоторую выгоду от объединения вещей в пакет. Поскольку это мой первый «настоящий» проект в CL, я думаю, что не совсем понимаю механизмы упаковки/загрузки, которые здесь происходят.
Моя основная проблема заключается в том, что у меня есть куча кода, который использует макросы для создания функций/классов, интернирует их в мой пакет, а затем экспортирует определенные функции/аксессоры, которые люди в конечном итоге будут использовать для взаимодействия с API. Если я загружаю файлы по отдельности, вот так:
(load "~/src/lisp/cl-bitcoin/bitcoin.lisp")
(load "~/src/lisp/cl-bitcoin/classes.lisp")
(load "~/src/lisp/cl-bitcoin/functions.lisp")
Все работает хорошо. Функции, объявленные моими макросами, правильно интернированы и экспортированы, и я могу вызывать их для взаимодействия с API. Однако, если я попытаюсь сделать следующее:
(ql:quickload :btc)
Quicklisp сообщает мне, что все было загружено правильно — и кажется, что большая часть процесса загрузки произошла, как я и ожидал, поскольку все мои зависимости загружены и доступны для использования. Проблема в том, что все, что связано с моим пакетом, недоступно. Сюда входят функции, которые экспортируются непосредственно из моего файла package.lisp. Для справки, вот мои файлы .asd и package:
пакет.lisp
(defpackage #:btc
(:use #:cl)
(:export #:set-connection-parameters
#:reset-rpc-id
#:with-connection-parameters
#:btc-base-err
#:btc-base-id))
btc.asd
(asdf:defsystem #:btc
:serial t
:depends-on (#:drakma
#:flexi-streams
#:cl-json)
:components ((:file "package")
(:file "bitcoin")
(:file "classes")
(:file "functions")))
Я чувствую, что здесь не хватает чего-то довольно очевидного - я изучал eval-when
и другие связанные функции загрузки, но не смог понять это. Может кто-нибудь объяснить мне, что здесь происходит?
Спасибо за вашу помощь.
Изменить: вот как выглядит мой REPL:
; SLIME 2011-02-04
CL-USER> (ql:quickload :btc)
To load "btc":
Load 1 ASDF system:
btc
; Loading "btc"
..
(:BTC)
CL-USER> (btc:help "getinfo")
Invoking restart: Return to SLIME's top level.
; Evaluation aborted on #<SIMPLE-ERROR #x30200175DF0D>.
CL-USER> ; Reader error: No external symbol named "HELP" in package #<Package "BTC"> .
; No value
CL-USER> (load "/Users/jordan/src/lisp/cl-bitcoin/bitcoin.lisp")
#P"/Users/jordan/src/lisp/cl-bitcoin/bitcoin.lisp"
CL-USER> (load "/Users/jordan/src/lisp/cl-bitcoin/classes.lisp")
#P"/Users/jordan/src/lisp/cl-bitcoin/classes.lisp"
CL-USER> (load "/Users/jordan/src/lisp/cl-bitcoin/functions.lisp")
#P"/Users/jordan/src/lisp/cl-bitcoin/functions.lisp"
CL-USER> (btc:help "getinfo")
#<BTC::BTC-SINGLE #x3020017DBDDD>
CL-USER>
И код для генерации функций:
;;;; package information
(in-package #:btc)
;;; externally visible functions - this class contains the public api for
;;; cl-bitcoin as well as the function building framework that we need to
;;; easily handle the multiple return types that are possible from the
;;; bitcoind server methods
;; function building framework - resolving function return types into
;; specific btc objects (as defined in classes.lisp)
(defun create-btc-obj (fn result err id)
(case fn
((:getbalance :help) (make-btc-single result err id))
(otherwise (error "Unable to parse function ~S to a btc object" fn))))
(defmacro defbtcfun (name &rest args)
(let ((g (gensym)) (result (gensym)) (err (gensym)) (id (gensym)))
`(progn
(defun ,name ,args
(let ((,g (intern (string ',name) :keyword)))
(multiple-value-bind (,result ,err ,id) (get-bitcoind-result ,g ,@args)
(create-btc-obj ,g ,result ,err ,id))))
(export ',name 'btc))))
;; function definitions (each of these functions should have a corresponding case in
;; create-btc-obj above, otherwise a condition will be signaled
(defbtcfun help method)
(defbtcfun getbalance account minconf)
defpackage
я явно экспортирую 5 функций - ни одна из этих функций не доступна в моемbtc
пакете после загрузки. Кроме того, все символы, которые будут экспортированы моими макросами (все они экспортируются и доступны в пакетеbtc
, когда я загружаю файлы по отдельности), недоступны послеquickload
- person Jordan Kaye   schedule 30.11.2013btc
нет внешнего символа с именемhelp
. Глядя на определение пакетаbtc
, я вижу только пять экспортированных символов, иhelp
не входит в их число. После загрузки файловhelp
экспортируется изbtc
. Как определяетсяhelp
и где находится код, экспортирующий его из пакета? - person Joshua Taylor   schedule 30.11.2013(ql:quickload :btc)
во второй раз, а не загружаете файлы вручную? Дает лиquickload
два раза нужный экспорт символов? - person Joshua Taylor   schedule 30.11.2013~/quicklisp/local-projects/
... - person Joshua Taylor   schedule 30.11.2013(ql:quickload 'btc)
, вывод, который я вижу, включает:* (ql:quickload 'btc) \ To load "btc": \ Load 1 ASDF system: \ btc \ ; Loading "btc" \ ........ \ (BTC) \ * 'btc:help \ BTC:HELP
. Этот ряд точек печатается во время загрузки файла. Я не вижу этого в вашем выводе, и мне интересно, действительно ли quicklisp вызывает загрузку ваших файлов. Он явно загружает определение пакета, поскольку пакет доступен, но, возможно, по какой-то причине он не загружает код. - person Joshua Taylor   schedule 30.11.2013