全志A64 lichee编译脚本build.sh分析

本文解析了lichee编译脚本的工作流程,包括如何通过./build.sh启动编译过程,涉及的环境变量设置,以及针对不同目标平台的编译逻辑。详细介绍了mklichee、mkbr、mkkernel和mkrootfs等函数的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

lichee目录下的./build.sh脚本:

    set -e  #用于指此脚本里执行的命令返回值非0时,终止当前脚本的执行.
    buildroot/scripts/mkcommon.sh $@   
    #接着执行mkcommon.sh脚本,并把执行"./build.sh"附带的所有参数($@)传递过去,这里$@是空的.

buildroot/scripts/mkcommon.sh:

    BR_SCRIPTS_DIR=`dirname $0` #$0表示第0个参数,即是"buildroot/scripts/mkcommon.sh"
                       #dirname命令用于获取路径, `dirname $0`获取得到"buildroot/scripts"

. ${BR_SCRIPTS_DIR}/shflags/shflags
[ -f .buildconfig ] && . .buildconfig #如有.buildconfig文件,则导出里面的变量. 此文件是由"./build.sh config"生成的.
. ${BR_SCRIPTS_DIR}/mkcmd.sh #导出脚本里的下面function命令,以便在当前脚本里可以调用访问.
        mkboot      build boot
        mkbr        build buildroot
        mkkernel    build kernel
        mkrootfs    build rootfs for linux, dragonboard
        mklichee    build total lichee
        mkclean     clean current board output
        mkdistclean clean entires output
        mkpack      pack firmware for lichee
        mkhelp      show this message


[ -f .buildconfig ] && . .buildconfig #如有.buildconfig文件,则导出下面的环境变量. 此文件用于指定编译的目标平台
    export LICHEE_CHIP=sun50iw1p1
    export LICHEE_PLATFORM=android
    export LICHEE_SECURE=
    export LICHEE_KERN_VER=linux-3.10
    export LICHEE_BOARD=p1


if [ "x$1" = "xconfig" ] ; then  #执行"./build.sh config"时触发
    . ${BR_SCRIPTS_DIR}/mksetup.sh  #出现选择界面
    exit $?   #返回
elif [ "x$1" = "xpack" ] ; then  #执行"./build.sh pack"时触发
    if [  "x$2" = "x-d" ] ; then
        init_defconf        #init_defconf命令是由buildroot/scripts/mkcmd.sh里提供的
        mkpack -d card0     #mkpack命令是由buildroot/scripts/mkcmd.sh里提供的
        exit $?
    else
        init_defconf
        mkpack
        exit $?
    fi
elif [ "x$1" = "xpack_debug" ] ; then  #执行"./build.sh pack_debug"时触发
    init_defconf
    mkpack -d card0
    exit $?
elif [ "x$1" = "xpack_dump" ] ; then   #执行"./build.sh pack_dump"时触发
    init_defconf
    mkpack -m dump
    exit $?
elif [ "x$1" = "xpack_secure" ] ; then  #执行"./build.sh pack_secure"时触发
    init_defconf
    mkpack -s secure
    exit $?
elif [ "x$1" = "xpack_debug_secure" ] ; then #执行"./build.sh pack_debug_secure"时触发
    init_defconf
    mkpack -s secure -d card0
    exit $?
elif [ "x$1" = "xpack_prev_refurbish" ] ; then #执行"./build.sh pack_prev_refurbish"时触发
        init_defconf
        mkpack -s secure -f prev_refurbish
        exit $?
elif [ "x$1" = "xpack_prvt" ] ; then  #执行"./build.sh pack_prvt"时触发
    init_defconf
    mkpack -f prvt
    exit $?
elif [ "x$1" = "xpack_nor" ] ;then #执行"./build.sh pack_nor"时触发
    init_defconf
    if [ "x$2" = "xdebug" ] ; then
        mkpack -f spinor -d card0
    else
        mkpack -f spinor
    fi
    exit $?
elif [ "x$1" = "xpack_erase" ] ; then  #执行"./build.sh pack_erase"时触发
    init_defconf
    mkpack -f erase
    exit $?
