Makefile——Linux下C/C++编译方法

这篇具有很好参考价值的文章主要介绍了Makefile——Linux下C/C++编译方法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. C

linux下常见的C语言项目相关的文件如下图所示。
linux怎么编译c++文件,c++,linux,makefile

1.1 编译C

通常使用GCC来编译C文件。编译过程为源文件.c文件 -> 预编译成.i文件 -> 编译成汇编语言.s -> 汇编成.o文件 -> 链接成可执行文件。编译命令为gcc -参数 .c -o 输出文件名称

  1. 预处理:将头文件拷贝进.c文件内容中,执行预编译命令。采用gcc -E命令
gcc -E [.c源文件] -o [输出文件名.i]
  1. 编译成汇编:将c语言代码编译为对应的汇编指令。采用gcc -S命令
gcc -S [.c源文件] -o [输出文件名.s]
  1. 编译成目标文件:二进制文件
gcc -c [.c源文件] [.c源文件] [...] -o [文件名]
  1. 编译成可执行文件:
gcc [.c源文件] [.c源文件] [...] -o [输出文件名]
gcc [.c源文件] [.c源文件] [...] -o [输出文件名] -l[库名] -L[库所在路径]

1.2 创建静态库

程序库是已写好的、供使用的可复用代码,每个程序都要依赖很多基础的底层库。从本质上,库是一种可执行代码的二进制形式。静态库可以在编译c项目时,将引用的库一起链接到可执行文件中,可执行文件在运行时不再需要库的支持,但可执行文件会变大。

  1. 将库的.c源文件编译成.o目标文件
gcc -c [.c] -o [自定义文件名] 
gcc -c [.c] [.c] ...
  1. 将.o目标文件编译成静态库
ar -r [lib自定义库名.a] [.o] [.o] ...
  1. 将C程序和静态库链接,编译成可执行文件。库名为lib***.a的***。
gcc [.c] -o [输出文件名] -l[库名] -L[库所在路径]

1.3 创建动态库

动态库在程序编译时不会链接到目标代码中,而是在程序运行时才被调用,可执行文件比静态链接的可执行文件要小。不同的程序可以共享相同的动态库。

  1. 将库的.c源文件编译成.o目标文件(要加入-fpic选项)
gcc -c -fpic [.c/.cpp][.c/.cpp]... 
  1. 将.o目标文件编译成动态库
gcc -shared [.o][.o]... -o [lib自定义库名.so]

#将1和2合并为一步
gcc -fpic -shared [.c源文件] [.c源文件] [...] -o lib[库名].so
  1. 将C程序和动态库链接,编译成可执行文件。库名为lib***.so的***。
gcc [.c/.cpp] -o [自定义可执行文件名]  -l[库名] -L[库路径] -Wl,-rpath=[库路径]

2. C++

编译C++的流程与编译C几乎一致,只不过用的时g++命令。将上述编译.c的gcc改为g++即可编译cpp文件。静态库与动态库同理。

3. Makefile

makefile是自动化编译的一款工具。实际中C/C++工程项目可能十分庞大,直接用手一条一条的敲gcc/g++效率极低。在makefile文件中编写编译流程可以简化编译工作。

  • make 会在当前目录下找到一个名字叫 Makefile 或 makefile 的文件
  • 如果找到,它会找文件中第一个目标文件(target),并把这个文件作为最终的目标文件
  • 如果 target 文件不存在,或是 target 文件依赖的 .o 文件(prerequities)的文件修改时间要比 target 这个文件新,就会执行后面所定义的命令 command 来生成 target 这个文件
  • 如果 target 依赖的 .o 文件(prerequisties)也存在,make 会在当前文件中找到 target 为 .o 文件的依赖性,如果找到,再根据那个规则生成 .o 文件
#makefile格式
targets : prerequisties
[tab键]command

targets为生成的目标文件;
prerequisties为为了生成targets目标而所需的依赖目标文件;
conmmand为需要运行的命令

为了避免 target 和 Makefile 同级目录下 文件/文件夹 重名的这种情况,我们可以使用一个特殊的标记 .PHONY 来显式地指明一个目标是 “伪目标”,如下例中的clean

.PHONY : clean

3.1 变量

  1. 变量定义用:=
cpp := src/main.cpp 
obj := objs/main.o
  1. 使用变量()或{}
cpp := src/main.cpp 
obj := objs/main.o

$(obj) : ${cpp} #cpp中的字符串代表的依赖文件,obj为生成的目标文件
	@g++ -c $(cpp) -o $(obj)  
	#等价于g++ -c src/main.cpp -o objs/main.o
compile : $(obj) #compile为伪目标,可执行make compile命令
  1. 预定义变量:
    $@: 目标(target)的完整名称
    $<: 第一个依赖文件(prerequisties)的名称
    $^: 所有的依赖文件(prerequisties),以空格分开,不包含重复的依赖文件
