首页 > 解决方案 > 打开共享对象时出错:如何嵌入共享对象或以编程方式指定不同的路径名?

问题描述

所以,我正在将 lisp 图像部署到 webapp 的服务器。到目前为止,这是一次很好的体验,除了这个特殊情况:

我正在使用这个生成webapp:

sbcl --dynamic-space-size 1024 \
     --noinform \
     --load $HOME/quicklisp/setup.lisp \
     --eval '(ql:quickload :webapp)' \
     --eval '(swank-loader:init :load-contribs t)' \
     --eval "(sb-ext:save-lisp-and-die \"webapp\" :toplevel #'webapp::executable-entry-point :executable t :compression t)"

但是,当我在服务器上启动 webapp 时,我被扔进了调试器:

debugger invoked on a SIMPLE-ERROR in thread
#<THREAD "main thread" RUNNING {10006285B3}>:
  Error opening shared object "/home/username/quicklisp/dists/quicklisp/software/clsql-20160208-git/db-mysql/clsql_mysql64.so":
  /home/username/quicklisp/dists/quicklisp/software/clsql-20160208-git/db-mysql/clsql_mysql64.so: cannot open shared object file: No such file or directory.

Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
  0: [CONTINUE       ] Skip this shared object and continue.
  1: [RETRY          ] Retry loading this shared object.
  2: [CHANGE-PATHNAME] Specify a different pathname to load the shared object from.
  3: [ABORT          ] Exit from the current thread.

(SB-SYS:DLOPEN-OR-LOSE #S(SB-ALIEN::SHARED-OBJECT :PATHNAME #P"/home/username/quicklisp/dists/quicklisp/software/clsql-20160208-git/db-mysql/clsql_mysql64.so" :NAMESTRING "/home/username/quicklisp/dists/quicklisp/software/clsql-20160208-git/db-mysql/clsql_mysql64.so" :HANDLE NIL :DONT-SAVE NIL))
0] back

Backtrace for: #<SB-THREAD:THREAD "main thread" RUNNING {10006285B3}>
0: (SB-SYS:DLOPEN-OR-LOSE #S(SB-ALIEN::SHARED-OBJECT :PATHNAME #P"/home/username/quicklisp/dists/quicklisp/software/clsql-20160208-git/db-mysql/clsql_mysql64.so" :NAMESTRING "/home/username/quicklisp/dists/quicklisp/software/clsql-20160208-git/db-mysql/clsql_mysql64.so" :HANDLE NIL :DONT-SAVE NIL))
1: (SB-ALIEN::TRY-REOPEN-SHARED-OBJECT #S(SB-ALIEN::SHARED-OBJECT :PATHNAME #P"/home/username/quicklisp/dists/quicklisp/software/clsql-20160208-git/db-mysql/clsql_mysql64.so" :NAMESTRING "/home/username/quicklisp/dists/quicklisp/software/clsql-20160208-git/db-mysql/clsql_mysql64.so" :HANDLE NIL :DONT-SAVE NIL))
2: (SB-SYS:REOPEN-SHARED-OBJECTS)
3: (SB-IMPL::FOREIGN-REINIT)
4: (SB-IMPL::REINIT)
5: ((FLET SB-UNIX::BODY :IN SAVE-LISP-AND-DIE))
6: ((FLET "WITHOUT-INTERRUPTS-BODY-36" :IN SAVE-LISP-AND-DIE))
7: ((LABELS SB-IMPL::RESTART-LISP :IN SAVE-LISP-AND-DIE))

0] 3

我不确定这是否仅限于clsql- 有没有办法嵌入共享对象或以编程方式指定路径名,因为这看起来甚至在toplevel调用函数之前就发生了错误。

确实存在关于将共享对象文件嵌入到 lisp 图像中的两年前的讨论——建议使用 ECL,至少在 ASDF 指令明确之前。

对于 SBCL,我还发现sb-alien:load-shared-object了该:dont-save nil选项;但不知道如何在这里使用它。

标签: common-lispclsql

解决方案


在一般情况下,部署应该可以解决问题。(感谢 u/flaming_bird 在这里指出。)

但是,在这种特殊情况下,clsql.soclsql-sys:*foreign-library-search-paths*. 这种“查找”发生在编译/制作期间。完成后,使用的路径将被硬编码到图像中,如果库不在完全相同的路径中,则会引发错误。

另一种方法是在构建映像之前从安装目录(在这种情况下)中删除(或重命名).so文件,并将其放在部署服务器中需要它的位置(例如,当前目录)。然后,修改构建命令以推送共享库位置(例如)就可以了:clsql$HOME/quicklisp/software/clsql-20160208-git/db-mysql/#P"./"#P"./"

sbcl --dynamic-space-size 1024 \
     --noinform \
     --load $HOME/quicklisp/setup.lisp \
     --eval '(ql:quickload :clsql)' \
     --eval '(push #P"./" clsql-sys:*foreign-library-search-paths*)' \
     --eval '(ql:quickload :webapp)' \
     --eval '(swank-loader:init :load-contribs t)' \
     --eval '(py4cl2:pystop)' \
     --eval "(sb-ext:save-lisp-and-die \"webapp\" :toplevel #'webapp::executable-entry-point :executable t :compression t)"

推荐阅读