1. 下载内核

1
2
repo init -u https://mirrors.ustc.edu.cn/aosp/kernel/manifest.git/ -b android-msm-redbull-4.19-android11-qpr3
repo sync

2. 编译内核

./build/build.sh

3. 引子

魔幻的地方来了,网上千篇一律都是推荐这么编译,偏偏我这里报错不断。花了一点时间,跟踪了build的脚本执行流程。

4. 分析

build.sh 其实就是准备Linux 内核编译所需的各种编译参数,如交叉编译工具链,编译环境变量等。 还有android特有的一些配置,如特殊的内核源码位置,输出文件的位置等。 以下按照调用流程分析:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
# build/build.sh
# 配置环境变量
source "${ROOT_DIR}/build/_setup_env.sh"


# build/_setup_env.sh
# 定义配置参数
export BUILD_CONFIG=${BUILD_CONFIG:-build.config}

# build/build.config
# 配置编译器 环境变量等
. ${ROOT_DIR}/${KERNEL_DIR}/build.config.redbull.common.clang
# 给 POST_DEFCONFIG_CMDS 赋值,之后在build.sh会调用到
POST_DEFCONFIG_CMDS="check_defconfig && update_nocfi_config"

# private/msm-google/build.config.redbull.common.clang
. ${ROOT_DIR}/${KERNEL_DIR}/build.config.redbull.common
CC=clang # 设置编译器
LD=ld.lld
CLANG_TRIPLE=aarch64-linux-gnu-

# private/msm-google/build.config.redbull.common
# 编译器选项
CROSS_COMPILE=aarch64-linux-gnu-
CROSS_COMPILE_ARM32=arm-linux-gnueabi-
CROSS_COMPILE_COMPAT=$CROSS_COMPILE_ARM32
# 编译器模式,编译器所在的目录
LLVM=1
DEPMOD=depmod
CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r383902/bin
BUILDTOOLS_PREBUILT_BIN=build/build-tools/path/linux-x86

