假设我们有以下文件结构:
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)
安装 CMake(如果尚未安装)。
在项目文件夹中创建一个名为 build 的子文件夹,用于构建项目。
在 build 文件夹中打开终端,运行以下命令:
cmake …
这将根据 CMakeLists.txt 创建构建文件。
运行以下命令进行编译:
make
这将使用构建文件编译项目,并生成名为 myProgram 的可执行文件。
这些命令将在终端中执行。一旦编译完成,你可以在终端中运行 ./myProgram 来执行你的程序。
使用 CMake 有助于管理更复杂的项目结构,并能够轻松添加其他依赖项、调整编译选项以及添加测试等功能。 Makefile 也是一种相似的方法,它可以用于管理代码的编译和链接过程
下面是一个简单的 Makefile 示例,用于构建包含多个源文件的 C++ 项目。在这个示例中,我们有 main.cpp、 file.cpp、file2.cpp、file1.cpp 四个源文件和一个common.h头文件。我们将使用 Makefile 来编译这些源文件并生成可执行文件。
假设我们有以下文件结构:
project_folder
│ Makefile
│ main.cpp
│ common.h
│ file.cpp
│ file1.cpp
│ file2.cpp
把下面内容写到文件结构中的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)
在项目文件夹中打开终端,运行以下命令:
运行 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
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();
}