前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >Makefile && CMake 简单入门

Makefile && CMake 简单入门

作者头像
利刃大大
发布2025-02-11 13:14:06
发布2025-02-11 13:14:06
7500
代码可运行
举报
文章被收录于专栏:csdn文章搬运csdn文章搬运
运行总次数:0
代码可运行

Ⅰ. Makefile

版本一

代码语言:javascript
代码运行次数:0
复制
hello: main.cpp print.cpp factorial.cpp
	g++ -o hello main.cpp print.cpp factorial.cpp

版本二

​ 上面版本的问题,就是一个源文件每次我们都要重新去编译,而有可能该源文件本身就没有修改过,所以 最好是生成 .o 文件,这样子只有被修改过的源文件才会重新生成 .o 文件,减少编译的时间,并且这里引入了变量,使用 $ 和括号 () 来囊括,如下所示:

代码语言:javascript
代码运行次数:0
复制
CXX = g++
TARGET = hello
OBJ = main.o print.o factorial.o

$(TARGET) : $(OBJ)
	$(CXX) -o $(TARGET) $(OBJ)

main.o : main.cpp
	$(CXX) -c main.cpp
print.o : print.cpp
	$(CXX) -c print.cpp
factorial.o : factorial.cpp
	$(CXX) -c factorial.cpp

版本三

​ 版本二的问题就是如果每当增加了新的源文件,我们都要写它的 .o 生成规则,这就很麻烦,特别是源文件很多的情况,所以我们可以用匹配符 % 来匹配 .o 以及 .cpp 文件,然后又引入 @、^、

​ 此外还引入了伪目标 .PHONY,它可以标记一个命令进行执行,该命令不会因为文件路径中有同名的文件而被干扰,并且每次执行该命令都是会重新执行的,而不是看是否有文件被修改过!

​ 后面我们有了新的源文件之后,我们 只需要在 OBJ 变量中添加其 .o 文件名即可

代码语言:javascript
代码运行次数:0
复制
CXX = g++
TARGET = hello
OBJ = main.o print.o factorial.o

CXXFLAGS = -c -Wall

$(TARGET) : $(OBJ)
	$(CXX) -o $@ $^

%.o: %.cpp
	$(CXX) $(CXXFLAGS) $< -o $@

.PHONY:clean
clean:
	rm -f *.o $(TARGET)

版本四

​ 有更好的方案,就是当我们添加新的源文件到当前目录中的时候,我们也不需要去添加对应的 .o 文件!如何做到的呢❓❓❓

​ 这里只添加了第三行,以及修改第四行,其它都是不变的!

​ 第三行表示将当前目录中的符合 .cpp 后缀的文件都放到 SRC 变量中;而第四行使用 patsubst 表示将 SRC 变量中的 .cpp 后缀都改为 .o,这样子一来就相当于帮我们处理完了 .o 文件了,只不过要注意的是 在当前目录中

代码语言:javascript
代码运行次数:0
复制
CXX = g++
TARGET = hello
SRC = $(wildcard *.cpp)
OBJ = $(patsubst %.cpp, %.o, $(SRC))

CXXFLAGS = -c -Wall

$(TARGET) : $(OBJ)
	$(CXX) -o $@ $^

%.o: %.cpp
	$(CXX) $(CXXFLAGS) $< -o $@

.PHONY:clean
clean:
	rm -f *.o $(TARGET)

Ⅱ. CMake

一、简单语法

​ 引入 cmake 是因为跨平台的原因,因为在不同平台中编写的 makefile 是不同的,所以就要有一个工具也就是 cmake 来解决!

​ 一般 cmake 文件我们 统一命名为 CMakeLists.txt,然后看下面的例子:(还是使用上面讲 makefile 中提到的几个文件来举例)

代码语言:javascript
代码运行次数:0
复制
cmake_minimum_required(VERSION 3.10)

project(hello)

add_executable(hello main.cpp print.cpp factorial.cpp)

​ 第一句的意思就是这个 cmake 的版本最低就是 3.10;然后第二句表示要生成的工程就是 hello;第三句表示要执行的语句。这样子 cmake 就写完了!

二、执行操作

​ 最暴力的方式就是在当前工作目录中直接用下面的指令:

代码语言:javascript
代码运行次数:0
复制
[liren@VM-8-7-centos ~]$ cmake .

​ 它就会执行 cmake 的规则后就会生成 makefile 文件,接着我们执行 make 指令就能创建以下这些文件:

​ 这样子其实直接放在工作目录中是很凌乱的,所以我们不推荐这样子做!因为要这些文件要删除的时候要手动删,如果文件很多的话,看起来是非常吃力的!所以我们一般推荐这么做:

  1. 在当前目录中创建一个文件夹 build
  2. 进入文件夹 build 中,然后执行指令 cmake .. 表示去上一层目录中找文件 CMakeLists.txt 进行操作。
  3. 此时就生成 makefile 文件,然后直接 make 后就能得到目标文件了!

​ 这样子做的好处就是将这些生成文件放到一个文件夹 build 中统一保管,这样子一来看起来整洁,并且删除起来我们只需要删除整个文件夹即可,非常方便!

Ⅲ. 遇到的问题

两种生成规则的区别

​ 第一个 Makefile 的规则如下:

代码语言:javascript
代码运行次数:0
复制
$(OBJ) : $(SRC)
	$(CC) $(CFLAGS) -o $@ -c $<

​ 这个规则使用了 < 变量,它表示所有依赖文件中的第一个文件,即

​ 而第二个 Makefile 的规则如下:

代码语言:javascript
代码运行次数:0
复制
$(OBJDIR)/%.o : $(SRCDIR)/%.cc
	$(CC) $(CFLAGS) -o $@ -c $<

​ 这个规则使用了 模式匹配,并且将目标文件和依赖文件的路径都指定为模式。这样,对于每个源文件,该规则都会生成对应的目标文件,并将其放到指定的目录中

​ 因此,第二个 Makefile 的规则更加准确和合理,可以正确地根据每个源文件生成对应的目标文件。而第一个 Makefile 在处理多个源文件时存在问题,只会使用第一个源文件生成所有目标文件,这是不正确的。

​ 所以,第二个 Makefile 是正确的形式,建议使用该形式来生成目标文件。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-02-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Ⅰ. Makefile
    • 版本一
    • 版本二
    • 版本三
    • 版本四
  • Ⅱ. CMake
    • 一、简单语法
    • 二、执行操作
  • Ⅲ. 遇到的问题
    • 两种生成规则的区别
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档