14.OrangePiZero2系统移植

OrangePiZero2系统移植

之前我们讲解香橙派的使用时, 都是直接在香橙派上进行代码编译, 但在实际的项目开发过程中,更多

的还是使用交叉编译环境进行代码的编译。再编译完成之后再把代码放到香橙派等ARM开发板上运行。

因此这章节专门讲解下交叉编译环境的搭建、Uboot移植和内核移植内容

1.OrangePi Zero2 SDK说明

SDK 全称 Software Development Kit,即软件开发工具包。一般包括了一些工具(如交叉编译工具

链)、库、文档和示例代码。香橙派的Linux SDK其实指的就是 orangepi-build 这套代码集,orangepi

build 在脚本和配置文件中会指定 u-boot、Linux内核和交叉编译工具链的地址,运行 orangepi-build

时,当其发现本地没有这些东西,会自动去相应的地方下载的。使用 orangepi-build 可以编译出多个版

本的 Linux 镜像。

1.1.环境要求

新版本的orangepi-build对编译主机(也就是搭建的vmware 虚拟机)的要求:新版本的orangepi-build是在Ubuntu22.04的x64电脑或者虚拟机上运行的

  • 确认自己的虚拟机或者Ubuntu实体机是不是22.04的方法如下:

    kevin@kevin-virtual-machine:~$ lsb_release -a
    No LSB modules are available.
    Distributor ID: Ubuntu
    Description:    Ubuntu 22.04.5 LTS
    Release:        22.04
    Codename:       jammy
    
  • 如果不是,可从ubuntu官网重新下载ubuntu 22.05 x64镜像,重新更新下虚拟机,ubuntu 22.05

    X64镜像下载地址:

    http://releases.ubuntu.com/jammy/ubuntu-22.04.5-desktop-amd64.iso
    
  • 编译出来的完整SDK大概有16 G大小,因此建议在创建虚拟机时,至少分配50G的存储给虚拟机使用。

1.2.获取Linux SDK

1.2.1.方法一:从 github 下载 orangepi-build(*要求网络要好,因此当前不是特别推荐)

搭建完虚拟机后, 从github下载香橙派Linux SDK:

kevin@kevin-virtual-machine:~$ sudo apt update
kevin@kevin-virtual-machine:~$ sudo apt install git
kevin@kevin-virtual-machine:~$ git clone https://github.com/orangepi-xunlong/orangepi-build.git -b next
  • 如果git clone失败, 也可以直接访问该网址, 把orangepi-build的压缩包下载下来后,再放到编

译主机里。

然后解压下载下来的压缩包:

unzip orangepi-build-next.zip
  • orangepi-build 下载完后会包含下面的文件和文件夹

    a. build.sh: 编译启动脚本, 我们可以通过build.sh编译uboot、内核、根文件系统甚至完整的img

    b. external: 包含编译镜像需要用的配置文件、特定的脚本以及部分程序的源码等

    c. LICENSE: GPL 2 许可证文件

    d. README.md: orangepi-build 说明文件

    e. scripts: 编译 linux 镜像的通用脚本

  • 解压完后,需要去修改适配orangepizero2的配置脚本

    cd ~/orangepi-build-next
    vi ./external/config/sources/familiessun50iw9.conf
    

配置文件 sun50iw9.conf修改,在next分支里的内核配置版本(默认是6.1.y这里改成5.16.y版本),不然6.1.y默认编译出来的内核默

认没有无线网卡、I2C也不支持。

## For Linux5.16.y
KERNELBRANCH="branch:orange-pi-5.16-sunxi64"
LINUXCONFIG="linux-5.16-sun50iw9-current"

## For Linu6.1.y
#KERNELBRANCH="branch:orange-pi-6.1-sun50iw9"
#LINUXCONFIG="linux-6.1-sun50iw9-next"

1.2.2.方法二:从百度网盘下载(推荐使用该方法, 就不用考虑github下载过程中出现下载失败导致最后编译出 来的系统可能是异常的)

从下面的百度网盘链接下载提前编译好的oragepi-build SDK包:

链接:https://pan.baidu.com/s/1y3db5GZFPZSnyYOCrKQcmQ
提取码:92gt

下载下来后是几个拆分好的压缩包, 如下所示:

kevin@kevin-virtual-machine:~/orange-build$ ls 
orangepi-build-ok.tar.gz_00 orangepi-build-ok.tar.gz_01 orangepi-buildok.tar.gz_02

这个时候可以用如下的命令进行合并解压:

