linux下编写C/C++代码须知———串讲

一、C/C++的编辑编译与链接

  1. 敲代码的过程就是编辑过程,在编辑完成程序后需要经过编译和链接两个步骤才可以把程序变成我们所需要的可执行程序。
  2. 编译过程(包括预处理、编译,汇编(test.s到test.o)三个过程)最终在linux系统上生成.o文件,在windows系统上生成.obj文件。这个过程会将.cpp文件中包含的头文件添加到.cpp文件中,意思大概就是用头文件里面的具体内容替代include这句话,但是不需要具体的实现内容。
    • 形如:include<>,是在系统指定目录中查找头文件,在linux系统中指定的默认目录包括:usr/include;usr/local/include;/usr/aarch64-linux-gnu/include
    • 形如:include””,是在引号里面的目录中查找头文件,如果寻找不到的话在去默认目录中查询。
    • 该过程的实现:例如有三个文件,main.cpp,test1.cpp,test1.hpp在同一个文件夹下,具体内容如下:
main.cpp
#include"test1.hpp"
int main()
{
    test1print();
    return -1;
}

test1.hpp
#include<stdio.h>
void test1print(void);

test1.cpp
#include"test1.hpp"
void test1print()
{
    printf("this is a test\n");
}
上面三个文档位于同一个文件夹下面,则使用g++的编译方式为:
g++  -c main.cpp
g++  -c test1.cpp

上面看似没有用到test1.hpp,如果把test1.hpp去除,则编译部分无法完成,而去除test1.cpp对main的编译没有没有影响。按照上面所说,也可以把test1.hpp移动到系统默认文件中。
3. 链接就是把目标文件、目标文件所需要的库文件,其他目标代码(指所依赖的其他.o文件—可以是编译中生成的,不是源文件)等进行组织,生成可执行文件的过程,在linux系统上生成没有后缀的可执行文件,在windows系统中生成.exe文件。
* 该过程的实现:在2中生成了main.o和test1.o两个目标文件,这里需要进行链接,按照定义,就是主要的目标文件(mian.o)和其他目标文件(test1.o)进行链接,如果main.o用到的库的文件,这里也会自动链接到库中。
* 使用g++的链接方式为:

g++ main.o test1.o -o main

或者是

g++ -o main main.o test1.o

注意:.o后面跟着的是生成的文件名称。


二、静态库和动态库

前面说过链接的过程需要使用到库,这里的库其实就是函数库,linux系统下的静态函数库的后缀是.a,动态库是.so。静态库和动态库的区别是:
* 静态库由一系列的.o文件组成,在链接过程中,这些.o文件与主要的目标文件一起生成目标文件,生成之后就不需要这些.o文件了;
* 动态库在链接过程中并没有用到具体函数使用,它是在程序的运行过程中才动态的调用。正如windows系统中,我们看到需要的.exe文件夹中,包含了各式各样的.dll文件(windows下的动态库),当然所需要的.dll文件也有一部分在系统的默认路径下。


三、g++的几个常用命令

  1. 编译过程的预处理、编译、汇编的步骤也可以通过g++的命令实现,但是基本无用。
  2. 编译和链接的两个命令如一中所使用
  3. g++也可以直接生成可执行程序,一中的编译链接可以通过如下命令一步完成:
    g++ main.cpp test1.cpp -o main
  4. 也会常常遇到头文件和库文件不在指定目录和当前目录下的情况:这种情况可以通过以下命令指定所需要的目录路径来实现:

    g++ main.cpp -o main -I <path to opencv header files> -L <path to opencv libraries> -l<name of libraries>

    -I表示include,main.cpp包含的头文件地址,-L表示lib库表示所需要的库的地址,-l(小写的L)表示lib,为具体的-L下路径中的所需要的库的名称。


