Skip to content

Commit

Permalink
Build RISC-V binaries by default
Browse files Browse the repository at this point in the history
Let's update the Makefile and README to build RISC-V binaries by
default. Most distros now have enough RISC-V support to allow this by
just using the package manager.

Signed-off-by: Alistair Francis <[email protected]>
  • Loading branch information
alistair23 committed Sep 28, 2022
1 parent 12b066f commit ed36853
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 154 deletions.
74 changes: 48 additions & 26 deletions Configuration.mk
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,7 @@ PACKAGE_NAME ?= $(shell basename "$(shell pwd)")
# 2. (Optional) The name to use when creating the output file.
# 3. (Optional) The address to use as the fixed start of flash.
# 4. (Optional) The address to use as the fixed start of RAM.
#
# By default we currently only build the Cortex-M targets. To enable the RISC-V
# targets, set the RISCV variable like so:
#
# $ make RISCV=1
#
# Once the RV32 toolchain distribution stabilizes (as of June 2020 the toolchain
# isn't as easily obtained as we would like), we intend to make the RISC-V
# targets build by default as well.
ifeq ($(RISCV),)
ifneq ($(NORISCV),)
TOCK_TARGETS ?= cortex-m0 cortex-m3 cortex-m4 cortex-m7
else
# Specific addresses useful for the OpenTitan hardware memory map.
Expand Down Expand Up @@ -286,28 +277,57 @@ override WLFLAGS_rv32imac += $(WLFLAGS_rv32)

# Set the system libraries we link against for RISC-V. We support C++ apps by
# default.
override LINK_LIBS_rv32 += \
-lgcc -lstdc++ -lsupc++
ifeq ($(PICOLIBC),)
override LINK_LIBS_rv32 += \
-lgcc -lstdc++ -lsupc++