elif [ $# -eq 0 ] ; then  #执行"./build.sh"没任何参数时触发
    init_defconf
    mklichee   #编译内核及生成文件系统镜像
    exit $?
fi

“buildroot/scripts/mkcmd.sh” 556 行

function mklichee()
{

    mk_info "----------------------------------------"
    mk_info "build lichee ..."
    mk_info "chip: $LICHEE_CHIP"
    mk_info "platform: $LICHEE_PLATFORM"
    mk_info "secure: $LICHEE_SECURE"
    mk_info "kernel: $LICHEE_KERN_VER"
    mk_info "board: $LICHEE_BOARD"
    mk_info "output: out/${LICHEE_CHIP}/${LICHEE_PLATFORM}/${LICHEE_BOARD}" #这几个环境变量由.buildconfig提供.
    mk_info "----------------------------------------"

    check_env

    mkbr && mkkernel && mkrootfs  #分别执行mkbr, mkkernel, mkrootfs命令
    [ $? -ne 0 ] && return 1

    mk_info "----------------------------------------"
    mk_info "build lichee OK."
    mk_info "----------------------------------------"
}

脚本里所用的几个路径环境
LICHEE_TOP_DIR=`pwd`   #表示当前目录,即lichee目录下
LICHEE_BR_DIR=${LICHEE_TOP_DIR}/buildroot  #表示./buildroot目录
LICHEE_KERN_DIR=${LICHEE_TOP_DIR}/${LICHEE_KERN_VER}  #表示./linux-3.10目录
LICHEE_TOOLS_DIR=${LICHEE_TOP_DIR}/tools   #表示./tools目录
LICHEE_OUT_DIR=${LICHEE_TOP_DIR}/out       #表示./out目录


function mkbr()
{
    mk_info "build buildroot ..."

    local build_script="scripts/build.sh"
    (cd ${LICHEE_BR_DIR} && [ -x ${build_script} ] && ./${build_script})
    #cd ./buildroot  及执行./buildroot/scripts/build.sh脚本
        #因选择编译的目标平台为android,这个脚本里只作了配置交叉编译器。没有编译uboot

    [ $? -ne 0 ] && mk_error "build buildroot Failed" && return 1

    mk_info "build buildroot OK."
}

function mkkernel()
{
    mk_info "build kernel ..."

    local build_script="scripts/build.sh"

    prepare_toolchain

    # mark kernel .config belong to which platform
     #因可以选择编译android, linux等几个不同的目标平台, 内核里用.config.mark文件记录编译目标平台.
     #当选择的编译目标平台与上次编译的平台不同,则需要清除内核里已编译文件.
    local config_mark="${LICHEE_KERN_DIR}/.config.mark"
    if [ -f ${config_mark} ] ; then
        if ! grep -q "${LICHEE_PLATFORM}" ${config_mark} ; then
            mk_info "clean last time build for different platform"
            (cd ${LICHEE_KERN_DIR} && [ -x ${build_script} ] && ./${build_script} "clean")
            echo "${LICHEE_PLATFORM}" > ${config_mark}
        fi
    else
        echo "${LICHEE_PLATFORM}" > ${config_mark}
    fi

    (cd ${LICHEE_KERN_DIR} && [ -x ${build_script} ] && ./${build_script})
    #进入内核源码目录./linux-3.10下,执行里面的./script/build.sh脚本
    #默认会编译内核,动态驱动模块和ramfs等.
    [ $? -ne 0 ] && mk_error "build kernel Failed" && return 1

    mk_info "build kernel OK."
}

function mkrootfs()  #因编译的目标平台为android, 所以这里基本什么都不做.
{
    mk_info "build rootfs ..."

    if [ ${LICHEE_PLATFORM} = "linux" ] ; then
        make O=${LICHEE_BR_OUT} -C ${LICHEE_BR_DIR} target-generic-getty-busybox
        [ $? -ne 0 ] && mk_error "build rootfs Failed" && return 1
        make O=${LICHEE_BR_OUT} -C ${LICHEE_BR_DIR} target-finalize
        [ $? -ne 0 ] && mk_error "build rootfs Failed" && return 1
        make O=${LICHEE_BR_OUT} -C ${LICHEE_BR_DIR} LICHEE_GEN_ROOTFS=y rootfs-ext4
        [ $? -ne 0 ] && mk_error "build rootfs Failed" && return 1
        cp ${LICHEE_BR_OUT}/images/rootfs.ext4 ${LICHEE_PLAT_OUT}
          if [ -f "${LICHEE_BR_OUT}/images/rootfs.squashfs" ]; then
           cp ${LICHEE_BR_OUT}/images/rootfs.squashfs ${LICHEE_PLAT_OUT}
        fi
        if [ "x$PACK_TINY_ANDROID" = "xtrue" ];then
            packtinyandroid
        fi
    elif [ ${LICHEE_PLATFORM} = "dragonboard" ] ; then
        echo "Regenerating dragonboard Rootfs..."
           (
            cd ${LICHEE_BR_DIR}/target/dragonboard; \
            if [ ! -d "./rootfs" ]; then \
            echo "extract dragonboard rootfs.tar.gz"; \
            tar zxf rootfs.tar.gz; \
            fi
          )
        tooldir_32=${LICHEE_BR_OUT}/external-toolchain_32
        export PATH=${tooldir_32}/bin:$PATH
        export LICHEE_TOOLCHAIN_PATH=${tooldir_32}
        mkdir -p ${LICHEE_BR_DIR}/target/dragonboard/rootfs/lib/modules
        rm -rf ${LICHEE_BR_DIR}/target/dragonboard/rootfs/lib/modules/*
        cp -rf ${LICHEE_KERN_DIR}/output/lib/modules/* ${LICHEE_BR_DIR}/target/dragonboard/rootfs/lib/modules/
        (cd ${LICHEE_BR_DIR}/target/dragonboard; ./build.sh)
        cp ${LICHEE_BR_DIR}/target/dragonboard/rootfs.ext4 ${LICHEE_PLAT_OUT}
    else
        mk_info "skip make rootfs for ${LICHEE_PLATFORM}"
    fi

    mk_info "build rootfs OK."
}

内核源码编译脚本 linux-3.10/scripts/build.sh里的内核编译命令:

LICHEE_KDIR=`pwd`
LICHEE_MOD_DIR=${LICHEE_KDIR}/output/lib/modules/${KERNEL_VERSION}

build_kernel()
{
    echo "Building kernel"

    cd ${LICHEE_KDIR}

    rm -rf output/
    echo "${LICHEE_MOD_DIR}"
    mkdir -p ${LICHEE_MOD_DIR}

    # We need to copy rootfs files to compile kernel for linux image
    echo "lichee_chip = $LICHEE_CHIP"
    if [ "${LICHEE_CHIP}" = "sun8iw10p1" ] || [ "${LICHEE_CHIP}" = "sun8iw11p1" ]; then
        echo "cp rootfs_32bit.cpio.gz"
        cp -f rootfs_32bit.cpio.gz output/rootfs.cpio.gz
    else
        cp -f rootfs.cpio.gz output/   #复制rootfs.cpio.gz文件系统镜像到output目录
    fi
    #exchange sdc0 and sdc2 in sun50iw1p1 for dragonBoard card boot
    if [ "x${LICHEE_PLATFORM}" = "xdragonboard"  -a "x${LICHEE_CHIP}" = "xsun50iw1p1" ]; then  #不成立
        local SYS_CONFIG_FILE=../tools/pack/chips/${LICHEE_CHIP}/configs/${LICHEE_BOARD}/sys_config.fex
        local DTS_PATH=./arch/arm64/boot/dts/

        #sun50iw1p1_bak.dtsi means the orginal dtsi
        if [ -f ${DTS_PATH}/sun50iw1p1_bak.dtsi ];then
            #sun50iw1p1.dtsi that we use in fact
            rm -f ${DTS_PATH}/sun50iw1p1.dtsi
            mv ${DTS_PATH}/sun50iw1p1_bak.dtsi ${DTS_PATH}/sun50iw1p1.dtsi
        fi
        # if find dragonboard_test=1 in sys_config.fex ,then will exchange sdc0 and sdc2
        if [ -n "`grep "dragonboard_test" $SYS_CONFIG_FILE | grep "1" | grep -v ";"`" ]; then
            cp ${DTS_PATH}/sun50iw1p1.dtsi  ${DTS_PATH}/sun50iw1p1_bak.dtsi
            rm -f ${DTS_PATH}/sun50iw1p1.dtsi
            cp  ${DTS_PATH}/sun50iw1p1_for_dragonboard.dtsi   ${DTS_PATH}/sun50iw1p1.dtsi
        fi
    fi

    if [ ! -f .config ] ; then  #如果没有内核的配置文件.config, 则使用arch/arm64/configs/sun50iw1p1smp_android_defconfig配置文件
        printf "\n\033[0;31;1mUsing default config ${LICHEE_KERN_DEFCONF} ...\033[0m\n\n"
        cp arch/${ARCH}/configs/${LICHEE_KERN_DEFCONF} .config
    fi

    if [ "x$SUNXI_CHECK" = "x1" ];then
        SUNXI_SPARSE_CHECK=1
        SUNXI_SMATCH_CHECK=1
        SUNXI_STACK_CHECK=1
    fi
    if [ "x$SUNXI_SPARSE_CHECK" = "x" ] && [ "x$SUNXI_SMATCH_CHECK" = "x" ];then
        make ARCH=${ARCH} CROSS_COMPILE=${CROSS_COMPILE} -j${LICHEE_JLEVEL} all modules
    else
        if [ "x$SUNXI_SPARSE_CHECK" = "x1" ] && [ -f ../tools/codecheck/sparse/sparse ];then
            echo "\n\033[0;31;1mBuilding Round for sparse check ${KERNEL_CFG}...\033[0m\n\n"
            make clean
            make CHECK="../tools/codecheck/sparse/sparse" ARCH=${ARCH} CROSS_COMPILE=${CROSS_COMPILE} -j${LICHEE_JLEVEL} C=2 all modules 2>&1|tee output/build_sparse.txt
            cat output/build_sparse.txt|egrep -w '(warn|error|warning)' >output/warn_sparse.txt
        fi
        if [ "x$SUNXI_SMATCH_CHECK" = "x1" ]&& [ -f ../tools/codecheck/smatch/smatch ];then
            echo "\n\033[0;31;1mBuilding Round for smatch check ${KERNEL_CFG}...\033[0m\n\n"
            make clean
            make CHECK="../tools/codecheck/smatch/smatch --full-path --no-data -p=kkernel" ARCH=${ARCH} CROSS_COMPILE=${CROSS_COMPILE} -j${LICHEE_JLEVEL} C=2 all modules 2>&1|tee output/build_smatch.txt
            cat output/build_smatch.txt|egrep -w '(warn|error|warning)' >output/warn_smatch.txt
        fi
    fi
    if [ "x$SUNXI_STACK_CHECK" = "x1" ];then
        make ARCH=${ARCH} CROSS_COMPILE=${CROSS_COMPILE} -j${LICHEE_JLEVEL} checkstack 2>&1|tee output/warn_stack.txt
    fi
    update_kern_ver

    #The Image is origin binary from vmlinux.
    if [ -f arch/${ARCH}/boot/Image ]; then
        cp -vf arch/${ARCH}/boot/Image output/bImage
    fi

    if [ -f arch/${ARCH}/boot/zImage ] || [ -f arch/${ARCH}/boot/uImage ]; then
        cp -vf arch/${ARCH}/boot/[zu]Image output/
    fi

    if [ -f arch/${ARCH}/boot/Image.gz ]; then
        cp -vf arch/${ARCH}/boot/Image.gz output/
    fi

    cp .config output/

    tar -jcf output/vmlinux.tar.bz2 vmlinux
    for file in $(find drivers sound crypto block fs security net -name "*.ko"); do
        cp $file ${LICHEE_MOD_DIR}
    done
    cp -f Module.symvers ${LICHEE_MOD_DIR}

}
<think>好的,我现在需要帮助用户将全志8152相关的C文件编译为Linux内核模块(.ko文件)。首先,我应该回忆一下内核模块编译的基本步骤。根据引用[2],内核模块的编译分为静态和动态两种,这里用户需要动态编译成ko文件,所以需要用到动态编译的方法。 首先,用户需要有全志8152的C源码,并且确认源码中包含模块所需的入口和出口函数,比如module_init和module_exit。然后,用户需要对应的内核头文件或者已经编译好的内核源码树,这样才能正确编译模块。 接下来,用户需要编写一个Makefile。根据引用[2]中的信息,Makefile需要指定内核源码的路径。例如,使用obj-m来指定模块名称,然后通过-C指向内核源码目录,再回到当前目录执行编译。这应该是一个标准的Makefile模板。 另外,用户可能需要配置内核选项。如果模块依赖某些内核配置,可能需要先运行make menuconfig之类的命令来确保相关选项已启用。但如果是动态加载的模块,可能不需要修改内核配置,只要内核支持模块加载即可。 然后,编译命令应该是make -C指定内核目录,然后M=当前模块目录。这需要用户的内核源码已经编译过,生成了必要的头文件和模块符号表。如果用户的内核源码没有编译过,可能需要先编译内核,如引用[3]提到的多线程编译,可以用make -j128来加速。 用户可能遇到的问题包括内核版本不匹配、缺少依赖的头文件或者配置不正确。需要提醒用户检查内核版本是否与模块兼容,确保Makefile中的路径正确,以及安装必要的开发工具和依赖包。 另外,全志平台可能有特定的编译脚本或工具,比如引用[1]提到的build.sh脚本,或者引用[5]中的mkfs.sh,但这里主要是编译内核模块,可能不需要这些脚本,但需要注意平台相关的配置选项。 最后,生成ko文件后,用户可以通过insmod或modprobe加载模块,测试是否正常工作。如果出现错误,可能需要查看dmesg日志来调试。 总结步骤应该是:准备源码和内核环境,编写Makefile,执行编译命令,处理可能的问题,测试模块。同时需要确保用户具备必要的编译环境,如gcc、make工具链,以及内核开发包等。</think>要将全志8152的C源码编译为Linux内核模块(.ko文件),需遵循以下步骤: --- ### 1. **准备内核头文件/源码** - 确保已安装与当前运行内核版本一致的内核头文件或完整内核源码树。 - 全志平台通常需要基于其定制内核编译,可从官方获取对应SDK(如引用[3]提到的Tina Linux)并完成基础编译: ```bash make kernel_menuconfig # 配置内核选项(可选) make -jN # 编译内核,N为线程数(如-j128) ``` --- ### 2. **编写模块源码** - C源码需包含模块初始化函数(`module_init()`)和退出函数(`module_exit()`),例如: ```c #include <linux/module.h> static int __init my_module_init(void) { printk("全志8152模块加载成功\n"); return 0; } static void __exit my_module_exit(void) { printk("模块卸载\n"); } module_init(my_module_init); module_exit(my_module_exit); MODULE_LICENSE("GPL"); ``` --- ### 3. **编写Makefile** - 创建`Makefile`文件,指定内核源码路径和模块名称(假设源码文件为`my_module.c`): ```makefile obj-m += my_module.o # 模块目标名称 KERNEL_DIR ?= /path/to/kernel # 替换为全志SDK中的内核路径(如lichee/linux-xxx) all: make -C $(KERNEL_DIR) M=$(PWD) modules clean: make -C $(KERNEL_DIR) M=$(PWD) clean ``` - **注意**:全志平台的内核路径通常在SDK的`lichee`目录下(引用[1][3])。 --- ### 4. **执行编译** - 在源码目录运行: ```bash make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- # 若需交叉编译(如ARM平台) ``` - 编译成功后生成`my_module.ko`文件。 --- ### 5. **模块加载与测试** - 将`.ko`文件传输到设备,使用以下命令操作模块: ```bash insmod my_module.ko # 加载模块 dmesg | tail # 查看内核日志验证输出 rmmod my_module # 卸载模块 ``` --- ### 常见问题解决 1. **依赖缺失** - 确保安装了`build-essential`、`kernel-package`等工具链(引用[4])。 2. **内核版本不匹配** - 使用`uname -r`查看运行内核版本,确保与编译环境一致。 3. **交叉编译配置** - 全志平台需使用指定工具链(如`arm-linux-gnueabihf-gcc`),需在Makefile或环境变量中配置(引用[3])。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值