############################################################################
# arch/risc-v/src/common/Toolchain.defs
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
############################################################################
# Setup for the selected toolchain
#
# Handle old-style chip-specific toolchain names in the absence of
# a new-style toolchain specification, force the selection of a single
# toolchain and allow the selected toolchain to be overridden by a
# command-line selection.
#
ifeq ($(filter y, $(CONFIG_RISCV_TOOLCHAIN_GNU_RV64)),y)
CONFIG_RISCV_TOOLCHAIN ?= GNU_RVG
else ifeq ($(filter y, $(CONFIG_RISCV_TOOLCHAIN_GNU_RV64ILP32)),y)
CONFIG_RISCV_TOOLCHAIN ?= GNU_RVG
else ifeq ($(filter y, $(CONFIG_RISCV_TOOLCHAIN_GNU_RV32)),y)
CONFIG_RISCV_TOOLCHAIN ?= GNU_RVG
else ifeq ($(filter y, $(CONFIG_RISCV_TOOLCHAIN_CLANG)),y)
CONFIG_RISCV_TOOLCHAIN ?= GNU_RVG
endif
#
# Supported toolchains
#
# Each toolchain definition should set:
#
# CROSSDEV The GNU toolchain triple (command prefix)
# ARCHCPUFLAGS CPU-specific flags selecting the instruction set
# options, etc.
# ARCHOPTIMIZATION The optimization level that results in
# reliable code generation.
#
ifeq ($(CONFIG_DEBUG_CUSTOMOPT),y)
ARCHOPTIMIZATION += $(CONFIG_DEBUG_OPTLEVEL)
else ifeq ($(CONFIG_DEBUG_FULLOPT),y)
ifeq ($(CONFIG_ARCH_TOOLCHAIN_CLANG),y)
ARCHOPTIMIZATION += -Oz
else
ARCHOPTIMIZATION += -Os
endif
endif
ifneq ($(CONFIG_DEBUG_NOOPT),y)
ARCHOPTIMIZATION += -fno-strict-aliasing
endif
ifeq ($(CONFIG_FRAME_POINTER),y)
ARCHOPTIMIZATION += -fno-omit-frame-pointer
else
ARCHOPTIMIZATION += -fomit-frame-pointer
endif
ifeq ($(CONFIG_STACK_CANARIES),y)
ARCHOPTIMIZATION += -fstack-protector-all
endif
ifeq ($(CONFIG_STACK_USAGE),y)
ARCHOPTIMIZATION += -fstack-usage
endif
ifneq ($(CONFIG_STACK_USAGE_WARNING),0)
ARCHOPTIMIZATION += -Wstack-usage=$(CONFIG_STACK_USAGE_WARNING)
endif
ARCHCFLAGS += -fno-common
ARCHCXXFLAGS += -fno-common
ARCHCFLAGS += -Wall -Wstrict-prototypes -Wshadow -Wundef -Wno-attributes -Wno-unknown-pragmas
ARCHCXXFLAGS += -Wall -Wshadow -Wundef -Wno-attributes -Wno-unknown-pragmas
# When all C++ code is built using GCC 7.1 or a higher version,
# we can safely disregard warnings of the type "parameter passing for X changed in GCC 7.1."
# Refer to : https://stackoverflow.com/questions/48149323/what-does-the-gcc-warning-project-parameter-passing-for-x-changed-in-gcc-7-1-m
ifneq ($(CONFIG_LIBCXXTOOLCHAIN),y)
ARCHCXXFLAGS += -nostdinc++
endif
ifneq ($(CONFIG_ARCH_TOOLCHAIN_CLANG),y)
ARCHCFLAGS += -Wno-psabi
ARCHCXXFLAGS += -Wno-psabi
endif
ifneq ($(CONFIG_CXX_STANDARD),)
ARCHCXXFLAGS += -std=$(CONFIG_CXX_STANDARD)
endif
ifneq ($(CONFIG_CXX_EXCEPTION),y)
ARCHCXXFLAGS += -fno-exceptions -fcheck-new
endif
ifneq ($(CONFIG_CXX_RTTI),y)
ARCHCXXFLAGS += -fno-rtti
endif
SHMODULEFLAGS = -Bsymbolic -G -Bdynamic --entry=__start
ifeq ($(CONFIG_ARCH_RV32),y)
LDFLAGS += -melf32lriscv
SHMODULEFLAGS += -melf32lriscv
else ifeq ($(CONFIG_ARCH_RV64ILP32),y)
LDFLAGS += -melf32lriscv
else
LDFLAGS += -melf64lriscv
endif
# Optimization of unused sections
ifeq ($(CONFIG_DEBUG_OPT_UNUSED_SECTIONS),y)
LDFLAGS += --gc-sections
ARCHOPTIMIZATION += -ffunction-sections -fdata-sections
endif
LDFLAGS += -nostdlib
ARCHOPTIMIZATION += -nostdlib
# Debug --whole-archive
ifeq ($(CONFIG_DEBUG_LINK_WHOLE_ARCHIVE),y)
LDFLAGS += --whole-archive
endif
# Debug link map
ifeq ($(CONFIG_DEBUG_LINK_MAP),y)
LDFLAGS += --cref -Map=$(call CONVERT_PATH,$(TOPDIR)$(DELIM)nuttx.map)
endif
ifeq ($(CONFIG_DEBUG_SYMBOLS),y)
ARCHOPTIMIZATION += $(CONFIG_DEBUG_SYMBOLS_LEVEL)
endif
# Generic GNU RVG toolchain
ifeq ($(CONFIG_RISCV_TOOLCHAIN),GNU_RVG)
# Generic GNU RVG toolchain, prefer to use riscv-none-elf-gcc from xPack
# if CROSSDEV is not defined.
ifeq ($(CONFIG_ARCH_TOOLCHAIN_CLANG),y)
CROSSDEV ?= riscv64-unknown-elf-
else
ifeq ($(shell riscv-none-elf-gcc --version > /dev/null 2>&1; echo $$?), 0)
CROSSDEV ?= riscv-none-elf-
else
ifeq ($(CONFIG_RISCV_TOOLCHAIN_GNU_RV32),y)
CROSSDEV ?= riscv32-unknown-elf-
else
CROSSDEV ?= riscv64-unknown-elf-
endif
endif
endif
# Detect cpu ISA support flags:
#
# Naming Convention
# RISC-V defines an exact order that must be used to define the RISC-V ISA subset:
#
# RV [32, 64, 128] I, M, A, F, D, G, Q, L, C, B, J, T, P, V, N
#
# For example, RV32IMAFDQC is legal, whereas RV32IMAFDCQ is not.
ARCHCPUEXTFLAGS = i
ifeq ($(CONFIG_ARCH_RV_ISA_M),y)
ARCHCPUEXTFLAGS := $(ARCHCPUEXTFLAGS)m
endif
ifeq ($(CONFIG_ARCH_RV_ISA_A),y)
ARCHCPUEXTFLAGS := $(ARCHCPUEXTFLAGS)a
endif
ifeq ($(CONFIG_ARCH_FPU),y)
ARCHCPUEXTFLAGS := $(ARCHCPUEXTFLAGS)f
endif
ifeq ($(CONFIG_ARCH_DPFPU),y)
ARCHCPUEXTFLAGS := $(ARCHCPUEXTFLAGS)d
endif
ifeq ($(CONFIG_ARCH_QPFPU),y)
ARCHCPUEXTFLAGS := $(ARCHCPUEXTFLAGS)q
endif
ifeq ($(CONFIG_ARCH_RV_ISA_C),y)
ARCHCPUEXTFLAGS := $(ARCHCPUEXTFLAGS)c
endif
ifeq ($(CONFIG_ARCH_RV_ISA_V),y)
ARCHCPUEXTFLAGS := $(ARCHCPUEXTFLAGS)v
endif
ifeq ($(CONFIG_ARCH_RV_ISA_ZICSR_ZIFENCEI),y)
ifeq ($(shell expr "$(GCCVER)" \>= 12), 1)
ARCHCPUEXTFLAGS := $(ARCHCPUEXTFLAGS)_zicsr_zifencei
endif
ifeq ($(CONFIG_ARCH_TOOLCHAIN_CLANG),y)
ARCHCPUEXTFLAGS := $(ARCHCPUEXTFLAGS)_zicsr_zifencei
endif
endif
ARCH_RV_EXPERIMENTAL_EXTENSIONS = $(strip $(subst ",,$(CONFIG_ARCH_RV_EXPERIMENTAL_EXTENSIONS)))
ifneq ($(ARCH_RV_EXPERIMENTAL_EXTENSIONS),)
ARCHCPUEXTFLAGS := $(ARCHCPUEXTFLAGS)_$(ARCH_RV_EXPERIMENTAL_EXTENSIONS)
ARCHOPTIMIZATION += -menable-experimental-extensions
endif
ARCH_RV_ISA_VENDOR_EXTENSIONS = $(strip $(subst ",,$(CONFIG_ARCH_RV_ISA_VENDOR_EXTENSIONS)))
ifneq ($(ARCH_RV_ISA_VENDOR_EXTENSIONS),)
ARCHCPUEXTFLAGS := $(ARCHCPUEXTFLAGS)_$(ARCH_RV_ISA_VENDOR_EXTENSIONS)
endif
ifeq ($(CONFIG_ARCH_RV_ISA_ZICFILP),y)
ARCHCPUEXTFLAGS := $(ARCHCPUEXTFLAGS)_zicfilp
endif
ifeq ($(CONFIG_ARCH_RV_ISA_ZICFISS),y)
ARCHCPUEXTFLAGS := $(ARCHCPUEXTFLAGS)_zicfiss
endif
# Detect abi type
ifeq ($(CONFIG_ARCH_RV32),y)
ARCHTYPE = rv32
ARCHABITYPE = ilp32
LLVM_ARCHTYPE := riscv32
else ifeq ($(CONFIG_ARCH_RV64),y)
ARCHTYPE = rv64
ifeq ($(CONFIG_ARCH_RV64ILP32),y)
ARCHABITYPE = ilp32
else
ARCHABITYPE = lp64
endif
LLVM_ARCHTYPE := riscv64
# https://www.sifive.com/blog/all-aboard-part-4-risc-v-code-models
ARCHCPUFLAGS = -mcmodel=medany
endif
# Construct arch flags
ARCHCPUFLAGS += -march=$(ARCHTYPE)$(ARCHCPUEXTFLAGS)
# Construct arch abi flags
ifeq ($(CONFIG_ARCH_DPFPU),y)
ARCHCPUFLAGS += -mabi=$(ARCHABITYPE)d
LLVM_ABITYPE := $(ARCHABITYPE)d
else ifeq ($(CONFIG_ARCH_FPU),y)
ARCHCPUFLAGS += -mabi=$(ARCHABITYPE)f
LLVM_ABITYPE := $(ARCHABITYPE)f
else
ARCHCPUFLAGS += -mabi=$(ARCHABITYPE)
LLVM_ABITYPE := $(ARCHABITYPE)
endif
endif
# RISCV has a modular instruction set. It's hard to define cpu-model to support all toolchain.
# For Zig, cpu model is this formal: generic_rv[32|64][i][m][a][f][d][c]
# For Rust, cpu model is this formal: riscv[32|64][i][m][a][f][d][c]
# So, it's better to map the NuttX config to LLVM builtin cpu model, these models supported by
# all LLVM based toolchain.
# Refer to : https://github.com/llvm/llvm-project/blob/release/15.x/llvm/lib/Target/RISCV/RISCV.td
# These models can't cover all implementation of RISCV, but it's enough for most cases.
ifeq ($(CONFIG_ARCH_RV32),y)
ifeq ($(findstring imc,$(ARCHCPUEXTFLAGS)),imc)
LLVM_CPUTYPE := sifive-e20
else ifeq ($(findstring imac,$(ARCHCPUEXTFLAGS)),imac)
LLVM_CPUTYPE := sifive-e31
else ifeq ($(findstring imafc,$(ARCHCPUEXTFLAGS)),imafc)
LLVM_CPUTYPE := sifive-e76
endif
else
ifeq ($(findstring imac,$(ARCHCPUEXTFLAGS)),imac)
LLVM_CPUTYPE := sifive-s51
else ifeq ($(findstring imafdc,$(ARCHCPUEXTFLAGS)),imafdc)
LLVM_CPUTYPE := sifive-u54
endif
endif
ifeq ($(CONFIG_MM_KASAN_INSTRUMENT_ALL),y)
ARCHOPTIMIZATION += -fsanitize=kernel-address
KASAN_PARAM += asan-stack=0
KASAN_PARAM += asan-instrumentation-with-call-threshold=0
ifeq ($(CONFIG_MM_KASAN_GLOBAL),y)
KASAN_PARAM += asan-globals=1
else
KASAN_PARAM += asan-globals=0
endif
ifeq ($(CONFIG_MM_KASAN_DISABLE_READS_CHECK),y)
KASAN_PARAM += asan-instrument-reads=0
endif
ifeq ($(CONFIG_MM_KASAN_DISABLE_WRITES_CHECK),y)
KASAN_PARAM += asan-instrument-writes=0
endif
ifeq ($(CONFIG_ARCH_TOOLCHAIN_CLANG),y)
ARCHOPTIMIZATION += $(addprefix -mllvm ,$(addprefix -,$(KASAN_PARAM)))
else
ARCHOPTIMIZATION += $(addprefix --param ,$(KASAN_PARAM))
endif
endif
ifeq ($(CONFIG_MM_UBSAN_ALL),y)
ARCHOPTIMIZATION += $(CONFIG_MM_UBSAN_OPTION)
endif
ifeq ($(CONFIG_MM_UBSAN_TRAP_ON_ERROR),y)
ARCHOPTIMIZATION += -fsanitize-undefined-trap-on-error
endif
# Instrumentation options
ifeq ($(CONFIG_ARCH_INSTRUMENT_ALL),y)
ARCHOPTIMIZATION += -finstrument-functions
endif
# Shadow Stack Protection
ifeq ($(CONFIG_ARCH_RV_SHADOW_STACK_ALL),y)
ARCHOPTIMIZATION += -fcf-protection=return
endif
# Link Time Optimization
ifeq ($(CONFIG_LTO_THIN),y)
ARCHOPTIMIZATION += -flto=thin
else ifeq ($(CONFIG_LTO_FULL),y)
ARCHOPTIMIZATION += -flto
ifeq ($(CONFIG_ARM_TOOLCHAIN_GNU_EABI),y)
ARCHOPTIMIZATION += -fuse-linker-plugin
endif
endif
# Clang toolchain
ifeq ($(CONFIG_ARCH_TOOLCHAIN_CLANG),y)
CC = $(CROSSDEV)clang
CXX = $(CROSSDEV)clang++
CPP = $(CROSSDEV)clang -E -P -x c
LD = $(CROSSDEV)clang
STRIP = $(CROSSDEV)llvm-strip --strip-unneeded
AR = $(CROSSDEV)llvm-ar rcs
NM = $(CROSSDEV)llvm-nm
OBJCOPY = $(CROSSDEV)llvm-objcopy
OBJDUMP = $(CROSSDEV)llvm-objdump
# Since the no_builtin attribute is not fully supported on Clang
# disable the built-in functions, refer:
# https://github.com/apache/nuttx/pull/5971
ARCHOPTIMIZATION += -fno-builtin
ARCHOPTIMIZATION += -fshort-enums
# Default toolchain
else
CC = $(CROSSDEV)gcc
CXX = $(CROSSDEV)g++
CPP = $(CROSSDEV)gcc -E -P -x c
STRIP = $(CROSSDEV)strip --strip-unneeded
OBJCOPY = $(CROSSDEV)objcopy
OBJDUMP = $(CROSSDEV)objdump
LD = $(CROSSDEV)ld
AR = $(CROSSDEV)ar rcs
NM = $(CROSSDEV)nm
# Link Time Optimization
ifeq ($(CONFIG_LTO_FULL),y)
ifeq ($(CONFIG_RISCV_TOOLCHAIN),GNU_RVG)
LD := $(CROSSDEV)gcc
AR := $(CROSSDEV)gcc-ar rcs
NM := $(CROSSDEV)gcc-nm
ARCHOPTIMIZATION += -fno-builtin
endif
endif
LDFLAGS += --print-memory-usage
endif
ifeq ($(CONFIG_ARCH_TOOLCHAIN_GNU),y)
ifeq ($(CONFIG_ARCH_TOOLCHAIN_CLANG),)
ifeq ($(GCCVER),)
export GCCVER := $(shell $(CC) --version | grep gcc | sed -E "s/.* ([0-9]+\.[0-9]+).*/\1/" | cut -d'.' -f1)
endif
ifeq ($(shell expr "$(GCCVER)" \>= 12), 1)
ifeq ($(CONFIG_ARCH_RAMFUNCS),y)
LDFLAGS += --no-warn-rwx-segments
else ifeq ($(CONFIG_BOOT_RUNFROMFLASH),)
LDFLAGS += --no-warn-rwx-segments
endif
endif
endif
endif
# Add the builtin library
COMPILER_RT_LIB = $(shell $(CC) $(ARCHCPUFLAGS) --print-libgcc-file-name)
ifeq ($(CONFIG_ARCH_TOOLCHAIN_CLANG),y)
ifeq ($(wildcard $(COMPILER_RT_LIB)),)
# if "--print-libgcc-file-name" unable to find the correct libgcc PATH
# then go ahead and try "--print-file-name"
COMPILER_RT_LIB := $(wildcard $(shell $(CC) $(ARCHCPUFLAGS) --print-file-name $(notdir $(COMPILER_RT_LIB))))
endif
endif
EXTRA_LIBS += $(COMPILER_RT_LIB)
ifeq ($(CONFIG_LIBM_TOOLCHAIN),y)
EXTRA_LIBS += $(wildcard $(shell $(CC) $(ARCHCPUFLAGS) --print-file-name=libm.a))
endif
ifeq ($(CONFIG_LIBSUPCXX_TOOLCHAIN),y)
EXTRA_LIBS += $(wildcard $(shell $(CC) $(ARCHCPUFLAGS) --print-file-name=libsupc++.a))
endif
ifeq ($(CONFIG_COVERAGE_TOOLCHAIN),y)
EXTRA_LIBS += $(wildcard $(shell $(CC) $(ARCHCPUFLAGS) --print-file-name=libgcov.a))
endif
# Loadable module definitions
CMODULEFLAGS = $(CFLAGS) -fvisibility=hidden
LDMODULEFLAGS = -r -T $(call CONVERT_PATH,$(TOPDIR)/libs/libc/elf/gnu-elf.ld)
ifeq ($(CONFIG_ARCH_RV32),y)
LDMODULEFLAGS += --oformat elf32-littleriscv
else ifeq ($(CONFIG_ARCH_RV64ILP32),y)
LDMODULEFLAGS += --oformat elf32-littleriscv
else
LDMODULEFLAGS += --oformat elf64-littleriscv
endif
# ELF module definitions
CELFFLAGS = $(CFLAGS) -fvisibility=hidden
CXXELFFLAGS = $(CXXFLAGS) -fvisibility=hidden
LDELFFLAGS = -e __start
ifeq ($(CONFIG_BINFMT_ELF_RELOCATABLE),y)
LDELFFLAGS += -r
endif
ifeq ($(CONFIG_ARCH_RV32),y)
LDELFFLAGS += --oformat elf32-littleriscv
else
LDELFFLAGS += --oformat elf64-littleriscv
endif
LDELFFLAGS += -T $(call CONVERT_PATH,$(TOPDIR)/libs/libc/elf/gnu-elf.ld)
ifneq ($(CONFIG_BINFMT_ELF_RELOCATABLE)$(CONFIG_LTO_FULL),)
# Lto not support in relocatable elf
CMODULEFLAGS += -fno-lto
CELFFLAGS += -fno-lto
CXXELFFLAGS += -fno-lto
endif
# Zig toolchain
include $(TOPDIR)/tools/Zig.defs
# Rust toolchain
include $(TOPDIR)/tools/Rust.defs
# LDC (LLVM D Compiler) toolchain
include $(TOPDIR)/tools/D.defs
# Swift 6 toolchain
include $(TOPDIR)/tools/Swift.defs
# Shared library build flags
SHCCFLAGS = -fPIC -fPIE -fvisibility=default
SHLDFLAGS = -shared -Bsymbolic -Bdynamic -G
ifeq ($(CONFIG_SIM_M32),y)
SHLDFLAGS += -melf_i386
endif