cpp := src/main.cpp 
obj := objs/main.o

$(obj) : ${cpp}
	@g++ -c $< -o $@
	#等价于g++ -c src/main.cpp -o objs/main.o
	@echo $^
	#执行shell命令echo,打印出cpp的内容

compile : $(obj)
.PHONY : compile
  1. 特殊符号:\为续行符,*通配符(匹配任意字符串,可用与目录名和文件名中),%通配符(匹配任意字符串,并将匹配到的字符串作为变量使用)

3.2 常用函数

函数执行格式通常为$(fn, arguments) or ${fn, arguments}

  1. shell:调用shell命令,返回shell命令执行结果,使用格式为
    $(shell <command> <arguments>)
# shell 指令,src 文件夹下找到 .cpp 文件
cpp_srcs := $(shell find src -name "*.cpp") 
# shell 指令, 获取计算机架构
HOST_ARCH := $(shell uname -m)
  1. subst:把字串 <text> 中的 <from> 字符串替换成 <to>,使用格式为
    $(subst <from>,<to>,<text>)
cpp_srcs := $(shell find src -name "*.cpp")
cpp_objs := $(subst src/,objs/,$(cpp_objs)) 
  1. patsubst:从 text 中取出 patttern(其中%为通配符), 替换成 replacement,使用格式为 $(patsubst <pattern>,<replacement>,<text>)
cpp_srcs := $(shell find src -name "*.cpp") #shell指令,src文件夹下找到.cpp文件
cpp_objs := $(patsubst %.cpp,%.o,$(cpp_srcs)) #cpp_srcs变量下cpp文件替换成 .o文件
  1. foreach:把字串<list>中的元素逐一取出来,执行<text>包含的表达式,使用格式为 $(foreach <var>,<list>,<text>)
library_paths := /lib \
                 /usr/local/lib64
#每一个元素前面加上-I
I_flag := $(foreach item,$(library_paths),-I$(item))
#等价于
I_flag := $(include_paths:%=-I%)
  1. dir:从文件路径+文件名字符串序列中取出目录部分,使用格式为
    $(dir <names…>)
$(dir src/foo.c hacks)    # 返回值是“src/ ./”。
  1. notdir:与dir函数相反,去除目录部分,只保留文件名
#嵌套使用,先用shell中的find命令寻找lib开头的文件,然后去掉这些文件的目录前缀
libs   := $(notdir $(shell find /usr/lib -name lib*))
  1. filter:从字符串序列中,过滤出满足条件的
libs    := $(notdir $(shell find /usr/lib -name lib*))
a_libs  := $(filter %.a,$(libs)) #过滤出静态库
so_libs := $(filter %.so,$(libs))  #过滤出动态库
  1. basename:去掉文件名后缀
libs    := $(notdir $(shell find /usr/lib -name lib*))
#去掉后缀和lib前缀,得到库名
a_libs  := $(subst lib,,$(basename $(filter %.a,$(libs))))
so_libs := $(subst lib,,$(basename $(filter %.so,$(libs))))
  1. filter-out:去除不要的字符串
objs := objs/add.o objs/minus.o objs/main.o
cpp_objs := $(filter-out objs/main.o, $(objs))

3.3 makefile编译文件

编译选项:
-m64: 指定编译为 64 位应用程序
-std=: 指定编译标准,例如:-std=c++11、-std=c++14
-g: 包含调试信息
-w: 不显示警告
-O: 优化等级,通常使用:-O3
-I: 加在头文件路径前
fPIC: (Position-Independent Code), 产生的没有绝对地址,全部使用相对地址,代码可以被加载到内存的任意位置,且可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的

链接选项:
-l: 加在库名前面
-L: 加在库路径前面
-Wl,<选项>: 将逗号分隔的 <选项> 传递给链接器
-rpath=: “运行” 的时候,去找的目录。运行的时候,要找 .so 文件,会从这个选项里指定的地方去找文章来源地址https://www.toymoban.com/news/detail-776537.html

cpp_srcs := $(shell find src -name *.cpp)
cpp_objs := $(patsubst src/%.cpp,objs/%.o,$(cpp_srcs))

include_dirs :=/home/include
I_options := $(include_dirs:%=-I%)
compile_options := -g -O3 -w $(I_options)

lib_dirs := /home/lib #库路径
link_libs := xxx      #库名
L_options := $(lib_dirs:%=-L%)
l_options := $(link_libs:%=-l%)
link_options := $(l_options) $(L_options) $(I_options)

#每个.cpp生成一个对应的目标文件
objs/%.o : src/%.cpp
	#创建文件夹,@表示make的时候不打印make信息
	@mkdir -p $(dir $@)
	@g++ -c $^ -o $@ $(compile_options)

workspace/exec : $(cpp_objs)
	@mkdir workspace/exec
	@g++ $^ -o $@ $(link_options)
	
# 输入make run即可生成run伪目标
run : workspace
	@./$<
	
