Reputation: 385
I want to load a lisp script located in a subdirectory in current working folder. The relative path is ./crossover-operators/ER.lisp.
In Linux this is done by:
(load "./crossover-operators/ER.lisp")
In Windows is done by:
(load ".\\crossover-operators\\ER.lisp")
How can I make a function which loads ER.lisp script independently of the operating system in which my Common Lisp script is running?
Upvotes: 4
Views: 670
Reputation: 385
Based on @coredump answer and other research, one fast answer is:
(load (make-pathname :name "ER"
:type "lisp"
:defaults (make-pathname :directory '(:relative "crossover-operators"))))
Upvotes: 3
Reputation: 38789
First of all, 19.1.1 Namestrings as Filenames says that indeed, namestring (strings as pathnames) are not portable.
A conforming program must never unconditionally use a literal namestring other than a logical pathname namestring because Common Lisp does not define any namestring syntax other than that for logical pathnames that would be guaranteed to be portable.
Note also that if you ask the user for filenames, you can use them portably:
However, a conforming program can, if it is careful, successfully manipulate user-supplied data which contains or refers to non-portable namestrings.
You have two options, which are not exclusive one to the other: using pathname constructors, and/or using logical pathnames.
Build pathnames with make-pathname
, merge-pathnames
. A pathname is a structure with different components (directory, name, type, etc.) which can be combined together. They are build with a prototypal inheritance approach, where you create new pathnames by copying an existing one and changing some of its components.
make-pathname
is just like a struct constructor, except it has a :defaults
argument that gives a pathname to use as a prototype.
merge-pathnames
is a bit different, since it also performs semantic operations.
For example, if *default-pathname-defaults*
, the special variable that holds the default pathname, is set as follows:
USER> (setf *default-pathname-defaults*
(make-pathname :directory '(:relative "crossover-operator")))
#P"crossover-operator/"
Then you have two different behaviours.
USER> (make-pathname :directory '(:relative "tmp")
:defaults *default-pathname-defaults*)
#P"tmp/"
make-pathname
replaces the directory component of the original pathname.
USER> (merge-pathnames *)
#P"crossover-operator/tmp/"
merge-pathnames
takes a pathname (here, the one we just built, denoted by *
), and merge the directory relatively to the one in *default-pathname-defaults*
.
Logical pathnames are a bit like URLs (Uniform Resource Locator) and only indirectly represents files. The programmer must define translation functions from logical pathnames to actual, physical pathnames, based on the HOST
part of the address.
The printed representation of pathnames (namestrings), are not portable, except for logical pathnames. See 19.3.1 Syntax of Logical Pathname Namestrings.
Other than having a defined syntax and translation functions (from logical to physical pathnames), they behave as other pathnames, so you can call merge-pathnames
as seen above.
Pathnames translations can map to non-portable namestrings (but you can setup the translations differently on different hosts), but also logical or physical pathnames. The hyperspec for LOGICAL-PATHNAME-TRANSLATIONS
has some examples on how to use logical pathnames, like this one:
;;;A more complex example, dividing the files among two file servers
;;;and several different directories. This Unix doesn't support
;;;:WILD-INFERIORS in the directory, so each directory level must
;;;be translated individually. No file name or type translations
;;;are required except for .MAIL to .MBX.
;;;The namestring syntax on the right-hand side is implementation-dependent.
(setf (logical-pathname-translations "prog")
'(("RELEASED;*.*.*" "MY-UNIX:/sys/bin/my-prog/")
("RELEASED;*;*.*.*" "MY-UNIX:/sys/bin/my-prog/*/")
("EXPERIMENTAL;*.*.*" "MY-UNIX:/usr/Joe/development/prog/")
("EXPERIMENTAL;DOCUMENTATION;*.*.*"
"MY-VAX:SYS$DISK:[JOE.DOC]")
("EXPERIMENTAL;*;*.*.*" "MY-UNIX:/usr/Joe/development/prog/*/")
("MAIL;**;*.MAIL" "MY-VAX:SYS$DISK:[JOE.MAIL.PROG...]*.MBX")))
;;;Sample use of that logical pathname. The return value
;;;is implementation-dependent.
(translate-logical-pathname "prog:mail;save;ideas.mail.3")
=> #P"MY-VAX:SYS$DISK:[JOE.MAIL.PROG.SAVE]IDEAS.MBX.3"
Upvotes: 5