首页 > 其他分享 >g++编译过程学习笔记

g++编译过程学习笔记

时间:2024-06-03 21:31:05浏览次数:25  
标签:文件 ++ 笔记 编译 cpp main hello

g++编译过程学习笔记

学习用例

使用很简单的多文件编译项目,进行编译过程的学习,主要文件构成如下:

.
├── include
│   └── hello.h
└── src
    ├── hello.cpp
    └── main.cpp

其中hello.h声明了一个可以输出Hello World!的函数并在hello.cpp中完成实现。main.cpp中调用hello.cpp,运行时输出相应的内容。

  • hello.h
#ifndef HELLO_H_
#define HELLO_H_
    void SayHello();
#endif
  • hello.cpp
#include "hello.h"
#include<iostream>
void SayHello(){
    std::cout<<"Hello World!"<<std::endl;
}
  • main.cpp
#include"hello.h"
int main(){
    SayHello();
    return 0;
}

g++命令及参数介绍

  • -g 编译生成带调试信息的可执行文件
g++ -g main.cpp
  • -O[n] 优化源代码
# -O0 不做优化
# -O1 默认优化
# -O2 除了完成-O1的优化之外,还进行一些额外的调整工作,如指令调整等。
# -O3 则包括循环展开和其他一些与处理特性相关的优化工作。 
# 选项将使编译的速度比使用 -O 时慢, 但通常产生的代码执行速度会更快
g++ -O2 main.cpp
  • -L和**-l** 指定库文件路径
# -L 后为库文件路径,可以是绝对路径也可以是相对路径
# -l 后紧跟库名,即libmytest.a 掐头(lib)去尾(.a)剩下的名字
g++ -L ../lib/ -lmytest main.cpp
  • -I 指定头文件搜索路径
g++ -I ../include/ main.cpp
  • -o 指定输出文件名
g++ main.cpp -o main

编译过程

大多数时候,作为初学者的我们使用IDE或者各种扩展工具来完成cpp文件的编译,此过程中我们习惯性地忽略编译过程。但是,想要学习使用CMake构建大型项目时,如果能够熟悉编译过程,那么就能够很快的学会编写CMakeLists.txt文件。
  这篇学习笔记参考了很多优秀的教程和说明,如有兴趣可以参考相关教程1相关教程2相关教程3

预处理过程(Pre-Proccessing)

预处理阶段:主要完成对包含的头文件和宏定义以及注释等的处理工作,头文件的包含和宏定义其实大多采用直接替换的策略实现的。
  在src文件夹下使用以下命令可以实现对源文件的预处理操作,指定生成.ii文件:

g++ -E hello.cpp -I ../include -o hello.ii
g++ -E main.cpp -I ../include -o main.ii

可以通过查看.ii文件,了解预处理过程产生的结果。比如,这里展示一下main.ii文件内容如下:

# 1 "main.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "main.cpp"
# 1 "../include/hello.h" 1


    void SayHello();
# 2 "main.cpp" 2
int main(){
    SayHello();
    return 0;
}

编译过程(Compiling)

编译阶段:主要进行语法错误的检查,如果检查无误,则将代码翻译成汇编语言。
  在src文件夹下使用以下命令执行编译过程,指定生成.s文件:

g++ -S hello.ii -o hello.s
g++ -S main.ii -o main.s

这一过程将生成汇编代码,不同的机器可能生成的汇编代码有所不同,这里展示一下main.s的文件内容如下:

	.file	"main.cpp"
	.text
	.globl	main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	endbr64
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	call	_Z8SayHellov@PLT
	movl	$0, %eax
	popq	%rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0"
	.section	.note.GNU-stack,"",@progbits
	.section	.note.gnu.property,"a"
	.align 8
	.long	 1f - 0f
	.long	 4f - 1f
	.long	 5
0:
	.string	 "GNU"
1:
	.align 8
	.long	 0xc0000002
	.long	 3f - 2f
2:
	.long	 0x3
3:
	.align 8
4:

汇编过程(Assembling)

