Jump to page: 1 2 3
Thread overview
Building LDC runtime for a microcontroller
Sep 07, 2020
Severin Teona
Sep 07, 2020
IGotD-
Sep 07, 2020
aberba
Sep 07, 2020
IGotD-
Sep 07, 2020
Adam D. Ruppe
Sep 16, 2020
Remi
Sep 16, 2020
Adam D. Ruppe
Sep 17, 2020
Remi
Sep 17, 2020
Remi
Sep 17, 2020
Adam D. Ruppe
Sep 17, 2020
wjoe
Sep 17, 2020
H. S. Teoh
Sep 18, 2020
Remi
Sep 18, 2020
Adam D. Ruppe
Sep 19, 2020
Johan
Sep 19, 2020
Imperatorn
Sep 18, 2020
Dylan Graham
Sep 19, 2020
aberba
Sep 20, 2020
Dylan Graham
Sep 20, 2020
Dylan Graham
Sep 19, 2020
IGotD-
Sep 20, 2020
Dylan Graham
Sep 23, 2020
Dylan Graham
Sep 23, 2020
Denis Feklushkin
Sep 23, 2020
Dylan Graham
Sep 07, 2020
kinke
September 07, 2020
Hello,

I have been trying to build the LDC runtime for a Nucleo-f429zi board with a Cortex-M4 CPU, by following [1]. The target is not dependent on
any operating system (as the target board uses a STM32 microcontroller), so the gcc toolchain I have used is arm-none-eabi-gcc(9.3.1).
The error I am getting after running “CC=arm-none-eabi-gcc ldc-build-runtime --reset --ninja --dFlags="-mtriple=thumb-none-linux-eabi” is:

———
CMake Error at /snap/cmake/549/share/cmake-3.18/Modules/CMakeTestCCompiler.cmake:66 (message):
  The C compiler

    "/home/teona/gcc-arm-none-eabi-9-2020-q2-update/bin/arm-none-eabi-gcc"

  is not able to compile a simple test program.

  It fails with the following output:

    Change Dir: /home/teona/runtime_thumb/ldc-build-runtime.tmp/CMakeFiles/CMakeTmp

    Run Build Command(s):/usr/bin/ninja cmTC_31c30 && [1/2] Building C object CMakeFiles/cmTC_31c30.dir/testCCompiler.c.o
    [2/2] Linking C executable cmTC_31c30
    FAILED: cmTC_31c30
    : && /home/teona/gcc-arm-none-eabi-9-2020-q2-update/bin/arm-none-eabi-gcc  -rdynamic CMakeFiles/cmTC_31c30.dir/testCCompiler.c.o -o cmTC_31c30   && :
    arm-none-eabi-gcc: error: unrecognized command line option '-rdynamic'
    ninja: build stopped: subcommand failed.

CMake will not be able to correctly generate this project.
———

After searching online for a solution, I found that the same issue appeared when using Golang and one answer [2] stated that it might work by passing to the linker “-Wl,-export-dynamic” instead of “-rdynamic”. Do you have any idea how I could do that?
CMake version is 3.18,
arm-none-eabi-gcc version is 6.3.1,
ldc2 version is 1.23.0 and the system I am running on is Ubuntu 18.04 LTS.

I would also appreciate any advice regarding ways to build or create a small runtime for microcontrollers (runtime that can fit in the memory of a microcontroller).
Thank you very much,
Teona

[1]: https://wiki.dlang.org/Building_LDC_runtime_libraries
[2]: https://github.com/golang/go/issues/36633#issuecomment-576411479
September 07, 2020
On Monday, 7 September 2020 at 15:23:28 UTC, Severin Teona wrote:
>
> I would also appreciate any advice regarding ways to build or create a small runtime for microcontrollers (runtime that can fit in the memory of a microcontroller).
> Thank you very much,
> Teona
>
> [1]: https://wiki.dlang.org/Building_LDC_runtime_libraries
> [2]: https://github.com/golang/go/issues/36633#issuecomment-576411479

