What is the process for adding a new cpu type and operating system to Nim's compiler? Specifically, since the homebrew scene on the Nintendo Switch is getting fired up, I was hoping to be able to cross compile homebrew apps to the Switch with Nim. I think Nim would be perfect for Switch development because it's so fricken fast.
So my question is, how can I add support for cross compiling Nim to Nintendo switch? The architecture requirements are below, stripped from the "hello world" libnx demo (Switch's dev library).
ARCH := -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE
CFLAGS := -g -Wall -O2 -ffunction-sections \
$(ARCH) $(DEFINES)
CFLAGS += $(INCLUDE) -D__SWITCH__
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LIBS := -lnx
So thanks to @mratsim and @yglukhov, I got fairly far down the rabbit hole. I think I'm fairly close, but I hit a snag when adding all of the DevkitPro compiler information to the Nim compiler repo.
After modifying the compiler to support
nim c --cpu:armv8a57 --os:nintendoswitch test.nim
where test.nim:
echo "Hello world"
I got this message:
lib/system/dyncalls.nim(171, 10) Error: no implementation for dyncalls
So I took a look at that line in dyncalls.nim, and found a section where I need to add the ability for the switch os to support dyncalls (dlopen, etc). The problem is, DevkitA64 (the libraries to cross compile to the switch) doesn't support dlopen, dlclose, etc.
@Araq or @dom96, maybe you'd be best able to answer this next question. Why does Nim's compiler error out due to dlopen not being supported? Are dyncalls required for Nim to work?
@Arrrrrrrrr Thanks for the heads up! I'll definitely include it :)
Alright, so I've got most things working and I can actually produce an executable! However, it will not boot on the switch and there's a concerning message printed when the compilation finishes. Once I get this working, I'll definitely make a pull request after some tweaks.
@Araq or @dom96, have you encountered an error like this when implementing the other OS targets?
$ nim c --cpu:armv8a57 --os:nintendoswitch test.nim
Hint: used config file '/home/joey/Nim/config/nim.cfg' [Conf]
Hint: used config file '/home/joey/Downloads/scratch/nimswitch/nim.cfg' [Conf]
Hint: system [Processing]
Hint: test [Processing]
CC: test
CC: stdlib_system
Hint: [Link]
/opt/devkitpro/devkitA64/lib/gcc/aarch64-none-elf/8.1.0/../../../../aarch64-none-elf/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000000038
Hint: operation successful (11991 lines compiled; 0.975 sec total; 16.219MiB peakmem; Debug Build) [SuccessX]
Great to see another one from the Switch hb scene here!
The problem is probably that you haven't configured the linker to link with libnx.
It's mandantory, because it's startup function will setup malloc, C std fs and networking and then start your main function(see here: https://github.com/switchbrew/libnx/tree/master/nx/source/runtime)
@doofenstein, thank you! I am currently linking with libnx, however I'm not using the startup function because I didn't port over libnx to Nim. Guess I'm doing that now :) Hopefully with c2nim it won't be too much work. Glad to see another switch hb dev as well :)
@Araq, it looks like the linker call is the same, however it looks to be more complicated than I thought, with multiple calls to link the objects, then generate a file, to generate a file, to generate another file to finally generate the final binary that then can be run on the switch's Homebrew loader. Do you think it's better to modify the compiler to do this, or write a nimscript file?