1################################################################################
2# Toolchains
3################################################################################
4SHELL				= /bin/bash
5ROOT				?= $(CURDIR)/..
6TOOLCHAIN_ROOT 			?= $(ROOT)/toolchains
7RUST_TOOLCHAIN_PATH 		?= $(TOOLCHAIN_ROOT)/rust
8UNAME_M				:= $(shell uname -m)
9ARCH				?= arm
10
11# Download toolchain macro for saving some repetition
12# $(1) is $AARCH.._PATH		: i.e., path to the destination
13# $(2) is $SRC_AARCH.._GCC	: is the downloaded tar.gz file
14# $(3) is $.._GCC_VERSION	: the name of the file to download
15define dltc
16	@if [ ! -d "$(1)" ]; then \
17		echo "Downloading $(3) ..."; \
18		mkdir -p $(1); \
19		curl --retry 5 -k -s -S -L $(2) -o $(TOOLCHAIN_ROOT)/$(3).tar.xz || \
20			{ rm -f $(TOOLCHAIN_ROOT)/$(3).tar.xz; cd $(TOOLCHAIN_ROOT) && rmdir $(1); echo Download failed; exit 1; }; \
21		tar xf $(TOOLCHAIN_ROOT)/$(3).tar.xz -C $(1) --strip-components=1 || \
22			{ rm $(TOOLCHAIN_ROOT)/$(3).tar.xz; echo Downloaded file is damaged; \
23			cd $(TOOLCHAIN_ROOT) && rm -rf $(1); exit 1; }; \
24		(cd $(1)/bin && shopt -s nullglob && for f in *-none-linux*; do ln -s $$f $${f//-none} ; done;) \
25	fi
26endef
27
28# Build buildroot toolchain macro for saving some repetition
29# $(1) is $ARCH			: target architecture
30# $(2) is $AARCH.._PATH		: i.e., path to the destination
31# $(3) & $(4)			: parts of toolchain target triplet
32define build_toolchain
33	@echo Building $1 toolchain
34	@mkdir -p ../out-$1-sdk $2
35	@(cd .. && $(PYTHON3) build/br-ext/scripts/make_def_config.py \
36		--br buildroot --out out-$1-sdk --br-ext build/br-ext \
37		--top-dir "$(ROOT)" \
38		--br-defconfig build/br-ext/configs/sdk-$1 \
39		--br-defconfig build/br-ext/configs/sdk-common \
40		--make-cmd $(MAKE))
41	+@$(MAKE) -C ../out-$1-sdk clean
42	+@$(MAKE) -C ../out-$1-sdk sdk
43	@tar xf ../out-$1-sdk/images/$3-buildroot-linux-$4_sdk-buildroot.tar.gz \
44		-C $2 --strip-components=1
45	@touch $2/.done
46endef
47
48# Download the Rust toolchain
49define dl-rust-toolchain
50	@if [ ! -d "$(1)" ]; then \
51		mkdir -p $(1) && \
52		export RUSTUP_HOME=$(1)/.rustup && \
53		export CARGO_HOME=$(1)/.cargo && \
54		curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path; \
55	fi
56endef
57
58ifeq ($(UNAME_M),x86_64)
59ifeq ($(ARCH),arm)
60# Please keep in sync with br-ext/configs/toolchain-aarch32
61# and below for aarch64 host
62AARCH32_PATH 			?= $(TOOLCHAIN_ROOT)/aarch32
63AARCH32_CROSS_COMPILE 		?= $(AARCH32_PATH)/bin/arm-linux-gnueabihf-
64AARCH32_GCC_VERSION 		?= arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-linux-gnueabihf
65SRC_AARCH32_GCC 		?= https://developer.arm.com/-/media/Files/downloads/gnu/11.3.rel1/binrel/$(AARCH32_GCC_VERSION).tar.xz
66
67# Please keep in sync with br-ext/configs/toolchain-aarch64
68AARCH64_PATH 			?= $(TOOLCHAIN_ROOT)/aarch64
69AARCH64_CROSS_COMPILE 		?= $(AARCH64_PATH)/bin/aarch64-linux-gnu-
70AARCH64_GCC_VERSION 		?= arm-gnu-toolchain-11.3.rel1-x86_64-aarch64-none-linux-gnu
71SRC_AARCH64_GCC 		?= https://developer.arm.com/-/media/Files/downloads/gnu/11.3.rel1/binrel/$(AARCH64_GCC_VERSION).tar.xz
72
73.PHONY: toolchains
74toolchains: aarch32-toolchain aarch64-toolchain rust-toolchain
75
76.PHONY: aarch32-toolchain
77aarch32-toolchain:
78	$(call dltc,$(AARCH32_PATH),$(SRC_AARCH32_GCC),$(AARCH32_GCC_VERSION))
79
80.PHONY: aarch64-toolchain
81aarch64-toolchain:
82	$(call dltc,$(AARCH64_PATH),$(SRC_AARCH64_GCC),$(AARCH64_GCC_VERSION))
83
84.PHONY: rust-toolchain
85rust-toolchain:
86	$(call dl-rust-toolchain,$(RUST_TOOLCHAIN_PATH))
87
88CLANG_VER			?= 12.0.0
89CLANG_PATH			?= $(ROOT)/clang-$(CLANG_VER)
90
91# Download the Clang compiler with LLVM tools and compiler-rt libraries
92define dl-clang
93	@if [ ! -d "$(2)" ]; then \
94		./get_clang.sh $(1) $(2); \
95	else \
96		echo "$(2) already exists"; \
97	fi
98endef
99
100.PHONY: clang-toolchains
101clang-toolchains:
102	$(call dl-clang,$(CLANG_VER),$(CLANG_PATH))
103
104else ifeq ($(ARCH),riscv)
105RISCV64_PATH 			?= $(TOOLCHAIN_ROOT)/riscv64
106RISCV64_CROSS_COMPILE 		?= $(RISCV64_PATH)/bin/riscv64-unknown-linux-gnu-
107RISCV64_GCC_RELEASE_DATE	?= 2023.07.07
108RISCV64_GCC_VERSION		?= riscv64-glibc-ubuntu-22.04-gcc-nightly-$(RISCV64_GCC_RELEASE_DATE)-nightly
109SRC_RISCV64_GCC			?= https://github.com/riscv-collab/riscv-gnu-toolchain/releases/download/$(RISCV64_GCC_RELEASE_DATE)/$(RISCV64_GCC_VERSION).tar.gz
110
111.PHONY: toolchains
112toolchains: riscv64-toolchain
113
114.PHONY: riscv64-toolchain
115riscv64-toolchain:
116	$(call dltc,$(RISCV64_PATH),$(SRC_RISCV64_GCC),$(RISCV64_GCC_VERSION))
117
118endif
119
120else ifeq ($(UNAME_M),aarch64)
121
122# Please keep in sync with br-ext/configs/toolchain-aarch32
123# and above for x86_64 host
124AARCH32_PATH 			?= $(TOOLCHAIN_ROOT)/aarch32
125AARCH32_CROSS_COMPILE 		?= $(AARCH32_PATH)/bin/arm-linux-gnueabihf-
126AARCH32_GCC_VERSION 		?= arm-gnu-toolchain-11.3.rel1-aarch64-arm-none-linux-gnueabihf
127SRC_AARCH32_GCC 		?= https://developer.arm.com/-/media/Files/downloads/gnu/11.3.rel1/binrel/$(AARCH32_GCC_VERSION).tar.xz
128
129# There isn't any native aarch64 toolchain released from Arm and buildroot
130# doesn't support distribution toolchain [1]. So we are left with no choice
131# but to build buildroot toolchain from source and use it.
132#
133# [1] https://buildroot.org/downloads/manual/manual.html#_cross_compilation_toolchain
134AARCH64_PATH 			?= $(TOOLCHAIN_ROOT)/aarch64
135AARCH64_CROSS_COMPILE 		?= $(AARCH64_PATH)/bin/aarch64-linux-
136
137.PHONY: toolchains
138toolchains: aarch32-toolchain $(AARCH64_PATH)/.done rust-toolchain
139
140.PHONY: aarch32-toolchain
141aarch32-toolchain:
142	$(call dltc,$(AARCH32_PATH),$(SRC_AARCH32_GCC),$(AARCH32_GCC_VERSION))
143
144$(AARCH64_PATH)/.done:
145	$(call build_toolchain,aarch64,$(AARCH64_PATH),aarch64,gnu)
146
147.PHONY: rust-toolchain
148rust-toolchain:
149	$(call dl-rust-toolchain,$(RUST_TOOLCHAIN_PATH))
150
151else # $(UNAME_M) != x86_64 or $(UNAME_M) != aarch64
152AARCH32_PATH 			:= $(TOOLCHAIN_ROOT)/aarch32
153AARCH32_CROSS_COMPILE 		:= $(AARCH32_PATH)/bin/arm-linux-
154AARCH64_PATH 			:= $(TOOLCHAIN_ROOT)/aarch64
155AARCH64_CROSS_COMPILE 		:= $(AARCH64_PATH)/bin/aarch64-linux-
156
157.PHONY: toolchains
158toolchains: $(AARCH64_PATH)/.done $(AARCH32_PATH)/.done
159
160$(AARCH64_PATH)/.done:
161	$(call build_toolchain,aarch64,$(AARCH64_PATH),aarch64,gnu)
162
163$(AARCH32_PATH)/.done:
164	$(call build_toolchain,aarch32,$(AARCH32_PATH),arm,gnueabihf)
165endif
166
167# Recipe to build Clang from sources and install it in
168# $(TOOLCHAIN_ROOT)/clang-x.y.z/bin
169
170CLANG_BUILD_VER_MAJ=18
171CLANG_BUILD_VER=$(CLANG_BUILD_VER_MAJ).1.7
172CLANG_BUILD_IMAGE=clang-$(CLANG_BUILD_VER)-$(UNAME_M)
173
174clang-toolchains-build:
175	docker build --build-arg VER_MAJ=$(CLANG_BUILD_VER_MAJ) --build-arg VER=$(CLANG_BUILD_VER) -t $(CLANG_BUILD_IMAGE) clang/
176	id=$$(docker create $(CLANG_BUILD_IMAGE)) && \
177		docker cp $${id}:/root/clang-$(CLANG_BUILD_VER) $(TOOLCHAIN_ROOT) && \
178		docker rm $${id}
179