Use betterC, which is much better suited for microcontrollers than the full D. The disadvantage is that many great features are disabled in betterC.

I have ported druntime/phobos to my system. This is pretty large job because structure of druntime/phobos is not very good for adding/porting to new systems. It's a cascade of version(this) {} else version(that) {}. Some functionality must be ported, some others can just be stubbed.

Keep in mind that you in general have to port phobos as well because it contains many useful functions like parsing and conversion. The OS dependent stuff is mixed together with OS independent.

For an ARM target I get about a compiled size of about 500KB of a simple Hello world program when linked statically. This isn't really microcontroller size to begin with. The size quickly increases as you start to use more modules from druntime/phobos.

Another interesting observation is that druntime has a option to use malloc/free in a clib rather than map/VirtualAlloc for GC allocations. What druntime does is over allocate because it requires page aligned memory. The result is that this workaround waste a lot of memory.

The conclusion is that D as it is isn't really suitable for systems that are memory limited or lack an MMU (reason is that shared libraries don't work). D is like C++ will full STL support which is also very large. Embedded programmers who use C++ almost never use STL because of this, among other things.

September 07, 2020
On Monday, 7 September 2020 at 15:23:28 UTC, Severin Teona wrote:
> CMake Error at /snap/cmake/549/share/cmake-3.18/Modules/CMakeTestCCompiler.cmake:66 (message):

This is apparently a non-LDC specific issue, a default CMake C compiler sanity check fails. When looking at that file, you'll see that this test should be skipped when providing CMAKE_C_COMPILER_WORKS=TRUE in the CMake cmdline, as provided in one of the exemplary cmdlines on the Wiki page (just append it to the ldc-build-runtime cmdline).
September 07, 2020
On Monday, 7 September 2020 at 16:18:00 UTC, IGotD- wrote:
> On Monday, 7 September 2020 at 15:23:28 UTC, Severin Teona wrote:
>> [...]
>
> Use betterC, which is much better suited for microcontrollers than the full D. The disadvantage is that many great features are disabled in betterC.
>
> [...]

How about an alternative runtime + standard library for embedded systems...with a least bare minimum. I've seen a number of efforts to get D to run in those environments but almost none of them is packaged for others to consume.
September 07, 2020
On Monday, 7 September 2020 at 19:12:59 UTC, aberba wrote:
>
> How about an alternative runtime + standard library for embedded systems...with a least bare minimum. I've seen a number of efforts to get D to run in those environments but almost none of them is packaged for others to consume.

Adam D. Ruppe's book "D cookbook" describes another way by augmenting object.d in order to get "full D" to compile. I guess this was written before betterC existed. It will be similar to betterC, a very naked system without druntime. To be honest I like this approach better as it opens up for gradually adding functionality.

A small runtime + standard library is about the only possibility in order to fit in those microconroller systems. Alternatively it might be better just start from scratch and implement often limited functionality they requires. The problem as I mentioned before was that OS dependent stuff is mixed with OS independent. I think that OS independent should be broken out so that it can more easily be used for embedded programming.

Memory management can be a problem too. OS independent library code might expect full GC support and there seems to be no documentation which functions that does and which doesn't. I was thinking GC might not be that much of a problem for medium sized microcontroller systems. In practice you can have a fixed pool that is initialized from the beginning, non expandable. Still there is a GC memory overhead penalty.


In the C/C++ world generic standard C libraries for embedded systems are rare, often unfinished, limited, GPL soiled so there are difficulties there as well. Often there are tons of POSIX filth in them as they are assumed to run on some kind Linux system.

September 07, 2020
On Monday, 7 September 2020 at 20:55:54 UTC, IGotD- wrote:
> I guess this was written before betterC existed.

Well, -betterC existed even then, but it was *completely* useless. It didn't become useful until 2016 or 2017.

But around that same time, going minimal runtime got even easier, so I never really got on the betterC train anyway. On my tetris webassembly thing last month, I went with a minimal druntime http://dpldocs.info/this-week-in-d/Blog.Posted_2020_08_10.html#druntime

