面试后查缺补漏--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++ 程序

  1. 单文件 : g++ -o 输出文件名 源文件.cpp

  2. 多文件: 列出所有源文件或分别编译后链接

  3. 常用选项 : -Wall(警告), -g(调试), -O(优化)

  4. 运行 : ./可执行文件名

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))

实用技巧

  1. 使用 -j 选项并行编译

    bash

    复制代码
    make -j4  # 使用4个线程并行编译
  2. 查看详细输出

    bash

    复制代码
    make V=1  # 显示完整的编译命令
  3. 只编译不链接

    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})

实用技巧

  1. 指定编译器

    bash

    复制代码
    cmake .. -DCMAKE_CXX_COMPILER=g++-9
  2. 指定构建类型

    bash

    复制代码
    cmake .. -DCMAKE_BUILD_TYPE=Release
  3. 查看详细输出

    bash

    复制代码
    make VERBOSE=1
  4. 并行编译

    bash

    复制代码
    make -j4
  5. 安装程序

    bash

    复制代码
    make install

与 Makefile 对比的优势

  • 跨平台: 可生成 VS 项目、Xcode 项目、Makefile 等

  • 依赖管理: 自动处理头文件依赖

  • 模块化: 更好的项目结构管理

  • 生态系统: 大量现成的 Find 模块

  • 配置灵活: 支持条件编译、选项设置

总结

CMake 的基本使用流程:

  1. 编写 CMakeLists.txt

  2. 生成 : cmake 生成构建系统

  3. 编译 : make 或其他构建工具

  4. 运行: 执行生成的可执行文件

其他常考面试题

Q:Makefile和CMake的区别?

A:

  • Makefile: 直接指定构建规则,语法相对简单,但跨平台性差

  • CMake: 生成器,根据CMakeLists.txt生成对应平台的构建文件(Makefile、Visual Studio项目等)

  • 现代趋势: CMake因其跨平台性和更好的依赖管理而更受欢迎

Q: 静态库和动态库的区别?

  • 静态库(.a): 编译时链接到可执行文件中,程序独立但体积大

  • 动态库(.so): 运行时加载,多个程序可共享,便于更新

Q: 头文件包含的两种方式?

A:

复制代码
#include <iostream>    // 系统头文件,从系统路径查找
#include "myheader.h"  // 用户头文件,从当前目录开始查找
相关推荐
煤球王子2 小时前
浅学任务调度
linux
102400243 小时前
ubuntu系统中 jupyter Kernel 频繁崩溃原因
linux·运维·服务器
深圳市恒讯科技3 小时前
使用站群服务器做SEO,如何避免被搜索引擎判定为“站群作弊”?
服务器·搜索引擎·php
LilySesy3 小时前
ABAP+如果在join的时候需要表1的字段某几位等于表2的字段的某几位,需要怎么做?
服务器·前端·数据库·sap·abap·alv
大唐荣华3 小时前
工业制造领域的ODM、OEM、EMS、JDM、CM、OBM都是啥
运维·产品运营·制造
z10_143 小时前
海外住宅ip怎么区分干净程度以及怎么选择海外住宅ip
服务器·网络·网络协议·tcp/ip
R-G-B4 小时前
【P7】docker镜像发布和部署
运维·docker·容器·docker镜像·docker镜像发布和部署·镜像发布和部署·docker镜像发布
jzhwolp4 小时前
nginx epoll 里黑科技位运算+指针复用
linux·nginx·架构
岸边的风4 小时前
FileRise 让文件管理变简单,搭配cpolar实现远程自由访问
服务器