汇编阶段:主要是将汇编代码生成机器可执行的目标代码,即二进制码,可以发现编辑器已经不能识别和查看二进制文件了。
  在src文件夹下使用以下命令执行汇编过程,最后将生成.o文件:

g++ -c hello.s -o hello.o
g++ -c main.s -o main.o

链接过程(Linking)

链接阶段:主要将各个.o文件进行链接生成可执行文件,核心工作是解决各个模块之间相互引用的问题。linux系统中生成的可执行文默认为a.out;windows系统中生成的可执行文件后缀为.exe;可以使用-o参数来指定生成的可执行文件名称。
  在src文件下使用以下命令生成可执行文件:

g++ main.o hello.o -o main

运行可执行文件

运行可执行文件,查看是否正确完成源文件到可执行文件的编译过程:

./main

程序正常运行,并打印了Hello world!,如下图所示:

静态编译和动态编译

编译cpp文件的过程又分为静态编译和动态编译两种。
  静态编译是将所有的模块都编译进可执行文件中,当启动可执行文件时,所有的模块都已经具备了,因此具有加载速度快,执行速度快的特点,但是程序体积也会更大,一旦静态库需要更新,程序就需要重新编译,多个程序使用时都需要单独加载,比较浪费内存。
  动态编译是将应用程序所需要的模块都编译成动态链接库,当程序启动时,并不会加载所有的模块,只有用到某个模块时才动态的加载使用的模块,多个程序可以使用同一个加载到内容中的动态库,因此Linux中动态库也称为共享库。

静态库和动态库

静态库

Linux中的静态库由程序ar将.o文件打包生成,目标文件以lib为前缀,以.a作为文件后缀,中间的库名称可以自定义。比如:libhello.a
  生成的静态库需要连同相应的头文件发布给使用者,以链接到可执行文件中。

生成并使用静态库
  • 第一步:生成.o文件
    在src文件夹下使用以下命令由hello.cpp生成.o文件:
g++ -c hello.cpp -I ../include/
  • 第二步:打包成静态库
    在src文件夹下使用以下命令将生成的.o文件打包成名为libhello.a静态库文件:
ar crsv libhello.a hello.o

其中c参数不管是否存在,都创建一个库;r参数表示如果模块名已存在则替换;s参数表示创建目标文件索引;v参数表示输出详细信息。

  • 第三步:使用静态库编译源文件
    在src文件夹下使用以下命令编译main.cpp,并指定输出名为static_main的可执行文件:
g++ main.cpp -I ../include/ -L ./ -lhello -o static_main
  • 执行生成的可执行文件
    在src文件夹下执行可执行文件static_main,以验证是否正常编译。
./static_main 

程序正常执行,并输出Hello World!

动态库

Linux中的动态库的目标文件以lib为前缀,以.so作为文件后缀,中间的库名称可以自定义。比如:libhello.so
  动态库中的函数和变量地址使用的是相对地址(静态库中使用的是绝对地址),其真实地址只有在应用程序加载动态库时才形成。

生成并使用动态库
  • 第一步:生成.o文件
    在src文件夹下使用以下命令由hello.cpp生成.o文件,这里使用了一个新的参数-fPIC,作用是告知编译器生成的二进制.o文件采用相对地址:
g++ -c hello.cpp -I ../include/ -fPIC
  • 第二步:打包称动态库
    在src文件夹下使用以下命令将生成的.o文件打包成名为libhello.so的动态库文件:
g++ -shared hello.o -o libhello.so
  • 第三步:使用动态库编译源文件
    在src文件夹下使用以下命令编译main.cpp,并指定输出名为shared_main的可执行文件:
g++ main.cpp -I ../include/ -L ./ -lhello -o shared_main
  • 执行生成的可执行文件
    在src文件夹下使用以下命令执行shared_main文件,以验证是否正常编译,动态编译形成的可执行文件如果使用了不再系统路径中的动态库则需要指定动态库的路径:
LD_LIBRARY_PATH=./ ./shared_main 

