Cakelisp C support and dynamic environments

Macoy Madson

This article is mirrored on my blog.

News

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 https://macoy.me 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 macoy.me.

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:

  • A syntax definition, which tells Cakelisp which things are XML tags.
  • A writer. The writer allows the programmer to freely interweave XML tags and Cakelisp code because the writer can simply write the syntax-defined XML tags and execute everything else as Cakelisp code.

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:

  • C had stricter header inclusion rules. For example, stdbool.h needs to be included in C, but not in C++.
  • Some declarations and definitions needed to be tweaked to prefer C syntax, which C++ also supports
  • I had to eschew the use of C++'s nullptr and instead prefer NULL, which is supported in both languages. Luckily, in Cakelisp I already had a special keyword null that meant that no "end user" code changes were required there.
  • Various changes needed to be made to GameLib, usually header file inclusions
  • A separate C compiler option, build-time-c-compiler, was added to allow setting a specific compiler for C. The build-time-compiler specifies the C++ compiler.

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.

Shouldn't the link to enter in feed reader be https://macoy.me/rss instead of https://macoy.me ?

I tried your feed in the feed reader I've written and had a small display issue which I fixed on my side but might be useful to know for you.

All the elements in your feed start with a new line. For example:

<title>
Macoy.me</title>

As far as I know (which might be wrong), in xml, white-spaces are part of the character data and should be kept in the text (https://www.w3.org/TR/xml/#sec-white-space ), which means that the result for this title is `\nMacoy.me'.

It doesn't matter which URL is provided because I support RSS Autodiscovery in all the blog posts and the home page.

Thanks for pointing out the new line issue, I will look into that!

Has there been any forward progress with the tiny c compiler modifications since you last posted this? Also, when people say tcc already does something akin to a dynamic c environment, what exactly do you have to modify? I'm not too familiar with tcc or what it's capable of.

Hi! I just wrote up a post to update where I left off.