评估网站建设方案,php网站是什么,深圳企业网站制作公司怎样,网站和网页的设计原则前言: 在阅读本文之前#xff0c;你哦需要了解makefile文件的编写规则#xff0c;这里我们推荐两篇入门:
Makefile 规则-CSDN博客
Makefile 快速入门-CSDN博客 编译定义
编译是指将源代码文件#xff08;如C/C文件#xff09;经过预处理、编译、汇编和链接等步骤#x…前言: 在阅读本文之前你哦需要了解makefile文件的编写规则这里我们推荐两篇入门:
Makefile 规则-CSDN博客
Makefile 快速入门-CSDN博客 编译定义
编译是指将源代码文件如C/C文件经过预处理、编译、汇编和链接等步骤转换为可执行文件的过程。将源代码转换成机器代码的过程称为编译Compile编译的工作需要编译器Complier来完成。 本地编译 定义: 本地编译是指在当前的编译平台上生成能在当前平台上运行的可执行文件。 例如在x86平台上使用x86平台上的工具开发针对x86平台本身的可执行程序这个编译过程称为本地编译。 以一个简单的例子来说明本地编译假设有一个hello.c文件它包含以下内容
验证程序 #include stdio.h int main() { printf(Hello, world!\n); return 0; } 我们想要在x86平台上进行本地编译并在x86平台上运行这个程序。 编译: gcc -o hello hello.c 运行: ./hello 演示 交叉编译 定义 交叉编译是指在当前的编译平台上生成能在体系结构不同的另一种目标平台上运行的可执行文件。例如在x86平台上使用针对ARM平台的工具开发针对ARM平台的可执行程序这个编译过程称为交叉编译。 一句话 -- 这本平台上编译生成其他平台能运行的可执行文件。 准备 想要在x86平台上进行交叉编译并在ARM平台上运行这个程序。首先需要在家目录下的.bashrc最后配置添加交叉编译工具链
进入配置文件vi .bashrc
添加: export PATH$PATH:/home/$(whoami)/orangepi-build/toolchains/gcc-arm-9.2-2019.12- x86_64-aarch64-none-linux-gnu/bin 验证 -- 查看版本号: 执行aarch64-none-linux-gnu-gcc --version 可以看到对应的版本号 -------------------------
file命令补充
定义
file 命令是一个在 Unix 和类 Unix 系统如 Linux中常用的命令用于确定文件的类型。通过检查文件的内容、魔数magic number位于文件开头的几个字节用于标识文件类型或其他特定的签名file 命令可以准确地告诉你一个文件是什么类型的。 作用 file 命令主要用于确定文件的MIME类型或更一般的文件类型。它对于检查未知文件特别有用因为它可以帮助你了解文件的内容而不需要打开或执行它。它也可以用来检查文件的编码如文本文件的字符集。 格式
file 命令的基本格式如下
bash复制代码
file [选项] 文件名...
选项 file 命令有一些选项用于改变其输出或行为。以下是一些常用的选项 -b只显示文件类型不显示文件名。-i显示MIME类型的输出而不是更详细的描述。-z尝试查看压缩文件的内容。-L对于符号链接显示链接指向的文件的内容类型而不是链接文件本身。--mime-type与 -i 选项相似但仅显示MIME类型不包括字符集信息。 示例 显示文件的类型
bash复制代码
file example.txt # 输出可能是example.txt: ASCII text 显示多个文件的类型
bash复制代码
file file1.jpg file2.pdf # 输出可能是 # file1.jpg: JPEG image data, JFIF standard 1.01 # file2.pdf: PDF document, version 1.4 显示MIME类型
bash复制代码
file -i example.txt # 输出可能是example.txt: text/plain; charsetus-ascii 只显示类型不显示文件名
bash复制代码
file -b example.txt # 输出可能是ASCII text
通过 file 命令你可以轻松地识别文件类型这对于处理未知文件或确定文件是否已被篡改特别有用。 case1: 简单的交叉编译演示 在x86平台上进行交叉编译
编译
执行如下命令 (前提已经安装配置了编译工具) aarch64-none-linux-gnu-gcc -o hello hello.c file命令查看类型 利用file命令可以看到编译出来的程序是ARM aarch64的二进制程序 运行 这时候需要将该文件拷贝到比如香橙派等ARM开发板上运行 在X86宿主机上是无法正常运行的 拷贝到目标平台 -- arm 平台(香橙派)上 scp hello orangepi192.168.1.28:/home/orangepi 在orangepi上能运行见下图:
执行命令运行 这样就实现了交叉编译 case2: 交叉编译wiringOP库: -- 对库文件的交叉编译 目的 在x86平台上面编译后拷贝到orangepi 的根目录即可调用 编译完放 file 查看类型正确后就压缩一下传到香橙派上即可使用 压缩: tar -zcvf _install.tar.gz _install
用配置出来的 交叉编译工具编译移植wiringOP库:
0.下载wiringPi文 然后进到wiringOP 文件夹 git clone https : //github.com/orangepi-xunlong/wiringOP // 下载源码 cd wiringOP // 进入文件夹 1. 修改build.sh脚本在echo WiringPi Library 之前添加
目的 -- 在当前目录下面创建_install/usr/local 文件夹(路径)并且分别生成binincludelib文件夹 mkdir $PWD/_install/usr/local/bin -p mkdir $PWD/_install/usr/local/include -p mkdir $PWD/_install/usr/local/lib -p mkdir - p 补充
定义 mkdir -p 是一个在 Unix 和类 Unix 系统如 Linux中常用的命令用于创建目录或文件夹。-p 选项是该命令的一个非常有用的参数。 功能
mkdir -p 命令允许你创建多级目录即使上级目录不存在。如果上级目录不存在mkdir 会自动创建它们。如果没有 -p 选项当上级目录不存在时mkdir 会报错。
示例
创建一个单层目录
如果你只想创建一个单层目录你可以简单地使用 mkdir 命令不需要 -p 选项。 bash复制代码
mkdir mydir
创建多级目录
如果你想要创建一个多级目录如 dir1/dir2/dir3并且 dir1 和 dir2 还不存在你可以使用 mkdir -p。 bash复制代码
mkdir -p dir1/dir2/dir3
使用 -p 选项mkdir 会首先创建 dir1然后在 dir1 内部创建 dir2最后在 dir2 内部创建 dir3。如果其中任何一个目录已经存在mkdir -p 不会报错而是继续创建剩余的目录。
注意事项
如果使用 mkdir不带 -p尝试创建多级目录并且上级目录不存在你会收到一个错误消息。mkdir -p 不会覆盖已经存在的目录或文件。如果尝试创建的目录已经存在mkdir -p 会静默地成功退出不会显示任何错误或警告。mkdir -p 对于脚本编写特别有用因为你可以确保多级目录结构在继续执行脚本之前被正确创建而无需担心目录是否已经存在。 2. 修改devLib/Makefile、gpio/Makefile、wiringPiD/Makefile 可以借助 vscode的ctrl shift f (能快速查找并且一键修改) 将所有Makefile中的CC : gcc 改成 CC : aarch64-none-linux-gnu-gcc
( 将本地编译需要用到的全部 gcc修改为交叉编译需要用的命令 aarch64-none-linux-gnu-gcc) 3. 修改devLib/Makefile、gpio/Makefile、wiringPiD/Makefile 、wiringPi/Makefile 修改DESTDIR?/usr 替换为DESTDIR? $(shell pwd)/../_install/usr
// shell pwd 拿到当前路径
// 我们希望在他的上层目录下面直接创建_install/usr/路径 4. 修改wiringPi/Makefile 的软连接 1、将 $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 //我们前面修改了 DESTDIR 路径这里如果还用默认的)$(DESTDIR就找不到目标文件了 需要加上$(PREFIX)指定到正确的路径 修改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 //修改利用同上 5. devLib/Makefile
INCLUDE -I. 修改为INCLUDE -I. -I$(DESTDIR)$(PREFIX)/include
//添加 -I 参数允许你指定编译器应该在哪些额外的目录中查找这些头文件。 注意: -I 参数后面直接跟的是目录的路径而不是头文件的路径。并且你可以使用多个 -I 参数来指定多个搜索目录。当编译器查找一个头文件时它会按照 -I 参数指定的目录顺序进行搜索并在找到文件后停止搜索。如果没有在 -I 指定的目录中找到文件编译器会回退到默认的系统头文件搜索路径中查找。 6. 然后执行 ./build
然后tree 就能看到我们生成的文件/夹 7.file 查看文件类型
验证教程编译成功 编译过后我们可以看到什么生成的gpio 形式 8.压缩整合文件 9.拷贝到orangepi上 10.验证
后面我们就可以把_INSTALL里的内容拷贝到香橙派的根目录下然后执行 sudo ldconfig 作用 配置运行需要的一些列软链接 就可以使用该库了可以使用 sudo gpio readlall 交叉编译 wiringPi库成功 -- 在×86平台 上编译然后移植到 arm 平台 orangepi上面能直接运行 sudo ldconfig补充
sudo ldconfig 是一个在 Unix 和类 Unix 系统如 Linux中用于更新动态链接器如 ld.so 或 ld-linux.so运行时的绑定和缓存的命令。 ldconfig 命令的简要说明和其主要功能
更新共享库缓存当系统管理员添加、删除或修改了共享库.so 文件时ldconfig 会更新动态链接器的缓存。这个缓存通常存储在 /etc/ld.so.cache 文件中它包含了系统中所有共享库的位置和版本信息。搜索指定目录默认情况下ldconfig 会搜索 /lib、/usr/lib 以及在 /etc/ld.so.conf 文件和 /etc/ld.so.conf.d/ 目录下的配置文件中指定的目录。这些目录通常包含系统的共享库文件。重新排序和删除当调用 ldconfig 时它会按照链接器的配置文件的顺序对库进行排序并且还会从缓存中删除不再需要的库的条目例如已经被删除或移动的文件。需要超级用户权限由于 ldconfig 需要修改系统级的缓存文件因此通常需要超级用户root权限来执行。这就是为什么你会看到 sudo ldconfig 这样的命令。使用场景当你安装了新的库或更新了现有的库时通常建议运行 sudo ldconfig 来确保动态链接器知道这些新的或更新过的库的位置。错误处理如果 ldconfig 在尝试更新缓存时遇到问题例如因为某些库文件损坏或丢失它通常会显示一个错误消息但通常会继续更新剩余的库。
总之sudo ldconfig 是一个用于更新动态链接器缓存的命令以确保系统能够正确地找到和使用共享库。 交叉编译 项目以智能垃圾分类为例: 观前提醒 对这个项目不太了解的朋友推荐先看这篇: 垃圾分类最终篇 -- 添加网络控制功能-CSDN博客
希望对这个项目有更多了解的朋友还可以去专栏了解详细内容智能垃圾桶项目_mx_jun的博客-CSDN博客 0. 创建文件夹: inc -- 存放所有头(.h)文件 src -- 存放所有源(.c)文件 3rd -- 存放 这个工程依赖的第三方的头文件和库 --------------
1.下载需要的库文件编译链接文件 增加 3rd 目录用于存放 wiringOP 和 python3.10 等第三方依赖库和头文件。需增加如下几个依赖库 . 首先从香橙派上利用 apt download 下载依赖包的头文件和库文件并拷贝到宿主机里 在orangepi 上面安装好后我们就可以拷贝到我们的宿主家 -- Ubuntu上面 执行以下命令下载: apt download zlib1g zlib1g-dev libpython3.10 libpython3.10-dev libexpat1 libexpat1-dev libcrypt1 libcrypt-dev 如下命令拷贝到 ×86 平台-- 宿主机 scp *deb mxjun192.168.88.132:/home/mxjun 说明: apt download -- 只下载不安装 apt install -- 既下载又安装 .deb -- .deb 文件是 Debian 软件包格式的文件 2.在×86平台上面解压文件 deb 包的解压命令是 dpkg
解压文件 dpkg -x .deb文件 存放位置 3.编写Makefile 文件(细节活) 然后去makefile里面加上所有的头文件路径 Makefile 带注释形式 :带注释形式 CC : aarch64-none-linux-gnu-gcc# SRC -- 存放所有的 .c 文件 SRC : $(shell find src -name *.c)# INC -- 存放所有的 头文件 (包括自己写的 和 第三方) 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 # 把需要包含的 .c 文件替换为.o 文件 OBJ : $(subst src/.,obj/,$(SRC:.c.o)) # 创建目标 并且指定存放位置 TARGET obj/garbage # -I./inc -- 存放头文件路径 CFLAGS : $(foreach item,$(INC),-I$(item)) # -I 指定的 第三方连接 库文件路径 LIBS_PATH : ./3rd/usr/local/lib \ ./3rd/lib/aarch64-linux-gnu \ ./3rd/usr/lib/aarch64-linux-gnu \ ./3rd/usr/lib/python3.10 \ # -L ./3rd/usr/local/LIBS LDFLAGS : $(foreach item,$(LIBS_PATH),-L$(item)) # 指定我们要链接的库 LIBS : -lwiringPi -lpython3.10 -pthread -lexpat -lz -lcrypt # 生成obj文件夹里面包含源文件对应的.o文件 obj/%.o:src/%.CC mkdir -p obj $(CC) -o $ -c $ $(CFLAGS) # 依赖obj 下面的.o文件 编译 $(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 纯净版本: 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)) TARGETobj/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 4. 验证 编译通过后到obj 发现已经生成了我们的可执行文件 5. 拷贝到我们的香橙派中: scp garbage orangepi192.168.1.11:/home/orangepi 6.执行
请确保相关服务已经打开比如我程序里面调用的是 mjpg-stream 来实现拍照功能那么执行之前这个服务纪就要确保打开 -l(l) -I(i) 参数补充
-l(l) 参数补充 定义 在 GCCGNU Compiler Collection中-l 参数用于指定在链接阶段要链接的库library。当你编译一个程序并且它依赖于某个库时你需要告诉 GCC 在链接阶段将这个库包含进来。
-l 参数后面通常跟着库的名字但需要注意的是你不需要指定库文件的前缀如 lib或后缀如 .so、.a 等。GCC 会自动根据系统配置和库文件的实际位置来查找这些库。
例如如果你的程序依赖于数学库 libm.so或 libm.a取决于你的系统和编译选项你应该在编译命令中使用 -lm 而不是 -llibm。
以下是一个简单的示例 bash复制代码
gcc myprogram.c -o myprogram -lm
在这个例子中myprogram.c 是你的源代码文件-o myprogram 指定输出文件的名称而 -lm 告诉 GCC 在链接阶段链接数学库。
需要注意的是链接库的顺序有时很重要。如果库之间有依赖关系你需要先链接依赖的库然后再链接依赖于它的库。但是对于大多数常见的库如数学库、标准 C 库等这个顺序通常不是问题。
此外如果你知道库文件的实际路径你也可以使用 -L 参数来指定库的搜索路径。例如 bash复制代码
gcc myprogram.c -o myprogram -L/path/to/libs -lmylib
在这个例子中-L/path/to/libs 告诉 GCC 在 /path/to/libs 目录下搜索库文件而 -lmylib 指定要链接的库名为 mylib即 libmylib.so 或 libmylib.a。 -I (-i)参数补充 在 gccGNU Compiler Collection中-I 参数注意是大写的 I用于指定编译器搜索头文件header files的额外目录。
当你在 C 或 C 代码中包含#include一个头文件时编译器需要找到这个头文件的实际位置以便能够正确地编译代码。默认情况下编译器会在一些标准的位置如 /usr/include 和 /usr/local/include中查找头文件。但是如果你的头文件不在这些标准位置中你就需要使用 -I 参数来告诉编译器在哪里可以找到这些头文件。
例如如果你的头文件位于 /home/user/myproject/include 目录中你可以在编译时添加 -I/home/user/myproject/include 来告诉编译器在那里查找头文件 bash复制代码
gcc -I/home/user/myproject/include myfile.c -o myprogram
在这个例子中编译器会在 /home/user/myproject/include 目录中查找 myfile.c 中包含的任何头文件。
-I 参数对于组织大型项目或当头文件位于非标准位置时特别有用。通过使用 -I 参数你可以确保编译器能够找到你的项目所需的所有头文件而不管它们实际存储在哪里。