cat orangepi-build-ok.tar.gz_0* > orangepi-build-ok.tar.gz
tar -xvf orangepi-build-ok.tar.gz

1.3 首次编译完整SDK

下载完源码后, 即可用build.sh进行首次编译.(注:如果是从6.1.2节 方法二:从百度网盘下载后, 由

于已经缓存了交叉编译工具链、uboot和内核源码, 可以不运行build.sh脚本

1.4.执行编译

1.运行 build.sh 脚本,记得加 sudo 权限

sudo ./build.sh

2.选择Full OS image for flashing 进行完整镜像的编译

3.选择不修改配置

4.根据实际的香橙派派开发版的型号, 选orangepizero2

  1. 选择根文件系统类型, 这边选择ubuntu 22.04 的根文件系统, 也就是jammy:

6.选择带桌面环境,即接入HDMI显示器后,是有桌面显示的:

7.最后选择桌面环境,这边选择xfce:

  1. 这里的软件主要是一些额外第三方软件包的安装, 都不选择,直接ok开始编译

9.如果是第一次运行 orangepi-build 中的 build.sh 脚本时会自动下载交叉编译工具链、 u-boot 和

linux 内核源码,成功编译完一次 linux 镜像后在 orangepi-build 中可以看到 的文件和文件夹有:

  • a. build.sh: 编译启动脚本
  • b. external: 包含编译镜像需要用的配置文件、特定功能的脚本以及部分程序 的源码,编译镜像过程中缓存的 rootfs 压缩包也存放在 external 中
  • c. kernel: 存放 linux 内核的源码,内核源码的文件夹的名字请不要手动修改,如 果修改了,编译系统运行时会重新下载内核源码
  • d. LICENSE: GPL 2 许可证文件
  • e. README.md: orangepi-build 说明文件
  • f. output: 存放编译生成的 u-boot、linux 等 deb 包、编译日志以及编译生成的 镜像等文件
  • g. scripts: 编译 linux 镜像的通用脚本
  • h. toolchains: 存放交叉编译工具链
  • i. u-boot: 存放 u-boot 的源码,u-boot 源码的文件夹的名字请不要手动修改,如果修改了,编译系统运行时会重新下载 u-boot 源码
  • j. userpatches: 存放编译脚本需要用到的配置文件。

10.经过漫长等待编译完成后, 会在

orangepi-build/output/images/Orangepizero2_3.1.0_ubuntu_jammy_desktop_xfce_linux5.16.17/

Orangepizero2_3.1.0_ubuntu_jammy_desktop_xfce_linux5.16.17.img镜像。 可以直接拿这个

img 烧入到SD卡中运行

2.交叉编译工具链配置

2.1.关于编译

编译是指将源代码文件(如C/C++文件)经过预处理、编译、汇编和链接等步骤,转换为可执行文件的过

程。将源代码转换成机器代码的过程称为编译(Compile),编译的工作需要编译器(Complier)来完

成。

2.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!

2.3.交叉编译

交叉编译是指在当前的编译平台上,生成能在体系结构不同的另一种目标平台上运行的可执行文件。例

如,在x86平台上,使用针对ARM平台的工具,开发针对ARM平台的可执行程序,这个编译过程称为交

叉编译。

以一个简单的例子来说明本地编译,假设有一个hello.c文件,它包含以下内容:

#include <stdio.h>
int main()
{
    printf("Hello, world!\n");
    return 0;
}

想要在x86平台上进行交叉编译,并在ARM平台上运行这个程序。首先需要在家目录下的.bashrc最后配

置添加交叉编译工具链:

kevin@kevin-virtual-machine:~$ 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环境变量

kevin@kevin-virtual-machine:~$ export

同时执行aarch64-none-linux-gnu-gcc --version可以看到对应的版本号:

kevin@kevin-virtual-machine:~$ 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的二进制程序:

kevin@kevin-virtual-machine:~$ 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.4.129:/home/orangepi

3.Makefile的入门

3.1.编译工具及构建工具介绍

在之前的课程,都是直接使用gcc对代码进行编译,这简单的工程是可以的,但当我们遇到复杂的工程

时,每次用gcc等编译工具去操作就会显得很低效。因此make工具就出现了, make的出现是为了解决手

动编译和链接大型工程的问题,它可以避免重复的工作,提高效率,保证正确性。make工具就根据

makefile中的命令进行编译和链接的。但是当工程非常大的时候,手写makefile也是非常麻烦的,如果

换了个平台makefile又要重新修改,因此更高级的一些构建系统或者工具工具像cmake、qmake、ninja

和auto make就出现了,它们可以根据一些配置文件来自动化编译和链接软件项目。

cmake是一个跨平台的构建系统,它可以根据CMakeLists.txt中的指令来生成不同平台和工具的工程文

件,例如Makefile、Visual Studio解决方案、Ninja文件等。cmake可以支持多种语言和多种架构,它还

提供了一些高级功能,如测试、打包、安装等。

qmake是一个用于Qt项目的构建系统,它可以根据.pro或.pri中的指令来生成Makefile或其他形式的工程

文件。

ninja是一个小巧而快速的构建工具,它可以根据ninja.build中的规则来执行编译和链接命令。ninja主要

关注于性能和效率,它可以利用多核处理器和并行处理来加速构建过程。ninja通常不需要用户直接编写

配置文件,而是由其他构建系统(如cmake)来生成

auto make是一个用于生成Makefile.in文件的工具,Makefile.in是一种用于auto conf的配置文件格式,

auto conf是一个用于生成configure脚本的工具。configure脚本是一个用于检测系统环境并生成最终的

Makefile文件的脚本Makefile.am是一种用于auto make的配置文件格式,它包含了一些指令和变量,用

于定义程序或库的源文件、目标文件、依赖关系和编译选项等。

make是一个经典而通用的构建工具,它可以根据Makefile中的规则来执行编译和链接命令。make可以

支持多种平台和工具,它还提供了一些高级功能,如条件判断、函数调用、模式匹配。

3.2 Makefile的简单讲解

3.2.1.编译的四个阶段

回顾下编译的四个过程:预处理(Pre-Processing)、编译(Compiling)、汇编 (Assembliang)、链接

(Linking)

3.2.1.Makefile的规则

a.基本规则
target ... : prerequisites ...
<tab缩进>command
<tab缩进>...
<tab缩进>...

target 也就是一个目标文件,可以是 Object File,也可以是执行文件。还可以是一个标签( Label),

对于标签这种特性,在后续的讲“伪目标”中会有叙述。prerequisites 就是,要生成那个 target 所需要的

文件或是目标。command 也就是 make 需要执行的任意shell命令。

Makefile一个示例:

debug:
	@echo "hello world"

如果,我们要编译下面这个最简单的例子:

#include <stdio.h>
int main(int argc, char *argv[])
{
    printf("hello world!\n");
    return 0;
}

Makefile修改如下:

debug:
	@echo "hello world"
test:
	gcc -o test test.c

执行命令make test 可以生成 test文件, 执行make debug可以输出“hello world”:

kevin@kevin-virtual-machine:~/makefileCode$ make debug
hello world!
kevin@kevin-virtual-machine:~/makefileCode$ ls
makefile  test.c
kevin@kevin-virtual-machine:~/makefileCode$ make test
gcc -o test test.c
kevin@kevin-virtual-machine:~/makefileCode$ ls
makefile  test  test.c
b.伪目标

如果一个目标和一个实际文件同名,那么make会认为该目标已经是最新的,不需要重新生成,也不会执

行其命令。通过将目标声明为伪目标,可以避免这种情况,强制执行其命令。

debug:
	@echo "hello world!"
test:
	gcc -o test test.c
.PHONY: test
c.变量赋值和预定义变量

Makefile中的变量赋值运算符有四种,分别是=、:=、?=和+=, $符号表示取变量的值,当变量名多于一

个字符时,使用"( )":

= 表示延迟展开赋值,即变量的值是在使用时才确定,可能会受到后面的赋值影响。例如,VAR_A = A,

VAR_B = $(VAR_A) B,VAR_A = AA,那么最后VAR_B的值是AA B,而不是A B。

:= 表示直接赋值,即变量的值是在定义时就确定,不会受到后面的赋值影响。例如,VAR_A := A,

VAR_B := $(VAR_A) B,VAR_A := AA,那么最后VAR_B的值是A B,而不是AA B。

?=表示条件赋值,即只有当变量没有被赋值时,才使用等号后面的值作为变量的值。例如,VAR ?=

new_value,如果VAR在之前没有被赋值,那么VAR的值就为new_value,否则保持原来的值不变。

+= 表示追加赋值,即将等号后面的值追加到变量原来的值之后,形成一个新的值。例如,VAR +=

new_value,如果VAR在之前没有被赋值,那么VAR的值就为new_value,如果VAR在之前被赋值为

old_value,那么VAR的值就为old_value new_value

$符的其他用法:

$^ 表示所有的依赖文件

$@ 表示生成的目标文件

$< 代表第一个依赖文件

d.注释和换行符

采用#进行一行注释

采用\作为续行符

e.变量的替换引用

语法格式是:

$(var:a=b)或${var:a=b}

表示把变量var的值中的a后缀替换成b后缀。例如:

src := a.c b.c c.c
obj := $(src:c=o)

把变量src的值中的.c后缀替换成.o后缀,赋值给变量obj,结果是:

obj := a.o b.o c.o

举例:

# 这是一个Makefile的注释
TARGET = hello #TARGET延迟赋值hello
CC := gcc #CC立即赋值gcc
CC += -g #CC追加赋值-g, gcc -g表示添加调试信息,可用于gdb的调试
SRC = hello.c
OBJ = $(SRC:.c=.o) #变量的替换引用,把hello.c的.c替换成.o
debug :
	@echo "hello world"
	echo $(SRC)
	echo $(OBJ)
    $(TARGET): $(SRC)
    $(CC) -o $@ $<
    # $(CC) -o ${TARGET} hello.c
compile: $(TARGET)
clean:
	@rm hello hello.o -r
.PHONY: clean compile
f.常见函数

Makefile函数的基本格式是:$( )或者是${ },其中,是函数名,是函数的参数,参数之间要用逗号分隔

开,参数和函数名之间使用空格分开。调用函数的时候要使用字符“$”,后面可以跟小括号或者大括号。

1) wildcard 通配符:

