Transpile to C or C++

Is there a way to transpile Crystal to C or C++ whether through command line options or a separate tool?

The purpose is to quickly get Crystal programs running on other platforms.

What other platforms would you want to compile to?
Crystal uses an LLVM backend, so the technical aspect of code generation can target a large number of platforms already.

More restrictive is support for the stdlib runtime, but transpiling to a different language wouldn’t help with that at all.
So I don’t think you could realistically achieve much by transpiling to C or C++.

Common targets for gamedev include Windows, Mac, Linux, iOS, Android, Nintendo Switch, Playstation and Xbox. There are also embedded targets that interest people. It’s not clear to me that using LLVM means that all targets are immediately accessibe/supported whereas as C source code does.

Nim serves as an example of a language that transpiles to C (or C++; your choice) and people have found it easy to get working anywhere/everywhere. But Crystal’s take on OOP (and some other issues) is so much better than Nim’s.

There are other potential issues around LLVM that have been discussed in the Rust, Zig and ODIN communities. Here is a video regarding LLVM usage in ODIN, including some interesting comments on the video. https://www.youtube.com/watch?v=g1qF9LZOoFE

1 Like

There is nothing preventing you from transpiling LLVM IR (which Crystal generates) to other languages.

Like, if you really wanted to compile Crystal using the go compiler, maybe you could using GitHub - andybalholm/leaven: translate LLVM IR to Go or something.

OTOH: it’s probably a totally useless thing to do :-D

1 Like

Maybe not all targets, but the ones you mention here are all supported by LLVM. Actually, LLVM/Clang is the primary toolchain for Apple, Nintendo and Sony products. So yeah those are certainly covered.
The former mentions are all operating systems, so there’s not even much specific about codegen except supporting the general object format.

More interesting are the hardware architectures with different instruction sets.
Embedded targets is a wide world, but even there LLVM addresses some of the more common ones, like avr, risc-v, arm, msp.

It’s true though that more exotic targets are not available, even though they would be for C.
Unfortunately, I don’t think there’s much we can do about that, except for writing a compiler backend that spits out C code. Might be a fun project, but not really an important goal at the moment.

2 Likes

There used to be a dead effort to add a C backend to LLVM, but it looks like it has been resurrected: GitHub - JuliaHubOSS/llvm-cbe: resurrected LLVM "C Backend", with improvements

2 Likes

Frequently Asked Questions

How to output LLVM IR

Use the following command:

crystal build --emit llvm-ir example.cr

This will generate example.ll. Since this includes many standard libraries, use this command for a simpler output:

crystal build --emit llvm-ir --prelude empty example.cr

How to create an executable from LLVM IR:

You can use clang like this:

clang example.ll -lm -levent -lgc

Crystal code, even simple ones, rely on garbage collection, so libevent and libgc are often required. Make sure these libraries are available on your platform.

How to pass extra flags during build:

Use the --link-flags option like this:

crystal build a.cr --link-flags "-L/path/to/the/dir -lfoo"
2 Likes

I’ve been wondering about a C backend, it could be fun to have, and make bootstrapping crystal to whatever target much easier, and we could distribute a compiler bootstrap or an application as C source code, ready to be compiled anywhere.

But there’s a major challenge for Crystal: the point of such a transpile is that we don’t know anything about the target (neither its CPU architecture nor libc), so we can’t have explicit libc bindings, and thus can’t type libc bindings. We’d also don’t know anything about which features are available (epoll? kqueue? something else?) and we’d have to generate everything + C macros to enable this or that during the C compilation. There are probably event more issues.

What I really wish for is a C program that would wrap libclang for example to parse C headers and generate crystal bindings on any target (or cross toolchain) so we can cross-compile for said target (or just keep the src/lib_c bindings updated).

2 Likes

Is that really the (main) point? I understand the question here is about (hypothetically) targeting platforms that LLVM doesn’t support - but some C compiler does.
In that case we could very well know which target to build for and have appropriate C buildings, just no way to produce object code with the LLVM backend.

1 Like

I guess that makes two points :stuck_out_tongue:

1 Like