# 回到_setup_env.sh
# 设置环境变量PATH
PREBUILTS_PATHS=(
LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN
LINUX_GCC_CROSS_COMPILE_ARM32_PREBUILTS_BIN
LINUX_GCC_CROSS_COMPILE_COMPAT_PREBUILTS_BIN
CLANG_PREBUILT_BIN
LZ4_PREBUILTS_BIN
DTC_PREBUILTS_BIN
LIBUFDT_PREBUILTS_BIN
BUILDTOOLS_PREBUILT_BIN
)
for PREBUILT_BIN in "${PREBUILTS_PATHS[@]}"; do
    PREBUILT_BIN=\${${PREBUILT_BIN}}
    eval PREBUILT_BIN="${PREBUILT_BIN}"
    if [ -n "${PREBUILT_BIN}" ]; then
        # Mitigate dup paths
        PATH=${PATH//"${ROOT_DIR}\/${PREBUILT_BIN}:"}
        PATH=${ROOT_DIR}/${PREBUILT_BIN}:${PATH}
    fi
done
export PATH

# 回到 build.sh
# 导出环境变量
export CLANG_TRIPLE CROSS_COMPILE CROSS_COMPILE_COMPAT CROSS_COMPILE_ARM32 ARCH SUBARCH MAKE_GOALS

# 设置编译器
  HOSTCC=clang
  HOSTCXX=clang++
  CC=clang
  LD=ld.lld
  AR=llvm-ar
  NM=llvm-nm
  OBJCOPY=llvm-objcopy
  OBJDUMP=llvm-objdump
  READELF=llvm-readelf
  OBJSIZE=llvm-size
  STRIP=llvm-strip

# 编译前的准备工作,主要是生成内核编译所需的 .config 文件
  if [ -n "${POST_DEFCONFIG_CMDS}" ]; then
    echo "========================================================"
    echo " Running pre-make command(s):"
    set -x
    eval ${POST_DEFCONFIG_CMDS} # 就是 check_defconfig && update_nocfi_config
    set +x
  fi

# 生成 .config  build/build.config
function update_nocfi_config() {
  # Disable clang-specific options
  ${KERNEL_DIR}/scripts/config --file ${OUT_DIR}/.config \
    -e THINLTO \
    -d CFI \
    -d CFI_PERMISSIVE \
    -d CFI_CLANG
  (cd ${OUT_DIR} && \
    make O=${OUT_DIR} CLANG_TRIPLE=${CLANG_TRIPLE} CROSS_COMPILE=${CROSS_COMPILE} "${TOOL_ARGS[@]}" ${MAKE_ARGS} olddefconfig)
  # 展开为:
  + make O=/kernel_android-msm-redbull-4.19-android11-qpr3/out/android-msm-pixel-4.19/private/msm-google CLANG_TRIPLE=aarch64-linux-gnu- CROSS_COMPILE=aarch64-linux-gnu- LLVM=1 DEPMOD=depmod olddefconfig
  + GEN     ./Makefile
  + scripts/kconfig/conf  --olddefconfig Kconfig
  + # configuration written to .config
}

# 接下来的主要工作就是编译内核了
# build/build.sh
echo " Building kernel"
set -x
(cd ${OUT_DIR} && make O=${OUT_DIR} "${TOOL_ARGS[@]}" ${MAKE_ARGS} ${MAKE_GOALS})
set +x
# 展开为:
+ cd /kernel_android-msm-redbull-4.19-android11-qpr3/out/android-msm-pixel-4.19/private/msm-google
+ make O=/kernel_android-msm-redbull-4.19-android11-qpr3/out/android-msm-pixel-4.19/private/msm-google LLVM=1 DEPMOD=depmod

5. 问题解决

报错1:

编译内核时报错: /usr/bin/as: unrecognized option '-EL': 排查为在编译时,之前设置的环境变量没有被获取到。 临时解决方式: 打印出环境变量,手动export,并执行make: env 保存到 env.sh source env.sh

手动执行 echo " Building kernel" 步骤。

或者:

1
2
3
4
5
6
7
echo " Building kernel"

set -x
echo "----------env:"
env > /tmp/env
echo "----------done"
(cd ${OUT_DIR} && source /tmp/env && make O=${OUT_DIR} "${TOOL_ARGS[@]}" ${MAKE_ARGS} ${MAKE_GOALS})

报错2:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
In file included from /kernel_android-msm-redbull-4.19-android11-qpr3/private/msm-google/init/version.c:9:
./include/generated/compile.h:7:24: error: missing terminating '"' character [-Werror,-Winvalid-pp-token]
#define LINUX_COMPILER "Android (6443078 based on r383902) clang version 11.0.1 (https://android.googlesource.com/toolchain/llvm-project b397f81060ce6d701042b782172ed13bee898b79)
                       ^
./include/generated/compile.h:8:1: error: unknown type name 'Found'
Found CUDA installation: /usr/local/cuda, version 7.0, LLD 11.0.1 (/buildbot/tmp/tmp6_m7QH b397f81060ce6d701042b782172ed13bee898b79)"
^
./include/generated/compile.h:8:11: error: expected ';' after top level declarator
Found CUDA installation: /usr/local/cuda, version 7.0, LLD 11.0.1 (/buildbot/tmp/tmp6_m7QH b397f81060ce6d701042b782172ed13bee898b79)"
          ^
          ;
./include/generated/compile.h:8:133: error: missing terminating '"' character [-Werror,-Winvalid-pp-token]

查看 compile.h内容: cat out/android-msm-pixel-4.19/private/msm-google/include/generated/compile.h

1
2
3
4
5
6
7
8
/* This file is auto generated, version 1 */
/* SMP PREEMPT */
#define UTS_MACHINE "aarch64"
#define UTS_VERSION "#1 SMP PREEMPT Tue Jul 30 23:49:29 CST 2024"
#define LINUX_COMPILE_BY "xxx"
#define LINUX_COMPILE_HOST "xxxx"
#define LINUX_COMPILER "Android (6443078 based on r383902) clang version 11.0.1 (https://android.googlesource.com/toolchain/llvm-project b397f81060ce6d701042b782172ed13bee898b79)
Found CUDA installation: /usr/local/cuda, version 7.0, LLD 11.0.1 (/buildbot/tmp/tmp6_m7QH b397f81060ce6d701042b782172ed13bee898b79)"

多了最后一行。

grep了整个项目,发现,最后一行在clang中有关键字:

1
2
3
4
5
6
7
8
9
grep -nr 'Found CUDA installation' ./
grep: ./prebuilts-master/clang/host/linux-x86/clang-r377782c/bin/clang-10: binary file matches
grep: ./prebuilts-master/clang/host/linux-x86/clang-r377782c/bin/clang-check: binary file matches
grep: ./prebuilts-master/clang/host/linux-x86/clang-r377782c/bin/clang-tidy.real: binary file matches
grep: ./prebuilts-master/clang/host/linux-x86/clang-r377782c/lib64/libclang_cxx.so.10git: binary file matches
grep: ./prebuilts-master/clang/host/linux-x86/clang-r377782c/lib64/liblldb.so.10.0.5git: binary file matches
grep: ./prebuilts-master/clang/host/linux-x86/clang-r377782c/lib64/libclang.so.10git: binary file matches
grep: ./prebuilts-master/clang/host/linux-x86/clang-r377782b/bin/clang-10: binary file matches
...

最终在 kernel: Force disable LLVM CUDA 找到答案:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
index 2409894..40285e5 100644
--- a/build/tasks/kernel.mk
+++ b/build/tasks/kernel.mk
@@ -239,7 +239,7 @@
     endif
     PATH_OVERRIDE += PATH=$(TARGET_KERNEL_CLANG_PATH)/bin:$$PATH
     ifeq ($(KERNEL_CC),)
-        KERNEL_CC := CC="$(CCACHE_BIN) clang"
+        KERNEL_CC := CC="$(CCACHE_BIN) clang --cuda-path=/dev/null"
     endif
 endif

编辑:private/msm-google/Makefile

1
2
- CLANG_FLAGS :=
+ CLANG_FLAGS := --cuda-path=/dev/null

终极解决方案, 换版本。其他版本的内核 执行 bash build/build.sh 可以直接编译成功(makefile 中 cuda 的修改仍是必须的)。

6. 不能启动问题修复

找到aosp编译中的原版 boot.img:
out/target/product/bramble/boot.img
解压工具:(Android_boot_image_editor)[https://github.com/cfig/Android_boot_image_editor.git]

1
2
3
4
5
6
7
8
9
cd Android_boot_image_editor
./gradlew unpack
cp /aosp/out/target/product/bramble/boot.img ./
cd build/unzip_boot
cp /android-msm-redbull-4.19-android13/out/android-msm-pixel-4.19/dist/Image.lz4-dtb ./kernel
./gradlew pack

adb reboot bootloader
fastboot boot boot.img.signed

此时启动会卡住,然后重启。

1
2
3
4
cd private/msm-google/arch/arm64/configs
mv redbull_defconfig redbull_defconfig_bak
拷贝上面 build/unzip_boot 的 kernel_configs.txt
cp /Android_boot_image_editor/build/unzip_boot/kernel_configs.txt out/android-msm-pixel-4.19/private/msm-google/.config

7. 启动kasan

编辑aosp 中 device/google/redbull/BoardConfig-common.mk

1
2
3
4
5
# Kernel modules
# 最有一个else
KERNEL_MODULE_DIR := $(TARGET_KERNEL_DIR)
# 改为
KERNEL_MODULE_DIR := $(TARGET_KERNEL_DIR)/kasan

重新 编译工程,生成新的 boot.img 拷贝新 boot.img 的 config 作为编译 config

内核编译中的环境变量

  • 默认配置 自定义config 的时候 置为1 export SKIP_DEFCONFIG=1
  • 清理编译临时文件 一般增量编译的时候,置为1 export SKIP_MRPROPER=1

./build/build.sh