程序正常执行,并输出Hello World!

标签:文件,++,笔记,编译,cpp,main,hello
From: https://blog.csdn.net/qq_33596792/article/details/139382593

相关文章

  • JAVA学习笔记6
    学习目标:精通JAVA学习内容:1.方法调用packagecn.itcast.day04.demo02;/*publicclassDemo01Method{publicstaticvoidmain(String[]args){for(intj=1;j<5;j++){for(inti=1;i<20;i++){System.out.print(“*”);}System.out.println();}}}......
  • TensorRT c++部署onnx模型
    在了解一些概念之前一直看不懂上交22年开源的TRTModule.cpp和.hpp,好在交爷写的足够模块化,可以配好环境开箱即用,移植很简单。最近稍微了解了神经网络的一些概念,又看了TensorRT的一些api,遂试着部署一下自己在MNIST手写数字数据集上训练的一个LeNet模型,识别率大概有98.9%,实现用pytor......
  • COD读书笔记
    计算机组成与设计课程复习与CSAPP中类似的部分做了忽略或者简化性能的度量知识回顾对于某个计算机X,定义性能和执行时间的关系表达式:\[\text{性能}_X=\frac{1}{\text{执行时间}_X}\]描述时钟周期和时钟频率的关系:\[\text{时钟周期}=\frac{1}{\text{时钟频率}}\]对......
  • C++命名空间(详解)
    C++基础语法C++基于C语言的改进:c++在C语言的基础上引入并扩充了面向对象的概念C++基础概念:C++是基于C语言而产生的,它即可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行面向对象的程序设计在1998年出现C++98C++成熟他是标......
  • 概率论笔记(上)
    学习视频如下:主要学习视频:《概率论与数理统计》教学视频全集(宋浩)_哔哩哔哩_bilibili其余知识点补充: 二维连续型随机变量的积分计算_哔哩哔哩_bilibili 014二维连续型随机变量_哔哩哔哩_bilibili 矩估计&最大似然估计通俗易懂版解释(自用)_哔哩哔哩_bilibili ......
  • C/C++多文件目录编译
    本人的项目目录如下:-helloworld -header helloworld.h -src helloworld.cpp main.cpp -bin a.exe在编译g++src/main.cppsrc/helloworld.cpp-obin/a.exe时控制台error:fatalerror:header/helloworld.h:Nosuchfileordirectory,源文件是这样#include"he......
  • c++——vector
    c++——vectorvector的介绍vector的简介迭代器的作用vector的迭代器失效问题可能导致vector迭代器失效的操作vector的模拟实现完整代码vector.hTest.h代码测试结果vector的介绍vector的文档介绍vector的简介vector是表示可变大小数组的序列容器。vector采用的连......
  • [C++] 小游戏 斗破苍穹 2.2.1至2.11.5所有版本(下) zty出品
    2.10.6#include<stdio.h>#include<iostream>#include<ctime>#include<bits/stdc++.h>#include<time.h>#include<windows.h>//SLEEP函数usingnamespacestd;intboss1=0,boss2=0;structPlayer{//玩家结构体,并初始化playercharname[21......
  • 编程奇境:C++之旅,从新手村到ACM/OI算法竞赛大门(武器:排序算法)
    引言现在你已经拥有了c++的基础语法知识,人物已经有了基本属性,那么想要打怪,手里必须要有趁手的武器,各种算法就是手中的武器,要根据怪物的不同特性来选择不同的武器。本章节讲的就是新手第一把武器:排序算法。所谓排序算法就是把一些乱序的序列按照从小到大或从大到小进行排序,是......
  • C++:priority_queue的模拟实现 | 仿函数
    ✨✨✨学习的道路很枯燥,希望我们能并肩走下来!文章目录文章目录前言一priority_queue的介绍二priority_queue的使用三 priority_queue的初步模拟实现四仿函数  4.1什么是仿函数4.2常见仿函数 ​编辑 4.3常见仿函数的模拟实现4.3.1less 4.3.2 gre......