一、交叉编译工具链配置
二、交叉编译wiringOP库
三、交叉编译智能分类工程代码
四、Makefile 用于编译 WiringPi 库
一、交叉编译工具链配置
1、关于编译
编译是指将源代码文件(如C/C++文件)经过预处理、编译、汇编和链接等步骤,转换为可执行文件的过
程。将源代码转换成机器代码的过程称为编译(Compile),编译的工作需要编译器(Complier)来完
成。
2、本地编译
本地编译是指在当前的编译平台上,生成能在当前平台上运行的可执行文件。例如,在x86平台上,使用
x86平台上的工具,开发针对x86平台本身的可执行程序,这个编译过程称为本地编译。
以一个简单的例子来说明本地编译,假设有一个hello.c文件,它包含以下内容:
#include <stdio.h>
int main()
{
printf("Hello, world!\n");
return 0;
}
我们想要在x86平台上进行本地编译,并在x86平台上运行这个程序。可以使用以下命令:
gcc -o hello hello.c
运行:
./hello
输出结果为:
Hello, world!
3、交叉编译
交叉编译是指在当前的编译平台上,生成能在体系结构不同的另一种目标平台上运行的可执行文件。例
如,在x86平台上,使用针对ARM平台的工具,开发针对ARM平台的可执行程序,这个编译过程称为交
叉编译。
以一个简单的例子来说明本地编译,假设有一个hello.c文件,它包含以下内容:
#include <stdio.h>
int main()
{
printf("Hello, world!\n");
return 0;
}
想要在x86平台上进行交叉编译,并在ARM平台上运行这个程序。首先需要在家目录下的.bashrc最后配
置添加交叉编译工具链:
test@test:~$ vi .bashrc
最后面添加
export PATH=$PATH:/home/$(whoami)/orangepi-build/toolchains/gcc-arm-9.2-2019.12-
x86_64-aarch64-none-linux-gnu/bin
然后断开重连桌重新登陆后, 执行export指令,即可看到最新导入的PATH环境变量
test@test:~$ export
declare -x DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/1000/bus"
declare -x DISPLAY="localhost:10.0"
declare -x HOME="/home/pg"
declare -x LANG="en_US.UTF-8"
declare -x LC_ADDRESS="zh_CN.UTF-8"
declare -x LC_IDENTIFICATION="zh_CN.UTF-8"
declare -x LC_MEASUREMENT="zh_CN.UTF-8"
declare -x LC_MONETARY="zh_CN.UTF-8"
declare -x LC_NAME="zh_CN.UTF-8"
declare -x LC_NUMERIC="zh_CN.UTF-8"
declare -x LC_PAPER="zh_CN.UTF-8"
declare -x LC_TELEPHONE="zh_CN.UTF-8"
declare -x LC_TIME="zh_CN.UTF-8"
declare -x LESSCLOSE="/usr/bin/lesspipe %s %s"
declare -x LESSOPEN="| /usr/bin/lesspipe %s"
declare -x LOGNAME="pg"
declare -x MOTD_SHOWN="pam"
declare -x OLDPWD="/home/pg/orangepi-build/toolchains/gcc-arm-9.2-2019.12-x86_64-
aarch64-none-linux-gnu/bin"
declare -x
PATH="/home/pg/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin
:/bin:/usr/games:/usr/local/games:/snap/bin:/home/pg/orangepibuild/toolchains/gcc-arm-9.2-2019.12-x86_64-aarch64-none-linuxgnu/bin:/home/pg/orangepi-build/toolchains/gcc-arm-9.2-2019.12-x86_64-aarch64-
none-linux-gnu/bin"
同时执行aarch64-none-linux-gnu-gcc --version 可以看到对应的版本号:
test@test:~$ aarch64-none-linux-gnu-gcc --version
aarch64-none-linux-gnu-gcc (GNU Toolchain for the A-profile Architecture 9.2-
2019.12 (arm-9.10)) 9.2.1 20191025
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
在x86平台上进行交叉编译,可以使用以下命令:
aarch64-none-linux-gnu-gcc -o hello hello.c
利用file命令可以看到编译出来的程序是ARM aarch64的二进制程序
test@test:~/test$ file hello
hello: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically
linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, with
debug_info, not stripped
这时候需要将该文件拷贝到比如香橙派等ARM开发板上运行, 在X86宿主机上是无法正常运行的。
scp hello orangepi@192.168.1.28:/home/orangepi
二、交叉编译wiringOP库
在之前《3.1 wiringPi外设SDK安装》里,我们是直接在香橙派里直接编译的wiringOP库,这一节讲解利
用《6.2交叉编译工具链配置》配置出来的交叉编译工具编译一直wiringOP库。
- 修改build.sh脚本,在echo “WiringPi Library” 之前添加:
mkdir $PWD/_INSTALL/usr/local/bin -p
mkdir $PWD/_INSTALL/usr/local/include -p
mkdir $PWD/_INSTALL/usr/local/lib -p
- 修改devLib/Makefile、gpio/Makefile、wiringPiD/Makefile
将所有Makefile中的CC := gcc 改成 CC := aarch64-none-linux-gnu-gcc
- 修改devLib/Makefile、gpio/Makefile、wiringPiD/Makefile 、wiringPi/Makefile
修改DESTDIR?=/usr 替换为DESTDIR?= $(shell pwd)/../_INSTALL/usr
- 修改wiringPi/Makefile
将$Q ln -sf $(DESTDIR)$(PREFIX)/lib/libwiringPi.so.$(VERSION)
$(DESTDIR)/lib/libwiringPi.so修改为:$Q ln -sf
$(DESTDIR)$(PREFIX)/lib/libwiringPi.so.$(VERSION)
$(DESTDIR)$(PREFIX)/lib/libwiringPi.so
修改devLib/Makefile
将$Q ln -sf $(DESTDIR)$(PREFIX)/lib/libwiringPiDev.so.$(VERSION)
$(DESTDIR)/lib/libwiringPiDev.so修改为:$Q ln -sf
$(DESTDIR)$(PREFIX)/lib/libwiringPiDev.so.$(VERSION)
$(DESTDIR)$(PREFIX)/lib/libwiringPiDev.so
- devLib/Makefile
INCLUDE = -I. 修改为INCLUDE = -I. -I$(DESTDIR)$(PREFIX)/include
- 然后执行:
./build
然后输入26(选择板子为修改DESTDIR?=/usr 替换为orangepizero2)
这时候,就会wiringOP-master下生成_INSTALL目录,里面有完整编译出来的库文件和头文件
test@test:~/test/wiringOP-master/_INSTALL$ tree -a
.
└── usr
└── local
├── bin
│ └── gpio
├── include
│ ├── ads1115.h
│ ├── bmp180.h
│ ├── drcNet.h
│ ├── drcSerial.h
│ ├── ds1302.h
│ ├── ds18b20.h
│ ├── font.h
│ ├── gertboard.h
│ ├── htu21d.h
│ ├── lcd128x64.h
│ ├── lcd.h
│ ├── max31855.h
│ ├── max5322.h
│ ├── maxdetect.h
│ ├── mcp23008.h
│ ├── mcp23016.h
│ ├── mcp23016reg.h
│ ├── mcp23017.h
│ ├── mcp23s08.h
│ ├── mcp23s17.h
│ ├── mcp23x0817.h
│ ├── mcp23x08.h
│ ├── mcp3002.h
│ ├── mcp3004.h
│ ├── mcp3422.h
│ ├── mcp4802.h
│ ├── oled.h
│ ├── OrangePi.h
│ ├── pcf8574.h
│ ├── pcf8591.h
│ ├── piFace.h
│ ├── piGlow.h
│ ├── piNes.h
│ ├── pseudoPins.h
│ ├── rht03.h
│ ├── scrollPhat.h
│ ├── sn3218.h
│ ├── softPwm.h
│ ├── softServo.h
│ ├── softTone.h
│ ├── sr595.h
│ ├── w25q64.h
│ ├── wiringPi.h
│ ├── wiringPiI2C.h
│ ├── wiringPiSPI.h
│ ├── wiringSerial.h
│ ├── wiringShift.h
│ └── wpiExtensions.h
├── lib
│ ├── libwiringPiDev.so -> /home/pg/test/wiringOPmaster/devLib/../_INSTALL/usr/local/lib/libwiringPiDev.so.2.46
│ ├── libwiringPiDev.so.2.46
│ ├── libwiringPi.so -> /home/pg/test/wiringOPmaster/wiringPi/../_INSTALL/usr/local/lib/libwiringPi.so.2.46
│ └── libwiringPi.so.2.46
└── share
└── man
└── man1
└── gpio.1
后面我们就可以把_INSTALL里的内容拷贝到香橙派的根目录下,然后执行
sudo ldconfig
就可以使用该库了,可以使用
sudo gpio readall
测试库是否链接正常。
三、交叉编译智能分类工程代码
原有项目的目录结构为:
test@test:~/garbage$ tree
.
├── garbage.c
├── garbage.h
├── garbage.py
├── main.c
├── myoled.c
├── myoled.h
├── pwm.c
├── pwm.h
├── socket.c
├── socket.h
├── uartTool.c
└── uartTool.h
调整目录结构:
test@test:~/garbage$ tree -a
.
├── inc
│ ├── garbage.h
│ ├── myoled.h
│ ├── pwm.h
│ ├── socket.h
│ └── uartTool.h
├── src
│ ├── garbage.c
│ ├── garbage.py
│ ├── main.c
│ ├── myoled.c
│ ├── pwm.c
│ ├── socket.c
│ └── uartTool.c
增加3rd目录,用于存放wiringOP和python3.10等第三方依赖库和头文件。需增加如下几个依赖库.
首先,从香橙派上利用apt download下载依赖包的头文件和库文件,并拷贝到宿主机里:
apt download zlib1g zlib1g-dev libpython3.10 libpython3.10-dev libexpat1
libexpat1-dev libcrypt1 libcrypt-dev
scp *.deb test@192.168.1.10:/home/test #test为宿主机用户名, 192.168.1.10为宿主机ip
然后,利用dpkg -x命令解压deb文件到garbage/3rd目录下:
dpkg -x libpython3.10_3.10.12-1~22.04.2_arm64.deb garbage/3rd
dpkg -x libpython3.10-dev_3.10.12-1~22.04.2_arm64.deb garbage/3rd/
dpkg -x libcrypt1_1%3a4.4.27-1_arm64.deb garbage/3rd/
dpkg -x libexpat1_2.4.7-1ubuntu0.2_arm64.deb garbage/3rd/
dpkg -x libpython3.10-dev_3.10.12-1~22.04.2_arm64.deb garbage/3rd/
dpkg -x libpython3.10_3.10.12-1~22.04.2_arm64.deb garbage/3rd
dpkg -x libexpat1_2.4.7-1ubuntu0.2_arm64.deb garbage/3rd/
dpkg -x libexpat1-dev_2.4.7-1ubuntu0.2_arm64.deb garbage/3rd/
dpkg -x libcrypt1_1%3a4.4.27-1_arm64.deb garbage/3rd/
dpkg -x zlib1g_1%3a1.2.11.dfsg-2ubuntu9.2_arm64.deb garbage/3rd/
dpkg -x libcrypt-dev_1%3a4.4.27-1_arm64.deb garbage/3rd/
dpkg -x zlib1g-dev_1%3a1.2.11.dfsg-2ubuntu9.2_arm64.deb garbage/3rd/
因为默认提供的aarch64-none-linux-gnu-gcc 9.2.0的版本编译是, 如果去加载上面的依赖库是, 会出
现库版本的依赖问题, 因此。 宿主机安装aarch64-linux-gnu-gc 11.2版本并使用该交叉编译工具:
sudo apt intall gcc-aarch64-linux-gnu
Makefile 文件内容如下:
CC := aarch64-linux-gnu-gcc
SRC := $(shell find src -name "*.c")
INC := ./inc \
./3rd/usr/local/include \
./3rd/usr/include \
./3rd/usr/include/python3.10 \
./3rd/usr/include/aarch64-linux-gnu/python3.10 \
./3rd/usr/include/aarch64-linux-gnu
OBJ := $(subst src/,obj/,$(SRC:.c=.o))
TARGET=obj/garbage
CFLAGS := $(foreach item, $(INC),-I$(item)) # -I./inc -I./3rd/usr/local/include
LIBS_PATH := ./3rd/usr/local/lib \
./3rd/lib/aarch64-linux-gnu \
./3rd/usr/lib/aarch64-linux-gnu \
./3rd/usr/lib/python3.10
LDFLAGS := $(foreach item, $(LIBS_PATH),-L$(item)) # -L./3rd/usr/local/libs
LIBS := -lwiringPi -lpython3.10 -pthread -lexpat -lz -lcrypt
obj/%.o:src/%.c
mkdir -p obj
$(CC) -o $@ -c $< $(CFLAGS)
$(TARGET) :$(OBJ)
$(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS) $(LIBS)
compile : $(TARGET)
clean:
rm $(TARGET) obj $(OBJ) -rf
debug:
echo $(CC)
echo $(SRC)
echo $(INC)
echo $(OBJ)
echo $(TARGET)
echo $(CFLAGS)
echo $(LDFLAGS)
echo $(LIBS)
.PHONY: clean compile debug
最后在工程里执行
make
就会在obj目录下生成garbage文件, 将该文件拷贝到香橙派里即可执行。
四、Makefile 用于编译 WiringPi 库
这个 Makefile 主要用于编译 WiringPi 库。下面是对该 Makefile 的注释和一个简单的示例 Makefile 的解释:
# Makefile:
# wiringPi - Wiring Compatible library for the Raspberry Pi
#
# Copyright (c) 2012-2015 Gordon Henderson
# 版本信息
VERSION=$(shell cat ../VERSION)
DESTDIR?=/usr
PREFIX?=/local
LDCONFIG?=ldconfig
# 如果没有设置 VERBOSE($V),则默认关闭详细输出
ifneq ($V,1)
Q ?= @
endif
# 静态库和动态库的文件名
STATIC=libwiringPi.a
DYNAMIC=libwiringPi.so.$(VERSION)
# 调试选项(可以根据需要注释/取消注释)
# DEBUG = -g -O0 # 调试选项
DEBUG = -O2 # 优化选项
# 编译器和选项
CC = gcc
INCLUDE = -I.
DEFS = -D_GNU_SOURCE
CFLAGS = $(DEBUG) $(DEFS) -Wformat=2 -Wextra -Winline $(INCLUDE) -pipe -fPIC
LIBS = -lm -lpthread -lrt -lcrypt
# 板子类型设置,默认为 orangepioneplus-h6
BOARD = orangepioneplus-h6
# 板子类型的额外编译选项
EXTRA_CFLAGS = -DCONFIG_ORANGEPI_LITE2
# 源文件列表
SRC = wiringPi.c \
wiringSerial.c wiringShift.c \
piHiPri.c piThread.c \
wiringPiSPI.c wiringPiI2C.c \
softPwm.c softTone.c \
mcp23008.c mcp23016.c mcp23017.c \
mcp23s08.c mcp23s17.c \
sr595.c \
pcf8574.c pcf8591.c \
mcp3002.c mcp3004.c mcp4802.c mcp3422.c \
max31855.c max5322.c ads1115.c \
sn3218.c \
bmp180.c htu21d.c ds18b20.c rht03.c \
drcSerial.c drcNet.c \
pseudoPins.c \
wpiExtensions.c \
w25q64.c \
oled.c OrangePi.c
# 头文件列表
HEADERS = $(shell ls *.h)
# 目标文件列表
OBJ = $(SRC:.c=.o)
# 主要的目标,生成动态库
.PHONY: all
all: $(DYNAMIC)
# 静态库的目标
.PHONY: static
static:
@cat noMoreStatic
# 生成动态库的规则
$(DYNAMIC): $(OBJ)
@echo "[Link (Dynamic)]"
$(CC) -shared -Wl,-soname,libwiringPi.so$(WIRINGPI_SONAME_SUFFIX) -o libwiringPi.so.$(VERSION) $(OBJ) $(LIBS)
# 编译每个 .c 文件到 .o 文件的规则
.c.o:
@echo [Compile] $<
$(CC) -c $(EXTRA_CFLAGS) $(CFLAGS) $< -o $@
# 清理生成的文件
.PHONY: clean
clean:
@echo "[Clean]"
rm -f $(OBJ) *~ core tags Makefile.bak libwiringPi.*
# 生成 ctags
.PHONY: tags
tags: $(SRC)
@echo [ctags]
ctags $(SRC)
# 安装头文件和动态库到指定位置
.PHONY: install
install: $(DYNAMIC)
@echo "[Install Headers]"
install -m 0755 -d $(DESTDIR)$(PREFIX)/include
install -m 0644 $(HEADERS) $(DESTDIR)$(PREFIX)/include
@echo "[Install Dynamic Lib]"
install -m 0755 -d $(DESTDIR)$(PREFIX)/lib
install -m 0755 libwiringPi.so.$(VERSION) $(DESTDIR)$(PREFIX)/lib/libwiringPi.so.$(VERSION)
ln -sf $(DESTDIR)$(PREFIX)/lib/libwiringPi.so.$(VERSION) $(DESTDIR)/lib/libwiringPi.so
$(LDCONFIG)
# 卸载已安装的头文件和动态库
.PHONY: uninstall
uninstall:
@echo "[UnInstall]"
cd $(DESTDIR)$(PREFIX)/include/ && rm -f $(HEADERS)
cd $(DESTDIR)$(PREFIX)/lib/ && rm -f libwiringPi.*
$(LDCONFIG)
# 生成依赖关系文件
.PHONY: depend
depend:
makedepend -Y $(SRC)
这个 Makefile 主要用于编译 WiringPi 库,提供了编译选项、依赖关系生成、静态库和动态库的编译规则,以及安装和卸载的规则。这个库是用于树莓派 GPIO 操控的工具库。