# 输入make clean即可生成clean伪目标
clean :
	@rm -rf objs workspace/exec

debug :
	@echo $(as_files)

.PHONY : debug run clean

到了这里,关于Makefile——Linux下C/C++编译方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Linux】编译器gcc | make | Makefile | 模拟进度条 | gitee

    目录 1. 编译器 gcc 1.1 背景知识 1.2 gcc如何完成 2.1 Makefile背景 2.2 Makefile原理 2.3 Makefile常用符号 3. 模拟倒计时 4. 模拟进度条 5. 使用 git 命令行 5.1 安装 git 5.2 创建项目下载到本地 5.3 推送本地代码到远端仓库 1. 编译器 gcc 1.1 背景知识 预处理(进行宏替换) 编译(生成汇编) 汇编

    2024年03月12日
    浏览(54)
  • 【Linux】Linux编译器-gcc/g++ && Linux项目自动化构建工具-make/Makefile

    目录 Linux编译器-gcc/g++使用 1.背景知识  Linux中头文件的目录在 Linux 库 条件编译的典型应用 2.gcc如何完成 动态库 vs 静态库 debug release Linux项目自动化构建工具-make/Makefile 背景 用法 特殊符号  预处理(去注释,头文件展开,条件编译,宏替换) 编译(生成汇编) 汇编(生成

    2024年02月20日
    浏览(39)
  • 【Linux】gcc编译过程、make和makefile的概念与区别、Linux简单进度条实现

      1. 预处理(进行宏替换)   2. 编译(生成汇编)   3. 汇编(生成机器可识别代码)   4. 连接(生成可执行文件或库文件)   预处理(Preprocessing):在这个阶段,gcc会对源代码进行预处理,主要包括处理宏定义、头文件包含、条件编译等操作。预处理器会根据预处

    2024年02月12日
    浏览(31)
  • Linux下gcc编译,动态库和静态库,makefile,gdb调试

    展开头文件, 宏替换(变量宏、函数宏)、替换空格等 逐行检查程序中出现的语法错误,简单的逻辑错误 将 .s 汇编文件中所有的汇编指令翻译成二进制机器码(下面就是来了个截图,二进制显示了乱码) 将 .o 的目标文件,链接库文件、数据段合并,地址回填(把汇编里相

    2024年02月08日
    浏览(35)
  • Linux(基础IO、文件权限、Makefile)

    目录 1、man 手册 1.1 汉化 1.2 具体使用 2、文件权限 2.1 权限理解 2.2 文件详细信息查询 2.3 权限更改 3、常用函数接口 3.1 open 3.2 read 3.3 write 3.4 close 3.5 函数使用示例 4、make与Makefile 4.1 make 与 Makefile区别 4.2 Makefile的编写 5、vim简单操作 安装中文包 使用三种方式查询open接口的详

    2024年02月11日
    浏览(35)
  • Linux驱动开发笔记(一):helloworld驱动源码编写、makefile编写以及驱动编译基本流程

    若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/130534343 红胖子网络科技博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中… 上一篇:没有了 下一篇:《Linu

    2024年02月08日
    浏览(41)
  • 【Linux】--- Linux编译器-gcc/g++、调试器-gdb、项目自动化构建工具-make/Makefile 使用

    格式: gcc [选项] 要编译的文件 [选项] [目标文件] , gcc / g++ 安装: sudo yum install -y gcc-c++ 。安装后的编译器默认的版本是较低的,我们可以 使用选项 -std=c99 (即使用c99标准), -std=c++11 (即使用c++11的标准)来进行版本提升 。使用 -o 选项,可以将编译生成的可执行重命名

    2024年03月10日
    浏览(90)
  • 韦东山Linux教学视频中的makefile文件详细介绍

    (1)在学习韦东山Linux教学视频的时候,他的makefile并没有做详细的介绍。以至于我学了很长时间对他的makefile文件不理解。所以本文将会详细介绍韦东山Linux教学视频中的makefile文件含义。 (2)注意:我使用的是韦东山的配套i.max6ull pro开发板。 如果是其他系列开发板,mak

    2024年02月16日
    浏览(37)
  • Linux驱动开发笔记(三):基于ubuntu的helloworld驱动源码编写、makefile编写以及驱动编译加载流程测试

    若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/130542981 红胖子网络科技博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中… 上一篇:《Linux驱动开发笔记(二

    2024年02月05日
    浏览(35)
  • C语言,Linux,静态库编写方法,makefile与shell脚本的关系。

    静态库编写: 编写.o文件 gcc -c( 小写) seqlist.c(需要和头文件、main.c文件在同一文件目录下) libs.a- 去掉lib与.a剩下的为库的名称‘s’。 -ls 是指库名为s。 -L 库的路径。 makefile文件编写: 这个是编译后的文件,app文件为编译后的二进制文件。      makefile与shell脚本关系 shell 脚

    2024年02月12日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包