VS Code使用 CMake 或 Makefile管理C++多文件編譯
- 一、Cmake方式
- 1、文件結構
- 2、構建項目
- 二、Makefile方式
- 1、文件結構
- 2、Makefile
- 3、構建項目
- 三、附件
- 示例中使用到的文件及代碼
使用 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();
}