面试后查缺补漏--cmake,makefiles,g++,gcc(自写精华版)
概览
在Linux C++开发中,编译构建涉及以下核心工具:
源代码(.cpp/.h) → 编译器(g++/gcc) → 目标文件(.o) → 链接器(ld) → 可执行文件↓ 构建系统(Makefile/CMake) 负责管理整个流程
1.g++,gcc
gcc: GNU C 编译器,主要用于编译 C 程序
g++: GNU C++ 编译器,主要用于编译 C++ 程序
单文件:
g++ -o 输出文件名 源文件.cpp多文件: 列出所有源文件或分别编译后链接
常用选项:
-Wall(警告),-g(调试),-O(优化)运行:
./可执行文件名
2.makefiles- 构建自动化
Makefile 是一个文本文件,包含了一系列规则,告诉 make 工具如何编译和链接程序。
基本语法结构
makefile
目标: 依赖命令
注意: 命令前必须是 Tab 字符,不能是空格!
简单的 Makefile 示例
示例 1: 基础单文件编译
makefile
# 注释以 # 开头 hello: hello.cppg++ -o hello hello.cppclean:rm -f hello
使用:
bash
make # 编译程序 make clean # 清理生成的文件
示例 2: 多文件项目
假设项目结构:
text
project/ ├── main.cpp ├── utils.cpp ├── utils.h └── Makefile
对应的 Makefile:
makefile
# 定义变量 CXX = g++ CXXFLAGS = -Wall -std=c++11 TARGET = myapp OBJS = main.o utils.o# 默认目标 $(TARGET): $(OBJS)$(CXX) $(CXXFLAGS) -o $(TARGET) $(OBJS)main.o: main.cpp utils.h$(CXX) $(CXXFLAGS) -c main.cpputils.o: utils.cpp utils.h$(CXX) $(CXXFLAGS) -c utils.cppclean:rm -f $(TARGET) $(OBJS).PHONY: clean # 声明 clean 为伪目标
完整的 Makefile 模板
makefile
# 编译器设置 CXX = g++ CXXFLAGS = -Wall -g -std=c++14 LDFLAGS = # 项目设置 TARGET = myprogram SRCDIR = src OBJDIR = obj# 自动查找源文件 SOURCES = $(wildcard $(SRCDIR)/*.cpp) OBJECTS = $(SOURCES:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o)# 默认目标 $(TARGET): $(OBJECTS)$(CXX) $(OBJECTS) -o $(TARGET) $(LDFLAGS)# 编译源文件为目标文件 $(OBJDIR)/%.o: $(SRCDIR)/%.cpp | $(OBJDIR)$(CXX) $(CXXFLAGS) -c $< -o $@# 创建目标目录 $(OBJDIR):mkdir -p $(OBJDIR)# 清理 clean:rm -rf $(OBJDIR) $(TARGET)# 安装 install: $(TARGET)cp $(TARGET) /usr/local/bin/# 声明伪目标 .PHONY: clean install
常用变量和自动变量
$@: 当前目标名称$<: 第一个依赖项$^: 所有依赖项$?: 比目标更新的依赖项$*: 不包含扩展名的目标文件
实际开发步骤
1. 创建项目结构
text
myproject/ ├── src/ │ ├── main.cpp │ ├── utils.cpp │ └── utils.h ├── obj/ # 自动创建 └── Makefile
2. 编写 Makefile
使用上面的模板,根据项目需求调整。
3. 构建项目
bash
make # 编译项目 ./myprogram # 运行程序 make clean # 清理构建文件
4. 重新构建
bash
make # make 会自动检测哪些文件需要重新编译
高级特性
条件判断
makefile
DEBUG = 1 ifeq ($(DEBUG), 1)CXXFLAGS += -DDEBUG -O0 elseCXXFLAGS += -O2 endif
包含其他 Makefile
makefile
include config.mk
函数使用
makefile
SOURCES = $(wildcard src/*.cpp) OBJECTS = $(patsubst src/%.cpp,obj/%.o,$(SOURCES))
实用技巧
使用
-j选项并行编译:bash
make -j4 # 使用4个线程并行编译
查看详细输出:
bash
make V=1 # 显示完整的编译命令
只编译不链接:
bash
make main.o # 只编译 main.cpp
总结
Makefile 的核心优势:
自动化: 自动检测文件变化,只重新编译必要的文件
高效: 支持并行编译,加快构建速度
灵活: 可以定义复杂的构建规则
可移植: 在不同 Unix-like 系统上都能工作
对于小型到中型 C++ 项目,Makefile 是一个非常实用的构建工具!
3.cmake- 跨平台构建系统
CMake 是一个跨平台的自动化构建系统,可以生成 Makefile、Visual Studio 项目文件等。它比直接写 Makefile 更高级和方便。
CMake 使用 CMakeLists.txt 文件来描述构建过程,然后生成对应平台的构建文件。
基本操作步骤
1. 创建项目结构
text
myproject/ ├── CMakeLists.txt ├── src/ │ ├── main.cpp │ ├── utils.cpp │ └── utils.h └── build/ # 建议的构建目录
2. 编写 CMakeLists.txt
最简单的 CMakeLists.txt:
cmake
# 指定 CMake 最低版本要求 cmake_minimum_required(VERSION 3.10)# 设置项目名称 project(MyProject)# 设置 C++ 标准 set(CMAKE_CXX_STANDARD 11)# 添加可执行文件 add_executable(myapp src/main.cpp src/utils.cpp)
3. 构建项目
bash
# 进入构建目录 mkdir build cd build# 生成构建系统 cmake ..# 编译项目 make# 运行程序 ./myapp
完整的 CMakeLists.txt 示例
cmake
# CMake 最低版本要求
cmake_minimum_required(VERSION 3.10)# 项目定义
project(MyProject VERSION 1.0DESCRIPTION "A simple C++ project"LANGUAGES CXX
)# 设置 C++ 标准和相关属性
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)# 编译选项
if(CMAKE_BUILD_TYPE STREQUAL "Debug")set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -g -O0")
else()set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O2")
endif()# 包含目录
include_directories(${CMAKE_SOURCE_DIR}/src)# 查找源文件
file(GLOB SOURCES "src/*.cpp")# 创建可执行文件
add_executable(${PROJECT_NAME} ${SOURCES})# 链接库(如果有)
# target_link_libraries(${PROJECT_NAME} pthread)# 安装规则(可选)
install(TARGETS ${PROJECT_NAME} DESTINATION bin)更高级的项目结构
对于多目录项目:
text
myproject/ ├── CMakeLists.txt ├── src/ │ ├── CMakeLists.txt │ ├── main.cpp │ └── utils.cpp ├── include/ │ └── utils.h └── build/
根目录 CMakeLists.txt:
cmake
cmake_minimum_required(VERSION 3.10) project(MyProject)# 添加子目录 add_subdirectory(src)
src/CMakeLists.txt:
cmake
# 包含头文件目录
include_directories(${CMAKE_SOURCE_DIR}/include)# 源文件
set(SOURCES main.cpp utils.cpp)# 创建可执行文件
add_executable(${PROJECT_NAME} ${SOURCES})常用 CMake 命令和变量
重要命令
project(): 定义项目add_executable(): 添加可执行目标add_library(): 添加库目标target_link_libraries(): 链接库include_directories(): 添加头文件路径find_package(): 查找外部包
常用变量
CMAKE_SOURCE_DIR: 根源码目录CMAKE_BINARY_DIR: 构建目录CMAKE_CXX_COMPILER: C++ 编译器CMAKE_CXX_FLAGS: 编译标志PROJECT_NAME: 项目名称CMAKE_BUILD_TYPE: 构建类型 (Debug/Release)
实际开发工作流
1. 首次构建
bash
mkdir build && cd build cmake .. -DCMAKE_BUILD_TYPE=Debug make
2. 重新构建(修改代码后)
bash
make # 在 build 目录中
3. 重新配置(修改 CMakeLists.txt 后)
bash
cmake .. # 重新生成构建系统 make
4. 清理构建
bash
# 方法1:删除构建目录 rm -rf build# 方法2:在构建目录中清理 make clean
高级特性示例
查找和使用外部库
cmake
# 查找 OpenCV
find_package(OpenCV REQUIRED)# 包含头文件
include_directories(${OpenCV_INCLUDE_DIRS})# 链接库
target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS})条件编译
cmake
option(USE_OPENMP "Use OpenMP for parallelization" ON)if(USE_OPENMP)find_package(OpenMP)if(OpenMP_CXX_FOUND)target_link_libraries(${PROJECT_NAME} OpenMP::OpenMP_CXX)endif()
endif()添加测试
cmake
# 启用测试
enable_testing()# 添加测试
add_test(NAME MyTest COMMAND ${PROJECT_NAME})实用技巧
指定编译器:
bash
cmake .. -DCMAKE_CXX_COMPILER=g++-9
指定构建类型:
bash
cmake .. -DCMAKE_BUILD_TYPE=Release
查看详细输出:
bash
make VERBOSE=1
并行编译:
bash
make -j4
安装程序:
bash
make install
与 Makefile 对比的优势
跨平台: 可生成 VS 项目、Xcode 项目、Makefile 等
依赖管理: 自动处理头文件依赖
模块化: 更好的项目结构管理
生态系统: 大量现成的 Find 模块
配置灵活: 支持条件编译、选项设置
总结
CMake 的基本使用流程:
编写
CMakeLists.txt生成:
cmake生成构建系统编译:
make或其他构建工具运行: 执行生成的可执行文件
其他常考面试题
Q:Makefile和CMake的区别?
A:
Makefile: 直接指定构建规则,语法相对简单,但跨平台性差
CMake: 生成器,根据CMakeLists.txt生成对应平台的构建文件(Makefile、Visual Studio项目等)
现代趋势: CMake因其跨平台性和更好的依赖管理而更受欢迎
Q: 静态库和动态库的区别?
静态库(.a): 编译时链接到可执行文件中,程序独立但体积大
动态库(.so): 运行时加载,多个程序可共享,便于更新
Q: 头文件包含的两种方式?
A:
#include <iostream> // 系统头文件,从系统路径查找 #include "myheader.h" // 用户头文件,从当前目录开始查找
