安装第3方库无非就是4步:
(1)编译第三方库源码为动态库或者静态库(可以直接下载别人编译好的库);
(2)在开发工具中进行配置,这样才能引用;
(3)代码中引用、编程;
(4)打包成可执行文件。
需要理清楚的就3个问题:
(1)第三库的形式有哪些,在linux和windows中的形式?
(2)不同开发工具如何配置第三方库?
(3)编译和打包工具怎么使用?
学习编程就是先学习:
(1)编程语言;
(2)各种工具(集成工具vs,发布工具git,数据库工具mysql等等);
(3)各种第3方库,也可以算作工具,别人写好的一些功能。
(4)解决实际问题;
参考文档:
Windows下使用MinGW在命令行编译运行C++程序案例实操
预处理主要处理源文件中的“#include”、“#define”等预处理命令
预处理主要完成的工作有:
(1)删除#define,展开宏;
(2)处理条件编译指令,预处理程序先判断条件,在根据条件修改源代码;
(3)删除注释;
(4)添加行号,以及文件名标识,便于调试
(5)删除“#include”,插入相应的头文件;
使用g++ -E test.cpp -o test.i命令,预处理后得到test.i文件
生成汇编代码的过程,使用命令g++ -S test.i -o test.s生成汇编文件test.s文件,当然直接从test.cpp文件得到汇编文件也可以。
将汇编代码转化成机器指令,生成目标二进制代码。
使用命令g++ -c test.s -o test.o 生成test.o文件
通过链接库文件,将目标文件转化成可执行文件
使用命令g++ test.o -o test.exe -L 所需库文件路径 其中L为link的缩写
当然,一般情况下,可以直接使用g++ test.cpp -o test 就可以生成可执行程序了,不用上面一步一步操作。
和2.1节一样,编译的4步,可以直接使用g++ test.cpp -o test 就可以生成可执行程序了。
Windows下使用MinGW在命令行编译运行C++程序案例实操
Linux平台开发运行C++程序大体流程与Windows下差别不大
1.准备好第3方库和数据,一些.h文件之类的支持文件,这些文件一般都会放在一起,或者相对位置是固定的;
2.编写.cpp文件,C++代码都在里面;
3.编译文件,生成可执行文件,在Windows中为.exe,Linux下是.out文件或者没有后缀名的文件;
4.运行可执行文件,Linux下通过命令运行可执行文件,./yourprocess 直接用这个执行当前目录下的yourprocess程序;
要想让编好的代码在Linux上运行,我们需要使用GCC
预编译:将hello.c和stdio.h预编译为hello.i
编译:将hello.i编译为hello.s,这是汇编文件。
汇编:将hello.s翻译为机器指令hello.o(.o目标文件)
链接:链接各种需要的库和其他目标文件(该hello程序不需要)得到可执行文件hello.out(相当于windows的.exe)
linux平台编译运行c++程序_linux编译cpp文件案例实操_Menglon的博客-CSDN博客
debug的意思是“排除错误,调试”,release是“释放,释放”;
Debug文件夹:调试–调试完成成功生成可执行程序,失败返回失败数据
Release文件夹:发布版本–发布需要发布的可执行程序
Debug 版本
Debug 是“调试”的意思,Debug 版本就是为调试而生的,编译器在生成 Debug 版本的程序时会加入调试辅助信息,并且很少会进行优化,程序还是“原汁原味”的。
你没听错,不是任何一个程序都可以调试的,程序中必须包含额外的辅助信息才能调试,否则调试器也无从下手。
Release 版本
Release 是“发行”的意思,Release 版本就是最终交给用户的程序,编译器会使尽浑身解数对它进行优化,以提高执行效率,虽然最终的运行结果仍然是我们期望的,但底层的执行流程可能已经改变了。
编译器还会尽量降低 Release 版本的体积,把没用的数据一律剔除,包括调试信息。
最终,Release 版本是一个小巧精悍、非常纯粹、为用户而生的程序。
首先是如雷贯耳的这几位仁兄,MSVC、GCC、Cygwin、MingW(Cygwin和MingW的英文发音),另外还有些小众和新秀,像ICC(Intel C/C++ Compiler)、BCC(Borland C/C++ Compiler,快销声匿迹了)、RVCT(ARM的汇编/C/C++编译器,内置在ARM的IDE——RVDS中)、Pgi编译器……其实有一大串,我们只要熟悉常用的最强大的几款就可以了。
lx必看,这个文档太好了,太好了,捋一捋gcc/g++/MingW/MSVC与make/CMake的关系 - 知乎
比较好用的c++编译器(好用的C++编译器)
GCC/G++,可以认为它们是一样的,在windows和linux系统下都可以用g++进行编译。
在Linux虚拟机上安装gcc/g++_linux安装g++_WW
MinGW(Minimalist GNUfor Windows),它是一个可自由使用和自由发布的Windows特定头文件和使用GNU工具集导入库的集合,允许你在Windows平台生成本地的Windows程序而不需要第三方C运行时(C Runtime)库。
用MinGW的时候实际上也是运行一些g++命令,因为MinGW集成了一下GNU组织的g++工具。
用Clion等软件时也需要配置好MinGW或者MSVC;
运行时库:支持程序运行的基本函数的集合,一般是静态库lib或动态库dll。
而MSVC,就是上文所说的第三方C运行时库:由微软开发的VC运行时库,被Visual Studio IDE所集成。所以我们使用VS时会附带MSVC编译器。
所以可以看到啦,MinGW和MSVC都是Windows C/C++语言编译支持,配置环境时遇到两者择其一即可。
下载安装MinGW-w64详细步骤(c/c++的编译器gcc的windows版,win10真实可用)_jjxcsdn的博客-CSDN博客
有了前文,对LLVM与clang不用解释应该也知道了。
LLVM是构架编译器(compiler)的框架系统,以C++编写而成,用于优化以任意程序语言编写的程序的编译时间(compile-time)、链接时间(link-time)、运行时间(run-time)以及空闲时间(idle-time),对开发者保持开放,并兼容已有脚本。
LLVM计划启动于2000年,最初由美国UIUC大学的Chris Lattner博士主持开展。2006年Chris Lattner加盟Apple Inc.并致力于LLVM在Apple开发体系中的应用。Apple也是LLVM计划的主要资助者。
目前LLVM已经被苹果IOS开发工具、Xilinx Vivado、Facebook、Google等各大公司采用。
有了编译器GCC等等, 为什么要有make这个构建生成器,同样是老生常谈的内容。
编译hello.c非常简单,只需要
$ gcc hello.c
就可以了,但当项目庞大起来后,假设hello.c依赖与a.c、b.c,而a.c又依赖于库w.lib,每一次编译,我们都要重新编写一次gcc编译命令行吗?
所以,GNU发明了make这个工具软件,可以编写makefile文件来指定特定的项目构建过程,当项目一个文件的代码更改时,我们只需要重新make一下就可以了。
make工具可以看成是一个智能的批处理工具,它本身并没有编译和链接的功能。
但make依然有很多不足,比如
make对于类unix系统是通用的,但对windows系统并不友好(不能跨平台),当然windows系统中也可以安装make,但是在windows下创建的makefile无法在linux上用。
make语法简单,也就导致了它功能的限制
不同编译器的语法规则不同,编写的makefile语法如果适合GCC则不适合MSVC
所以,CMake就应运而生啦。
CMake是比Make更高一层的工具,Make是编写对应编译器的makefile从而实现编译,而CMake是写一份独立的CmakeList.txt文件,然后该文件会根据当前系统环境选择适合的构建生成器(如VS或者make),然后将CmakeList.txt翻译为适合的文件,再进一步调用系统编译器进行项目构建。
总结:
(1)make软件的作用只有1个:
解决项目依赖很多第3方库时,g++功能不足的问题,是在g++基础上的一个软件,用于把依赖库给理清楚,然后调用g++工具进行编译,弥补g++的缺陷,实现维护第3方库的功能。
(2)Cmake软件的作用只有1个:
弥补make不能跨平台的缺陷,实现跨平台和维护第3方库的2个功能。
(3)二者区别:
区别1:make软件只能用于linux系统,也有的说可以用于windows,但是不能通用1个makefile文件,Cmake软件可以跨平台使用;
区别2:make软件编写makefile文件实现编译;Cmake编写执行CmakeList.txt实现编译。
lx必看,这个文档太好了,太好了,捋一捋gcc/g++/MingW/MSVC与make/CMake的关系 - 知乎
lx必看, Makefile和Cmake的区别和联系_cmake和makefile区别_这个文档里的Cmake介绍有一个错误,它也支持windows,不仅仅是linux
windows平台下makefile操作教程_windows makefile_帅德布耀德的博客-CSDN博客
从零开始详细介绍CMake_哔哩哔哩_bilibili
【cmake教程】为你的项目引入外部第三方库(以真实项目partio为例)_哔哩哔哩_bilibili
(1)Windows下就用的Mingw或者MSVC,会Cmake;
(2)linux下就用g++,make,Cmake
(1)当我们编译一个程序的时候,用到的是g++编译软件或者Mingw软件,而不是vs、vscode、clion这些软件。
(2)我们编写程序的时候无非是用txt就行,编译软件的时候直接用Mingw软件,这样就可以得到可执行文件了。
(3)vs、vscode、clion的作用就是把记事本(或其它文本编辑器)、编译软件Mingw给集成在一起了,它就是一个集成的工具。在vs、vscode、clion里面可以更换编译软件Mingw或者MSVC。
看上面第4节讲的,它们都是文件,分别用于make软件和Cmake软件处理。
(1)Makefile
Makefile 文件描述了 Linux 系统下 C/C++ 工程的编译规则,它用来自动化编译 C/C++ 项目。一旦写编写好 Makefile 文件,只需要一个 make 命令,整个工程就开始自动编译,不再需要手动执行 GCC 命令。
(2)Cmakelists
CMake通过CMakeLists.txt配置项目的构建系统,配合使用cmake命令行工具生成构建系统并执行编译、测试,相比于手动编写构建系统(如Makefile)要高效许多。对于C/C++项目开发,非常值得学习掌握。
Makefile教程:Makefile文件编写1天入门
CMakeLists教程(实战总结)_开酒不喝车的博客-CSDN博客
CMake应用:CMakeLists.txt完全指南 - 知乎
(1)makefile的写法
[1] 王道训练营的视频课
[2]makefile 完美教程_makefile教程_WittXie的博客-CSDN博客
[3] Makefile基础教程_makefile菜鸟教程-C文档类资源-CSDN文库
(2)Cmakelist的写法;
看第4章的Cmakelist导入第三方库,里面有很多教程。
(3)编程中不同系统不同软件如何引用第3方库进行编程;
1 Windows+记事本:
2 Windows+VS:
3 Windows+vscode:
4 Windows+Clion:
5 Linux+VIM:
6 Linux+Clion:
7 Linux+vscode:
(4)编程中不同系统不同软件如何打包含第3方库的代码生成可执行文件;
GNU是一个开放组织,GCC/G++是它的产品。
GCC就是g++;
首先我们可以将GCC/G++看成一个整体,不存在GCC专门编译C语言,G++专门编译C++语言这种分别,因为编程语言发展至今是非常复杂的,编译器同样也是。我们将两者都看成GCC,GCC支持C、C++和Fortran语言。
而GCC(GNU Compiler Collection,GNU编译器集合),就是GNU运动的代表性成果,它的初衷是为GNU的自由系统开发完整的编译器。
所以,在Linux甚至Windows上各种涉及开发环境配置,源码编译的地方,都离不开gcc和g++。
lx必看,这个文档太好了,太好了,捋一捋gcc/g++/MingW/MSVC与make/CMake的关系 - 知乎
集成工具就是把编码工具、编译工具、debug调试工具等结合在一起的一个软件,不要想的多牛逼。
集成工具在你写代码的时候会给一些提示,方便一些;
编译工具等都可以在集成工具中进行调试。
还可以打断点,进行代码调试。
但是平时使用Visual Studio等软件时并没有接触到编译这个过程,因为VS是高度集成开发环境(IDE、Integrated Development Environment),集成了代码编辑器,编译器,调试器和图像化用户界面,上述所有程序编译和链接过程都用一步build构建带过了。
我们学习编程在集成工具上进行,除了编程语言本身语法特点外,还要了解集成工具的使用,使用集成工具来编辑代码实现特定功能,解决实际问题。
重要的话说3遍:
在编程时不用集成工具也行,只要给个记事本或者vim都可以进行编程的,但是集成工具更方便些!
在编程时不用集成工具也行,只要给个记事本或者vim都可以进行编程的,但是集成工具更方便些!
在编程时不用集成工具也行,只要给个记事本或者vim都可以进行编程的,但是集成工具更方便些!
VS(Visual Studio)工具介绍
(1)编译过程的文件:
.i 高级语言进行编译4步中第1步预处理后得到的文件;
.s 汇编文件test.s,由高级语言编译得到,下一步是通过这个文件汇编成.o机器指令文件;
.o 机器指令文件,也叫目标二进制代码文件;
.out linux系统下的可执行文件,和windows下的.exe文件一样
.exe windows下的可执行文件;
(2)第三方库文件:
.h 头文件:用于声明第3方库类、函数;
makefile文件:用于make软件中编译c++程序源文件;
CmakeLists文件:用于Cmake软件编译c++程序源文件;
windows和linux中的静态库和动态库,具体区别见下面第3章的库文件介绍:
(2.1)Windows中:
.lib: Windows中生成c++的静态库,Windows中生成静态库的工程,编译生成成功后,只产生一个.lib文件。
.dll和.lib: Windows中c++的动态库,Windows中生成动态库的工程,编译成功后,产生一个.lib文件和一个.dll文件。
(2.2)linux中:
.a文件: c++语言在linux系统中的静态库,c++静态库在linux中是以.a(archive)为后缀,作用是在进行链接生成可执行文件时,从静态库文件中拷贝需要的内容到最终的可执行文件中。
.so文件:c++语言在linux系统中的动态库,动态库在linux中是以.so(shared object)为后缀,它并不在链接时将需要的二进制代码都拷贝到可执行文件中,而是拷贝一些重定位和符号表信息,当程序运行时需要的时候再通过符号表从动态库中获取。
(1)编程时:在编辑的时候如何引用第3方库;
(2)编译时:打包编译可执行程序的时候如何用第三方库。
(3)执行时:程序执行时能正常执行。
(1)在记事本上写读取文件并输出的功能,并编译成可执行文件,不用vs、vscode、clion。
(2)在记事本上调用第3方库,opencv写读取图像并改变大小保存的功能,并编译成可执行文件正常运行。
(3)在Clion和VS上或vscode调用第3方库,opencv写读取图像并改变大小保存的功能,并编译成可执行文件正常运行。(熟练软件应用)
(4)在linux系统中实现上面3个同样的功能。
第三方库这个说法,不知道出自哪里,但一般是指开发者,系统/平台提供商之外的第三个参与者提供的程序库。大多数开源软件库在软件系统中都是第三方库。
完全不使用库的开发,在90年代就已经被放弃了,开源运动的兴起使得第三方库成为主力使用库。
C++领域有一些非常特殊的库,比如早期的STLport和当前的Boost,它们就像是语言的事实标准,基本在每个程序中都可以见到他们的身影。
一、引入第三方库就是引入动态库或静态库,引入源码也可以(但是一般不用源码,会把源码编译成动态库或者静态库)
二、使用第3方库可以让我们免去自己造轮子的过程,直接用别人造好的工具,大大提高开发效率和简化开发难度。
三、但第三方库也会导致相当多的问题,主要总是包括:
(1)版本不一致。同一个软件系统中,如果引用了同一个第三方库的两个不同版本,那一定会暗生问题。
(2)编译选项不一致。一般为了减少编译时间,第三方库都会以编译后的.a/.lib形式参与软件编译,第三方库的编译选项与软件系统的编译选项不同,也是会有一些潜在的问题。特别是x86/x64,ansi/utf-8这些选项不同,根本就不能用。
(3)版本管理库变大。在一些大项目中常常会有几个G的版本库,每次clone代价很大。其实很多都是第三方库,不同版本,不同编译选项生成的库引入。
四、第三方库升级问题:
另一方面,如果第三方库升级,就是一个比较复杂的工程,如果不升级,又只能看着第三方库的问题得不到解决。
在Linux上这个问题并不严重,系统级的软件管理工具可以代管大多数的第三方。比如debian系的,可以使用apt得到大多数的开源库,同时如果需要最新版本,也可以通过第三方源来取得。
在交叉编译和window平台上这个问题就非常头痛了。我们需要从几个层次来解决这个问题。
需要有中心化的第三方源代码获取平台,这个平台需要支持按用户/组织+第三方库+版本的形式取得源代码,同时还需要保证及时跟踪来源。这个类似于bintray/github都可以。公司内部可以使用gitlab来搭建。
需要有一个构建脚本平台,存放在不同工具链和平台的情况下,这个脚本可以从源代码中心的源代码,把源代码编译成库。同样可以用github这类工具搭建和管理。
在项目中提供一个配置文件,需要的开源库(只需指定编译脚本,脚本是针对开源库)。这个只需要一个文本文件即可。
在开发者的机器和编译服务器上,下载编译脚本,生成库。源代码、最终结果可以缓存在本机上。可以使用项目原本的构建工具。
(1)第3方库源代码,通过源代码使用,几乎不用这种方式;
(2)第3方静态库;
(3)第3方动态库;
可以自己编译第3方库源代码得到第3方动态库或者第3方静态库,也可以直接下载别人编译好的。一遍第3种方式最为常用。
头文件是包含函数声明,宏定义,类的声明的文件,里面就是一些声明(声明了之后这样你的.cpp文件才能用这些函数、类)。
在linux中一般头文件会在/usr/include中,如果没有可以使用 locate命令查找文件所在位置。
(1)为什么只用在程序头部写上包含的头文件,头文件中并没有实现内容就可以使用声明的函数呢?
因为头文件和库文件相关联,找到头文件就找到了库文件。
库文件是一种目标文件,静态库是可重定位目标文件,动态库是共享目标文件。
我们在实际用的时候用1种就行了,比如opencv库,可以有动态库和静态库,我们用其中一个就行,不要都用。
linux中的库文件一般在/usr/lib、/usr/lib64、/lib、/lib64都包含库文件
(1)库文件分为动态库和静态库:
**静态库:**在链接步骤中,连接器将从库文件取得所需的代码,复制到生成的可执行文件中,这种库称为静态库,其特点是可执行文件中包含了库代码的一份完整拷贝;缺点就是被多次使用就会有多份冗余拷贝。即静态库中的指令都全部被直接包含在最终生成的 EXE 文件中了。在vs中新建生成静态库的工程,编译生成成功后,只产生一个.lib文件。
**动态库:**动态链接库是一个包含可由多个程序同时使用的代码和数据的库,DLL不是可执行文件。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。函数的可执行代码位于一个 DLL 中,该 DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。在vs中新建生成动态库的工程,编译成功后,产生一个.lib文件和一个.dll文件。
(2)那么上述静态库和动态库中的lib有什么区别呢?
静态库中的lib:该LIB包含函数代码本身(即包括函数的索引,也包括实现),在编译时直接将代码加入程序当中
动态库中的lib:该LIB包含了函数所在的DLL文件和文件中函数位置的信息(索引),函数实现代码由运行时加载在进程空间中的DLL提供
总之,lib是编译时用到的,dll是运行时用到的。如果要完成源代码的编译,只需要lib;如果要使动态链接的程序运行起来,只需要dll。
(3)在linux和windows当中,静态库和动态库形式的区别:
lx非常好,非常好:动态库与静态库的区别、在windows及linux环境下的制作及用法_windows linux 动态库
头文件是进行类、函数的声明;
库文件是存放类、函数的代码。
lx非常好非常好,头文件和库文件区别,动态库和静态库的区别,动静态库的生成_头文件和库文件的区别
在解释静态库和动态库之前,需要简单了解一下什么是目标文件。目标文件常常按照特定格式来组织,在linux下,它是ELF格式(Executable Linkable Format,可执行可链接格式),而在windows下是PE(Portable Executable,可移植可执行)。
而通常目标文件有三种形式:
(1)可执行目标文件。即我们通常所认识的,可直接运行的二进制文件。
(2)可重定位目标文件。包含了二进制的代码和数据,可以与其他可重定位目标文件合并,并创建一个可执行目标文件。
(3)共享目标文件。它是一种在加载或者运行时进行链接的特殊可重定位目标文件。
使用readelf -a filename 可以查看目标文件的ELF格式
0最根本的区别是使用到的阶段不同:
在使用静态库时,只需要将静态库文件包含在项目中,并在代码中引用静态库中的函数或变量即可。在编译时,编译器会将静态库文件的代码和数据链接到可执行程序中,生成一个包含静态库代码和数据的可执行程序。在运行时,可执行程序不需要引用静态库文件,因为静态库的代码和数据已经被链接到可执行程序中了。
在使用动态库时,需要将动态库(导入库)文件包含在项目中,并在代码中引用动态库中的函数或变量。在编译时,编译器不会将动态库文件的代码和数据链接到可执行程序中,而是在运行时动态链接动态库文件。
1.可执行文件大小不一样
静态链接的可执行文件要比动态链接的可执行文件大得多,因为它将需要用到的代码从二进制文件中拷贝了一份,而动态链接仅仅是复制了一些重定位和符号表信息。静态库简单,运行速度较快;但是生成的exe文件较大,升级维护不方便。动态库用起来相对麻烦一点,但是模块化容易。
2.占用磁盘大小不一样
如果有多个可执行文件,那么静态库中的同一个函数的代码就会被复制多次,而动态库只有一份,因此使用静态库占用的磁盘空间相对比动态库要大。
3.拓展性与兼容性不一样
如果静态库中某个函数的实现变了,那么可执行文件必须重新编译,而对于动态链接生成的可执行文件,只需要更新动态库本身即可,不需要重新编译可执行文件。正因如此,使用动态库的程序方便升级和部署。
4.依赖不一样
静态连接的可执行文件不需要依赖其他的内容即可运行,而动态链接的可执行文件必须依赖动态库的存在。所以如果你在安装一些软件的时候,提示某个动态库不存在的时候也就不奇怪了。
即便如此,系统中一般存在一些大量公用的库,所以使用动态库并不会有什么问题。
5.复杂性不一样
相对来说,动态库的处理要比静态库要复杂,例如如何在运行时确认地址?多个进程如何共享一个动态库?当然,作为调用者我们不需要关注,另外动态库版本的管理也是一项技术活。这也不在本文的讨论范围。
6.加载速度不一样
由于静态库在链接时就和可执行文件在一块了,而动态库在加载或者运行时才链接,因此,对于同样的程序,静态链接的要比动态链接加载更快。所以选择静态库还是动态库是空间和时间的考量。但是通常来说,牺牲这点性能来换取程序在空间上的节省和部署的灵活性是值得的。再加上局部性原理,牺牲的性能并不多。(局部性原理是指CPU访问存储器时,无论是存取指令还是存取数据,所访问的存储单元都趋于聚集在一个较小的连续区域中。)
lx非常好非常好,头文件和库文件区别,动态库和静态库的区别,动静态库的生成_头文件和库文件的区别
1、 这个问题困扰了自己好久,一开始以为动态库没有.lib文件,实际上动态库也有.lib文件,但是和静态库的.lib文件有区别。在vs2019里面设置的库目录也就是.lib库,在动态库中也叫导入库。实际上我们用的是第3方动态库,这里根本就没有第3方动态库。
2、在Windows中,动态库文件通常包含两个文件,一个是导入库文件(Import Library),扩展名为“.lib”,另一个是动态链接库文件(Dynamic Link Library),扩展名为“.dll”。
导入库文件(.lib)是一个包含符号表的二进制文件,它允许编译器在编译时解析函数和变量的引用。导入库文件中包含了动态链接库中所有导出函数的符号信息,以及函数的入口地址等信息。在编译时,编译器会将导入库文件链接到可执行文件中,以便在运行时加载动态链接库。
动态链接库文件(.dll)是一个包含可执行代码和数据的二进制文件,它可以在运行时被加载到内存中,并且可以被多个进程共享。动态链接库中包含了一组导出函数,这些函数可以被其他程序调用。当一个程序调用动态链接库中的函数时,操作系统会将函数的入口地址解析出来,并将控制权转移到该函数的代码中。
总之,导入库文件(.lib)和动态链接库文件(.dll)是动态库的两个组成部分,它们通常一起使用,以便在编译时和运行时正确地链接和加载动态库。
3、静态库中的lib:该LIB包含函数代码本身(即包括函数的索引,也包括实现),在编译时直接将代码加入程序当中
动态库中的lib:该LIB包含了函数所在的DLL文件和文件中函数位置的信息(索引),函数实现代码由运行时加载在进程空间中的DLL提供
总之,lib是编译时用到的,dll是运行时用到的。如果要完成源代码的编译,只需要lib;如果要使动态链接的程序运行起来,只需要dll。
4、动态库怎么还有.lib文件?即无论是静态链接库还是动态链接库,最后都有lib文件,那么两者区别是什么呢?其实,两个是完全不一样的东西。
静态库中的Library.lib的大小为190KB,动态库中的Library.lib的大小为3KB,静态库对应的lib文件叫静态库,动态库对应的lib文件叫【导入库】。实际上静态库本身就包含了实际执行代码、符号表等等,而对于导入库而言,其实际的执行代码位于动态库中,导入库只包含了地址符号表等,确保程序找到对应函数的一些基本地址信息。
5、在Linux中,动态库文件通常包含一个共享目标文件(Shared Object),扩展名为“.so”。linux中动态库文件只有so,而没有.a。windows中linux不一样,Windows中,动态库文件通常包含两个文件,一个是导入库文件(Import Library),扩展名为“.lib”,另一个是动态链接库文件(Dynamic Link Library),扩展名为“.dll”。
6、我们在vs2019中使用gdal程序时,需要在项目属性中设定库目录。分两种情况,1是如果我们使用的是动态库,这里的库目录也就是.lib导入库的位置,最后还需要把.dll动态库文件放到exe同级目录。2如果是静态库,这里的库目录也就是.lib静态库的位置,最后也不用.dll文件了。
详谈静态库和动态库的区别_动态库和静态库的区别_内核大本营的博客-CSDN博客
一、windows中
(1)静态库:头文件(.h文件)+静态库文件(.lib文件),就这2类文件组成;
(2)动态库:头文件(.h文件)+静态库文件(也叫导入库,.lib文件)+动态库文件(.dll文件),就这3类文件组成;
二、linux中
(1)静态库:头文件(.h文件)+静态库文件(.a文件),就这2类文件组成;
(2)动态库:头文件(.h文件)+动态库文件(.so文件),就这2类文件组成;
静态库对函数库的链接是放在编译时期完成的。
程序在运行时与函数库再无瓜葛,移植方便。
浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。
动态库把对一些库函数的链接载入推迟到程序运行的时期。
可以实现进程之间的资源共享。(因此动态库也称为共享库)
将一些程序升级变得简单。
甚至可以真正做到链接载入完全由程序员在程序代码中控制(显示调用)。
1、lx非常好非常好:如何生成动态库和静态库,lib 和 dll 的区别、生成以及使用详解
2、lx非常好,非常好:动态库与静态库的区别、在windows及linux环境下的制作及用法_windows linux 动态库
静态库在linux中是以.a(archive)为后缀,作用是在进行链接生成可执行文件时,从静态库文件中拷贝需要的内容到最终的可执行文件中。
//在使用gcc编译时采用 -static选项来进行静态文件的链接:
gcc -c main.c
gcc -static -o main main.o
linux系统中静态库的生产:
//1.先写出相应的.h文件和对应的.c文件
//2.编译.c文件
//3.使用ar工具将.o文件归档生成.a静态库文件
[root@localhost linux]# ls
add.c add.h main.c sub.c sub.h
[root@localhost linux]# gcc -c add.c -o add.o
[root@localhost linux]# gcc -c sub.c -o sub.o
生成静态库
[root@localhost linux]# ar -rc libmymath.a add.o sub.o
ar是gnu归档工具,rc表示(replace and create)
查看静态库中的目录列表
[root@localhost linux]# ar -tv libmymath.a
rw-r–r-- 0/0 1240 Sep 15 16:53 2017 add.o
rw-r–r-- 0/0 1240 Sep 15 16:53 2017 sub.o
t:列出静态库中的文件
v:verbose 详细信息
[root@localhost linux]# gcc main.c -L. -lmymath
-L 指定库路径
-l 指定库名
测试目标文件生成后,静态库删掉,程序照样可以运行。
注意:静态库文件和动态库文件的命名规则是libxxxx.a/libxxxx.so,在进行链接时只用lxxxx即可,不用写libxxxx.so。
动态库在linux中是以.so(shared object)为后缀,它并不在链接时将需要的二进制代码都拷贝到可执行文件中,而是拷贝一些重定位和符号表信息,当程序运行时需要的时候再通过符号表从动态库中获取。
//使用gcc编译默认采用动态链接
gcc -o main main.c
除了把编译的库引入项目,也有人以源代码的形式引入开源软件,比如GCC、SDL、WxWights、QT。如果第三方库本身编译不复杂,原代码也很简单,这么做比较好。
但是像Boost.Thread这样的库,就不行了。它需要编译成动态库,静态引用会有问题。
第3方库的引入方式一共有3种:
(1)源码: 在工程中需包含引用工程的源文件(.cpp)和头文件(.h),这种方法会导致工程较为庞大,引用2个东西。
(2)动态库: 只需包含引用工程的dll文件即可,引用工程的头文件和lib库文件可选,通常都会带上。引用3个东西。
(3)静态库: 只需包含引用工程编译生成的lib文件和头文件,工程看起来较为清爽简洁,引用2个东西。
(1)准备数据:对第三方库的源码进行编译成动态库或者静态库(我们可以找到编译好的动态库或静态库,这样避免自己编译出错)。这步是最根本的,无论是在linux中还是在windows中,没有下载好编译好的第3方库就无法使用它们。
(2)配置环境:配置到你的项目中,可以是vs、clion、记事本,为你的项目导入该a文件或者lib文件和头文件。
windows和linux平台C++工程 如何连接第三方依赖库_libopencv_world.so.4.5_于工不移山的博客-CSDN博客
(3)编程:引用头文件,并调用第三方库函数编程:进行编程。
(4)编译:打包成可执行程序:Cmake打包编译,或者g++编译。
(5)运行:运行可执行程序:如果是动态库的话,需要将.dll文件或者.so文件放到.exe或.out的同级目录,静态库的话不用这步。
lx非常好非常好 C++中第三方库的一般使用方式(libxl库为例)
windows下引入第三方库就是引入动态库或者静态库,源码也行,但是一般不用源码。
windows引入第3方库两种方式:一是使用Cmakelist文件组织、类似于maven;二是在vs、clion等软件中直接配置。
windows中使用静态库的方法导入第3方库,就是配置好.h头文件和.lib文件这两个文件。
(1)在vs2019中的项目属性的vc++里,包含目录配置头文件目录,库目录配置.lib目录。
(2)在输入的附加依赖项中配置好要导入的静态文件名。
windows中使用动态库的方法导入第3方库,就是配置好.h头文件和.lib文件和.dll这3个文件。
(1)在vs2019中的项目属性的vc++里,包含目录配置头文件目录,库目录配置.lib目录。
(2)在输入的附加依赖项中配置好要导入的静态文件名(也叫导入库)。
(3)在静态库的基础上再把.dll动态库文件放到.exe同级目录。
首先明确一点,linux下引入第三方库就是引入动态库或者静态库。
(1)linux中使用静态库的方法导入第3方库,就是配置好.h头文件和.a文件这两个文件。
(2)linux中使用动态库的方法导入第3方库,就是配置好.h头文件和.so文件这两个文件,再把.so动态库文件放到程序同级目录。
(3)linux中引入第3方库的两种方式:一是使用makefile文件;二是使用Cmakelist文件组织。
具体案例可以看第4章的描述
案例一:
使用第三方库的方法(假定库名为FOO):
(1)准备数据:编译源码:编译FOO的cpp文件(连同需要的h文件)一起编译为o文件。将o文件打包为a文件或者lib文件。
(2)配置环境:配置到你的项目中,可以是vs、clion、记事本,为你的项目导入该a文件或者lib文件和头文件。
(3)编程:引用头文件,并调用第三方库函数编程:进行编程。
(4)编译:打包成可执行程序:Cmake打包编译,或者g++编译。
(5)运行:运行可执行程序:如果是动态库的话,需要将.dll文件或者.so文件放到.exe或.out的同级目录。
案例二:
lx非常好非常好 C++中第三方库的一般使用方式(libxl库为例)
一种是在程序代码中进行配置(不用)
一种是Cmakelist或者vs等软件按钮中进行配置;
Windows中C++动态库和静态库的使用方法和区别_使用静态库需要头文件吗_QuattroA8的博客-CSDN博客
包管理器就是一个用来管理这些库的!!!你想用谁的库,就用谁的库!!!vcpkg是一个C++的包管理器,各语言的包管理都已经做的很NB,C++才开始起步。
还在手动编译第三方库?vcpkg来帮你解决,完美的C++包管理器!!速速食用!!哔哩哔哩_bilibili
C++第三方库管理工具vcpkg使用教程_令狐掌门的博客-CSDN博客
一共4步:
1 添加头文件目录include
2 添加静态库目录lib库
3 添加附加依赖项,也就是具体的静态库文件
4 将动态库文件放到.exe的同级目录下
但是平时使用Visual Studio等软件时并没有接触到编译这个过程,因为VS是高度集成开发环境(IDE、Integrated Development Environment),集成了代码编辑器,编译器,调试器和图像化用户界面,上述所有程序编译和链接过程都用一步build构建带过了。
[1] lx非常好非常好 如何调用动态库和静态库 lib 和 dll 的区别、生成以及使用详解
[2] lx非常好非常好 C++中第三方库的一般使用方式(libxl库为例)
[3] C++基础-如何引入第三方静态库、动态库或自定义库_c++如何导入第三方库
[4] C++第三方日志库Glog的安装与使用介绍
[1] CLion中使用CMake导入第三方库的方法_clion中引入第三方库的详细方法
下面这个写的很清楚,要先将源码编译成动态库或者静态库再导入
[2] CLion中C++加载静态库和动态库-CSDN博客
[3] lx非常好非常好CMakeLists.txt 语法简明教程CSDN博客
vscode调用第三方库好像要配置json文件。
VScode中使用C++语言调用第三方库的方法 - 知乎
CmakeList.txt是Cmake软件执行的一个文件,通过CmakeList可以直接引入第3方库,添加第3方库主要就是3个命令:
1 是添加.h头文件;
2 是添加库文件;
3 是添加动态库(添加的是动态库的话)
#设置cmake版本
cmake_minimum_required(VERSION 3.22)
#项目名字
project(first)
#设置编译版本
set(CMAKE_CXX_STANDARD 14)
#引入头文件
include_directories(D:\\XiaoMaCode\\CPlusPlusCode\\Third_party_library\\gdal\\include)
#引入库文件
link_directories(D:\\XiaoMaCode\\CPlusPlusCode\\Third_party_library\\gdal\\lib)
#编译文件,这个不知道应该放在最后还是放在这里
add_executable(first main.cpp)
#将第三方库连接在一起
target_link_libraries(first libgdal.a)
target_link_libraries需要放在add_executable之后,用于指明连接进来的库,官方推荐使用这个接口,而不推荐使用link_libraries,link_libraries需要放到add_executable之前。
lx非常好非常好CMakeLists.txt 语法简明教程CSDN博客
CMakeLists.txt的超傻瓜手把手教程(附实例源码)_Yngz_Miao-DevPress官方社区
cmake 添加头文件目录,链接动态、静态库-CSDN博客
从零开始详细介绍CMake_哔哩哔哩_bilibili
CLion中使用CMake导入第三方库的方法_clion中引入第三方库的详细方法
CMake 引入第三方库_cmake添加第三方库_ccsu_zzh的博客-CSDN博客
cmake 引入第三方库(头文件目录、库目录、库文件)_cmakelist 添加第三方库_仲夏夜之梦~的博客-CSDN博客
CMake 引入第三方库_cmake添加第三方库_ccsu_zzh的博客-CSDN博客
# CMakeList.txt: QT_CMake 的 CMake 项目,在此处包括源代码并定义
cmake_minimum_required (VERSION 3.20.1)
project (QT_CMake CXX)
# 添加c++ 17标准支持
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 寻找OpenCV库
set(OpenCV_DIR "D:/vcpkg/vcpkg/packages/opencv4_x64-windows")
find_package(OpenCV REQUIRED)
# GDAL库路径、GDAL_INCLUDE头文件、GDAL_LIBRARY库文件
set(GDAL_DIR "D:/gdal_tool/release-1928-x64-dev/release-1928-x64")
file(GLOB_RECURSE GDAL_LIBRARY "${GDAL_DIR}/lib/*.lib")
file(GLOB_RECURSE GDAL_INCLUDE "${GDAL_DIR}/include/*.h")
# 设置OpenCV与GDAL头文件的目录
include_directories(${OpenCV_INCLUDE_DIRS})
set(GDAL_INCLUDE_DIRS "${GDAL_DIR}/include" "${GDAL_DIR}/include/proj7")
include_directories(${GDAL_INCLUDE_DIRS})
# 将源代码添加到此项目的可执行文件。
add_executable (${PROJECT_NAME} main.cpp ${GDAL_INCLUDE})
# message(STATUS " include path: ${GDAL_INCLUDE}")
# 链接OpenCV与GDAL库
target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS})
target_link_libraries(${PROJECT_NAME} ${GDAL_LIBRARY})
# 拷贝GDAL_DLL到执行项目目录下
file(GLOB_RECURSE GDAL_DLLS "${GDAL_DIR}/bin/*.dll")
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${GDAL_DLLS} $<TARGET_FILE_DIR:${PROJECT_NAME}>)
只需要把上面添加动态库流程的最后一步“拷贝GDAL_DLL到执行项目目录下”,这一步去掉就行了。
和windows下的一样,因为CmakeList就是为了实现跨平台的。
[1] 王道训练营的视频课
[2]makefile 完美教程_makefile教程_WittXie的博客-CSDN博客
[3] Makefile基础教程_makefile菜鸟教程-C文档类资源-CSDN文库
按照下面的流程进行gdal的安装,clion中使用gdal的辛酸历程_gdal clion 配置_jayce_tang的博客-CSDN博客,还是会报错
之后百度发现报这个错是因为确实dll动态链接库:将libgdal.dll文件放到exe同级目录,执行成功。
CLion程序编译错误 0xC0000135_clion编译出现链接问题怎么解决_Cliven_的博客-CSDN博客
参考:
[1] clion中使用gdal的辛酸历程_gdal clion 配置_jayce_tang的博客-CSDN博客
[2] VS2017编译配置GDAL——超详细,适合初学者!!!_vs编译gdal_长安游的博客-CSDN博客
网上的教程一般都是基于VS的,实际上前面的编译无论是VS还是Clion都应该是一样的。
我们自己无法编译,就用别人编译好的文件。
然后在Clion中进行配置。
自己在vs2019上成功执行了下面程序,安装流程是参考的这个博客,里面唯一的错误就是lib库不用配置到环境变量中,而是要把bin目录下的.dll库放到生成的.exe文件的同级目录,非常好!成功了!!!
C++下GDAL的详细使用案例(含项目配置、tif读取为cv::Mat、Mat保存为tif)_c++ gdal_万里鹏程转瞬至的博客-CSDN博客
// 获取栅格信息
#include
#include
#include
#include
using namespace std;
int main() {
//注册所有的驱动
GDALAllRegister();
//设置支持中文路径和文件名
//CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO");
//打开文件
string file_path_name = "E:/data/GF2_PMS2_E113.8_N38.8_20201216_L1A0005315319/GF2_PMS2_E113.8_N38.8_20201216_L1A0005315319-PAN2.tiff";
GDALDataset* poDataset = (GDALDataset*)GDALOpen(file_path_name.c_str(), GA_ReadOnly);
if (poDataset == NULL)
{
cout << "指定的文件不能打开!" << endl;
return 0;
}
// 获取波段信息
GDALRasterBand* poBand = poDataset->GetRasterBand(1);
int nXSize = poDataset->GetRasterXSize();
int nYSize = poDataset->GetRasterYSize();
cout << "width = " << nXSize << endl;
cout << "height = " << nYSize << endl;
// 获取投影参考系
string projection = poDataset->GetProjectionRef();
cout << "Projection = " << projection << endl;
// 获取投影坐标范围
double geoTransform[6];
poDataset->GetGeoTransform(geoTransform);
double minX = geoTransform[0];
double minY = geoTransform[3] + nXSize * geoTransform[4] + nYSize * geoTransform[5];
double maxX = geoTransform[0] + nXSize * geoTransform[1] + nYSize * geoTransform[2];
double maxY = geoTransform[3];
cout.setf(ios::fixed);
cout.precision(8);
cout << "X-axis minimum:" << minX << ",\nY-axis minimum:" << minY << ",\nX-axis maximum:" << maxX << ",\nY-axis maximum:" << maxY << endl;
// 读取数据
int* pafScanline = new int[nXSize];
for (int i = 0; i < nYSize; i++) {
poBand->RasterIO(GF_Read, 0, i, nXSize, 1, pafScanline, nXSize, 1, GDT_Int16, 0, 0);
}
delete[] pafScanline;
//关闭栅格文件
GDALClose(poDataset);
return 0;
}
// 这个文件是读取shp的正确文件,用来验证配好的gdal库能不能用
#include "ogrsf_frmts.h"
#include
using namespace std;
int main()
{
GDALAllRegister();
GDALDataset* poDS;
CPLSetConfigOption("SHAPE_ENCODING", ""); //解决中文乱码问题
//读取shp文件
poDS = (GDALDataset*)GDALOpenEx("E:\\data\\ZhongxianShp\\Zhongxian.shp", GDAL_OF_VECTOR, NULL, NULL, NULL);
if (poDS == NULL)
{
cout << "ok";
return 0;
}
OGRLayer* poLayer;
poLayer = poDS->GetLayer(0); //读取层
OGRFeature* poFeature;
poLayer->ResetReading();
int i = 0;
while ((poFeature = poLayer->GetNextFeature()) != NULL)
{
//if (poFeature->GetFieldAsDouble("AREA") < ) continue; //去掉面积过小的polygon
i = i++;
cout << i << " ";
OGRFeatureDefn* poFDefn = poLayer->GetLayerDefn();
int iField;
int n = poFDefn->GetFieldCount(); //获得字段的数目,不包括前两个字段(FID,Shape);
for (iField = 0; iField < n; iField++)
{
//输出每个字段的值
cout << poFeature->GetFieldAsString(iField) << " ";
}
cout << endl;
OGRFeature::DestroyFeature(poFeature);
}
GDALClose(poDS);
system("pause");
return 0;
}
[1] windows下编译、安装及使用gdal-2.4.2_gdal2.4安装_草丛中的蝈蝈的博客-CSDN博客
[1] GDAL-3.4.0库 C++版编译_编译好的gdal_lufengok的博客-CSDN博客
【1】c++ GDAL读取shapefile文件_gdal 打开shapefile文件_Chaoying.的博客-CSDN博客
【2】(433条消息) 结合C++和GDAL实现shapefile(shp)文件的读取_weixin_33675507的博客-CSDN博客
// 在lx的vs中环境已经运行成功了,代码没问题
#include "ogrsf_frmts.h"
#include
using namespace std;
int main()
{
GDALAllRegister();
GDALDataset* poDS;
CPLSetConfigOption("SHAPE_ENCODING", ""); //解决中文乱码问题
//读取shp文件
poDS = (GDALDataset*)GDALOpenEx("E:\\data\\Zhongxian\\Zhongxian.shp", GDAL_OF_VECTOR, NULL, NULL, NULL);
if (poDS == NULL)
{
cout << "ok";
return 0;
}
OGRLayer* poLayer;
poLayer = poDS->GetLayer(0); //读取层
OGRFeature* poFeature;
poLayer->ResetReading();
int i = 0;
while ((poFeature = poLayer->GetNextFeature()) != NULL)
{
//if (poFeature->GetFieldAsDouble("AREA") < ) continue; //去掉面积过小的polygon
i = i++;
cout << i << " ";
OGRFeatureDefn* poFDefn = poLayer->GetLayerDefn();
int iField;
int n = poFDefn->GetFieldCount(); //获得字段的数目,不包括前两个字段(FID,Shape);
for (iField = 0; iField < n; iField++)
{
//输出每个字段的值
cout << poFeature->GetFieldAsString(iField) << " ";
}
cout << endl;
OGRFeature::DestroyFeature(poFeature);
}
GDALClose(poDS);
system("pause");
return 0;
}
【3】 C++调用GDAL实现栅格数据的读取_c++ 调用gdal_三千思丶的博客-CSDN博客
【4】GDAL C++开发总结(一)获取影像任一点坐标,对该点坐标进行坐标转换,如投影坐标转换为地理坐标,UTM转WGS84_c++ gdalallregister
// 在lx的vs环境中已经运行成功,代码没问题
#include
#include
#include
#include
using namespace std;
int main() {
//注册所有的驱动
GDALAllRegister();
//设置支持中文路径和文件名
//CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO");
//打开文件
string file_path_name = "E:/data/GF2_PMS2_E113.8_N38.8_20201216_L1A0005315319/GF2_PMS2_E113.8_N38.8_20201216_L1A0005315319-PAN2.tiff";
GDALDataset* poDataset = (GDALDataset*)GDALOpen(file_path_name.c_str(), GA_ReadOnly);
if (poDataset == NULL)
{
cout << "指定的文件不能打开!" << endl;
return 0;
}
// 获取波段信息
GDALRasterBand* poBand = poDataset->GetRasterBand(1);
int nXSize = poDataset->GetRasterXSize();
int nYSize = poDataset->GetRasterYSize();
cout << "width = " << nXSize << endl;
cout << "height = " << nYSize << endl;
// 获取投影参考系
string projection = poDataset->GetProjectionRef();
cout << "Projection = " << projection << endl;
// 获取投影坐标范围
double geoTransform[6];
poDataset->GetGeoTransform(geoTransform);
double minX = geoTransform[0];
double minY = geoTransform[3] + nXSize * geoTransform[4] + nYSize * geoTransform[5];
double maxX = geoTransform[0] + nXSize * geoTransform[1] + nYSize * geoTransform[2];
double maxY = geoTransform[3];
cout.setf(ios::fixed);
cout.precision(8);
cout << "X-axis minimum:" << minX << ",\nY-axis minimum:" << minY << ",\nX-axis maximum:" << maxX << ",\nY-axis maximum:" << maxY << endl;
// 读取数据
int* pafScanline = new int[nXSize];
for (int i = 0; i < nYSize; i++) {
poBand->RasterIO(GF_Read, 0, i, nXSize, 1, pafScanline, nXSize, 1, GDT_Int16, 0, 0);
}
delete[] pafScanline;
//关闭栅格文件
GDALClose(poDataset);
return 0;
}
安装opencv库无非就是直接用现有程序,或者用别人打包好的包。
参考这个文档,太简单了,所有版本都有:
2022 新版本c++安装opencv库的简单操作教程_行路难1895的博客-CSDN博客
1、主要参考下面两个文档实现:
opencv安装与配置vs2019_opencv vs2019_平杨猪的博客-CSDN博客
VS2019 OpenCV安装与配置教程_vs2019安装opencv_XHR-想象之中的博客-CSDN博客
2、上面安装的opencv包没有xfeature2d.hpp模块,这是opencv的一个扩展库,在使用SOUR算法的时候需要用到这个扩展库,扩展库的安装见下面链接:
OpenCV 没有xfeatures2d解决方法_opencv_安静55668-DevPress官方社区
3、根据上面的步骤来看比较麻烦,第2步缺少opencv_xfeatures2d453.lib等文件,在运行surf算法的时候怎么都跑不通,之后找到了下面的这个编译好的库。opencv库包含两个库,一个是opencv库,另一个是opencv_contrib库,相当于是基础opencv的拓展库。
opencv453+vs2019编译的动态库资源-CSDN文库
安装所有包都一样,就3步:
1、找到第3方库的包;
2、vs里配置头文件目录和静态库文件目录;
3、将动态库.dll放到可执行程序.exe的同级目录或者环境变量中。
// 测试opencv库是否可以正常使用的代码
#include
#include
using namespace std;
using namespace cv;
int maincecv(int argc, char** argv)
{
//VideoCapture cap(0);
VideoCapture cap("D:/resoure/表彰大会.mp4");
if (!cap.isOpened())
{
printf("Can not open a camera\n");
return -1;
}
while (true)
{
Mat frame;
cap >> frame;
if (frame.empty())
break;
imshow("frame", frame);
// 非均值滤波
Mat robot = (Mat_ <int>(2, 2) << 1, 0, 0, -1);
Mat result;
filter2D(frame, result, CV_32F, robot, Point(-1, -1), 127, BORDER_DEFAULT);
convertScaleAbs(result, result);
imshow("robot filter", result);
//等待 30 秒,如果按键则推出循环
if (waitKey(30) >= 0)
break;
}
waitKey(0);
return 0;
}
C++ 安装eigen -简单- 成功
两步:下载和导入
注意:无论是windows还是linux,主要专注的就3个东西,头文件、静态库、动态库。其中静态库有时候需要有时候不需要,还没有理清楚。只要下载好这3个文件夹,编译时候g++直接指定就行了。
vs2019不用g++指定,本质是你项目属性那里指定了,也是指定了;
linux中g++ -I 和-L来指定。
在C++中,可以使用main函数的参数来接收外部输入参数。具体来说,main函数可以有两个参数:argc和argv。
argc表示参数的数量,它是一个整数类型的变量。argv是一个指向字符指针数组的指针,它存储了每个参数的值。第一个参数是程序的名称,从argv[1]开始是传递给程序的实际参数。
(1)程序:
#include
using namespace std;
int main(int argc, char *argv[]) {
cout << "The program name is: " << argv[0] << endl;
cout << "The number of arguments is: " << argc << endl;
for(int i = 1; i < argc; i++) {
cout << "Argument " << i << " is: " << argv[i] << endl;
}
return 0;
}
(2)输出:
The program name is: ./test
The number of arguments is: 4
Argument 1 is: arg1
Argument 2 is: arg2
Argument 3 is: arg3
设置了LD_LIBRARY_PATH环境变量,编译和执行的时候程序用到第3方库,会自动到环境变量里去找。
1输出环境变量:echo $LD_LIBRARY_PATH
2设置环境变量:export LD_LIBRARY_PATH=/path/to/gdal/lib:$LD_LIBRARY_PATH
3将动态库复制到系统默认动态库环境变量中:sudo cp /path/to/gdal/lib/libgdal.so.* /usr/lib/
4防止编译时找不到动态库,可以在编译时指定动态库位置:编译程序时使用-Wl,-rpath选项来指定运行时库文件的搜索路径。g++ -o your_program your_program.cpp -I/path/to/gdal/include -Wl,-rpath,/path/to/gdal/lib -L/path/to/gdal/lib -lgdal
5查看可执行程序依赖的库文件列表,ldd命令会递归地查找所有依赖的库文件,并显示它们的路径和版本信息。ldd your_program
/usr/lib/
是Linux系统中的一个目录,用于存储共享库文件(也称为动态链接库文件)。共享库文件是一种可重用的代码库,可以在多个程序之间共享,从而减少系统资源的占用和程序的占用空间。
在Linux系统中,共享库文件通常以.so
为扩展名,例如libgdal.so
。这些文件通常存储在/usr/lib/
目录中,因为这是系统默认的共享库文件路径之一。当程序需要使用共享库文件时,系统会在默认的共享库文件路径中搜索相应的文件。
请注意,/usr/lib/
目录通常只允许管理员用户写入,因此如果您需要将共享库文件复制到该目录中,您需要具有管理员权限。
1 g++ -o executable_name source_file.cpp // 编译普通文件
2 g++ -o your_program your_program.cpp -lgdal // 编译带gdal包的文件,默认从环境变量找头文件和库文件。
3 g++ -o your_program your_program.cpp -I/path/to/gdal/include -L/path/to/gdal/lib -lgdal // -I选项用于指定头文件路径,不涉及库文件,-L选项用于指定库文件所在的目录,-l选项用于指定库文件名。-lgdal指令会去找libgdal.a或者libgdal.so,-L和-l不管是动态库还是静态库都一样。-l选项后面跟的是库文件的名称,不需要包含文件扩展名。
4 g++ -o your_program your_program.cpp -I/path/to/gdal/include -Wl,-rpath,/path/to/gdal/lib -L/path/to/gdal/lib -lgdal // 防止运行时找不到动态库文件,编译程序时使用-Wl,-rpath选项来指定运行时库文件的搜索路径。
(1)-L和-l选项用于指定库文件路径和库文件名,可以用于链接静态库和动态库。-I选项用于指定头文件路径,不涉及库文件。
静态库和动态库都可以使用-L和-l选项进行链接。-L选项用于指定库文件所在的目录,-l选项用于指定库文件名。例如,假设我们有一个名为libfoo.a的静态库文件和一个名为libbar.so的动态库文件,我们可以使用以下命令进行链接:
静态库链接:g++ main.cpp -L/path/to/lib -lfoo
动态库链接:g++ main.cpp -L/path/to/lib -lbar
其中,-L/path/to/lib指定了库文件所在的目录,-lfoo和-lbar分别指定了静态库文件和动态库文件的名称。需要注意的是,静态库文件的名称通常以.a结尾,而动态库文件的名称通常以.so结尾。
(2) g++ -o your_program your_program.cpp -std=c++11 -I/path/to/gdal/include -L/path/to/gdal/lib -lgdal,这里的-lgdal指向的是动态库还是静态库?
-lgdal指向的是GDAL库的动态库文件,因为在Linux系统中,动态库文件的命名规则是lib*.so,而静态库文件的命名规则是lib*.a。因此,如果-lgdal指向的是静态库文件,应该是-lgdal.a,而不是-lgdal。
需要注意的是,如果同时存在静态库和动态库文件,-lgdal默认会链接动态库文件。
(1)windows版本:
在windows版本中编译gdal动态库,会产生.lib文件,但是这个实际上和真正编译的静态库的.lib文件不一样,编译动态库产生的.lib文件是导入库。
(2)linux版本:
在编译动态库时,通常也会同时生成静态库文件(.a文件)。这是因为静态库和动态库虽然使用方式不同,但它们的源代码和编译过程是相同的,因此在编译过程中同时生成静态库和动态库是很常见的做法。这里产生的.a文件就是真正的静态库文件,但是使用动态库的时候时候不会用到.a静态库文件。
如果您只需要使用动态库,可以忽略静态库文件。如果您需要使用静态库,可以将静态库文件链接到您的应用程序中。在使用静态库时,需要在编译和链接时指定静态库文件名,否则默认加载的是动态库文件,例如:
g++ -o myapp myapp.cpp -L/path/to/lib -lgdal_static
// 其中,-L选项指定静态库文件所在的路径,-lgdal_static指定要链接的静态库文件名。
//需要注意的是,如果您的动态库和静态库同时存在,且它们的文件名相同,那么在链接时需要使用不同的选项来指定使用动态库还是静态库。
//例如,使用动态库时需要使用-lgdal,而使用静态库时需要使用-lgdal_static。
// 在Linux中,导入第三方库时需要使用export命令来设置环境变量,以便让系统能够找到库文件。具体命令如下:
export LD_LIBRARY_PATH=/path/to/library:$LD_LIBRARY_PATH
其中,/path/to/library是第三方库文件所在的路径,$LD_LIBRARY_PATH是系统默认的库文件搜索路径。通过将/path/to/library添加到LD_LIBRARY_PATH环境变量中,系统就能够在搜索库文件时找到第三方库。
需要注意的是,LD_LIBRARY_PATH环境变量只在当前终端窗口中生效,如果需要在其他终端窗口或者系统启动时自动设置LD_LIBRARY_PATH环境变量,可以将上述命令添加到.bashrc文件中。例如:
echo 'export LD_LIBRARY_PATH=/path/to/library:$LD_LIBRARY_PATH' >> ~/.bashrc
// linux2GdalReadShp.cpp
#include
#include
int main(int argc, char* argv[]) {
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " name " << std::endl;
return 1;
}
std::cout << " hello: " << argv[1] << std::endl;
return 0;
}
编译并测试执行成功了
g++ -o executable_name source_file.cpp
// 这个函数验证读取shp文件是否可行
#include "ogrsf_frmts.h"
#include
using namespace std;
int main(int argc, char* argv[])
{
GDALAllRegister();
GDALDataset* poDS;
const char* gdal_version = GDALVersionInfo("RELEASE_NAME");
std::cout << "GDAL version: " << gdal_version << std::endl;
CPLSetConfigOption("SHAPE_ENCODING", ""); //解决中文乱码问题
//读取shp文件
poDS = (GDALDataset*)GDALOpenEx(argv[1], GDAL_OF_VECTOR, NULL, NULL, NULL);
if (poDS == NULL)
{
cout << "ok";
return 0;
}
OGRLayer* poLayer;
poLayer = poDS->GetLayer(0); //读取层
OGRFeature* poFeature;
poLayer->ResetReading();
int i = 0;
while ((poFeature = poLayer->GetNextFeature()) != NULL)
{
//if (poFeature->GetFieldAsDouble("AREA") < ) continue; //去掉面积过小的polygon
i = i++;
cout << i << " ";
OGRFeatureDefn* poFDefn = poLayer->GetLayerDefn();
int iField;
int n = poFDefn->GetFieldCount(); //获得字段的数目,不包括前两个字段(FID,Shape);
for (iField = 0; iField < n; iField++)
{
//输出每个字段的值
cout << poFeature->GetFieldAsString(iField) << " ";
}
cout << endl;
OGRFeature::DestroyFeature(poFeature);
}
GDALClose(poDS);
system("pause");
return 0;
}
g++ -o your_program your_program.cpp -std=c++11 -I/path/to/gdal/include -L/path/to/gdal/lib -lgdal
// -o可以放了后面
g++ your_program.cpp -std=c++11 -I/path/to/gdal/include -L/path/to/gdal/lib -lgdal -o your_program
// 实战中在linux中执行成功的
,gdal库的头文件和库文件已经放到了下面两个文件夹中了,-std=c++11可以没有:
g++ linux2GdalReadShp.cpp -std=c++11 -I/usr/local/include -L/usr/local/lib -lgdal -o linux2GdalReadShp
#include
#include
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
// 输出OpenCV版本
cout << "OpenCV version : " << CV_VERSION << endl;
cout << "Usage: " << argv[0] << " " << endl;
// 检查命令行参数
if (argc != 2)
{
cout << "argc is wrong!!!" << endl;
return -1;
}
// 读取图像
Mat image = imread(argv[1], IMREAD_COLOR);
//Mat image = imread("E:/data/1putongImageMatch/shanghai2GaoQing.png", IMREAD_COLOR);
// 判断图像是否读取成功
if (image.empty())
{
cout << "Could not open or find the image" << endl;
return -1;
}
else
{
cout << "read the image succeed!!!" << endl;
}
// 转换为灰度图像
Mat gray_image;
cvtColor(image, gray_image, COLOR_BGR2GRAY);
// 保存灰度图像
string output_path = "./gray.jpg";
imwrite(output_path, gray_image);
return 0;
}
// 使用下面的命令成功编译运行
g++ linux3OpencvSaveImage.cpp -I/usr/local/opencv3.0/include -I/usr/local/opencv3.0/include/opencv2.0 -L/usr/local/opencv3.0/lib -lopencv_core -lopencv_imgcodecs -lopencv_imgproc -lopencv_highgui -o linux3OpencvSaveImage
// linux4readimg.cpp
#include "linux4readimg.h"
Mat imageread(string imgpath) {
Mat image = imread(imgpath, IMREAD_COLOR);
cout <<"width and height:" <<image.cols << " " << image.rows<<endl;
return image;
}
// linux4readimg.h
#pragma once
#include
using namespace cv;
using namespace std;
Mat imageread(string imgpath);
// linux4OpencvImg.cpp
// 测试4,使用两个文件
#include
#include
#include
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
// 输出OpenCV版本
cout << "OpenCV version : " << CV_VERSION << endl;
cout << "Usage: " << argv[0] << " " << endl;
// 检查命令行参数
if (argc != 2)
{
cout << "argc is wrong!!!" << endl;
return -1;
}
Mat image = imageread(argv[1]);
//Mat image = imageread("E:/data/1putongImageMatch/shanghai2GaoQing.png");
// 判断图像是否读取成功
if (image.empty())
{
cout << "Could not open or find the image" << endl;
return -1;
}
else
{
cout << "read the image succeed!!!" << endl;
}
return 0;
}
// 使用下面的命令成功编译运行,项目共3个文件,2个.cpp,1个.h
g++ linux4OpencvImg.cpp linux4readimg.cpp -I/usr/local/opencv3.0/include -I/usr/local/opencv3.0/include/opencv2.0 -L/usr/local/opencv3.0/lib -lopencv_core -lopencv_imgcodecs -lopencv_imgproc -lopencv_highgui -o linux4OpencvImg
// main.cpp和helper.cpp是源文件的名称,helper.h会被自动包含进去,不用再特殊指明位置了
// 使用opencv3版本的库成功执行
/usr/local/gcc-8.3.0/bin/g++ -o linux5TemplateMatch -std=c++11 linux5TemplateMatch.cpp GDALread.cpp GCPTransformer.cpp TemplateMatch.cpp -I/usr/local/opencv3.0/include -I/usr/local/opencv3.0/include/opencv2.0 -I/usr/local/include -L/usr/local/opencv3.0/lib -lopencv_core -lopencv_imgcodecs -lopencv_imgproc -lopencv_highgui -L/usr/local/lib -lgdal -Wl,-rpath=/usr/local/opencv3.0/lib
注意:多个版本的库可能存在冲突
// 当linux系统中有多个库的时候,/usr/local/lib下面有opencv2.0版本的库的时候,如果把-L/usr/local/lib放在-L/usr/local/opencv3.0/lib前面,会导致库的依赖2.0版本的库和3.0版本的库混乱,执行出错,所以顺序很重要
// opencv2是一个文件夹,在opencv3.0版本和opencv2.0版本中都存在,opencv2和opencv2.0不一样。
// 下面的编译可能会成功,也可能失败,即使编译成功,执行也会错误。
/usr/local/gcc-8.3.0/bin/g++ -o linux5TemplateMatch -std=c++11 linux5TemplateMatch.cpp GDALread.cpp GCPTransformer.cpp TemplateMatch.cpp ......
这将使用GCC编译器,并使用“-fopenmp”选项启用OpenMP支持。
运行可执行文件,应该看到代码块被多个线程并行执行,从而加速了程序的执行。
请注意,OpenMP的效果取决于代码的结构和计算负载。在某些情况下,使用OpenMP可能会导致性能下降,因此您需要进行测试和优化以获得最佳性能。
虽然OpenMP不是C++自带的,但许多C++编译器都支持OpenMP,并且可以使用OpenMP来加速C++程序的执行。例如,GCC、Clang和Microsoft Visual C++等编译器都支持OpenMP。
gcc -fopenmp your_code.c -o your_executable
g++ -o myprogram myprogram.cpp
// 自己的程序使用了下面的编译命令,但是运行时候报错segmentation fault(core dumped)
// 内存超了,所以需要减少内存,在命令中使用了减少进程的设置export OMP_NUM_THREADS=4 # 设置线程数为4,或者也可以在代码中进行设置omp_set_num_threads(4);确实成倍加快了速度
// 线程数最好不要超过cpu核数
/usr/local/gcc-8.3.0/bin/g++ -fopenmp -o linux6TemplateMatchMP -std=c++11 linux6TemplateMatchMP.cpp GDALread.cpp GCPTransformer.cpp TemplateMatch.cpp ......
(1)理清c++程序执行流程:5步:准备好编程所需文件、搭好环境、编程、编译、执行
(2)理清编译软件有哪些:
(3)理清编译流程分为哪4步:
(4)理清什么是动态库和静态库:
(5)理清在一个项目中如何使用第三方库,在c++程序执行的4步中都需要考虑第3方库:准备编程所需文件时要考虑第三方库是源码还是编译好的文件(是源码还需要先将第3方库进行编译),搭建环境的时候需要配置好第三方库,编程时引用第三方库头文件并使用第3方库函数,编译时考虑怎么打包,执行时考虑用不用第三方库的动态库的.dll文件。
(6)理清引入第3方库(导包):就是引入动态库或静态库,也可以是源码,这3种方式选择一种就行,但是一般不用直接用第三方库的源码,拿到了第3方库的源码也会先编程成动态库或静态库。
(7)windows中使用静态库的方法导入第3方库,就是配置好.h头文件和.lib文件这两个文件。
(8)windows中使用动态库的方法导入第3方库,就是配置好头文件和.lib文件和.dll这3个文件,在静态库的基础上再把.dll动态库文件放到.exe同级目录(debug和release模式下exe在不同文件夹)。
(9)linux中使用静态库的方法导入第3方库,就是配置好.h头文件和.a文件这两个文件。
(10)linux中使用动态库的方法导入第3方库,就是配置好.h头文件和.a文件这两个文件,在静态库的基础上再把.so动态库文件放到.out同级目录。
(11)windows和linux使用源码的方式导入第3方库,直接放到项目目录下就行,一般不用源码,而是提前把源码编译成动态库或者静态库的方式,再使用动态库或者静态库的方法导入第三方库。
(12)windows和linux导入第3方库都一样:就是导入动态库或静态库;
(13)windows引入第3方库两种方式:一是使用Cmakelist文件组织、类似于maven;二是在vs、clion等软件中直接配置。
(14)linux中引入第3方库的两种方式:一是使用makefile文件;二是使用Cmakelist文件组织。
(15)windows下,动态库文件中的.lib和静态库文件中的.lib是不一样的。
(16)理清在不同集成软件中如何使用第三方库: