g++ - 不反映在源文件中所做的更改
g++ - not reflecting changes made in source file
我正在构建一个结构如下的项目:
- Makefile
- main.cpp
- util.h
- subsrc/
- one.cpp
- two.cpp
我的 Makefile 设置为输出到构建目录:
all: $(BIN_FILE)
$(BIN_FILE): $(OBJ_FILES)
mkdir -p $(BIN_DIR)
g++ $^ -o $@
$(OBJ_DIR)/%.o: %.cpp
mkdir -p $(OBJ_DIR)
g++ -c $^ -o $@
$(OBJ_DIR)/subsrc/%.o: subsrc/%.cpp
mkdir -p $(OBJ_DIR)/subsrc
g++ -c $^ -o $@
clean:
rm -rf $(BUILD_DIR)/*
但是,我在手动 运行 g++ 时也看到了这个问题,所以我认为它与 Makefile 无关。
我可以从头开始构建,一切正常。问题是当我更改其中一个 subsrc 文件并尝试重新编译时,通过 make
或 运行 自己执行这些命令:
g++ -c subsrc/one.cpp -o build/obj/subsrc/one.o
g++ build/obj/main.o build/obj/subsrc/one.o build/obj/subsrc/two.o -o build/bin/prog
如果我这样做,在 one.cpp
中所做的更改 不会反映 在二进制输出中。如果我重新编译 main.cpp
(或者,当然,整个项目),它工作正常。这不是 g++ 没有正确覆盖文件的问题,因为即使我 rm build/obj/subsrc/one.o
and/or rm build/bin/prog
在 运行 执行上述命令之前,我仍然看不到更改.这对我来说毫无意义,我不知道发生了什么。
编辑:我在这里上传了一个最小的可复制示例。 https://github.com/scatter-dev/so_70242118_min_repro
复制说明:
- 使用
make
或通过 运行 上面的 g++ 命令构建。
- 运行 确保程序已正确构建。
- 更改
one.cpp
中 doWork
函数的输出。保存到磁盘。
- Re运行
make
并注意 one.o
文件被重新编译并且 prog
是用链接器重新创建的。
- 运行 再次运行程序,看到输出没有变化。
在评论者的建议下,我检查了步骤1和步骤4之间one.o
和prog
的md5sum,确实是一样的。即使我在重新编译 之前删除了one.o
,情况仍然如此。是的,我确定 one.cpp
正在保存到磁盘(它的 md5sum 确实发生了变化,同时 make clean && make
将使用新的更改进行编译)。
您的问题是您的代码写得很奇怪,因此您的 makefile 不完整。
在你的 main.cpp 中你有:
#include "subsrc/derived.h"
很好,但是 header 你有:
#include "one.cpp"
#include "two.cpp"
这非常奇怪。您几乎不想在其他源文件(或 header 文件)中包含 .cpp
文件。这只是个坏主意。
在这种情况下,您程序的所有内容都包含在 main.cpp
中,因此会出现在您的 main.o
文件中。在其他 objects(one.o
和 two.o
)中链接是无用且不必要的:它们将被忽略。
但是,在您的 makefile 中,您没有将 one.cpp
或 two.cpp
列为 main.o
的先决条件,这意味着当您修改这些源文件时 main.o
未更新,因此没有任何变化。如果您删除 main.o
,则会重新编译它并获得新的行为。
预计到达时间
你有两个选择:
您可以将 classes 的声明放入 derived.h
并将 doWork() 方法的定义放入 .cpp
文件。看起来像这样:
$ cat main.cpp
#include "subsrc/derived.h"
...
$ cat subsrc/derived.h
#include "../base.h"
class Derived1 : public Base {
public:
void doWork();
};
class Derived2 : public Base {
public:
void doWork();
};
$ cat subsrc/one.cpp
#include <iostream>
#include "derived.h"
void Derived1::doWork() {
std::cout << "I'm Derived1" << std::endl;
}
$ cat subsrc/two.cpp
#include <iostream>
#include "derived.h"
void Derived2::doWork()
{
std::cout << "I'm Derived2" << std::endl;
}
$ cat Makefile
...
$(OBJ_DIR)/main.o : base.h subsrc/derived.h
$(OBJ_DIR)/subsrc/one.o: base.h subsrc/derived.h
$(OBJ_DIR)/subsrc/two.o: base.h subsrc/derived.h
或者您可以按照您的方式在 header 文件中内嵌所有内容(但您真的不想使用 .cpp
扩展名命名这些文件,如果它们包含 class 声明)。或者,您可以只拥有一个 derived.h
,然后将 one.cpp
和 two.cpp
一起扔掉。
但您需要在 makefile 中添加先决条件:如果您保留多个 header,则 main.o
必须依赖它们。
我正在构建一个结构如下的项目:
- Makefile
- main.cpp
- util.h
- subsrc/
- one.cpp
- two.cpp
我的 Makefile 设置为输出到构建目录:
all: $(BIN_FILE)
$(BIN_FILE): $(OBJ_FILES)
mkdir -p $(BIN_DIR)
g++ $^ -o $@
$(OBJ_DIR)/%.o: %.cpp
mkdir -p $(OBJ_DIR)
g++ -c $^ -o $@
$(OBJ_DIR)/subsrc/%.o: subsrc/%.cpp
mkdir -p $(OBJ_DIR)/subsrc
g++ -c $^ -o $@
clean:
rm -rf $(BUILD_DIR)/*
但是,我在手动 运行 g++ 时也看到了这个问题,所以我认为它与 Makefile 无关。
我可以从头开始构建,一切正常。问题是当我更改其中一个 subsrc 文件并尝试重新编译时,通过 make
或 运行 自己执行这些命令:
g++ -c subsrc/one.cpp -o build/obj/subsrc/one.o
g++ build/obj/main.o build/obj/subsrc/one.o build/obj/subsrc/two.o -o build/bin/prog
如果我这样做,在 one.cpp
中所做的更改 不会反映 在二进制输出中。如果我重新编译 main.cpp
(或者,当然,整个项目),它工作正常。这不是 g++ 没有正确覆盖文件的问题,因为即使我 rm build/obj/subsrc/one.o
and/or rm build/bin/prog
在 运行 执行上述命令之前,我仍然看不到更改.这对我来说毫无意义,我不知道发生了什么。
编辑:我在这里上传了一个最小的可复制示例。 https://github.com/scatter-dev/so_70242118_min_repro
复制说明:
- 使用
make
或通过 运行 上面的 g++ 命令构建。 - 运行 确保程序已正确构建。
- 更改
one.cpp
中doWork
函数的输出。保存到磁盘。 - Re运行
make
并注意one.o
文件被重新编译并且prog
是用链接器重新创建的。 - 运行 再次运行程序,看到输出没有变化。
在评论者的建议下,我检查了步骤1和步骤4之间one.o
和prog
的md5sum,确实是一样的。即使我在重新编译 之前删除了one.o
,情况仍然如此。是的,我确定 one.cpp
正在保存到磁盘(它的 md5sum 确实发生了变化,同时 make clean && make
将使用新的更改进行编译)。
您的问题是您的代码写得很奇怪,因此您的 makefile 不完整。
在你的 main.cpp 中你有:
#include "subsrc/derived.h"
很好,但是 header 你有:
#include "one.cpp"
#include "two.cpp"
这非常奇怪。您几乎不想在其他源文件(或 header 文件)中包含 .cpp
文件。这只是个坏主意。
在这种情况下,您程序的所有内容都包含在 main.cpp
中,因此会出现在您的 main.o
文件中。在其他 objects(one.o
和 two.o
)中链接是无用且不必要的:它们将被忽略。
但是,在您的 makefile 中,您没有将 one.cpp
或 two.cpp
列为 main.o
的先决条件,这意味着当您修改这些源文件时 main.o
未更新,因此没有任何变化。如果您删除 main.o
,则会重新编译它并获得新的行为。
预计到达时间
你有两个选择:
您可以将 classes 的声明放入 derived.h
并将 doWork() 方法的定义放入 .cpp
文件。看起来像这样:
$ cat main.cpp
#include "subsrc/derived.h"
...
$ cat subsrc/derived.h
#include "../base.h"
class Derived1 : public Base {
public:
void doWork();
};
class Derived2 : public Base {
public:
void doWork();
};
$ cat subsrc/one.cpp
#include <iostream>
#include "derived.h"
void Derived1::doWork() {
std::cout << "I'm Derived1" << std::endl;
}
$ cat subsrc/two.cpp
#include <iostream>
#include "derived.h"
void Derived2::doWork()
{
std::cout << "I'm Derived2" << std::endl;
}
$ cat Makefile
...
$(OBJ_DIR)/main.o : base.h subsrc/derived.h
$(OBJ_DIR)/subsrc/one.o: base.h subsrc/derived.h
$(OBJ_DIR)/subsrc/two.o: base.h subsrc/derived.h
或者您可以按照您的方式在 header 文件中内嵌所有内容(但您真的不想使用 .cpp
扩展名命名这些文件,如果它们包含 class 声明)。或者,您可以只拥有一个 derived.h
,然后将 one.cpp
和 two.cpp
一起扔掉。
但您需要在 makefile 中添加先决条件:如果您保留多个 header,则 main.o
必须依赖它们。