override LINK_LIBS_rv32i += $(LINK_LIBS_rv32)
override LINK_LIBS_rv32imc += $(LINK_LIBS_rv32)
override LINK_LIBS_rv32imac += $(LINK_LIBS_rv32)
# Use precompiled libaries we provide to link against.
override LEGACY_LIBS_rv32i += \
$(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32i/libc.a\
$(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32i/libm.a

override LEGACY_LIBS_rv32im += \
$(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32im/libc.a\
$(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32im/libm.a

override LEGACY_LIBS_rv32imc += $(LEGACY_LIBS_rv32im)

override LEGACY_LIBS_rv32imac += \
$(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32imac/libc.a\
$(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32imac/libm.a
else
override LEGACY_LIBS_rv32i += \
/usr/lib/picolibc/riscv64-unknown-elf/lib/rv32i/ilp32/libc.a\
/usr/lib/picolibc/riscv64-unknown-elf/lib/rv32i/ilp32/libm.a
override LEGACY_LIBS_rv32im += \
/usr/lib/picolibc/riscv64-unknown-elf/lib/rv32im/ilp32/libc.a\
/usr/lib/picolibc/riscv64-unknown-elf/lib/rv32im/ilp32/libm.a

override LEGACY_LIBS_rv32imc += $(LEGACY_LIBS_rv32im)

# Use precompiled libaries we provide to link against.
override LEGACY_LIBS_rv32i += \
$(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32i/libc.a\
$(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32i/libm.a
override LEGACY_LIBS_rv32imac += \
/usr/lib/picolibc/riscv64-unknown-elf/lib/rv32imac/ilp32/libc.a\
/usr/lib/picolibc/riscv64-unknown-elf/lib/rv32imac/ilp32/libm.a

override LEGACY_LIBS_rv32im += \
$(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32im/libc.a\
$(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32im/libm.a
override CFLAGS_rv32i += -I/usr/lib/picolibc/riscv64-unknown-elf/include/
override CPPFLAGS_rv32i += -I/usr/lib/picolibc/riscv64-unknown-elf/include/

override LEGACY_LIBS_rv32imc += $(LEGACY_LIBS_rv32im)
override CFLAGS_rv32im += -I/usr/lib/picolibc/riscv64-unknown-elf/include/
override CPPFLAGS_rv32im += -I/usr/lib/picolibc/riscv64-unknown-elf/include/

override LEGACY_LIBS_rv32imac += \
$(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32imac/libc.a\
$(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32imac/libm.a
override CFLAGS_rv32imc += -I/usr/lib/picolibc/riscv64-unknown-elf/include/
override CPPFLAGS_rv32imc += -I/usr/lib/picolibc/riscv64-unknown-elf/include/

override CFLAGS_rv32imac += -I/usr/lib/picolibc/riscv64-unknown-elf/include/
override CPPFLAGS_rv32imac += -I/usr/lib/picolibc/riscv64-unknown-elf/include/

override LINK_LIBS_rv32 += \
-lgcc
endif

override LINK_LIBS_rv32i += $(LINK_LIBS_rv32)
override LINK_LIBS_rv32imc += $(LINK_LIBS_rv32)
override LINK_LIBS_rv32imac += $(LINK_LIBS_rv32)

################################################################################
##
Expand Down Expand Up @@ -442,6 +462,8 @@ override CPPFLAGS += -Wwrite-strings # # { char* c = "foo"; c[0] = 'b
override CPPFLAGS_gcc += -Wlogical-op # # "suspicious use of logical operators in expressions" (a lint)
override CPPFLAGS_gcc += -Wtrampolines # # attempt to generate a trampoline on the NX stack

override CPPFLAGS_gcc += -Wno-error=sign-compare # Triggers an error inside picolibc

#CPPFLAGS += -Wabi -Wabi-tag # inter-compiler abi issues
#CPPFLAGS += -Waggregate-return # warn if things return struct's
#CPPFLAGS += -Wcast-align # { char *c; int *i = (int*) c}, 1 byte -> 4 byte align
Expand Down
251 changes: 124 additions & 127 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,161 +33,158 @@ Prerequisites
$ cd libtock-c
```

1. The main requirement to build the C applications in this repository is having
cross compilers for embedded targets. You will need an `arm-none-eabi`
toolchain for Cortex-M targets.
1. There are two requirements for building libtock-c applications.

**MacOS**:
```
$ brew tap ARMmbed/homebrew-formulae && brew update && brew install arm-none-eabi-gcc
```
1. Cross compiler for embedded targets

**Ubuntu (18.04LTS or later)**:
```
$ sudo apt install gcc-arm-none-eabi
```
*ARM*

**Arch**:
```
$ sudo pacman -Syu arm-none-eabi-gcc arm-none-eabi-newlib
```
You will need an `arm-none-eabi` toolchain for Cortex-M targets.

**Fedora**:
```
$ sudo dnf install arm-none-eabi-newlib arm-none-eabi-gcc-cs
```
**MacOS**:
```
$ brew tap ARMmbed/homebrew-formulae && brew update && brew install arm-none-eabi-gcc
```

2. Optional: libtock-c also includes support for building for ***RISC-V
targets***. These are not included by default since obtaining the toolchain
can be difficult (as of July 2022). You will need a RISC-V toolchain that
supports rv32 targets (64 bit toolchains support rv32 if compiled with
multilib support). Some toolchains that can work:
**Ubuntu (18.04LTS or later)**:
```
$ sudo apt install gcc-arm-none-eabi
```

- riscv64-none-elf
- riscv32-none-elf
- riscv64-elf
- riscv64-unknown-elf
- riscv32-unknown-elf
**Arch**:
```
$ sudo pacman -Syu arm-none-eabi-gcc
```

To actually build for the RISC-V targets, add `RISCV=1` to the make command:
**Fedora**:
```
$ sudo dnf install arm-none-eabi-gcc-cs
```

$ make RISCV=1
*RISC-V*

**MacOS**:
```
$ brew tap riscv/riscv && brew update && brew install riscv-gnu-toolchain
```
You will need a RISC-V toolchain that supports rv32 targets (64 bit
toolchains support rv32 if compiled with multilib support).
Some toolchains that can work:
- riscv64-none-elf
- riscv32-none-elf
- riscv64-elf
- riscv64-unknown-elf
- riscv32-unknown-elf

**Ubuntu (21.10 or later)**:
```
$ sudo apt install gcc-riscv64-unknown-elf picolibc-riscv64-unknown-elf
```
**MacOS**:

**Ubuntu (21.04 or earlier)**:
```shell
$ brew tap riscv/riscv && brew update && brew install riscv-gnu-toolchain
```

Unfortunately, older Ubuntu does not provide a package for RISC-V libc. We
have created a .deb file you can use to install a suitable libc based on
newlib:
```
$ wget http://cs.virginia.edu/~bjc8c/archive/newlib_3.3.0-1_amd64.deb
$ sudo dpkg -i newlib_3.3.0-1_amd64.deb
```
**Ubuntu (21.10 or later) or Debian (11 or later)**:

If you would rather compile your own newlib-based libc, follow the steps
below. Section [newlib-nano](newlib-nano) describes some extra config options
to build a size optimised newlib.
```
# Download newlib 3.3 from https://sourceware.org/newlib/
$ wget ftp://sourceware.org/pub/newlib/newlib-3.3.0.tar.gz
$ tar -xvf newlib-3.3.0.tar.gz
$ cd newlib-3.3.0
# Disable stdlib for building
$ export CFLAGS=-nostdlib
# Run configure
$ ./configure --disable-newlib-supplied-syscalls --with-gnu-ld --with-newlib --enable-languages=c --target=riscv64-unknown-elf --host=x86 --disable-multi-lib --prefix /usr
# Build and then install
$ make -j8
$ sudo make install
```
```shell
$ sudo apt install gcc-riscv64-unknown-elf
```

Alternatively, you may use a pre-compiled toolchain that we created with
Crosstool-NG.
```
$ wget http://cs.virginia.edu/~bjc8c/archive/gcc-riscv64-unknown-elf-8.3.0-ubuntu.zip
$ unzip gcc-riscv64-unknown-elf-8.3.0-ubuntu.zip
# add gcc-riscv64-unknown-elf-8.3.0-ubuntu/bin to your `$PATH` variable.
```
**Arch**:
```shell
$ sudo pacman -Syu riscv64-elf-gcc
```

**Arch**:
```
$ sudo pacman -Syu riscv64-elf-gcc riscv32-elf-newlib arm-none-eabi-newlib riscv64-elf-newlib
```
**Other distros**:

**Fedora**:
If your distro doesn't provide a RISC-V toolchain you can build one yourself
or just disable RISC-V support by running
**dnf** does not contain the `riscv-gnu-toolchain`, an alternative is to
compile from source. Start with some of the tools we need to compile the
source.
```
$ sudo dnf install make automake gcc gcc-c++ kernel-devel texinfo expat expat-devel
$ sudo dnf group install "Development Tools" "C Development Tools and Libraries"
```
Get `riscv-gnu-toolchain`, [summarised instructions as stated
here](https://github.com/riscv-collab/riscv-gnu-toolchain/blob/master/README.md)
```
$ git clone https://github.com/riscv/riscv-gnu-toolchain
$ cd riscv-gnu-toolchain/
```
**Note: add /opt/riscv/bin to your PATH**, then,
```
$ ./configure --prefix=/opt/riscv --enable-multilib
```
`--enable-multilib` ensures that "the multilib compiler will have the prefix
riscv64-unknown-elf- or riscv64-unknown-linux-gnu- but will be able to target
both 32-bit and 64-bit systems."
```
$ sudo make [might need elevated privileges writing to `/opt/`]
```
additionally, with
```
$ sudo make linux
```
you can also build `riscv64-unknown-linux-gnu`, which can be useful with tock
where `riscv64-unknown-linux-gnu-objcopy` is used.
```shell
NORISCV=1 make
```
After the the source has been compiled and copied to `/opt/riscv` and
`/opt/riscv/bin`has appended to the PATH, the toolchain is ready to be used.
1. libc for embedded targets
*ARM*
**newlib-nano**:
**Ubuntu (21.10 or later) or Debian (11 or later)**:
newlib can require a large amount of memory, especially for printing.
If this is a concern you can instead use a more size optimised version.
As of August 2020 there are a few options for this.
```shell
$ sudo apt install picolibc-arm-unknown-elf libnewlib-arm-none-eabi
```
- See if the version of newlib from your distro already has the flags below
enabled. If it does it's already size optimsed.
- See if your distro pacakges a newlib-nano (Debian does this) that will
already include the flags below.
- See if your distro packages picolibc, which is a optimised fork of newlib.
- You can compile newlib with these extra flags:
**Arch**:
```
--enable-newlib-reent-small \
--disable-newlib-fvwrite-in-streamio \
--disable-newlib-fseek-optimization \
--disable-newlib-wide-orient \
--enable-newlib-nano-malloc \
--disable-newlib-unbuf-stream-opt \
--enable-lite-exit \
--enable-newlib-global-atexit \
--enable-newlib-nano-formatted-io
$ sudo pacman -Syu arm-none-eabi-newlib
```
3. Optional: libtock-c also includes support for building RISC-V targets with
**Fedora**:
```
$ sudo dnf install arm-none-eabi-newlib
```
*RISC-V*
**Ubuntu (21.10 or later) or Debian (11 or later)**:
Use picolibc instead of newlib
```shell
$ sudo apt install picolibc-riscv64-unknown-elf
```
**Arch**:
```shell
$ sudo pacman -Syu riscv32-elf-newlib
```
*newlib-nano*
newlib can require a large amount of memory, especially for printing.
If this is a concern you can instead use a more size optimised version.
As of August 2020 there are a few options for this.
- See if the version of newlib from your distro already has the flags below
enabled. If it does it's already size optimsed.
- See if your distro packages picolibc, which is a optimised fork of newlib.
- You can compile newlib with these extra flags:
```shell
--enable-newlib-reent-small \
--disable-newlib-fvwrite-in-streamio \
--disable-newlib-fseek-optimization \
--disable-newlib-wide-orient \
--enable-newlib-nano-malloc \
--disable-newlib-unbuf-stream-opt \
--enable-lite-exit \
--enable-newlib-global-atexit \
--enable-newlib-nano-formatted-io
```

If you would rather compile your own newlib-based libc, follow the steps
below.

```shell
# Download newlib 4.1 from https://sourceware.org/newlib/
$ wget ftp://sourceware.org/pub/newlib/newlib-4.1.0.tar.gz
$ tar -xvf newlib-4.1.0.tar.gz
$ cd newlib-4.1.0
# Disable stdlib for building
$ export CFLAGS=-nostdlib
# Run configure
$ ./configure --disable-newlib-supplied-syscalls --with-gnu-ld --with-newlib --enable-languages=c --target=riscv64-unknown-elf --host=x86 --disable-multi-lib --prefix /usr
# Build and then install
$ make -j8
$ sudo make install
```

1. Optional: If using picolibc (Debian can do this) then specify the `PICOLIBC`
variable. picolibc is an optimised version of newlib

```shell
$ make PICOLIBC=1
```

1. Optional: libtock-c also includes support for building RISC-V targets with
the LLVM clang compiler. If you have a compatible clang toolchain, you can
add `CLANG=1` to the make command to use clang instead of the default GCC.

$ make RISCV=1 CLANG=1
```shell
$ make CLANG=1
```

This support is only included for RISC-V targets as Cortex-M targets require
the FDPIC support only present in GCC.
Expand Down
2 changes: 1 addition & 1 deletion libtock/console.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

Expand Down

0 comments on commit ed36853

Please sign in to comment.