And it has some class support too in not a lot of code: https://github.com/adamdruppe/webassembly/blob/master/arsd-webassembly/object.d

(and if you aren't doing classes and built-in arrays, you can cut a bunch of that out too).

> To be honest I like this approach better as it opens up for gradually adding functionality.

Yes, indeed.

betterC is nice that it gives a library community a shared target to rally around, but for your own custom application it is probably better to do your own thing (though betterC might work for you too, worth considering at least).
September 16, 2020
On Monday, 7 September 2020 at 22:13:20 UTC, Adam D. Ruppe wrote:
> On Monday, 7 September 2020 at 20:55:54 UTC, IGotD- wrote:
>> I guess this was written before betterC existed.
>
> Well, -betterC existed even then, but it was *completely* useless. It didn't become useful until 2016 or 2017.
>
> But around that same time, going minimal runtime got even easier, so I never really got on the betterC train anyway. On my tetris webassembly thing last month, I went with a minimal druntime http://dpldocs.info/this-week-in-d/Blog.Posted_2020_08_10.html#druntime
>
> And it has some class support too in not a lot of code: https://github.com/adamdruppe/webassembly/blob/master/arsd-webassembly/object.d
>
> (and if you aren't doing classes and built-in arrays, you can cut a bunch of that out too).
>
>> To be honest I like this approach better as it opens up for gradually adding functionality.
>
> Yes, indeed.
>
> betterC is nice that it gives a library community a shared target to rally around, but for your own custom application it is probably better to do your own thing (though betterC might work for you too, worth considering at least).

I tried to modify the hello.d example from your blog post. It works without changes but when I tried to do a string concatenation, I'm hitting linker errors related to TypeInfo:

	lld: error: server/omg.o: undefined symbol: _D12TypeInfo_Aya6__initZ

Using this in hello.d

	string tmp = "hello";
	tmp ~= " world !";
	writeln(tmp);

I've hit this when trying to make a minimal runtime like yours but I couldn't figure out from the LDC source how that happens. Would you be able to help me understand how to solve this __init symbol issue? Thanks.

- Remi.
September 16, 2020
On Wednesday, 16 September 2020 at 17:59:41 UTC, Remi wrote:
> I tried to modify the hello.d example from your blog post. It works without changes but when I tried to do a string concatenation

Yeah, concatenation is one of the features that uses druntime, and specifically, it is done through TypeInfo. I would actually personally skip it if you are doing a minimal custom thing.

If you skip it, you can implement your own type instead of using the built-in array concat. You can make a struct with an operator overload to look basically the same, and it can give a slice to pass to other functions. This is much easier here - no druntime code needed and the user code will be clearer that they might have to manage the memory. Typical code with normal append tends to just assume there's no stomping, that the GC takes care of it, etc.

> I'm hitting linker errors related to TypeInfo:

But if you do implement it, as of right now, you have to define TypeInfo. Which suckssssss because it is super tedious. There's a WIP pull request up there with dmd to templatize this which would help a lot. But right now it means implementing at least some of it.

You'd need the base class TypeInfo, then TypeInfo_a (a == "char"), TypeInfo_Array, TypeInfo_Aa (which means "array of char"), then finally, TypeInfo_Aya, which is "array of immutable char", aka, string.

Once you get enough of that up - and the compiler is picky about those right now - then the append operation is `_d_arrayappendcTX`, which takes TypeInfo as a param.

Search these names in the druntime source to see their official implementations... it is a bit of a beast, which is why I recommend actually skipping them if you can. It quickly explodes in size and by the time you follow it to its final conclusion, you've reimplemented 3/4 of full druntime anyway and might as well have just done a port.

September 17, 2020
On Wednesday, 16 September 2020 at 18:34:05 UTC, Adam D. Ruppe wrote:
> On Wednesday, 16 September 2020 at 17:59:41 UTC, Remi wrote:
>> I tried to modify the hello.d example from your blog post. It works without changes but when I tried to do a string concatenation
>
> Yeah, concatenation is one of the features that uses druntime, and specifically, it is done through TypeInfo. I would actually personally skip it if you are doing a minimal custom thing.
>
> If you skip it, you can implement your own type instead of using the built-in array concat. You can make a struct with an operator overload to look basically the same, and it can give a slice to pass to other functions. This is much easier here - no druntime code needed and the user code will be clearer that they might have to manage the memory. Typical code with normal append tends to just assume there's no stomping, that the GC takes care of it, etc.
>
>> I'm hitting linker errors related to TypeInfo:
>
> But if you do implement it, as of right now, you have to define TypeInfo. Which suckssssss because it is super tedious. There's a WIP pull request up there with dmd to templatize this which would help a lot. But right now it means implementing at least some of it.
>
> You'd need the base class TypeInfo, then TypeInfo_a (a == "char"), TypeInfo_Array, TypeInfo_Aa (which means "array of char"), then finally, TypeInfo_Aya, which is "array of immutable char", aka, string.
>
> Once you get enough of that up - and the compiler is picky about those right now - then the append operation is `_d_arrayappendcTX`, which takes TypeInfo as a param.
>
> Search these names in the druntime source to see their official implementations... it is a bit of a beast, which is why I recommend actually skipping them if you can. It quickly explodes in size and by the time you follow it to its final conclusion, you've reimplemented 3/4 of full druntime anyway and might as well have just done a port.

I don't mind implementing enough to get my project running, I first tried Sebastiaan's WASM druntime port but I realised the project I'm working on wouldn't need that much to get running so I thought maybe I can slowly port each part until I get the project to run.

My problem here is mostly understanding the __initZ symbol and where it comes from. I mostly want classes and the bare minimum of std like you did for Tetris in WebAssembly for example. My project is OpenGL/SDL2 so there's a lot of glue code but just ruinning a simple example gives me problems I want to understand first.

I'll probably try what you describe in your "Zero-runtime classes" actually, and hopefully I can get away without the string manipulation or replace it with my own version of it.
September 17, 2020
On Thursday, 17 September 2020 at 09:53:57 UTC, Remi wrote:
> [snip]
>
> My problem here is mostly understanding the __initZ symbol and where it comes from. I mostly want classes and the bare minimum of std like you did for Tetris in WebAssembly for example. My project is OpenGL/SDL2 so there's a lot of glue code but just ruinning a simple example gives me problems I want to understand first.

Well... I just found out that it wasn't an issue with the code but rather the order of files as given to the compiler:

    (ldc-1.23.0)speps:~/dlang/wasm/webassembly$ ldc2 -i=. -i=std -Iarsd-webassembly/ -L-allow-undefined -oftetris.wasm -mtriple=wasm32-unknown-unknown-wasm arsd-webassembly/object.d tetris.d
arsd-webassembly/object.d(112): Error: Global variable type does not match previous declaration with same mangled name: _D11TypeInfo_Ai6__initZ
arsd-webassembly/object.d(112):        Previous IR type: %object.TypeInfo_Array = type { [1 x i8*]*, i8*, %object.TypeInfo* }, mutable, non-thread-local
arsd-webassembly/object.d(112):        New IR type:      %object.TypeInfo_Ai = type { [1 x i8*]*, i8*, %object.TypeInfo* }, const, non-thread-local
    (ldc-1.23.0)speps:~/dlang/wasm/webassembly$ ldc2 -i=. -i=std -Iarsd-webassembly/ -L-allow-undefined -oftetris.wasm -mtriple=wasm32-unknown-unknown-wasm tetris.d arsd-webassembly/object.d
    (ldc-1.23.0)speps:~/dlang/wasm/webassembly$

If object.d is passed after tetris.d, everything works as expected. Otherwise you get issues with __initZ. It also means that I might have no control over what dub does with the order of files and I can't use dub to build my WASM project.
« First   ‹ Prev
1 2 3