sdl2:load-bmp 当前工作目录有问题,common-lisp

问题描述

在尝试处理 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 机器上使用当前发布的 sbclEmacssly 版本。我对 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*)))

现在真的没有借口了。

(你想检查上面的路径名合并是否真的正确:它似乎适合我,但每次我把目光移开超过几分钟时,我忘记了路径名规则的细节)。