VS Code使用 CMake 或 Makefile管理C++多文件编译

2023-12-13 19:29:23


使用 CMake 或 Makefile 是更加标准和灵活的方法来管理多文件编译。以下是一个简单的示例,展示了如何使用 CMake 来构建包含多个源文件的 C++ 项目。
【注】在我测试C++静态全局对象初始化的过程中,由于使用g++后面跟需要编译的文件名太过于麻烦,特整理下CMake的管理多文件编译的方法。(静态全局对象初始化顺序是未定义,测试的过程中发现和g++后面的文件间顺序有关,CMake也是一样的,感兴趣的可以自己测测,我使用的linux + VS Code + Cmake, windows的可以自己配置环境,windows + VS Code + mingw + CMame)

一、Cmake方式

1、文件结构

假设我们有以下文件结构:

project_folder
│ CMakeLists.txt
│ main.cpp
│ common.h
│ file.cpp
│ file1.cpp
│ file2.cpp

CMakeLists.txt

cmake_minimum_required(VERSION 3.0)
project(MyProject)

# 添加可执行文件, 下面的文件顺序会导致我定义的全局静态变量的初始化顺序也不一致
add_executable(myProgram mian.cpp file.cpp file2.cpp file1.cpp  common.h)

2、构建项目

安装 CMake(如果尚未安装)。
在项目文件夹中创建一个名为 build 的子文件夹,用于构建项目。
在 build 文件夹中打开终端,运行以下命令:

cmake …

这将根据 CMakeLists.txt 创建构建文件。
运行以下命令进行编译:

make

这将使用构建文件编译项目,并生成名为 myProgram 的可执行文件。

这些命令将在终端中执行。一旦编译完成,你可以在终端中运行 ./myProgram 来执行你的程序。
使用 CMake 有助于管理更复杂的项目结构,并能够轻松添加其他依赖项、调整编译选项以及添加测试等功能。 Makefile 也是一种相似的方法,它可以用于管理代码的编译和链接过程

二、Makefile方式

下面是一个简单的 Makefile 示例,用于构建包含多个源文件的 C++ 项目。在这个示例中,我们有 main.cpp、 file.cpp、file2.cpp、file1.cpp 四个源文件和一个common.h头文件。我们将使用 Makefile 来编译这些源文件并生成可执行文件。

1、文件结构

假设我们有以下文件结构:

project_folder
│ Makefile
│ main.cpp
│ common.h
│ file.cpp
│ file1.cpp
│ file2.cpp

2、Makefile

把下面内容写到文件结构中的Makefile文件中。(在 Makefile 中,通常不需要显式引入头文件(.h 文件),我在这里引入头文件)

我们创建了一个名为 HEADERS 的变量来存储头文件的名称。然后,我们在生成目标文件的规则中使用 $(HEADERS) 来指示每个 .o 目标都依赖于指定的头文件。这样可以确保在每次头文件发生变化时,相关的源文件将被重新编译。
这种方法使得 Makefile 更加清晰和易于维护,因为头文件的依赖关系被单独定义在一个地方,便于统一管理。

# Makefile
# 编译器
CXX = g++
# 编译选项
CXXFLAGS = -std=c++11 -Wall

# 目标文件
TARGET = myProgram
# 源文件
SRCS = main.cpp file.cpp file2.cpp file1.cpp

# 目标文件
OBJS = $(SRCS:.cpp=.o)

# 头文件
HEADERS = common.h

# 默认目标
all: $(TARGET)

# 生成可执行文件
$(TARGET): $(OBJS)
	$(CXX) $(CXXFLAGS) -o $@ $^

# 生成目标文件
%.o: %.cpp $(HEADERS)
	$(CXX) $(CXXFLAGS) -c $<

# 清理生成的文件
clean:
	rm -f $(OBJS) $(TARGET)

3、构建项目

在项目文件夹中打开终端,运行以下命令:
运行 make 来编译项目并生成可执行文件。(在Makefile的同级目录下执行下面命令)

make

然后运行 ./myProgram 来执行你的程序。

./myProgram

通过这种方式,Makefile 负责管理源文件的编译、链接和生成可执行文件的过程。你可以根据需要对 Makefile 进行调整,以满足项目的具体需求。

三、附件

大体内容就这些,下面是我测试时的示例代码。如有疑问,欢迎一起讨论。

示例中使用到的文件及代码

// main.cpp
#include"common.h"

int main()
{
    std::cout << "hello world." << std::endl;
    test_classA();
    test_classB();
    test_classC();
    return 0;

}
// common.h
#include<iostream>
class classA;
class classB;
class classC;

void test_classA();
void test_classB();
void test_classC();
// file.cpp
#include"common.h"

#include"common.h"

class classC
{
private:
    int x;
public:
    classC(/* args */);
    ~classC();
    void print() {
        std::cout << __FUNCTION__ << "(), " << __FILE__<< ", x = " << x << std::endl;  
    }
};

classC::classC(/* args */)
{
    std::cout << __FUNCTION__ << "(), " __FILE__ << std::endl;  
}

classC::~classC()
{
    std::cout << __FUNCTION__ << "(), " __FILE__ << std::endl;  
}

static classC objC;
void test_classC()
{
    objC.print();
}
// file1.cpp
#include"common.h"

class classA
{
private:
    int x;
public:
    classA(/* args */);
    ~classA();
    void print() {
        std::cout << __FUNCTION__ << "(), " << __FILE__<< ", x = " << x << std::endl;  
    }
};

classA::classA(/* args */)
{
    std::cout << __FUNCTION__ << "(), " __FILE__ << std::endl;  
}

classA::~classA()
{
    std::cout << __FUNCTION__ << "(), " __FILE__ << std::endl;  
}

static classA objA;
void test_classA()
{
    objA.print();
}
// file2.cpp
#include"common.h"

class classB
{
private:
    int m;
public:
    classB(/* args */);
    ~classB();
    void print() {
        std::cout << __FUNCTION__ << "(), " << __FILE__<< ", m = " << m << std::endl;  
    }
};

classB::classB(/* args */)
{
    std::cout << __FUNCTION__ << "(), " __FILE__ << std::endl;  
}

classB::~classB()
{
    std::cout << __FUNCTION__ << "(), " __FILE__ << std::endl;  
}

static classB objB;
void test_classB()
{
    objB.print();
}

文章来源:https://blog.csdn.net/BirdsLife/article/details/134833705
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。