问题描述
在尝试处理 cl-sdl2-tutorial 时,由于当前工作目录错误,我无法加载位图。
我想使用相对路径名来正确解决问题。
(defpackage #:sdl2-tutorial-2
(:use :common-lisp)
(:export :main))
(in-package :sdl2-tutorial-2)
(defparameter *screen-width* 640)
(defparameter *screen-height* 480)
(defmacro with-window-surface ((window surface) &body body)
`(sdl2:with-init (:video)
(sdl2:with-window (,window
:title "SDL2 Tutorial"
:w *screen-width*
:h *screen-height*
:flags '(:shown))
(let ((,surface (sdl2:get-window-surface,window))),@body))))
(defun main(&key (delay 2000))
(format t " cwd: ~a,~% dpd: ~a,~& e-p: ~a,~% pf: ~a,~& load: ~a"
(sb-posix:getcwd)
*default-pathname-defaults*
(uiop:file-exists-p "hello_world.bmp")
(probe-file "hello_world.bmp")
(sdl2:load-bmp "hello_world.bmp"))
(with-window-surface (window screen-surface)
(let ((image (sdl2:load-bmp "hello_world.bmp")))
(break "1 here with ~a~%" image)
(setf image (sdl2:load-bmp "hello_world.bmp"))
(break "2 here with ~a~%" image)
(break "3 error: ~a~%" (sdl2-ffi.functions:sdl-get-error))
(sdl2:blit-surface image
nil
screen-surface
nil)
(sdl2:update-window window)
(sdl2:with-event-loop (:method :poll)
(:quit () t)
(:idle ()
(sdl2:delay delay))))))
在编译上述代码并运行 (main)
之前,我通过以下方式更改了 REPL 中的工作目录:
(sb-posix:chdir (truename "/test/cl-sdl2-tutorial/2/"))
(setf *default-pathname-defaults* (truename "/test/cl-sdl2-tutorial/2/"))
在 REPL 中运行 (main)
时,上面的代码按预期打印:
SDL2-TUTORIAL-2> (sdl2-tutorial-2:main)
0: (SDL2-TUTORIAL-2:MAIN)
cwd: /test/cl-sdl2-tutorial/2,dpd: /test/cl-sdl2-tutorial/2/,e-p: /test/cl-sdl2-tutorial/2/hello_world.bmp,pf: /test/cl-sdl2-tutorial/2/hello_world.bmp,load: #<SDL-SURFACE {#X7F5CBC018DD0}>
问题:
找不到位图,因此无法加载。
对 (sdl2:load-bmp "hello_world.bmp")
的调用始终返回零指针 (#<SDL-SURFACE {#X00000000}>
) 和断点 3 状态:
3 error: Couldn't open /home/jue/hello_world.bmp
但是在断点 1 或 2 或 3 的中断期间对 (sdl2:load-bmp "hello_world.bmp")
求值是成功的并且继续 (main)
会显示图片。
问题:
- 为什么
sdl2:load-bmp
使用“错误”的工作目录,为什么它在断点期间使用“正确的”工作目录? - 如何让
sdl2:load-bmp
在使用相对路径时使用想要的工作目录(而不是“/home/jue/”)?
备注
(如果这很重要,我在 Linux 机器上使用当前发布的 sbcl
、Emacs
、sly
版本。我对 Common Lisp 及其开发环境只有中级经验,但是在 elisp 上进阶)
解决方法
我怀疑但不知道问题在于 sdl2 库对线程进行了幻想,结果工作目录不是您所想的那样。
根据我的经验,解决此问题的方法是永远不要让实现对您的喜好进行第二次猜测。在任何情况下,有一些接口说“对文件做某事”给它一个绝对路径名,所以它没有机会做任何自己的思考。做类似的事情。
(defparameter *where-my-bitmaps-live* (merge-pathnames
(pathname "lib/bitmaps/")
(user-homedir-pathname)))
...
(defun load-a-bitmap (name)
(load-bmp (merge-pathnames (pathname name) *where-my-bitmaps-live*)))
现在真的没有借口了。
(你想检查上面的路径名合并是否真的正确:它似乎适合我,但每次我把目光移开超过几分钟时,我忘记了路径名规则的细节)。