概览
在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.cpp
g++ -o hello hello.cpp
clean:
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.cpp
utils.o: utils.cpp utils.h
$(CXX) $(CXXFLAGS) -c utils.cpp
clean:
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
else
CXXFLAGS += -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.0
DESCRIPTION "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" // 用户头文件,从当前目录开始查找