uiop:call-with-current-directory broken on Linux
I think I've discovered a bug in call-with-current-directory
on Linux, demonstrated below.
First, a quick background:
The intention is to have ASDF automatically compile custom C code on system load for CFFI wrappers. The C code is conditionalised by platform, so all we need to do is invoke make
. This is going to be a common pattern and I'm trying to develop a good examplar to use as 'best practice' going forward.
Here's what I've tried:
(run-program (format nil "cd ~S && make" (namestring lib-dir)) :output t) ; works with slime, Linux
But that doesn't work from PowerShell nor MSYS2 bash.
(call-with-current-directory (native-namestring lib-dir)
(lambda ()
(run-program "make" :output t)))
works with MS Windows CLI and slime, but not Linux, and the problem appears to be that on Linux the current directory isn't being changed. By changing the run-program
command from make
to pwd
, we can see this (output of debugging statements included):
CL-USER(1): (asdf:load-system :cephes)
namestring: "/home/symbolics/common-lisp/cephes/scipy-cephes"
native namestring: "/home/symbolics/common-lisp/cephes/scipy-cephes"
Building #P"/home/symbolics/common-lisp/cephes/scipy-cephes/libmd.so"
/home/symbolics/common-lisp/cephes <-- this is the output of 'pwd'
The only way I can make this reliably work is:
(uiop:chdir (native-namestring lib-dir))
(run-program "make" :output t)
which fine, but call-with-current-directory
does seem broken. Tested on Ubuntu 18.
System definition:
;; Define a makefile as a kind of source file in ASDF
(defclass makefile (source-file) ((type :initform "m")))
(defmethod perform ((o load-op) (c makefile)) t)
(defmethod perform ((o compile-op) (c makefile))
(let* ((lib-dir (system-relative-pathname "cephes" "scipy-cephes"))
(lib (make-pathname :directory `(:relative ,(namestring lib-dir))
:name "libmd"
:type #+unix "so" #+(or windows win32) "dll"))
(built (probe-file (namestring lib))))
(format t "namestring: ~S~%" (namestring lib-dir))
(format t "native namestring: ~S~%" (native-namestring lib-dir))
(if built
(format *error-output* "Library ~S exists, skipping build" lib)
(format *error-output* "Building ~S~%" lib))
(unless built
;; (run-program (format nil "cd ~S && make" (namestring lib-dir)) :output t)))) ;works with slime and Linux
;; (call-with-current-directory (native-namestring lib-dir) (lambda () (run-program "make" :output t))) ;works with Windows CLI & slime
;; Works on MS Windows CLI, slime and Linux
(uiop:chdir (native-namestring lib-dir))
(run-program "make" :output t))))
(defsystem "cephes"
:description "Wrapper for the Cephes Mathematical Library"
:version "1.0.0"
:license :MS-PL
:depends-on ("cffi")
:serial t
:components ((:module "libmd"
:components ((:makefile "makefile")))
(:file "package")
(:file "init")
(:file "cephes")))