Makefile中的wildcard 是一个函数,用于扩展通配符,返回与通配符匹配的文件列表。通配符是一种特

殊的字符,可以表示多个文件名或目录名,常见的通配符有 * 和 ?,分别表示任意长度的任意字符和单个

任意字符。格式如下:

$(wildcard argments)

比如*.c 表示所有以 .c 结尾的文件名,a?.txt 表示所有以 a 开头,中间有一个任意字符,以 .txt 结尾的文

件名。例如:

SRC = $(wildcard src/*.c)

表示查找并返回src目录下所有的.c文件, *表示通配符, 匹配一个或者多个任意字符

2)shell:

$(shell <cmd> <args>)

cmd: 执行命令名称

args:参数列表

返回值: 返回命令执行结果

例如:

SRC = $(shell find . -name *.c)	

表示查找当前目录及子目录下的所有.c文件结尾的代码源文件

3) patsubst替换函数:

$(patsubst pattern,replacement,text)

pattern: 是一个包含通配符 % 的模式,表示匹配任意长度的任意字符

replacement: 是一个替换字符串,也可以包含 %,表示用 pattern 中匹配的字符替换。

text: 是一个要处理的文本,可以包含多个以空格分隔的单词。

返回值:patsubst 函数会在 text 中找到所有符合 pattern 的单词,并用 replacement 替换它们,然后

返回替换后的文本。

例如,如果有一个变量 src,它的值是:

src = a.c b.c c.c

想把它的值中的所有 .c 后缀替换成 .o 后缀,可以这样写:

obj = $(patsubst %.c,%.o,$(src))

这样,obj 的值就是:

obj = a.o b.o c.o

4) subst替换函数

$(subst from,to,text)

from: 是要被替换的字符或单词

to: 是替换后的字符或单词

text: 是要处理的字符串。

返回值:subst 函数会在 text 中找到所有的 from,并用 to 替换它们,然后返回替换后的字符串。

例如

$(subst ee,EE,feet on the street)

返回:

fEEt on the strEEt

综合举例,测试工程代码目录:

test@test:~/makefiletest$ tree
.
├── Makefile
└── src
└── test.c

Makefile内容:

CC = gcc
CC += -g
SRC := $(shell find . -name *.c)
TARGET := $(patsubst %.c, %,$(subst src,obj, $(SRC)))
debug:
    @echo "hello world"
    echo $(SRC)
    echo $(TARGET)
    $(TARGET): $(SRC)
    mkdir -p obj
    $(CC) -o $@ $<
compile: $(TARGET)
clean:
	@rm obj -r
.PHONY: clean compile

test.c内容:

#include <stdio.h>
int main()
{
    printf("hello world\n");
    return 0;
}

执行:

make compile

生成obj/test:

pg@pg-Default-string:~/makefiletest$ tree -a
.
├── Makefile
├── obj
│ └── test
└── src
└── test.c

5)dir函数:

$(dir NAMES...)

dir 函数是一个用于从文件名序列中提取目录部分的函数

优化Makefile内容:

CC = gcc
CC += -g
SRC := $(shell find . -name *.c)
TARGET := $(patsubst %.c, %,$(subst src,obj, $(SRC)))
debug:
    @echo "hello world"
    echo $(SRC)
    echo $(TARGET)
    $(TARGET): $(SRC)
    mkdir -p $(dir $(TARGET))
	$(CC) -o $@ $<
compile: $(TARGET)
clean:
	@rm $(dir $(TARGET)) -r
.PHONY: clean compile

6)suffix函数

$(suffix <names...>)

功能:从文件名序列中取出各个文件名的后缀。

返回值:返回文件名序列的后缀序列,如果文件没有后缀,则返回空字串。

例如:

$(suffix src/foo.c src-1.0/bar.c hacks)

返回:

.c .c

7)basename函数

格式:

$(basename <names...>)

功能:从文件名序列中取出各个文件名的前缀部分。

返回值:返回文件名序列的前缀序列,如果文件没有前缀,则返回空字串。

例如:

$(basename src/foo.c src-1.0/bar.c hacks)

返回:

src/foo src-1.0/bar hacks

8) addsuffix函数

$(addsuffix <suffix>,<names...>)

功能:把后缀加到中的每个单词后面。

返回:返回加过后缀的文件名序列。

例如:

$(addsuffix .c,foo bar)

返回值:

foo.c bar.c

9)addprefix函数

功能:把前缀加到中的每个单词后面。

返回值:返回加过前缀的文件名序列。

例如:

$(addprefix src/,foo bar)

返回值:

src/foo src/bar

10)foreach函数

$(foreach <var>,<list>,<text>)

把list中使用空格分割的单词依次取出并赋值给变量var, 然后执行text表达式

例如:

files := foo bar baz
files-with-c := $(foreach file,$(files),$(file).c)

11)条件判断语言

Makefile条件判断有下面几种:

ifeq/ifneq语句:

ifeq语句 : 判断参数 是否相等,相等为 true, 否则是 false.

ifeq (arg1, arg2)
	#arg1 arg2 相等执行这里的语句
else
	#arg1 arg2 不相等执行这里的语句
endif

ifneq语句:判断参数 是否不等,不等为 true, 否则为 false.

ifneq (arg1, arg2)
	#arg1 arg2 不相等执行这里的语句
else
	#arg1 arg2 相等执行这里的语句
endif

​ ifdef/ifndef语句

ifdef 语句: 判断参数 是否有值 ,有值为 true, 否则是 false

ifndef : 判断参数 是否没有值 ,没有值为 true, 否则为 false.

ifdef:

ifdef var
	#如果定义了var,执行这里的内容
else
	#如果没定义var,执行这里的内容
endif

ifndef:

infdef var
	#如果没定义var,执行这里的内容
else
	#如果定义var,执行这里的内容
endif

4.交叉编译wiringOP库

在之前《3.1 wiringPi外设SDK安装》里,我们是直接在香橙派里直接编译的wiringOP库,这一节讲解利

用《6.2交叉编译工具链配置》配置出来的交叉编译工具编译一直wiringOP库。

安装wiringOP库

cd ~
git clone https://github.com/orangepi-xunlong/wiringOP -b master #下载源码
cd wiringOP 			#进入文件夹

4.1.修改build脚本,在echo "WiringPi Library" 之前添加:

修改wiringOP库,编译出RAM上运行格式的外设

vi build

mkdir $PWD/_INSTALL/usr/local/bin -p
mkdir $PWD/_INSTALL/usr/local/include -p
mkdir $PWD/_INSTALL/usr/local/lib -p

4.2.所有的修改Makefile

通过vscode去查找替换

devLib/Makefile
examples/Makefile
examples/Gertboard/Makefile
examples/PiFace/Makefile
examples/PiGlow/Makefile
examples/q2w/Makefile
examples/scrollPhat/Makefile
gpio/Makefile
wiringPi/Makefile
wiringPiD/Makefile

将所有Makefile中的CC = gcc 改成 CC = aarch64-none-linux-gnu-gcc

4.3.修改devLib/Makefile、gpio/Makefile、wiringPiD/Makefile 、wiringPi/Makefile

修改DESTDIR?=/usr 替换为DESTDIR?= $(shell pwd)/../_INSTALL/usr

$(shell pwd)是指makefile的当前目录

4.4.更正文件路径

  • 修改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

4.5.devLib/Makefile

INCLUDE	= -I. 修改为INCLUDE = -I. -I$(DESTDIR)$(PREFIX)/include

4.6.编译

./build

然后输入26(选择板子为修改DESTDIR?=/usr 替换为orangepizero2)

这时候,就会wiringOP-master下生成_INSTALL目录,里面有完整编译出来的库文件和头文件

kevin@kevin-virtual-machine:~/wiringOP/_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/kevin/wiringOP/devLib/../_INSTALL/usr/local/lib/libwiringPiDev.so.2.46
        │   ├── libwiringPiDev.so.2.46
        │   ├── libwiringPi.so -> /home/kevin/wiringOP/wiringPi/../_INSTALL/usr/local/lib/libwiringPi.so.2.46
        │   └── libwiringPi.so.2.46
        └── share
            └── man
                └── man1
                    └── gpio.1

后面我们就可以把_INSTALL里的内容拷贝到香橙派的根目录下,然后执行

重写依赖

scp -r ~/wiringOP/_INSTALL orangepi@192.168.4.129:/home/orangepi
sudo ldconfig

就可以使用该库了,可以使用

sudo gpio readall

测试库是否链接正常。

5.交叉编译智能垃圾分类工程代码

原有的目录结构

kevin@kevin-virtual-machine:~/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

调整后的目录结构

kevin@kevin-virtual-machine:~/garbage$ tree
.
├── 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

将_INSTALL拷贝到项目3rd下

 cp -r ~/wiringOP/_INSTALL/* ~/garbage/3rd/

增加3rd目录,用于存放wiringOP和python3.10等第三方依赖库和头文件。需增加如下几个依赖库.

首先,从香橙派上利用apt download下载依赖包的头文件和库文件,并拷贝到宿主机里:

sudo apt update
sudo apt download zlib1g zlib1g-dev libpython3.10 libpython3.10-dev libexpat1 libexpat1-dev libcrypt1 libcrypt-dev
scp *.deb kevin@192.168.4.120:/home/kevin #kevin为宿主机用户名, 192.168.4.120为宿主机ip

然后,利用dpkg -x命令解压deb文件到garbage/3rd目录下:

dpkg -x libpython3.10_3.10.12-1~22.04.9_arm64.deb garbage/3rd
dpkg -x libpython3.10-dev_3.10.12-1~22.04.9_arm64.deb garbage/3rd/
dpkg -x libexpat1_2.4.7-1ubuntu0.6_arm64.deb garbage/3rd/
dpkg -x libexpat1-dev_2.4.7-1ubuntu0.6_arm64.deb garbage/3rd/
dpkg -x libcrypt1_1%3a4.4.27-1_arm64.deb garbage/3rd/
dpkg -x libcrypt-dev_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 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 install gcc-aarch64-linux-gnu

香橙派主机查询软链:

ls -l /lib/aarch64-linux-gnu/libz*

编译主机手动创建软链:

cd /home/kevin/garbage/3rd/lib/aarch64-linux-gnu
ln -s libcrypt.so.1.1.0 libcrypt.so
ln -s libexpat.so.1.8.7 libexpat.so
ln -s libz.so.1.2.11 libz.so

Makefile 文件内容如下:

cc := aarch64-linux-gnu-gcc
SRC := $(shell find src -name "*.c")
INC := ./inc \
		./3rd/usr/include \
		./3rd/usr/include/python3.10 \
		./3rd/usr/include/aarch64-linux-gnu \
		./3rd/usr/include/aarch64-linux-gnu/python3.10  \

OBJ := $(subst src/,obj/,$(SRC:.c=.o))

TARGET = obj/garbage

CFLAGS := $(foreach item,$(INC),-I$(item)) #-I./3rd/usr/include
LIBS_PAHT := ./3rd/lib/aarch64-linux-gnu \
			 ./3rd/usr/lib/aarch64-linux-gnu \
			 ./3rd/usr/lib/python3.10
LDFLAGS := $(foreach item,$(LIBS_PAHT),-L$(item)) #-L./3rd/usr/local/lib

LIBS := -lwiringPi -lpython3.10 -lpthread -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

就会在obj目录下生成garbage文件, 将该文件拷贝到香橙派里即可执行

scp /home/kevin/garbage/obj/garbage orangepi@192.168.4.129:/home/orangepi
scp /home/kevin/garbage/src/garbage.py orangepi@192.168.4.129:/home/orangepi
posted @ 2025-05-29 11:35  站着说话不腰疼  阅读(243)  评论(0)    收藏  举报