Makefile: Rework toolchain logic to enable multi-toolchains
We want to allow building Linux, and potentially other projects, with
a wide range of toolchains to catch compiler problems during
development. However, not all projects can be built with arbitrary
toolchains. Eg. kvm-unit-tests and u-boot don't build with gcc-5.1 but
we want to support it because that is the oldest toolchain supported by
Linux.
Extract the toolchain logic into toolchain.mk and wrap it with a
`define_toolchain` function. The function takes a toolchain name and
a prefix, and defines variables with the given prefix that contain paths
and information about the given toolchain. This way we can define a
different toolchains for Linux, KUT, u-boot, etc.
Migrate existing projects to this setup.
Bug: 193407077
Test: make test
Change-Id: I625ba13400be3c7b9ca3204cb7615fa2c000944a
diff --git a/Makefile b/Makefile
index 8979764..88096b0 100644
--- a/Makefile
+++ b/Makefile
@@ -46,6 +46,8 @@
LINUX_DIST := $(DIST_DIR)/linux
SCRIPTS_DIR := $(ROOT_DIR)/build
+include $(SCRIPTS_DIR)/toolchain.mk
+
##
## Common options
##
@@ -65,54 +67,7 @@
# GCC will always use the latest version for building everything else other
# than the kernel.
TOOLCHAIN ?= clang
-
-# Find the toolchain path for the current OS.
-UNNAME_S := $(shell uname -s | tr '[:upper:]' '[:lower:]')
-TOOLCHAIN_CLANG := $(ROOT_DIR)/toolchains/$(UNNAME_S)-x86/clang/clang-r416183b/
-TOOLCHAIN_GCC_49 := $(ROOT_DIR)/toolchains/$(UNNAME_S)-x86/gcc/aarch64-linux-gnu-4.9/
-TOOLCHAIN_GCC_51 := $(ROOT_DIR)/toolchains/$(UNNAME_S)-x86/gcc/aarch64-linux-gnu-5.1/
-TOOLCHAIN_GCC_92 := $(ROOT_DIR)/toolchains/$(UNNAME_S)-x86/gcc/aarch64-linux-gnu-9.2/
-
-# Set the toolchain build binary paths and prefixes.
-TARGET = aarch64-linux-gnu
-TARGET_GCC_92 = aarch64-none-linux-gnu
-
-ifeq ($(TOOLCHAIN), gcc-5.1)
-TOOLCHAIN_BIN := $(TOOLCHAIN_GCC_51)/bin
-else ifeq ($(TOOLCHAIN), gcc-9.2)
-TOOLCHAIN_BIN := $(TOOLCHAIN_GCC_92)/bin
-TARGET = $(TARGET_GCC_92)
-else ifeq ($(TOOLCHAIN), clang)
-TOOLCHAIN_BIN := $(TOOLCHAIN_CLANG)/bin
-CC := $(TOOLCHAIN_BIN)/clang
-LD := $(TOOLCHAIN_BIN)/ld.lld
-OBJCOPY := $(TOOLCHAIN_BIN)/llvm-objcopy
-OBJDUMP := $(TOOLCHAIN_BIN)/llvm-objdump
-# The GCC toolchain is needed when building kvm-unit-tests and Linux with Clang.
-GCC_TOOLCHAIN_DIR = $(TOOLCHAIN_GCC_49)
-GCC_TOOLCHAIN_BIN = $(GCC_TOOLCHAIN_DIR)/bin/
-LINUX_EXTRA = LLVM=1 LLVM_IAS=1 GCC_TOOLCHAIN_DIR="$(GCC_TOOLCHAIN_BIN)"
-# Some targets require additional flags to build with Clang.
-COMMON_CFLAGS := -Qunused-arguments --target=$(TARGET) -fno-integrated-as -Wno-asm-operand-widths -fpic --gcc-toolchain=$(GCC_TOOLCHAIN_DIR) --sysroot=$(GCC_TOOLCHAIN_DIR)/$(TARGET)/libc --prefix=$(GCC_TOOLCHAIN_BIN)/$(TARGET)-
-else
-$(error Unrecognized toolchain: TOOLCHAIN=$(TOOLCHAIN))
-endif
-
-LINUX_TOOLCHAIN_BIN := $(TOOLCHAIN_BIN)
-LINUX_TARGET := $(TARGET)
-
-# Common to all GCC versions:
-# Use the latest GCC toolchain to build everything other than the kernel
-# because kvm-unit-tests as well as u-boot require recent versions.
-ifneq ($(TOOLCHAIN), clang)
-TARGET = $(TARGET_GCC_92)
-TOOLCHAIN_BIN := $(TOOLCHAIN_GCC_92)/bin
-GCC_TOOLCHAIN_BIN := $(TOOLCHAIN_BIN)
-CC := $(TOOLCHAIN_BIN)/$(TARGET)-gcc
-LD := $(TOOLCHAIN_BIN)/$(TARGET)-ld
-OBJCOPY := $(TOOLCHAIN_BIN)/$(TARGET)-objcopy
-OBJDUMP := $(TOOLCHAIN_BIN)/$(TARGET)-objdump
-endif
+$(eval $(call define_toolchain,$(TOOLCHAIN)))
##
## Common targets
@@ -201,6 +156,16 @@
KUT_DIST := $(DIST_DIR)/kvm-unit-tests
KUT_STAMP := $(KUT_OUT)/kvm-unit-tests.stamp
+ifneq ($(TOOLCHAIN_IS_LEGACY),1)
+KUT_TOOLCHAIN ?= $(TOOLCHAIN)
+else
+KUT_TOOLCHAIN ?= gcc-9.2
+endif
+$(eval $(call define_toolchain,$(KUT_TOOLCHAIN),KUT_))
+
+ifeq ($(KUT_TOOLCHAIN_IS_LLVM),1)
+KUT_CFLAGS += --target=$(KUT_TARGET) -fpic
+endif
.PHONY: kvm-unit-tests
kvm-unit-tests $(KUT_STAMP):
@@ -209,9 +174,9 @@
$(KUT_SRC)/configure \
--erratatxt=$(KUT_SRC)/errata.txt \
--prefix=$(KUT_OUT) --arch=$(ARCH) \
- --cc=$(CC) --ld=$(LD) \
- --objcopy=$(OBJCOPY) --objdump=$(OBJDUMP)
- COMMON_CFLAGS="$(COMMON_CFLAGS)" \
+ --cc=$(KUT_CC) --ld=$(KUT_LD) \
+ --objcopy=$(KUT_OBJCOPY) --objdump=$(KUT_OBJDUMP)
+ COMMON_CFLAGS="$(KUT_CFLAGS)" \
$(MAKE) -C $(KUT_OUT) standalone
$(call copy_to_dist, $(KUT_OUT)/tests, $(KUT_DIST))
touch $(KUT_STAMP)
@@ -229,20 +194,30 @@
LINUX_VERBOSE ?= $(VERBOSE)
LINUX_SRC ?= $(ROOT_DIR)/linux
LINUX_VMLINUX = $(LINUX_OUT)/vmlinux
+LINUX_CONFIG := $(LINUX_OUT)/.config
LINUX_DIST_FILES = $(LINUX_CONFIG) $(LINUX_VMLINUX) $(KERNEL_IMAGE)
+LINUX_TOOLCHAIN ?= $(TOOLCHAIN)
+$(eval $(call define_toolchain,$(LINUX_TOOLCHAIN),LINUX_))
+
+ifeq ($(LINUX_TOOLCHAIN_IS_LLVM),1)
+LINUX_EXTRA += LLVM=1 LLVM_IAS=1
+endif
+
LINUX_MAKE := \
PATH=$(LINUX_TOOLCHAIN_BIN):$(PATH) \
ARCH=$(ARCH) \
CROSS_COMPILE="$(LINUX_TARGET)-" \
$(MAKE) \
$(LINUX_EXTRA) \
+ CC=$(LINUX_CC) \
+ LD=$(LINUX_LD) \
+ OBJCOPY=$(LINUX_OBJCOPY) \
+ OBJDUMP=$(LINUX_OBJDUMP) \
-C $(LINUX_SRC) \
V=$(LINUX_VERBOSE) \
O=$(LINUX_OUT)
-LINUX_CONFIG := $(LINUX_OUT)/.config
-
.PHONY: linux_defconfig
linux_defconfig $(LINUX_CONFIG):
+ $(LINUX_MAKE) $(LINUX_DEFCONFIG)
diff --git a/toolchain.mk b/toolchain.mk
new file mode 100644
index 0000000..355648c
--- /dev/null
+++ b/toolchain.mk
@@ -0,0 +1,57 @@
+# Copyright 2021 The Android KVM Authors
+#
+# Licensed 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.
+
+# Find the toolchain path for the current OS.
+UNNAME_S := $(shell uname -s | tr '[:upper:]' '[:lower:]')
+TOOLCHAIN_arm64_clang := $(ROOT_DIR)/toolchains/$(UNNAME_S)-x86/clang/clang-r416183b
+TOOLCHAIN_arm64_gcc-5.1 := $(ROOT_DIR)/toolchains/$(UNNAME_S)-x86/gcc/aarch64-linux-gnu-5.1
+TOOLCHAIN_arm64_gcc-9.2 := $(ROOT_DIR)/toolchains/$(UNNAME_S)-x86/gcc/aarch64-linux-gnu-9.2
+
+# Set the toolchain build binary paths and prefixes.
+TARGET_arm64_clang := aarch64-linux-gnu
+TARGET_arm64_gcc-5.1 := aarch64-linux-gnu
+TARGET_arm64_gcc-9.2 := aarch64-none-linux-gnu
+
+#
+# $(1): toolchain name
+# $(2): toolchain variables' prefix
+#
+define define_toolchain
+ $(2)TOOLCHAIN_IS_LEGACY := 0
+ $(2)TOOLCHAIN_IS_LLVM := 0
+
+ ifeq ($(1), gcc-5.1)
+ $(2)TOOLCHAIN_IS_LEGACY := 1
+ else ifeq ($(1), gcc-9.2)
+ else ifeq ($(1), clang)
+ $(2)TOOLCHAIN_IS_LLVM := 1
+ else
+ $$(error Unrecognized toolchain: $(1))
+ endif
+
+ $(2)TOOLCHAIN_BIN := $(TOOLCHAIN_$(ARCH)_$(1))/bin
+ $(2)TARGET := $(TARGET_$(ARCH)_$(1))
+
+ ifeq ($$($(2)TOOLCHAIN_IS_LLVM),1)
+ $(2)CC := $$($(2)TOOLCHAIN_BIN)/clang
+ $(2)LD := $$($(2)TOOLCHAIN_BIN)/ld.lld
+ $(2)OBJCOPY := $$($(2)TOOLCHAIN_BIN)/llvm-objcopy
+ $(2)OBJDUMP := $$($(2)TOOLCHAIN_BIN)/llvm-objdump
+ else
+ $(2)CC := $$($(2)TOOLCHAIN_BIN)/$$($(2)TARGET)-gcc
+ $(2)LD := $$($(2)TOOLCHAIN_BIN)/$$($(2)TARGET)-ld
+ $(2)OBJCOPY := $$($(2)TOOLCHAIN_BIN)/$$($(2)TARGET)-objcopy
+ $(2)OBJDUMP := $$($(2)TOOLCHAIN_BIN)/$$($(2)TARGET)-objdump
+ endif
+endef