第三周嵌入式作业-GCC背后的故事&相逢何必曾相识
文章目录
一、用gcc生成静态库和动态库
1.编写代码
(1)hello.h
#ifndef HELLO_H
#define HELLO_H
void hello(const char *name);
#endif//HELLO_H
(2)hello.c
void hello(const char *name)
{
printf("Hello %s\n",name);
}
(3)main.c
int main()
{
hello("everyone");
return 0;
}
2.静态库链接
(1)创建静态库
ar -crv libmyhello.a hello.o
(2)程序中使用静态库
①gcc -o hello main.c -L. -lmyhello
②gcc main.c libmyhello.a -o hello
③先生成main.o gcc -c main.c
生成可执行文件 gcc -o hello main.c libmyhello.a
(3)验证静态库的特点
在删掉静态库的情况下,运行可执行文件,发现程序仍旧正常运行,表明静态库跟程序执行没有联系。同时,也表明静态库是在程序编译的时候被连接到代码中的。
3.动态库链接
(1)创建动态库
gcc -shared -fPIC -o libmyhello.so hello.o
shared:表示指定生成动态链接库,不可省略
-fPIC:表示编译为位置独立的代码,不可省略
(2)在程序中执行动态库
mv libmyhello.so/usr/lib
二.自己编写函数实现动态库和静态库
1.编写代码
(1)main.c
(2)sub1.c
(3)sub2.c
(4)sub.h
2.静态库
3.动态库
三.gcc不是一个人战斗
1.gcc常用命令
1.生成一个实例文本
一步到位的编译指令
gcc test.c -o test
直接生成可执行文件
2.实质上,上述编译过程是分为四个阶段进行的,即预处理(也称预编译,Preprocessing)、编译 (Compilation)、汇编 (Assembly)和连接(Linking)。预处理实质上,上述编译过程是分为四个阶段进行的,即预处理(也称预编译Preprocessing)、编译 (Compilation)、汇编 (Assembly)和连接(Linking)。
(1)预处理
gcc -E test.c -o test.i
可以输出 test.i 文件中存放着 test.c 经预处理之后的代码。打开 test.i 文件,看一看,就明白了。后 面那条指令,是直接在命令行窗口中输出预处理后的代码。
预处理之后,可直接对生成的 test.i 文件编译,生成汇编代码: gcc -S test.i -o test.sgcc 的-S 选项,表示在程序编译期间,在生成汇编代码后,停止,-o 输出汇编代码文件。
对于上一小节中生成的汇编代码文件 test.s,gas 汇编器负责将其编译为目标文件,如下:
gcc -c test.s -o test.o
gcc 连接器是 gas 提供的,负责将程序的目标文件与所需的所有附加的目标文件连接起来,最终生 成可执行文件。附加的目标文件包括静态连接库和动态连接库。 对于上一小节中生成的 test.o,将其与C标准输入输出库进行连接,最终生成程序 test
gcc test.o -o test
(1)检错
gcc -pedantic illcode.c -o illcode
多个程序共同编译
gcc test1.c test2.c -o test
(2) 库文件链接
静态库链接时搜索路径顺序:
ld 会去找 GCC 命令中的参数-L
再找 gcc 的环境变量 LIBRARY_PATH
再找内定目录 /lib /usr/lib /usr/local/lib 这是当初 compile gcc 时写在程序内的。
动态链接时、执行时搜索路径顺序:
编译目标代码时指定的动态库搜索路径
环境变量 LD_LIBRARY_PATH 指定的动态库搜索路径
配置文件/etc/ld.so.conf 中指定的动态库搜索路径
默认的动态库搜索路径/lib
默认的动态库搜索路径/usr/lib。
2.gcc编译器背后的故事
2.分析ELF文件
ELF文件的段
text:已编译程序的指令代码段。
rodata:ro 代表 read only,即只读数据(譬如常数 const)。
data:已初始化的 C 程序全局变量和静态局部变量。
bss:未初始化的 C 程序全局变量和静态局部变量。
debug:调试符号表,调试器用此段的信息帮助调试。
反汇编ELF
四.opencv图像编程
1.图片
1.代码编写
首先创建一个代码存放文件夹 code ,然后进入文件夹中。
创建一个 test1.cpp 文件。
#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
CvPoint center;
double scale = -3;
IplImage* image = cvLoadImage("lena.jpg");
argc == 2? cvLoadImage(argv[1]) : 0;
cvShowImage("Image", image);
if (!image) return -1; center = cvPoint(image->width / 2, image->height / 2);
for (int i = 0;i<image->height;i++)
for (int j = 0;j<image->width;j++) {
double dx = (double)(j - center.x) / center.x;
double dy = (double)(i - center.y) / center.y;
double weight = exp((dx*dx + dy*dy)*scale);
uchar* ptr = &CV_IMAGE_ELEM(image, uchar, i, j * 3);
ptr[0] = cvRound(ptr[0] * weight);
ptr[1] = cvRound(ptr[1] * weight);
ptr[2] = cvRound(ptr[2] * weight);
}
Mat src;Mat dst;
src = cvarrToMat(image);
cv::imwrite("test.png", src);
cvNamedWindow("test",1); imshow("test", src);
cvWaitKey();
return 0;
}
(2)编译文件
g++ test1.cpp -o test1 `pkg-config --cflags --libs opencv`
(3)输出结果
./test1
(4)pck-config a. 检查库的版本号。如果所需要的库的版本不满足要求,它会打印出错误信息,避免链接错误版本的库文件。b. 获得编译预处理参数,如宏定义,头文件的位置。c. 获得链接参数,如库及依赖的其它库的位置,文件名及其它一些连接参数。d. 自动加入所依赖的其它库的设置。在该文件夹里面有个opencv.pc的文件,其实这就是pkg-config下OpenCV的配置文件。选项–cflags 它是用来指定程序在编译时所需要头文件所在的目录,选项 --libs则是指定程序在链接时所需要的动态链接库的目录。
2.视频
1.播放视频
(1)创建一个test2.cpp文件
(2)代码
(3)编译test2且输出结果
2.录制视频
(1)test3.cpp代码展示
(2)编译test3且输出结果
g++ test3.cpp -o test3 `pkg-config --cflags --libs opencv`
3.回答
(1)
while(1){
Mat frame;//定义一个Mat变量,用于存储每一帧的图像
cv::VideoCapture capture; capture.open("xxx.mp4");
if(frame.empty())//播放完毕,退出
break;
imshow("读取视频帧",frame);//显示当前帧
waitKey(30);//掩饰30ms
}
(2)Mat是一个类。由两部分组成:矩阵头和一个指向所有像素值的矩阵的指针,不能删除,这个函数是在一个给定的时间内(单位ms)等待用户按键触发;如果用户没有按下键,就继续循环。一定的延时是确保视频播放的前提,如果没有延时,视频播放会一下子就播放完成。
(3)
while(1){
Mat frame;//定义一个Mat变量,用于存储每一帧的图像
capture >> frame;//读取当前帧
if(frame.empty())//播放完毕,退出
break;
imshow("读取视频帧",frame);//显示当前帧
//waitKey(30);//掩饰30ms
if(waitKey(30)==27)break;
}
五.掌握git使用方法
1.git 工作流程
命令如下:
1. clone(克隆): 从远程仓库中克隆代码到本地仓库
2. checkout (检出):从本地仓库中检出一个仓库分支然后进行修订
3. add(添加): 在提交前先将代码提交到暂存区
4. commit(提交): 提交到本地仓库。本地仓库中保存修改的各个历史版本
5. fetch (抓取) : 从远程库,抓取到本地仓库,不进行任何的合并动作,一般操作比较少。
6. pull (拉取) : 从远程库拉到本地库,自动进行合并(merge),然后放到到工作区,相当于
fetch+merge
7. push(推送) : 修改完成后,需要和团队成员共享代码时,将代码推送到远程仓库
1.git 基本命令
3.4.1.*查看修改的状态(status)
命令形式:git status
3.4.2.*添加工作区到暂存区(add)
命令形式:git add 单个文件名|通配符 将所有修改加入暂存区:git add .
3.4.3.*提交暂存区到本地仓库(commit)
命令形式:git commit -m '注释内容'
3.4.4.*查看提交日志(log)
命令形式:git log [option]
options
--all 显示所有分支
--pretty=oneline 将提交信息显示为一行
--abbrev-commit 使得输出的commitId更简短
--graph 以图的形式显示
命令形式:git log [option]
options
--all 显示所有分支
--pretty=oneline 将提交信息显示为一行
--abbrev-commit 使得输出的commitId更简短
--graph 以图的形式显示
3.4.5.版本回退
命令形式:git reset --hard commitID
3.4.6.添加文件至忽略列表
一般我们总会有些文件无需纳入Git 的管理,也不希望它们总出现在未跟踪文件列表。 通常都是些自动 生成的文件,比如日志文件,或者编译过程中创建的临时文件等。 在这种情况下,我们可以在工作目录 中创建一个名为 .gitignore 的文件(文件名称固定),列出要忽略的文件模式。
五.总结
第一部分通过三个程序用gcc生成静态库和动态库的练习过程,学习了怎样生成静态库和动态库。静态库和动态库之间也存在着明显的差别,可执行文件是通过编译链接获取得到的,利用工具将源码编译得到.o文件,接下来就是将.o文件链接得到可执行文件。第二部分更加深入地了解了gcc的背景、命令语句以及编译、检错、库文件的连接和ELF文件。第三部分是下载安装了opencv和掌握一些基本的用法如图片的特效显示、播放视频和录制一段视频等。这个过程中出现了非常多的问题:环境的设置、代码的编写、摄像头的调用和视频如何播放等,但是在自己查阅资料以及同学的帮助下最终还是努力地解决了这些问题。