Cakelisp C support and dynamic environments

By Macoy Madson. Published on .


It has been nearly a month since my last post, and there have been some interesting developments.

RSS now supported

This blog now has RSS generated. I wrote the generator in Cakelisp, of course. You should be able to add this blog to your favorite feed reader by entering as the URL. Note that HTTP is not supported, so depending on your feed reader's defaults, you will likely need to specify the https:// rather than just

Comments on Linker-Loader

My post on bringing a dynamic environment to C was on the front page of Hacker News a few weeks ago. The post got a good amount of positive comments, which was rewarding. I also got some private emails from some who expressed their interest and support in the endeavor.

Some commentators astutely pointed out that the Tiny C Compiler already supported something similar. In fact, I had already started working on modifying TCC to work towards my goals before this post arrived. I mentioned this project in my argument for self-modifying applications.

Progress on that front is going very well, and I'm excited to demonstrate my results soon. I plan on recording a video demonstration of it once it is ready. Suffice it to say, I think TCC is the way to go in terms of the enabling of a dynamic environment for C. I plan to write why TCC is the answer and what my modifications to it are in a future article.

Recent Cakelisp changes

The dynamic environment project and the RSS feed generator both required some Cakelisp changes.

Deferred macro execution

I wrote about my XML generator in Writing XML with S-expressions. I used this same generator to write the RSS feed XML. However, due to a subtle execution order issue, the RSS feed generator broke the XML writer.

The XML writer consisted of two Cakelisp macros:

The problem arose when the write macro was executed before the syntax definition macro was. There was no facility in Cakelisp to detect dependencies between macros. Most dependencies were resolved simply by using different compilation phases, which I talk about in the Basics tutorial.

Now, macros can decide to defer their execution when they detect that e.g. a definition macro hasn't been executed yet. Cakelisp will respond to this by simply resolving other macros until there are none left to resolve. If all remaining macros are still trying to defer, that means the definition will never be resolved, and the build will fail. A helpful error indicates this by saying e.g. "Failed to resolve deferred references to <macro name>" and indicating the invocations that couldn't be resolved.

Essentially, this lets macros "wait and see" if they will ever be able to successfully execute.

This is admittedly strange and a bit complex, but because I had only encountered this construct once in all my Cakelisp code, I considered it acceptable.

C support

My dynamic environment project depends on my modified version of Tiny C Compiler. Before I started this project, Cakelisp transpiled to C++ by default. Needless to say, Tiny C Compiler cannot compile C++, so it was in my best interest to prefer C whenever possible.

I had done some preliminary work to output to C instead. The remaining work I did to make outputting to C the default was:

Cakelisp will keep track of which language features are required on a module-by-module basis, which means you can intermix C and C++ in the same Cakelisp project. For example, the instant your module references a namespace, that module will then require C++ and be automatically compiled as a C++ file. If you remove that reference it will become a C file instead. This is a nice feature because it means you can still reference C++ dependencies without having to infect your entire project with C++.

Exciting times

My dynamic environment project should be usable regardless of whether you want to write Cakelisp or prefer C. In fact, any language which produces ELF, PE, or COFF files should work with Tiny C Compiler's linker, though any features which depend on knowing the symbol's underlying type will not function.

I am very excited to be approaching my goal of a fully dynamic environment. I think this will not only open the door to new development processes, but also new forms of end-user applications, a la malleable systems.