学习Opencv(蝴蝶书/C++)相关——2.用clang++或g++命令行编译程序

本文介绍了如何使用Clang和GCC命令行编译C++程序,特别是涉及OpenCV库的项目。详细阐述了cpp程序的编译过程,包括预处理、编译、汇编和链接。在macOS环境下,通过Clang查看cpp程序的编译过程,并讲解了手动链接OpenCV库的方法。同时讨论了动态链接库和静态链接库的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

非常建议去看一下B站这个课程:基于VSCode和CMake实现C/C++开发 | Linux篇
就是讲在不使用Visual Studio这种IDE的情况下,纯靠g++/gcc这样的命令行去逐步执行cpp程序的编译,链接,执行等操作。

另外,也可以看一下这篇文章,都有助于理解用编译器的命令行去执行cpp程序:
MacOS使用clang

1. c/cpp程序的执行

1.1 cpp程序的编译过程

这里复习一下本科的知识,

  1. 编译程序把高级语言写的源程序(source program,比如:.cpp后缀)转换为机器指令的目标程序(object program,比如:.o后缀)
  2. 编译时是以源程序文件(即.c或者.cpp)为对象进行的,分别对每个源程序文件进行编译得到相应的目标程序,再将这些目标程序链接成为一个统一的二进制的可执行程序。
  3. 预处理指令和C++语句分开处理,前者由预处理器(或者也常称为预编译器)对预处理指令(#开头的,比如宏定义和include)进行预处理,详见 1.2 预处理指令
  4. 把预处理得到的结果和程序剩下的部分一起,组成一个完整的,可以用来编译的最终的源程序,编译程序对该源程序正式进行编译,得到目标程序。
  5. 不同的编译系统除了会提供C/CPP规定的标准库函数外,有些编译系统还会提供自己的专门的函数/库函数。

C/CPP的编译过程:

图自:什么是动态链接与静态链接?
在这里插入图片描述

  1. 编译自动包括预编译和正式编译两个阶段,编译得到本源文件的目标文件(Windows下一般是.obj的后缀,UNIX下一般是.o的后缀)。
  2. 再通过链接把所有需要的目标文件链接在一起,就得到了最后的可执行程序(Executive program,Windows下一般是.exe的后缀,UNIX下一般没有后缀)
    • 即便程序只有一个源程序文件(一个X.cpp),编译后得到的目标函数也不能直接运行,也需要经过连接阶段,因为要与库函数链接,才能生成可执行程序。

参考:

1.2 预处理指令

  • #include<iostream>这句话并不是C++语句,而是C++的一个预处理指令,以#开头与常规的C++语句相区别,行的末尾没有分号。
  • #include<iostream>是个包含指令,将iostream文件的内容包含到该命令所在的程序文件中,代替该指令。
  • 由于这类指令都放在程序开头,因此称为"头文件"(header file)
  • 编译时,先对所有的预处理命令进行处理,将头文件的具体内容替换#include指令,然后再对该程序单元进行整体编译。

1.3 编译过程的细节

这个属于编译原理的内容了,可以看看 Alfred V. Aho,Monica S.Lam的编译原理,这里大概放个图:
在这里插入图片描述
代码的编译过程可以分为预处理,词法分析,语法分析,语义分析,目标代码,链接,生成可执行程序。

2. macOS下使用Clang看cpp程序的编译过程

2.1 示例

如果想看gcc的,可以看 【本质】你知道C语言编译的过程吗?这篇文章。

以下内容,大部分出自:MacOS使用clang

编译用的clang_demo.cpp 源码

#include <iostream>
#define STR "Hello world"

int main(int argc, const char * argv[]) {
   
   
    std::string a = STR;
    std::cout << a << std::endl;
    return 0;
}

查看编译步骤:
(由于是cpp语言,因此用clang++,就好像gcc命令是c语言,g++就是cpp一样)

> clang++ -ccc-print-phases clang_demo.cpp
0: input, "clang_demo.cpp", c++
1: preprocessor, {
   
   0}, c++-cpp-output
2: compiler, {
   
   1}, ir
3: backend, {
   
   2}, assembler
4: assembler, {
   
   3}, object
5: linker, {
   
   4}, image
6: bind-arch, "x86_64", {
   
   5}, image

可以看到,分为6步:

0.输入c++源码程序
1.预处理器,0是输入,输出是把`#`等包含指令解开后的cpp代码
2.编译器, 1是输入, 输出是中间代码IR(intermediate representation)
3.后端,   2是输入,输出是汇编代码
4.汇编器, 3是输入, 输出是目标文件(机器码,01二进制)
5.链接器, 4是输入,输出是image
6.bind-arch处理架构相关的内容

但是一般我们只会看到四步:预处理,编译,汇编和链接。

  1. 预处理,生成完整的cpp源文件
  2. 编译,cpp→生成汇编代码
  3. 汇编,汇编代码→机器码(0101)
  4. 链接,生成可执行文件

命令的解释详见2.2.1 常见使用部分,官方文档每个步骤生成文件的意义解释见:clang - the Clang C, C++, and Objective-C compiler

每一步的结果具体如下:

2.1.1 第一步 预处理器-preprocessor

#包含指令的内容,和源文件其他C++语句组合成一个完整的源文件。

clang++ -E clang_demo.cpp -o clang_demo.i

运行上述指令后会得到一个clang_demo.i,打开拉到最下面,就能看到之前写的该文件中的C++语句部分,另外两个#语句,一个包含iostream库,另一个是定义了一个宏。
在这里插入图片描述
可以看到,宏的部分已经进行了替换。
在这里插入图片描述
另外,#include<iostream>文件里,由于iostream又include别的库,因此一层一层去包括,导致整个包含进来非常长。

这样就形成了完整的一个源文件。

2.1.2 第二步 编译器-compiler

从输入的cpp源文件,生成对应的汇编语言程序

clang++ -S clang_demo.cpp -o clang_demo.s

在这里插入图片描述
很明显,这里输出的已经是汇编代码了。

复习一下汇编,下面的书比较老了
在这里插入图片描述
可能稍微新一点的:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吨吨不打野

解决了问题,觉得还行就给点

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值