C/C++编译总结 (Linux下g++、makefile、automake)

C/C++编译总结 (Linux下g++、makefile、automake)

!! 阅读前提示:
1)本文是自己的学习过程和经验的总结,和大多数人一样,不懂就搜度娘、csdn、博客园等等,内容难免有不足之处和理解不到位的情况,请见谅。所有知识来源于网络,摘录内容会指明出处。
2)本文默认读者对基本名词已经清楚,如编译,c++,linux等。
3)本文更新于2022/11/5,未完待续,持续更新。

g++ 是C++语言的编译器;makefile 自动化编译工具;automake,自动生成makefile的工具。
makefile是自动化编译项目工程的工具,必须先明白编译过程

一、 C/C++的编译过程(理论过程)

总共四个阶段:预处理、编译、汇编、链接
【文章推荐:】

【C++程序编译过程_WhiteTian的博客-CSDN博客_c++编译https://blog.csdn.net/u011718663/article/details/118163962】(这位大佬写的非常详细)

二、 Linux下的C/C++编译

1. Linux下的C/C+ +编译器

在linux下编译C/C++程序,用到的编译器:

  • C语言用gcc编译
  • C++用g++编译器

【编译器的介绍:】

【gcc与g++的区别_ericwzy2012的博客-CSDN博客_g++和gcc的区别https://blog.csdn.net/wuzheyan2008/article/details/119715526】

【自己搜吧,我也没看见好的介绍,反正也不是历史学家,能用就行】

2. 编译目标(可执行程序、动态库、静态库)

编译是 源文件->目标文件 的过程,目标文件有以下几种:

文件类型 说明
*.i 预编译后的文件,见4编译选项的1)
*.s 编译后的文件,内容为汇编代码,见4编译选项的2)
*.o 目标文件,内容为二进制,见4编译选项的3)
*.d 依赖文件,内容为源文件的依赖关系。
*.elf 可执行二进制文件,一般得到的可执行文件没有写后缀名
*.a 静态库文件,windows下后缀名为*.lib
*.so 动态库文件,windows下后缀名*.dll

3. Linux下的编译命令

命令: g++ [编译选项]
例如:

g++ main.cpp –o main

4. 编译选项

编译选项决定了编译什么,怎么编译,编到出什么结果。下面开始介绍
!!注意:编译选项区分大小写,例如1)的 –E选项

g++ -E mian.cpp	//仅预处理,生成main.i文件
g++ -e main.cpp	//因为g++编译器没有-e选项,因此此条语句
//等价于g++ main.cpp ,直接生成a.out文件(a.out是g++的默认的可执行文件名称)

!!以下所有出现文件名的地方都可以相对路径或绝对路径。

【编译目标相关选项】

0)什么也不写,直接g++要编译的文件,得到a.out的可执行二进制文件。

g++ main.cpp	//g++采用默认参数,直接生成a.out文件
  1. -E:仅预处理,生成xxx.i文件,即使main.cpp有语法错误也能通过。
g++ -E mian.cpp	仅预处理,生成main.i文件
  1. -S:进行到编译,生成xxx.s文件,文件内容是所在机器的汇编代码。
g++ -S mian.cpp	将源文件进行到编译,得到main.s文件
  1. -c:进行到汇编,生成xxx.o文件。
g++ -c mian.cpp	将源文件进行到汇编,得到main.o文件
  1. -o:将结果输出到文件。
g++ -o main mian.cpp	编译mian.cpp,得到可执行文件main
  1. -M:列出源文件用到的所有头文件,包括系统头文件和自定义头文件,并生成文件依赖关系。(此条在后面makefile中有巨大作用)
g++ -M main.cpp
//执行上面这条语句,将得到
main.o: main.cpp /usr/include/stdc-predef.h /usr/include/c++/11/iostream \
 /usr/include/x86_64-linux-gnu/c++/11/bits/c++config.h \
 /usr/include/x86_64-linux-gnu/c++/11/bits/os_defines.h \
 /usr/include/features.h /usr/include/features-time64.h \
 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
 /usr/include/x86_64-linux-gnu/bits/timesize.h \
 /usr/include/x86_64-linux-gnu/sys/cdefs.h \
 /usr/include/x86_64-linux-gnu/bits/long-double.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
 /usr/include/x86_64-linux-gnu/c++/11/bits/cpu_defines.h \
 /usr/include/c++/11/pstl/pstl_config.h /usr/include/c++/11/ostream \
 /usr/include/c++/11/ios /usr/include/c++/11/iosfwd \
 /usr/include/c++/11/bits/stringfwd.h \
 /usr/include/c++/11/bits/memoryfwd.h /usr/include/c++/11/bits/postypes.h \
 /usr/include/c++/11/cwchar /usr/include/wchar.h \
 /usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
 /usr/include/x86_64-linux-gnu/bits/floatn.h \
 /usr/include/x86_64-linux-gnu/bits/floatn-common.h \
 /usr/lib/gcc/x86_64-linux-gnu/11/include/stddef.h \
 /usr/lib/gcc/x86_64-linux-gnu/11/include/stdarg.h \
 /usr/include/x86_64-linux-gnu/bits/wchar.h \
 /usr/include/x86_64-linux-gnu/bits/types/wint_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/mbstate_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/__FILE.h \
 /usr/include/x86_64-linux-gnu/bits/types/FILE.h \
 /usr/include/x86_64-linux-gnu/bits/types/locale_t.h \

