Any non-trivial application is going to have some third party dependencies. When working in C++, I have this very annoying habit to always have all third-party source in source control so that I could build it. And in fact, I would build the third-party libraries along with my own code. The benefits of this setup are:
- No extra package installation besides compilers and build tools (ideally, I'd put these in as well!)
- Package versions are fixed.
- Free to patch libraries because SVN would usually merge nicely on library upgrades.
As we know, Common Lisp is compiled so this annoying habit should carry over nicely. Unfortunately, until very recently, I just didn't get how I would do it. Tonight, I threw together a small hack that works well enough which is all you can hope for at the end of the day.
Typically, my project layouts look like:
sohail@dev:~/project$ find . -maxdepth 1
The vendor directory is where I usually stuff all the third-party dependencies. For example, you might have cl-fad as one of your dependencies. In the project's ASD file, you would add cl-fad as one of the modules you depend on. But the only problem is, how do you tell ASDF to look in ~/project/vendor/cl-fad for the asd files?
Obviously, the answer is asdf:*central-registry*, a list of directory pathnames that ASDF searches when asked to load something. But the problem is that I can check out my project anywhere on the file system, so I can't hardcode the paths.
So dynamically, we need to figure out the root of the checkout, call it *project-root*, get a list of all the ASDF-loadable packages in vendor and add their respective directories to asdf:*central-registry*. Simple enough, but I know more about pathnames than I ever wanted to know! Here is the code (put into project.asd):
(make-pathname :directory (pathname-directory *load-truename*)))
(merge-pathnames "vendor/" *project-root*))
(merge-pathnames "*/*.asd" *vendor-root*))
(dolist (asd-file *all-asd-files*)
(pushnew (make-pathname :directory (directory-namestring asd-file))
Fun! Hopefully someone knows a simpler way to do this but this makes me happy for now!