交叉编译项目设置
编译目录结构
build 主目录
├── deb 存放打包脚本所生成的deb包
├── deps 存放系统驱动头文件
├── obj 存放交叉编译产生的中间文件
├── output 存放交叉编译产生的目标文件
├── scripts 存放交叉编译脚本和打包脚本
└── src 存放项目源码
实现的要求
1:将项目编译所生成的中间文件和目标文件与源码分离
2:使用同一份源码调用相应的编译环境生成不同架构的驱动和应用
交叉编译脚本CrossedCompile.sh
#!/bin/bash
BUILD_PATH=$([[ "$0" = /* ]] && echo "$(realpath $(dirname $0)/../)" || echo "$(realpath $(dirname $PWD/$0)/../)")
DEPS_PATH=${BUILD_PATH}/deps
OBJ_PATH=${BUILD_PATH}/obj
SRC_PATH=${BUILD_PATH}/src
OUTPUT_PATH=${BUILD_PATH}/output
MKDIR="mkdir -p"
RMDIR="rm -rf"
LINK="ln -sf"
QMAKE=qmake
MAKE="make -j16"
function CompileApplication()
{
case ${1} in
x86_64)
QMAKE="qmake_x86_64";;
aarch64)
QMAKE="qmake_aarch64";;
loongarch64)
QMAKE="qmake_loongarch64";;
mips64)
QMAKE="qmake_mips64";;
*)
return 1;;
esac
local AbsoluteSrcPath=${2}
if [[ "${AbsoluteSrcPath}" = /* ]]; then
AbsoluteSrcPath=$(realpath -s ${AbsoluteSrcPath})
else
AbsoluteSrcPath=$(realpath -s $(dirname ${PWD}/${AbsoluteSrcPath}))
fi
local TargetObjPath=$(echo ${AbsoluteSrcPath} | sed "s#${SRC_PATH}#${OBJ_PATH}/${1}#")
local TargetOutputPath=$(echo ${AbsoluteSrcPath} | sed "s#${SRC_PATH}#${OUTPUT_PATH}/${1}#")
if [ -d ${AbsoluteSrcPath} ]; then
if [ -f ${AbsoluteSrcPath}/*.pro ]; then
${MKDIR} ${TargetObjPath} ${TargetOutputPath}
cd ${TargetObjPath} && ${QMAKE} "DESTDIR=${TargetOutputPath}" "LIBS+=-L${TargetOutputPath}" -o Makefile $(ls ${AbsoluteSrcPath}/*.pro) && make
elif [ -f $(ls ${AbsoluteSrcPath}/Makefile) ]; then
${MKDIR} ${TargetObjPath} ${TargetOutputPath}
${LINK} ${AbsoluteSrcPath}/Makefile ${TargetObjPath}
cd ${TargetObjPath} && ${MAKE} ARCH=${1} OBJ_PATH=${TargetObjPath} OUTPUT_PATH=${TargetOutputPath}
else
echo "编译失败: 目录(${AbsoluteSrcPath})没有可编译的项目"
return 1
fi
elif [ -f ${AbsoluteSrcPath} ]; then
if [[ "${AbsoluteSrcPath}" = *.pro ]]; then
TargetObjPath=$(dirname ${TargetObjPath})
TargetOutputPath=$(dirname ${TargetOutputPath})
${MKDIR} ${TargetObjPath} ${TargetOutputPath}
cd ${TargetObjPath} && ${QMAKE} "DESTDIR=${TargetOutputPath}" "LIBS+=-L${TargetOutputPath}" -o Makefile ${AbsoluteSrcPath} && make
elif [[ "${AbsoluteSrcPath}" = */Makefile ]]; then
TargetObjPath=$(dirname ${TargetObjPath})
TargetOutputPath=$(dirname ${TargetOutputPath})
${MKDIR} ${TargetObjPath} ${TargetOutputPath}
${LINK} ${AbsoluteSrcPath} ${TargetObjPath}
cd ${TargetObjPath} && ${MAKE} ARCH=${1} OBJ_PATH=${TargetObjPath} OUTPUT_PATH=${TargetOutputPath}
else
echo "编译失败: 项目文件(${AbsoluteSrcPath})无可用编译应用"
return 1
fi
else
echo "编译失败: 路径(${AbsoluteSrcPath})不存在"
return 1
fi
}
function CompileDriver()
{
local AbsoluteSrcPath=${3}
local Arch=${1}
case ${1} in
x86_64)
Arch="x86";;
aarch64)
Arch="arm64";;
loongarch64)
Arch="loongarch64";;
mips64)
Arch="mips";;
*)
return 1;;
esac
if [[ "${AbsoluteSrcPath}" = /* ]]; then
AbsoluteSrcPath=$(realpath -s ${AbsoluteSrcPath})
else
AbsoluteSrcPath=$(realpath -s $(dirname ${PWD}/${AbsoluteSrcPath}))
fi
local TargetObjPath=$(echo ${AbsoluteSrcPath} | sed "s#${SRC_PATH}#${OBJ_PATH}/${1}#")
local TargetOutputPath=$(echo ${AbsoluteSrcPath} | sed "s#${SRC_PATH}#${OUTPUT_PATH}/${1}#")
if [ -d ${AbsoluteSrcPath} ]; then
if [ -f ${AbsoluteSrcPath}/Makefile ]; then
${MKDIR} ${TargetObjPath} ${TargetOutputPath}
${LINK} ${AbsoluteSrcPath}/Makefile ${TargetObjPath}
cd ${TargetObjPath} && ${MAKE} DEC_OS_DRIVER_ARCH=${Arch} DEC_OS_HEADER_PATH=${2} DEC_OS_CROSS_COMPILE=${1}-linux-gnu- DEC_OS_OUTPUT_PATH=${TargetOutputPath}
else
echo "编译失败: 目录(${AbsoluteSrcPath})没有可编译的驱动"
return 1
fi
elif [ -f ${AbsoluteSrcPath} ]; then
if [[ "${AbsoluteSrcPath}" = */Makefile ]]; then
TargetObjPath=$(dirname ${TargetObjPath})
TargetOutputPath=$(dirname ${TargetOutputPath})
${MKDIR} ${TargetObjPath} ${TargetOutputPath}
${LINK} ${AbsoluteSrcPath} ${TargetObjPath}
cd ${TargetObjPath} && ${MAKE} DEC_OS_DRIVER_ARCH=${Arch} DEC_OS_HEADER_PATH=${2} DEC_OS_CROSS_COMPILE=${1}-linux-gnu- DEC_OS_OUTPUT_PATH=${TargetOutputPath}
else
echo "编译失败: 项目文件(${AbsoluteSrcPath})无可用编译策略"
return 1
fi
else
echo "编译失败: 路径(${AbsoluteSrcPath})不存在"
return 1
fi
}
argv=()
argc=1
argv[0]=${0}
for value in ${@}
do
argv[argc]=${value}
let argc++
done
if [ ${argc} -gt 4 ] && [ "${1}" = "km" ]; then
for ((i=4; i<${argc}; ++i))
do
printf "编译驱动 %12s架构 系统头文件路径(%s) 源码路径(%s)\n" ${argv[2]} ${argv[3]} ${argv[${i}]}
CompileDriver ${argv[2]} ${argv[3]} ${argv[${i}]}
done
elif [ ${argc} -gt 3 ] && [ "${1}" = "um" ]; then
for ((i=3; i<${argc}; ++i))
do
printf "编译应用 %12s架构 源码路径(%s)\n" ${argv[2]} ${argv[${i}]}
CompileApplication ${argv[2]} ${argv[${i}]}
done
else
echo "编译驱动: ${argv[0]} km 系统架构(x86_64/aarch64/loongarch64) 系统头文件路径 源码路径1 源码路径2 源码路径3 ..."
echo "编译应用: ${argv[0]} um 系统架构(x86_64/aarch64/loongarch64) 源码路径1 源码路径2 源码路径3 ..."
fi
作用:
编译应用和驱动时,由源码路径确定中间文件和目标文件在obj和output目录的相应位置,并传给Makefile或qmake实现中间文件和目标文件与源码分离,并加入架构参数实现同一份源码在使用不同架构的编译环境时,目标文件和中间文件相隔离。
参数 1: um(编译应用) 或 km(编译驱动)
参数2: x86_64、 aarch64 、 loongarch64 或 mips64
参数3:编译应用时可输入源码文件夹的绝对路径,pro文件的绝对路径或Makefile的绝对路径。
编译驱动时可输入源码文件夹的绝对路径或Makefile的绝对路径。
注意事项:
编译应用时:
若参数3输入的是pro文件的绝对路径,则会调用相应建构的qmake程序在obj目录的对应子目录底下生成Makefile文件。
若参数3输入的是Makefile文件的绝对路径,则会在obj目录的对应子目录底下生成所指定的Makefile文件的软连接。
若参数3输入的源码文件夹的绝对路径,则会优先使用源码文件夹中的pro文件,因此需要保证源码文件夹中只存在一个pro文件
若pro文件中不存在pro文件,则会查找源码文件夹中的Makefile文件。
编译驱动时:
若参数3输入的是Makefile文件的绝对路径,则会在obj目录的对应子目录底下生成所指定的Makefile文件的软连接。
若参数3输入的源码文件夹的绝对路径,则会查找源码文件夹中的Makefile文件。
由于目标文件被分离到output目录,因此若pro工程中要使用内部库,则要对pro文件的内部库路径设置进行修改,增加exists函数对内部库的路径进行判断。
exists($$OUT_PWD/../deccryptobase/libdeccryptobase.a): {
unix:!macx: LIBS += -L$$OUT_PWD/../deccryptobase/ -ldeccryptobase
unix:!macx: PRE_TARGETDEPS += $$OUT_PWD/../deccryptobase/libdeccryptobase.a
}
exists($$DESTDIR/libdeccryptobase.a): {
unix:!macx: LIBS += -L$$DESTDIR/ -ldeccryptobase
unix:!macx: PRE_TARGETDEPS += $$DESTDIR/libdeccryptobase.a
}
Makefile示例
编译应用
ARCH ?= $(shell arch)
SOURCE_PATH ?= $(shell realpath $(dir $(shell realpath `pwd`/Makefile)))
OBJ_PATH ?= $(shell pwd)
OUTPUT_PATH ?= $(shell pwd)
TARGET ?= $(shell echo $(SOURCE_PATH) | awk -F '/' '{ print $$NF }')
CC := ${ARCH}-linux-gnu-gcc
CXX := ${ARCH}-linux-gnu-g++
LINKER := $(CC)
CC_FLAGS := -I$(SOURCE_PATH)
CXX_FLAGS := -I$(SOURCE_PATH)
DIRS := $(shell find $(SOURCE_PATH) -maxdepth 1 -type d)
C_SOURCE := $(foreach dir, $(DIRS), $(wildcard $(dir)/*.c))
CXX_SOURCE := $(foreach dir, $(DIRS), $(wildcard $(dir)/*.cpp))
C_OBJS := $(patsubst $(SOURCE_PATH)%.c,$(OBJ_PATH)%-c.o,$(C_SOURCE))
CXX_OBJS := $(patsubst $(SOURCE_PATH)%.cpp,$(OBJ_PATH)%-cxx.o,$(CXX_SOURCE))
target: $(C_OBJS) $(CXX_OBJS)
if [ ! -d $(OUTPUT_PATH) ]; then mkdir -p $(OUTPUT_PATH); fi
${LINKER} -o $(OUTPUT_PATH)/$(TARGET) $(C_OBJS) $(CXX_OBJS) $(CC_FLAGS)
$(OBJ_PATH)/%-c.o : $(SOURCE_PATH)/%.c
if [ ! -d $(dir $@) ]; then mkdir -p $(dir $@); fi
${CC} -c $(CC_FLAGS) -o $@ $<
$(OBJ_PATH)/%-cxx.o : $(SOURCE_PATH)/%.cpp
if [ ! -d $(dir $@) ]; then mkdir -p $(dir $@); fi
${CXX} -c $(CXX_FLAGS) -o $@ $<
LINKER=$(CXX)
test:
@echo "C_SOURCE: $(C_SOURCE)"
@echo "CXX_SOURCE: $(CXX_SOURCE)"
@echo "C_OBJS: $(C_OBJS)"
@echo "CXX_OBJS: $(CXX_OBJS)"
@echo "SOURCE_PATH: $(SOURCE_PATH)"
@echo "OBJ_PATH: $(OBJ_PATH)"
@echo "OUTPUT_PATH: $(OUTPUT_PATH)"
@echo "TARGET: $(TARGET)"
clean:
rm -f $(OUTPUT_PATH)/${TARGET} $(C_OBJS) $(CXX_OBJS)
介绍
自动搜索当前目录及其目录底下的cpp文件和c文件并在OBJ_PATH目录底下生成中间文件,在OUTPUT_PATH底下生成目标文件。ARCH、SOURCE_PATH、OBJ_PATH、OUTPUT_PATH 和 TARGET由交叉编译脚本传入,若不设置则使用默认值。
编译驱动
DEC_OS_DRIVER_ARCH ?= x86
DEC_OS_HEADER_PATH ?= /lib/modules/`uname -r`/build
DEC_OS_CROSS_COMPILE ?= `arch`-linux-gnu-
DEC_OS_OUTPUT_PATH ?= `pwd`
SOURCE_PATH := $(dir $(shell realpath `pwd`/Makefile))
MOD_NAME := target
obj-m := $(MOD_NAME).o
$(MOD_NAME)-objs := a.o b.o c.o
all:
make -C $(DEC_OS_HEADER_PATH) M=`pwd` src=$(SOURCE_PATH) modules ARCH=$(DEC_OS_DRIVER_ARCH) CROSS_COMPILE=${DEC_OS_CROSS_COMPILE} && mv -f ${MOD_NAME}.ko ${DEC_OS_OUTPUT_PATH}
clean:
make -C $(DEC_OS_HEADER_PATH) M=`pwd` src=$(SOURCE_PATH) clean ARCH=$(DEC_OS_DRIVER_ARCH) CROSS_COMPILE=${DEC_OS_CROSS_COMPILE}
test:
${DEC_OS_CROSS_COMPILE}gcc $(SOURCE_PATH)/testko.c -o testko
介绍
DEC_OS_DRIVER_ARCH、DEC_OS_HEADER_PATH、DEC_OS_CROSS_COMPILE 和 DEC_OS_OUTPUT_PATH由交叉编译脚本传入,若为空则使用默认值,使用时只需将$(MOD_NAME)-objs变量修改为各个驱动工程实际所需编译的的.o文件。
交叉编译环境目录结构设计
x86_64架构
/usr/bin/x86_64-linux-gnu-*
qmake_x86_64 -> /opt/x86_64/qt-5.12.12
-> /opt/x86_64/qt-5.14.2
aarch64架构
软连接在编译脚本中根据需求修改软连接的指向切换7.5、8.3和9.2版本的编译器
|->/opt/aarch64/gcc-7.5
/usr/bin/aarch64-linux-gnu-* -> /opt/aarch64/gcc/bin/aarch64-linux-gnu-*
|->/opt/aarch64/gcc-8.3
|->/opt/aarch64/gcc-9.2
/usr/bin/qmake_aarch64 -> /opt/aarch64/qt-5.12.12/bin/qmake
|->/opt/aarch64/qt-5.12.12-7.5
|->/opt/aarch64/qt-5.12.12-8.3
loongarch64架构
软连接在编译脚本中根据需求修改软连接的指向的编译器
/usr/bin/loongarch64-linux-gnu-* -> /opt/aarch64/gcc/bin/loongarch64-linux-gnu-*
|->/opt/aarch64/gcc-8.3
/usr/bin/qmake_loongarch64 -> /opt/loongarch64/qt-5.12.12/bin/qmake
|->/opt/loongarch64/qt-5.12.12-8.3
mips64架构
软连接在编译脚本中根据需求修改软连接的指向切换7.3和8版本的编译器
/usr/bin/mips64-linux-gnu-* -> /opt/mips/gcc/bin/mips-linux-gnu-*
|->/opt/mips/gcc-7.3
|->/opt/mips/gcc-8
/usr/bin/mips-linux-gnu-gcc -mabi=64 $@
/usr/bin/mips-linux-gnu-g++ -mabi=64 $@
mips为32位与64位通用编译器,默认生成32位程序,要生成64位程序添加"-mabi=64"选项
/usr/bin/qmake_mips64 -> /opt/mips64/qt-5.12.12/bin/qmake
交叉编译驱动设置
使用非x86_64架构的头文件时需要替换原架构头文件路径中的部分可执行文件,以保证在x86_64架构下进行交叉编译。
#!/bin/bash
MAX_WIDTH=25
FileArray=(
"scripts/mod/modpost"
"scripts/basic/fixdep"
"scripts/recordmcount"
"scripts/genksyms/genksyms"
)
DirArray=(
"kylin-headers-4.4.131-20200422-generic"
"kylin-headers-4.4.131-20200429-generic"
"kylin-headers-4.4.131-20200529-generic"
"kylin-headers-4.4.131-20200704-generic"
"kylin-headers-4.4.131-20200710-generic"
"kylin-headers-4.4.131-20200821-generic"
"kylin-headers-4.4.131-20200901-generic"
"kylin-headers-4.4.131-20210120-generic"
"kylin-headers-4.4.131-20210727-generic"
)
for file in ${FileArray[@]}
do
for dir in ${DirArray[@]}
do
printf "cp -f linux-4.4.131/%-${MAX_WIDTH}s ../${dir}/%s\n" ${file} ${file}
cp -f linux-4.4.131/${file} ../${dir}/${file}
done
done
例如以上替换4.4内核头文件的脚本先下载linux对应版本的内核源码,运行make出现的选项选择默认,以此生成一些可执行文件,然后用生成的可执行文件替换原架构头文件目录底下对应的可执行文件,目前交叉编译sigfs、sigdisk和sigspy需要替换modpost、fixdep、genksyms和recordmcount这四个可执行文件。
标签:交叉,AbsoluteSrcPath,TargetObjPath,编译,设置,PATH,DEC,OS From: https://www.cnblogs.com/yuanhaoblog/p/17856719.html