二、交叉开发的概念
是指在通用PC端把程序编写、编译好之后,再下载到嵌入式产品中去运行 为什么要用交叉开发? (1)大多数的嵌入式产品只有运行环境。没有编译环境 (2)程序员的工作环境更加舒适、安全三、GEC-6818开发板简介
四、网络设置
1)设置虚拟机IP 1>虚拟机设置--》网络适配器--》桥连模式--》勾选上复制物理网络连接状态 2>设置--》网络--》设置--》IPV4-->改为手动分配IP--》设置IP地址、子网掩码、网关 --->重新打开网络连接 输入指令查看: ifconfig2)设置开发板IP 打开开发板的启动配置文件 vi /etc/init.d/rcS在文件的最末尾添加:
ifconfig eth0 down ifconfig eth0 hw ether 08:09:00:A0:38:68 ifconfig eth0 172.8.0(1).xx netmask 255.255.254.0 up重启开发板即可五、开发板的使用
1)先用串口线把开发板与电脑相连接 2)打开开发板控制终端(下载SecureCRT) 3)打开电脑的设备管理器,查看是否识别到了端口(快捷键:windoes+x) 如果没有识别出来端口--》请安装驱动 4)SecureCRT连接设置 协议:serial协议: 串口协议 端口:你设备管理器中识别出来的端口 波特率:115200 去掉流控RTS/CTS的勾选 ====》连接开发板上电之后,会有一个自启动程序,该程序会占用终端,
按下CTRL + C把开发板自启动程序杀掉六、文件下载
1)串口下载
(1)使用 rx 命令下载 使用语法: rx 需要下载的文件名 点击传输--》发送xmodem (2) 使用 rz 命令下载 1、安装 rz工具 2、解压 tar -vxf arm-rz.tar.xz 3、运行 arm-rz文件中的rzconf.sh 4、使用rz下载文件 语法: rz 回车2)通过 tftp 网络协议下载文件 tftp 和 ftp 都是用来传输文件的一种网络协议 tftp 实现是采用UDP协议 ftp 实现是采用 TCP 协议
tftp 只能用来传输文件(不能传输其他东西) 使用步骤: 1>先在虚拟机上安装 tftpd-hpa 工具 sudo apt-get install tftpd-hpa 2>配置 tftpd-hpa: sudo vim /etc/default/tftpd-hpa 3>(第一次安装)需添加内容: TFTP_USERNAME="tftp" //创建一个tftp的共享文件目录 TFTP_DIRECTORY="/home/china/tftpboot" //创建一个tftpboot共享文件目录 TFTP_ADDRESS="0.0.0.0:69" TFTP_OPTIONS="-l -c -s" 4> 设置 tftp共享目录的权限 chmod 0777 /home/china/tftpboot 第一次使用tftp时,需要手动启动tftp服务: sudo service tftpd-hpa start 后续使用就不需要在启动,可以使用重启: sudo service tftpd-hpa restart 停止tftp服务: sudo service tftpd-hpa stop 开发板从指定的 tftp 服务器 下载文件 或 传输文件 开发板下载命令: tftp -g -r 要下载的文件名 172.8.0.xxx (虚拟机的IP) 开发板传输文件命令: tftp -p -r 要传输的文件名 172.8.0.xxx(虚拟机IP) 注意:要下载的文件 必须要在tftpboot共享文件目录下 要传输前,请先确保你的 tftpboot中存在这个文件七、交叉编译 (1)采用交叉编译的规则去编译文件 arm-linux-gcc 1.c -o 1 arm-linux-gcc 是交叉编译工具
(2)把生成的可执行文件下载到开发板 rx 1 (3)给可执行文件增加可执行权限 chmod +x 1 (4)运行程序 ./1八、GCC编译过程 gcc hello.c -o hello
编译过程是不是一步到位的? //不是 编译过程: (1)预处理 处理代码中所有以'#'开头的行 主要处理:头文件以及宏定义 语句: gcc -E hello.c -o hello.i //hello.i还是一个c文件 (2)编译 把C文件编译成汇编文件(有语法的转换),会进行语法分析,有错误会报错 语句: gcc -S hello.c -o hello.s //hello.s 就是一个汇编文件 (3)汇编 把汇编文件生成一个可执行文件(机器指令)--》二进制文件 语句: gcc -c hello.s -o hello.o //hello.o 就是一个二进制文件 (4)链接 把所有的.o文件链接起来,生成一个目标文件 语句: gcc 1.o 2.o main.o -o main 为什么编译过程不能一步到位? //效率考虑
库
库
库(library) 是一种代码的封装形式,简单的说,库中封装着一堆目标文件(.o)当封装好了一个库之后,在其他地方就可以直接调用,但是用户却看不到具体的实现,不会造成源代码的泄漏。
根据库的不同的封装和链接形式,分为动态库、静态库1、动态库
操作流程:
1)创建(封装)一个动态库
(1)编写源代码 1.c 1.h 2.c 2.h main.c(主程序) (2)把源代码先编译成目标文件 gcc -c -fpic 1.c -o 1.o gcc -c -fpic 2.c -o 2.o (3)把目标文件封装成一个库 gcc -shared 1.o 2.o -o libxxx.so / gcc -shared -o libxxx.so 1.o 2.o 注: -fpic : 表示要生成的库与位置无关(简单的理解:库中的函数不知道会被哪个程序调用) ---(再简单的说,就是生成一个任意程序都能调用的动态库) -o : 表示指定生成目标文件 -shared: 表示要编译一个动态库(共享库) libxxx.so : lib是库的前缀,.so是动态库的后缀,xxx是动态库其实也可以把以上两步合为一:
gcc -shared -fpic -o libxxx.so 1.c 2.c (跟编译器环境有关)2)链接一个动态库 要想使用一个动态库的话,一般来讲需要提供对应的 .h 文件以及 .so 文件 然后用户编译的时候,只需要指定头文件与库文件的路径 以及 库的名字,就可以使用库
格式如下: gcc main.c -I头文件路径 -L库路径 -l库名 -o main3)直接运行程序会报错,因为动态库的使用必须要修改动态库搜索路径 1>把你的动态库加入到系统默认的动态库搜索路径下 cp libxxx.so /usr/lib
2>手动添加动态库搜索路径 在终端输入: export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/mnt/hgfs/CS2322/19.交叉开发/code2、静态库 使用动态库时,链接时需要添加动态库的路径,运行程序时也需要指定动态库的搜索路径 程序与动态库相互独立,彼此依赖
静态库的做法,与动态库不太一样,静态库在使用时是不需要添加库搜索路径,因为静态库在链接这一步骤时, 就已经把静态库的内容拷贝到程序中。 即程序本身运行过程中不再需要依赖静态库操作流程: 1)编写源文件 1.c 1.h main.c(主程序)
2)编译源文件得到目标文件 gcc -c 1.c -o 1.o 3)封装库 ar -rc libxxx.a 1.o 注: ar : 封装一个静态库 -rc: -r代表插入目标文件到静态库中,-c代表创建指定的静态库 libxxx.a : lib是库的前缀,xxx是库名,.a是静态库的后缀 4)链接静态库 用户编译程序时,只需要指定头文件、库文件路径,以及库文件名就可以使用,形式如下: gcc main.c -o main -I头文件路径 -L库路径 -l库名 5)直接运行程序即可,不需要考虑环境变量3、动态库与静态库的异同 1)动态库与静态库都是目标文件(二进制文件)的封装 2)对于动态库: 在编译程序时,并没有把动态库的内容添加进程序中,就仅仅是做了一个标记,表示需要 使用动态库的内容,当执行程序时,还需要指定动态库的搜索路径,才可以正常使用动态库 对于静态库 : 编译程序时,会直接把静态库的内容拷贝到程序中去,运行程序,就不再需要静态库
3)我们一般来讲,使用动态库比较多 理由: 1> 程序运行时,动态库只需要存在一份,但是静态库可能会存在多次拷贝,会造成代码的冗余 2> 当库进行更新时,对于动态库来讲,在接口不变的情况下,则不需要重新编译程序 对于静态库来说,库一旦发生改变,所有使用了该库的程序都需要重新编译
Makefile
Makefile 目标:完成一个简单的makefile文件即可 makefile(工程管理文件) 是一个脚本,用来实现自动化编译工程文件。
当我们执行make命令时,会自动找到相应的makefile文件 然后根据其makefile制定的规则去生成文件 make有两种用法: make -->make后面不带参数,那么默认执行第一条命令 make cmd -->指定执行cmd命令 要使用make命令,需要先下载make工具包 语法: sudo apt install make makefile 执行命令的格式: 目标文件:依赖文件列表 <TAB>cmd1 <TAB>cmd2 .... 注:每一条命令之前,必须要有一个TAB键空格(TAB键的空格需要有四格) makefile命令中,以#开头的行,代表注释 在 makefile 里面,我们可以自定义变量,且变量没有类型,通常是当作字符串来处理 给变量赋值,通常有四种方式: := 简单赋值,”就地赋值“ B:=123 //right B:$(A) //error,因为A没有定义 = 递归赋值,”向后展开赋值“ C=$(D) //right,D在后面有定义,C=="123" ... D:=123 += 追加赋值,”在原有的基础上,在后面添加,以空格隔开“ A:=JQY A+=XXF // A的内容为:"JQY XXF" ?= 条件赋值,只有当变量没有值的时候才会赋值 A:=123 A?=hello //A的内容为"123" 引用变量: $(变量名) 在makefile 里面,我们还可以使用makefile内置的变量,makefile赋予这些变量特殊的含义 $* :表示不包含拓展名的目标文件 eg: 目标文件:main.o --> $* = main $@ : 表示完整的目标文件名称 eg: 目标文件:main.o --> $@ = main.o $^ :所有的依赖文件,以空格隔开 eg: 依赖文件: 1.c 2.c --> $^ = 1.c 2.c $< : 表示第一个依赖文件的名称 eg: 依赖文件: 1.c 2.c --> $< = 1.c $? :表示所有时间戳比目标文件晚的依赖文件(后面经过修改的依赖文件),以空格隔开 eg: 依赖文件有: 1.c 2.c 3.c ,其中 1.c 3.c 都重新修改过内容 $? = 1.c 3.c