Crystal: `nodefaultlibs` in Crystal

Created on 9 Apr 2016  路  15Comments  路  Source: crystal-lang/crystal

How do I ask the Crystal compiler not to link with any of the default libraries and startup files?

Most helpful comment

A while ago I made a very simple kernel program in Crystal, it is indeed possible to write it with pure Crystal. (ok, I cheated with 5 lines of inline assembly, but that's all). Published so you can take a look: https://github.com/lbguilherme/os-crystal

The problem is that the language itself relies on having a runtime, and mostly on having a GC. So, if you add this to main.cr:

class A
end

a = A.new

It will already fail compilation:

$ make run
Compiling crystal code...
Creating kernel.elf...
main.o: In function `*A::new:A':
main_module:(.text+0x716): undefined reference to `malloc'
main_module:(.text+0x745): undefined reference to `memset'
Makefile:9: recipe for target 'kernel.elf' failed
make: *** [kernel.elf] Error 1

You have to implement your memory management from scratch. I would suggest preallocating some region of memory (say, 16MB) to be your kernel's heap. And use it to create your malloc. The free part I leave as an exercise for the reader. :)

All 15 comments

You can try to pass --prelude=empty, but you won't be able to do much with that. For example if you do [1, 2, 3] that won't compile because the constructor of Array is defined by requiring the regular prelude.

The real question is: why do you want to get rid of them?

@asterite I'm trying out Crystal in kernel mode (ring 0), that's why. Is there any way to go around this?

Crystal is primarily a high-level language, meant to build console apps, games (maybe?), web servers, etc. You won't be able to use it (at least not in a simple way) to build a kernel, driver, etc. Next thing you'll want is to get rid of the GC, which again won't be easy to achieve.

I strongly suggest using other languages for this, like C, C++ and Rust.

@asterite Oh, ok. Thanks for the clarification.

Thought there is nothing wrong in trying. It could be interesting, even if we don't support it.

Quick question: once you get rid of the core/stdlib, you should have no GC nor anything that needs it?

@ysbaddaden Yup, I haven't given up just yet.

Yeah, GC's are a strict no.

Actually I will have to get rid of anything thats dynamically allocated.

I'll definitely want to see what you come up to.

I'm afraid that it will look like C with a little nicer syntax, but still look exactly like C, with the same issues (memory, file descriptor leaks...).

Maybe blocks could help in having a nicer API, like wrapping POSIX calls to check for Errno, open a file and have it closed automatically, but without exceptions it's somehow useless.

@ysbaddaden I'll definitely post back here.

All the code in ring 0 looks like C until you can get an allocator set up. After that you can use the language in its full glory.

Well, you can certainly do things like tinycr. But what do you mean by "get an allocator set up"?

Oh well, tinycr is an example of manually built Crystal executable where you still need Linux to run the executable. I'm talking about running on bare metal without any operating systems, initially there is no way to dynamically allocate memory in that situation. That is what I meant.

Will watch what interesting problems/solutions arise with interest :-)

Are you trying writing an OS in Rust, but in Crystal? This is gonna be hard (thus incredible) since Crystal doesn't support going bare metal with no runtime like Rust allows to.

A while ago I made a very simple kernel program in Crystal, it is indeed possible to write it with pure Crystal. (ok, I cheated with 5 lines of inline assembly, but that's all). Published so you can take a look: https://github.com/lbguilherme/os-crystal

The problem is that the language itself relies on having a runtime, and mostly on having a GC. So, if you add this to main.cr:

class A
end

a = A.new

It will already fail compilation:

$ make run
Compiling crystal code...
Creating kernel.elf...
main.o: In function `*A::new:A':
main_module:(.text+0x716): undefined reference to `malloc'
main_module:(.text+0x745): undefined reference to `memset'
Makefile:9: recipe for target 'kernel.elf' failed
make: *** [kernel.elf] Error 1

You have to implement your memory management from scratch. I would suggest preallocating some region of memory (say, 16MB) to be your kernel's heap. And use it to create your malloc. The free part I leave as an exercise for the reader. :)

Well, or replace the Boehm GC in Crystal with your own allocation implementation. If it's a non GC-allocation-scheme, just add delete class methods to do the explicit free'ing. I'm toying with my own allocator implementation myself, but since Onyx takes my main focus, I've postponed it.
ensure could be a nice place to put de-allocations in ;-)

@ysbaddaden Yeah something like that. I am trying to work around that problem.

What I have learnt over the past few days toying with Crystal is that getting completely rid of the runtime support routines is a problem until the standard library is completely rewritten (like what @lbguilherme did in his proof-of-concept), this would mean loosing the GC, and other dynamic aspects of the language.

Was this page helpful?
0 / 5 - 0 ratings