Re: ASDF, Windows, symlinks
Kevin Layer <[email protected]> Fri, 15 Feb 2008 13:14:45 -0800
| Newsgroups | gmane.lisp.cclan.general |
|---|---|
| Message-ID | <[email protected]> |
I'd like to start with a quote from BSD's symlink(7) man page (http://www.stat.ucla.edu/cgi-bin/man-cgi?symlink+7), which I think is the definitive statement on symlinks as it is from the group that actually created them: Because a symbolic link and its referenced object coexist in the file system name space, confusion can arise in distinguishing between the link itself and the referenced object. Historically, commands and system calls have adopted their own link following conventions in a somewhat adhoc fashion. Rules for more a uniform approach, as they are implemented in this system, are outlined here. It is important that local applications conform to these rules, too, so that the user interface can be as consistent as possible. That sets the stage fairly well for what I'm about to say: ASDF's handling of symlinks is bad design and goes against the rules that have been in place for more than 20 years. They are good rules and there are good reasons for them. First, what is the behavior of ASDF that is in question? This is from revision 1.115 of asdf.lisp from cclan.cvs.sourceforge.net: 981 (defmacro defsystem (name &body options) 982 (destructuring-bind (&key (pathname nil pathname-arg-p) (class 'system) 983 &allow-other-keys) 984 options 985 (let ((component-options (remove-keyword :class options))) 986 `(progn 987 ;; system must be registered before we parse the body, otherwise 988 ;; we recur when trying to find an existing system of the same name 989 ;; to reuse options (e.g. pathname) from 990 (let ((s (system-registered-p ',name))) 991 (cond ((and s (eq (type-of (cdr s)) ',class)) 992 (setf (car s) (get-universal-time))) 993 (s ...) 998 (t 999 (register-system (quote ,name) 1000 (make-instance ',class :name ',name))))) 1001 (parse-component-form nil (apply 1002 #'list 1003 :module (coerce-name ',name) 1004 :pathname 1005 ;; to avoid a note about unreachable code 1006 ,(if pathname-arg-p 1007 pathname 1008 `(or (when *load-truename* 1009 (pathname-sans-name+type 1010 (resolve-symlinks 1011 *load-truename*))) 1012 *default-pathname-defaults*)) 1013 ',component-options)))))) Line 1010 contains a call to resolve-symlinks, which causes pathname for a system to be the resolved symlink of the file in which the defsystem appears (if :pathname is not specified in the defsystem options). Specifically, if /build/module/foo.cl is a symlink to /src/module/foo.cl and foo.cl uses asdf:defsystem, then as far as ASDF is concerned, the pathname of the module is /src/module/ and not /build/module/. This means the compiled versions of source files for the system will go into /src/module/ and not /build/module/. Second, what rule does ASDF break? In symlink(7) lingo, ASDF either falls into category #1 or #2, depending on how you view it. Clearly ASDF does not fall into category #3, as ASDF is does not traverse a file tree. If you disagree, then think about make(1), which is the most ASDF-like tool in UNIX, and it is not in category #3. Third, why is breaking ASDF the rules a bad thing? 1. It means ASDF doesn't behave in a way that would give the obvious behavior. These rules in question are there because they allow simple prediction of behavior, and construction of tools that rely on this behavior. ASDF toss this long assumed behavior out the window. 2. It is impossible to get the "correct" behavior out of ASDF. That is, the decision made by the ASDF authors means certain things are impossible with ASDF. 3. Hooks could be added to ASDF that would allow backward compatible behavior. That would allow both the old behavior and behavior that is currently excluded to be possible. Now, an example. Let's say I want to have one copy of my source code on the network and build from that. I build in parallel on many machines at the same time, and they all symlink to the single set of sources (directories are no linked to, only source files). The results of the builds are local, only the source code lives on the remote filesystem. This type of situation is common and has been employed for more than 20 years. Because of the way ASDF operates on the resolved name, the above is not possible. That is, the fasl files for all parallel builds end up in the same place using the same names. (Yes, one solution to this is to use different file extensions for each architecture, but that is a workaround to a broken design.) Before people start saying that this example is Franz specific: * http://bugs.mysql.com/bug.php?id=18888 "Our software-distribution system symlinks all source-files from another location (read-only filesystem) before build." * http://cvsman.com/cvs-1.12.12/cvs_113.php "Another approach is to set up a structure which allows developers to have their own copies of some files, and for other files to access source files from a central location. Many people have come up with some such a system using features such as the symbolic link feature found in many operating systems, or ..." * http://hackage.haskell.org/trac/ghc/wiki/Building/Using "So for every source tree we have zero or more build trees. Each build tree is initially an exact copy of the source tree, except that each file is a symbolic link to the source file, rather than being a copy of the source file." Regarding the message to which I'm actually replying, the idea of using Windows shortcuts is such a bad idea it boggles the mind. Nikodemus summarized well the issues in his email, but I'll repeat: Windows shortcuts are an explorer (GUI) hack, they are not built into the filesystem (NTFS/FAT32). The right thing to do is to change the design of ASDF to not manually indirect through symlinks. That would solve the problem with Windows and make ASDF have predictable and reasonable behavior. I'll end with a question. Since something drove the authors of ASDF to make the design choice they did, can someone shed some light on what it was? As is often the case with bad design choices, there is sometimes a better solution. Perhaps the original problem can be framed here so that we can all help think of a better solution than what we have. Kevin Franz Inc. ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/