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】编译应用和ko内核模块Makefile使用记录

    在Makefile中,变量的赋值可以使用以下几种方式: = :最基本的赋值符号,表示简单的延迟展开(lazy expansion)方式。变量的值将会在使用变量的时候进行展开。 := :立即展开(immediate expansion)的赋值方式。变量的值在赋值的时候立即展开,并且在后续的使用中不再改变。

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

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

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

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

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

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

    2024年02月08日
    浏览(51)
  • 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日
    浏览(49)
  • Linux驱动开发笔记(一):helloworld驱动源码编写、makefile编写以及驱动编译基本流程

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

    2024年02月08日
    浏览(77)
  • 【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日
    浏览(103)
  • 韦东山Linux教学视频中的makefile文件详细介绍

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

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

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

    2024年02月05日
    浏览(69)
  • 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日
    浏览(36)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包