文章目录
一.使用gcc生成.a静态库和.so动态库
1.编译生成子程序hello.h、hello.c以及main.c
创建作业目录,并用 vim编辑器编辑生成所需要的 3 个文件
mkdir test1
cd test 1
hello.h为该函数库的头文件
#ifndef HELLO_H
#define HELLO_H
void hello(const char *name);
#endif //HELLO
hello.c是函数库的源程序,其中包含公用函数 hello,该函数将在屏幕上输出"Hello
XXX!‘’
#include <stdio.h>
void hello(const char *name)
{
printf("Hello %s!\n", name);
}
main.c为测试库文件的主程序,在主程序中调用了公用函数 hello
#include "hello.h"
int main()
{
hello("everyone");
return 0;
}
2.将 hello.c 编译成.o 文件。
gcc -c hello.c
运行 ls 命令查看是否生存了 hello.o 文件
ls
3.由.o 文件创建静态库,并运行 ls 命令查看结果
ar -crv libdearhello.a hello.o
ls
4.在程序中使用静态库
gcc -o hello main.c -L. –ldearhello
5 .由.o 文件创建动态库文件并使用 ls 命令查看动态库文件是否生成。
gcc -shared -fPIC -o libdearhello.so hello.o
ls
6 .在程序中使用动态库
gcc -o hello main.c -L. -ldearhello
运行
./hello
运行./hello 会提示出错,因为虽然连接时用的是当前目录的动态库,但是运行时,是到/usr/lib 中找库文件的,将文件 libmyhello.so 复制到目录/usr/lib即可
mv libdearhello.so /usr/lib
又发现需要管理员权限,则使用sudo命令
sudo mv libdearhello.so /usr/lib
再次运行查看结果
二.改写一函数及对静态库、动态库的应用
(一)文件的建立及编译
1.建立main.c、sub1.c、sub2.c、sub.h文件
mkdir work1
cd work1
touch main.c sub1.c sub2.c sub.h
main.c:
#include"sub.h"
#include<stdio.h>
int main(){
int a=8,b=16;
printf("%f\n",x2x(a,b));
printf("%f\n",x2y(a,b));
return 0;
}
sub1.c
#include<stdio.h>
float x2x(int a,int b){
float x;
x=a*b;
return x;
}
sub2.c:
#include<stdio.h>
float x2y(int a,int b){
float c;
c=a+b;
return c;
}
sub.h:
#ifndef SUB_H
#define SUB_H
float x2x(int a,int b);
float x2y(int a,int b);
#endif
2.使用gcc分别编译sub1.c和sub2.c生成sub1.o和sub2.o并查看结果
gcc -c sub1.c sub2.c
ls
(二)静态库
1.生成静态库文件及可执行文件
ar -crv libmysub.a sub1.o sub2.o
./main
2.查看静态库大小
ls -l
(三)动态库
1.键入gcc -c -fpic sub1.c sub2.c
gcc -c -fpic sub1.c sub2.c
2.生成动态库文件及可执行文件
gcc -o main main.c libmysub.so
sudo mv libmysub.so /usr/lib
./main
3.查看动态库大小
ls -l
##(四)动态库与静态库文件大小的比较
两图对比,发现静态库和动态库生成的可执行文件大小差不多
三.Linux GCC常用命令及背后的故事
(一)准备工作
1.创建工作目录test2,并用vim编译生成一个hello.c程序
mkdir test2
cd test2
vi hello.c
hello.c文件:
#include <stdio.h>
int main(void)
{
printf("Hello World! \n");
return 0;
}
(二) 编译过程
1.预处理
gcc -E hello.c -o hello.i
预处理的过程主要包括以下过程:
(1) 将所有的#define 删除,并且展开所有的宏定义,并且处理所有的条件预编
译指令,比如#if #ifdef #elif #else #endif 等。
(2) 处理#include 预编译指令,将被包含的文件插入到该预编译指令的位置。
(3) 删除所有注释“//”和“/* */”。
(4) 添加行号和文件标识,以便编译时产生调试用的行号及编译错误警告行号。
(5) 保留所有的#pragma 编译器指令,后续编译过程需要使用它们
2.编译
gcc -S hello.i -o hello.s
编译过程就是对预处理完的文件进行一系列的词法分析,语法分析,语义分析及优化后生成相应的汇编代码
3.汇编
gcc -c hello.s -o hello.o
汇编过程调用对汇编代码进行处理,生成处理器能识别的指令,保存在后缀为.o的目标文件中。通过调用 Binutils 中的汇编器 as 根据汇编指令和处理器指令的对照表一一翻译
4.链接
链接分为动态链接和静态链接
(1) 静态链接是指在编译阶段直接把静态库加入到可执行文件中去,这样可执行
文件会比较大。链接器将函数的代码从其所在地(不同的目标文件或静态链接库中)拷贝到最终的可执行程序中。
(2) 动态链接则是指链接阶段仅仅只加入一些描述信息,而程序执行时再从系统中把相应动态库加载到内存中去。
由于链接动态库和静态库的路径可能有重合,所以如果在路径中有同名的静态库文件和动态库文件,比如 libtest.a 和 libtest.so,gcc 链接时默认优先选择动态库,会链接libtest.so,如果要让 gcc 选择链接 libtest.a 则可以指定 gcc 选项-static,该选项会强制使用静态库进行链接。
链接动态库:
gcc hello.c -o hello
使用size查看大小:
size hello
查看可执行文件链接的动态库
ldd hello
链接静态库:
gcc -static hello.c -o hello
(三)分析ELF文件
1.ELF 文件的段
- 一个典型的 ELF 文件包含下面几个段:
- .text:已编译程序的指令代码段。
- .rodata:ro 代表 read only,即只读数据(譬如常数 const)
- .data:已初始化的 C 程序全局变量和静态局部变量。
- .bss:未初始化的 C 程序全局变量和静态局部变量。
- .debug:调试符号表,调试器用此段的信息帮助调试。
查看其各个 section 的信息
readelf -S
2.反汇编 ELF
由于 ELF 文件无法被当做普通文本文件打开,如果希望直接查看一个 ELF 文件包
含的指令和数据,需要使用反汇编的方法。
objdump -D hello
使用 objdump -S 将其反汇编并且将其 C 语言源代码混合显示出来
gcc -o hello -g hello.c
objdump -S hello
四.基于Opencv完成图像程序编程
(一)安装opencv3.4.16
1.在官网安装opencv3.4.16.zip
https://opencv.org/releases/添加链接描述
点击source源,下载完成后解压成文件夹复制粘贴到Ubuntu的文件夹中
(途中显示文件已经过重命名)
2.安装依赖库和cmake ,如果提醒需要apt-get update,那就先sudo su进入root权限,再sudo apt-get update,然后在执行下面命令
sudo apt-get install cmake
sudo apt-get install build-essential libgtk2.0-dev libavcodec-dev libavformat-dev libjpeg.dev libtiff5.dev libswscale-dev libjasper-dev
3.安装完cmake之后执行命令 ,创建编译文件夹
mkdir build
cd build
cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local ..
4.执行命令
sudo make -j8
5.执行命令
sudo make install
(二)配置OpenCV的编译环境
1.首先将OpenCV的库添加到路径,从而可以让系统找到
sudo gedit /etc/ld.so.conf.d/opencv.conf
2.在文件末尾添加
/usr/local/lib
3.保存回到命令行界面
执行如下命令使得刚才的配置路径生效
sudo ldconfig
4.配置bash
sudo gedit /etc/bash.bashrc
5.在文件末尾添加
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig
export PKG_CONFIG_PATH
6.保存,执行如下命令使得配置生效
source /etc/bash.bashrc
7.更新
sudo updatedb
至此所有的配置都已经完成
(三)图像程序编程
1.首先创建一个代码存放文件夹 code1 ,然后进入文件夹中
cd code1
2.创建一个 test1.cpp 文件
gedit test1.cpp
3.输入如下代码:
#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("boy.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;
}
4.执行以下命令
g++ test1.cpp -o test1 `pkg-config --cflags --libs opencv`
5.在用同文件夹下准备一张图片,文件名为:lena.jpg
运行
./test1
可以看到由 boy.jpg 生成了一个 test.png ,呈现的效果不同了
(四)视频程序编程
1.虚拟机获取摄像头权限
使用快捷键 Win + R ,输入 services.msc ,并回车
找到VMware USB Arbitration S…保证启动
2.点击 “ 虚拟机 ” ,然后点击 “ 设置(S)… ”
3.选择 “ USB控制器 ” ,将 “ USB兼容性 ” 设置为 “ USB 3.0 ” ,并点击确定
4.播放视频
创建一个 test2.cpp 文件
gedit test2.cpp
test2代码:
#include <opencv2/opencv.hpp>
using namespace cv;
int main()
{
//从摄像头读取视频
VideoCapture capture("pink.mp4");
//循环显示每一帧
while(1){
Mat frame;//定义一个Mat变量,用于存储每一帧的图像
capture >> frame;//读取当前帧
if(frame.empty())//播放完毕,退出
break;
imshow("读取视频帧",frame);//显示当前帧
waitKey(30);//掩饰30ms
}
system("pause");
return 0;
}
5.准备一个小视频,我这里准备了 pink.mp4
6编译 test2.cpp 文件并输出结果
g++ test2.cpp -o test2 `pkg-config --cflags --libs opencv`
./test2
下图即为视频展示
(五)录制视频编程
1.创建test3.cpp并编译
gedit test3.cpp
代码如下:
/*********************************************************************
打开电脑摄像头,空格控制视频录制,ESC退出并保存视频RecordVideo.avi
*********************************************************************/
#include<iostream>
#include <opencv2/opencv.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
using namespace cv;
using namespace std;
int main()
{
//打开电脑摄像头
VideoCapture cap(0);
if (!cap.isOpened())
{
cout << "error" << endl;
waitKey(0);
return 0;
}
//获得cap的分辨率
int w = static_cast<int>(cap.get(CV_CAP_PROP_FRAME_WIDTH));
int h = static_cast<int>(cap.get(CV_CAP_PROP_FRAME_HEIGHT));
Size videoSize(w, h);
VideoWriter writer("RecordVideo.avi", CV_FOURCC('M', 'J', 'P', 'G'), 25, videoSize);
Mat frame;
int key;//记录键盘按键
char startOrStop = 1;//0 开始录制视频; 1 结束录制视频
char flag = 0;//正在录制标志 0-不在录制; 1-正在录制
while (1)
{
cap >> frame;
key = waitKey(100);
if (key == 32)//按下空格开始录制、暂停录制 可以来回切换
{
startOrStop = 1 - startOrStop;
if (startOrStop == 0)
{
flag = 1;
}
}
if (key == 27)//按下ESC退出整个程序,保存视频文件到磁盘
{
break;
}
if (startOrStop == 0 && flag==1)
{
writer << frame;
cout << "recording" << endl;
}
else if (startOrStop == 1)
{
flag = 0;
cout << "end recording" << endl;
}
imshow("picture", frame);
}
cap.release();
writer.release();
destroyAllWindows();
return 0;
}
2.编译
g++ test3.cpp -o test3 `pkg-config --cflags --libs opencv`
3.输出结果
./test3
生成了一个 .avi 文件,并不断生成帧
五.Gitee.com的基本使用
1.登录码云账号
2.新建仓库
3.将私有仓库设置为公开仓库
4.保存后点击仓库名返回仓库初始界面
5.在终端输入sudo apt-get install git来安装git
sudo apt-get install git
6.设置昵称和邮箱地址
git config --global user.name "你的名字"
git config --global user.email "你的邮箱地址"
7.得到连接的SSH公钥
ssh-keygen -C -t rsa "邮箱地址"
8.连接gitee.com
cd ~/.ssh
将文件中的内容复制粘贴到gitee.com的公钥中(图为添加成功后)
检查是否连接成功
检测Ubuntu能否连接到Gitee
9.上传文件
将文件初始化为本地仓库
git init
命令上传该文件夹内所有文件(add和.之间为两个空格)
git add .
克隆的SSH链接
获取克隆的SSH链接的方法:打开你在Gitee创建的那个仓库,点击克隆/下载按钮,出现下面的文本框里的就是克隆的SSH链接,点击复制即可
git remote add origin +SSH链接
同步Gitee仓库
git pull origin master
信息备注
git commit -m "备注内容''
开始上传文件至Gitee
git push origin master
刷新后即可得到上传文件
六.总结
通过本次练习,基本掌握了动态库、静态库的使用,gcc常用命令的使用,编译器的操作过程,以及opencv软件的安装以及图像视频的操作,对于练习过程中出现的问题,通过不断查阅资料,由于初次使用,使得花费时间较长,但最终完成了任务,自己对ubuntu有了更多的了解。
七.参考资料
https://blog.csdn.net/weixin_50617754/article/details/111722043
https://blog.csdn.net/ssj925319/article/details/109231145
https://cungudafa.blog.csdn.net/article/details/84451066
https://blog.csdn.net/qq_43279579/article/details/109026927
https://blog.csdn.net/ssj925319/article/details/109231145
https://blog.csdn.net/weixin_46129506/article/details/120646081