这个结果非常长,上面只列举了一部分。这就是所谓的依赖关系,依赖关系一般写为

xxx.o : xxx.cpp xxx.h xxx1.h xxx2.h …

意思是生成xxx.o文件需要后面这些文件(依赖关系是makefile工具不可或缺的一部分)。

-MM:作用同上,但是-M选项列举的太全面了,如果只希望列举出自己写的文件,

g++ -MM main.cpp
//就会得到
main.o: main.cpp

!与-M选项相关的,还有-MF,-MD,-MG,-MMD,-MT等等选项,讲解看这篇文章吧 【Linux Makefile 生成 *.d依赖文件及 gcc -M -MF -MP等相关选项说明_EtcFly的博客-CSDN博客https://blog.csdn.net/u014170207/article/details/88208520】

【编译参数相关选项】
6) -L:用于指定库路径
-l:用于指定库文件,例如:

g++ main.cpp –lXX –L./lib/	
//意思为,编译main.cpp需要用到库XX,库XX在main这个目录下的lib文件夹里,文件的名字是libXX.a或者libXX.so

补充:如果依赖的库是系统库,则不需要-L选项
TODO:库文件的搜索顺序

  1. -I:指定头文件位置
g++ main.cpp  –I../include	编译main需要用到../include文件夹下的文件
  1. -W:打印警告信息
    -w:关闭警告信息

【文章推荐:】(这位作者总结的很全) 【【GCC】gcc警告选项汇总–编辑中|gcc编译选项_bandaoyu的博客-CSDN博客https://blog.csdn.net/bandaoyu/article/details/115419255】

  1. -g:允许gcc产生带调试信息的可执行文件test

  2. -O数字:此选项为优化代码,建议选择-O2

-O 效果同-O1
-O0 不做优化
-O1 默认优化
-O2 在-O1基础上,进行一些额外调整,如指令调整
-O3 包含循环展开和其他优化工作
  1. –std:指定编译标准
g++ -std=c++11 main.cpp	以c++11标准编译main
  1. –D:加入编译宏,-D宏的名称
g++ -DLINUX –DDEBUG main.cpp	编译main时,加入LINUX或者DEBUG两个宏

5. 静态库的编译

问题:
什么是静态库,什么是动态库?
【】

Linux下静态库有统一名称格式:lib***.a,***就是库的真正名字

编译过程:
1)将所有源文件编译成目标文件(*.o)

g++ -c 源文件

2)打包所有目标文件。

ar crv libXXX.a *.o

【文章推荐:】

【linux编译生成动态库、静态库,以及使用_锅锅是锅锅的博客-CSDN博客_linux
编译动态库https://blog.csdn.net/u010835747/article/details/119151003】

【Linux —— 动态库和静态库_霄沫凡的博客-CSDN博客_linux
动态库https://blog.csdn.net/sjsjnsjnn/article/details/125836184】

6. 动态库的编译

Linux下动态库有统一名称格式:lib***.so,***就是库的真正名字
(2023.3.9更新,动态库的名字有命名规则(http://t.csdn.cn/WLj6Y)),我编译时ld死活找不到动态库,明明-L已经指定了路径,最后发现,文件夹内只有libXXX.so.0.0.0,而编译器只认libXXX.so)

编译过程:

gcc -fPIC -shared xxx.o -o libxxx.so
gcc -fPIC -shared xxx1.o xxx2.o xxx3.o -o libxxx.so

13)编译选项 -fPIC:生成位置无关代码

三、 makefile的使用

C/C++编译总结 (Linux下g++、makefile、automake)Makefile笔记

makefile的学习笔记搞完了,另开了一篇文章,主要是因为本文是用makedown写的,makefile笔记用了普通文档格式,懒得再去改一遍了。

四、automake的使用

automake最近用不到,有需要的看这篇吧,这位博主讲的很详细
linux下automake用法

参考资料:

1、跟我一起写makefile 陈皓

你可能感兴趣的:(c++,c语言,linux,ubuntu)