There is one thing that you really want to have when you are creating programs. You want to create binaries. You can give them to others so that they can run them, without the hassle of compiling your programs by themselves, or you do not want them to see your sourcecode for some strange reason.
When you look at ruby, perl, python or even the all praised Java (do you hear the holy horns play? >_< ) you will see that you always need to install the appropriate one with tons of libraries so that you can run the scripts. I know I know ... I already see you running in my direction with your blades pulled out. There are compilers and packagers out there that can create binaries and you can even create a static binary that runs without the need of additional libraries. But think for yourself are these solutions good? Is it working well? I remember trying gcj. I had a test program of some hundred of very simple and standard java code. It was screaming very loudly "I am not ready to do that, I am too young!" perhaps it is better these days but I can not imagine that it works as it should. I also tried a perl to c converter but it was even more a mess. As you know I am playing around with lisp, common lisp to be exact. As most people I was thinking that it will be the same way it is with the languages mentioned above. But I could not be wrong more. There are compilers and today most of the implementations do not even have an interpreter. Most of them compile the code to at least bytecode. (I know ruby does that too, and Java too ... damn do not pick out every word I say separately) But sbcl for example (my implementation of choice for now) compiles everything. In CMUCL from which SBCL was inherited still has an interpreter additional to the compiler. I wanted to try out how it works with compiling a binary. I first thought that it will work just like with gcc or other command line batch compilers but I once more could not be wrong more. What you do is start SBCL load all libraries you need with "require" or "load" also load your program code and initialize everything you need. Then you run: (sb-ext:save-lisp-and-die "my_binary" :executable t :toplevel 'main-program-function) After that you have "my_binary" on your disk and you can start it on every compatible machine. What it does is saving the state of the lisp with everything that is present at the time you run the command. When you leave out the :executable you get a core file that you can use to run with sbcl -core commandline parameter. The :executable command only adds to the core file the ability to be executed by the operating system. In fact sbcl binary is just this kind of core dump that was created at compiletime of sbcl. The :toplevel keyword says the save function which function should be called the next time the core gets loaded. In most cases it probably will be the main function of your program. But when you think about it a bit more you can imagine how much power it is to be able to say what function is the main function. 😉 (I know it from the lowlevel embedded programming side of the world 😉 ) But now comes up the Question. It is a coredump so what does it contain? Well there it comes. It contains everything. Really everything including all libraries and the lisp compiler. So when I compile the robots game I introduced in the previous post here I get a binary of 23MB (yes megabytes). That is pretty much. Sure it does not count if you have a really big system that is 100 times bigger but still that sucks somehow. I informed myself and now I know that there is something called "headless" in the works that will enable sbcl to create coredump with an integrated dynamic linker. This will make the binary significantly smaller and when you run your program it will dynamically link the libraries it needs. Just as it should be. Next thing is from the slime world. There is a profiler in the works that will be able to even more optimize the code so that you will be able to create really small binaries. All that is of course only SBCL other, commercial lisp implementations, like LispWorks or Allegro, already have very efficient mechanisms to create such binaries. But as long as you do not need that stuff immediately you can stay on the open source side of the world. 😉
I hope that was interesting, and also hope to get some comments. That would encourage me to write more…
That’s f*cking great! I know, it’s always easy to say that, but that’s exactly how I once imagined a new form of interpreter compiler. Anyway, 23 Megs for a program aren’t that much of a problem, since I fancy the overhead being quite constant – it only renders it useless for embedded systems (d’oh!)
Anyways, keep on writing, esden. I read you. 🙂
Oh I think there are enough embedded systems that have enough memory to run the whole thing. There are approaches to port sbcl to ARM and I do not think that the target of that is a desktop machine with 8GB ram and 500GB harddisk with an ARM processor. 😉
Good to know it’s that easy!
I tried it, and found that:
– it prints the SBCL banner when you run it
– if your function doesn’t return a (SIGNED-BYTE 32), it drops you into the debugger instead of quitting
The second is easy: return 0 (or whatever exit code you want).
I haven’t found a way around the first one. I see no arg for it. I tried calling save-lisp-and-die from an SBCL I’d started with –noinform, but that didn’t work.
The banner of SBCL is a problem yes. I have to try it myself to find out what can be done. I will also try the -noinform solution. Perhaps it works here.
And yes sure it drops into the debugger because the unix system requires you to return a value that is a (signed-byte 32).
It is nice, but I still would like to have a way to ship a program and using the system’s sbcl and libraries.
I know this might be a bit of a bump, but try gzexe. It dropped the size of my hello world application down from ~60 megs to ~8.9 megs.
Pingback: Common Lisp: Eine Anwendung veröffentlichen | bitcave