四、项目必备的makefile文件

  1. 在三中,如果工程项目包含了太多的头文件和库,会导致g++编译链接命令写的很长,如果各种依赖关系十分复杂,则g++命令会显得十分繁琐。因此需要使用一种方式,把这些命令组织起来。当程序想要编译和链接的时候,只需要一步操作就可以完成。
  2. 实现这种方式的工具是cmake工具,cmake是一个跨平台的工具,可以编写Cmakelist.txt文件完成上述操作,Cmakelists.txt也是一个跨平台的文件。在不同的平台下使用 cmake命令,会将Cmakelists.txt生成一个不同的文件,而makefile就是在linux系统下生成的文件。生成的makefile文件需要执行make命令完成程序的编译与链接。在linux系统中可以直接编写makefile文件。
  3. 简单的makefile的书写

    1. 仍然以前面的main.cpp,test1.cpp,test1.hpp为例。编写的makefile文件如下:

    example1:

    object:main.o test1.o
        g++ main.o test1.o -o test1
    command1:
        g++ -c test1.cpp
    command2:
        g++ -c main.cpp

    另外一种更加常用的写法是:
    example2:

    test1:main.o test1.o
        g++ main.o test1.o -o test1
    test1.o:
        g++ -c test1.cpp
    main.o:
        g++ -c main.cpp

    先大致浏览一下上面的makefile文件,可以看出,makefile的规则格式是:
    makefile文件的核心规则
    这个就是makefile文件的核心规则,makefile文件就是多种这样的命令格式的组合.对照example1.example2可以看出,这个makefile文件其实就是之前编译链接的步骤,只不过这个需要符合一定的格式。
    这里需要生成的目标其实只是一个名称而已,可以任意取,但是不知道为什么我所看到的很多程序都是按照example2的方式书写,可能是感觉更加规范吧。还有一种很常见的是在生成.o文件的命令中,添加.h的依赖项,例如:

    test1.o:test1.hpp
        g++ -c test1.cpp

    其实这个也是没有必要的,因为在test1.cpp中会根据自己的include自动添加.hpp文件。

  4. 简单的makefile如何运行
    a. 在终端中输入make命令,会自动搜索当前路径下的makefile或者是Makefile文件。
    b.开始执行第一行的命令,根据第一行命令需要找到所要依赖的main.o和test1.o文件,如果搜索路径(当前路径和默认路径)中不存在main.o,test1.o或者是main.c与test1.cpp有修改,则开始执行后面的命令,生成所需要的.o文件,反之,不执行后面的语句,直接执行该命令。
    c.按照example2中的makefile的书写,执行make命令后,可以看到程序执行了后面的命令,最后执行开始的命令。
    这里写图片描述
    d.在具体要执行的命令行之前加上@符号命令可以不在终端中显示。
    e.可以通过在makefile文件中添加一些指令,达到与在终端中运行命令相同的效果,这个被称之为伪指令。在makefile中用来清理产生的文件。
    example3:

    test1:main.o test1.o
        g++ main.o test1.o -o test1
    test1.o:
        g++ -c test1.cpp
    main.o:
        g++ -c main.cpp
    .PHONY : clean
    clean:
        rm main.o test1.o test1

    在终端中输入 make clean就可以清理产生的main.o ,test1.o和test1文件,与在终端中输入
    rm main.o test1.o test1有一样的效果。

  5. makefile的简化操作
    a.字符变量的使用
    example4:

    obj=main.o test1.o
    test1:$(obj)
        g++ $(obj) -o test1
    test1.o:
        g++ -c test1.cpp
    main.o:
        g++ -c main.cpp
    .PHONY : clean
    clean:
        rm $(obj) test1    

    由例子可以知道:可以=号给多个变量赋值到一个字符变量中,然后通过$(字符变量)的方式代替多个变量。
    ATTENTION:除此之外:还有?=, :=, +=等赋值符号
    ?=表示如果字符变量已经赋值过了,则不在进行赋值
    +=表示追加赋值
    这里有一篇文章介绍:=和=的区别:

    http://www.cnblogs.com/wanqieddy/archive/2011/09/21/2184257.html

    b.使用自动推导简化makefile文件
    在例子中,当第一行命令确定需要使用main.o和test1.o文件时,可以自动推导出g++ -c命令,不需要自己在写。例如:
    example5:

    obj=main.o test1.o
    
    test1:$(obj)
        g++ $(obj) -o test1
    test1.o:
    main.o:
    
    .PHONY : clean
    clean:
        rm $(obj) test1

    进一步简化
    example6:

    obj=main.o test1.o
    
    test1:$(obj)
        g++ $(obj) -o test1
    test1.o:main.o:
    
    .PHONY : clean
    clean:
    rm $(obj) test1

    把变量添加进去,进一步简化
    example7:

    obj=main.o test1.o
    test1:$(obj)
        g++ $(obj) -o test1
    $(obj):
    .PHONY : clean
    clean:
        rm $(obj) test1

coding地址:https://git.coding.net/DavidZh666/linux_C_C_plus.git

猜你喜欢

转载自blog.csdn.net/weixin_40100431/article/details/80435708