VS2008:我能否在不同文件夹中使用相同名称的2个CPP文件构建项目?

8

这是我的文件夹结构:

/
|
 -- program.cpp
 -- utility.h
 -- utility.cpp
|
 -- module/
    |
     -- utility.h
     -- utility.cpp

// Note that I have two files named utility.h and two named utility.cpp

在构建项目时,我遇到了链接错误(LNK2028: unresolved token等),表示某些符号未定义。我已确认所有符号都已定义,并且所有声明的函数都有相应的定义。
我有一种感觉,在编译我的项目时,来自两个文件夹的utility.cpp文件会被编译成输出文件夹中的同一个utility.obj,结果其中一个会被覆盖。
以下是需要回答的问题:
  1. 这是预期行为吗?
  2. 如何构建一个C++二进制文件,其中有两个名称相同的文件(尽管在不同的文件夹中)?

你要找的是命名空间。 - user177800
4
这与命名空间无关。只有2个.obj文件中的一个被引入链接步骤中。 - Michael Burr
1
@fuzzy:假设第一个要编译的 utility.cpp 定义了命名空间 foo_ns 下的所有内容,而第二个要编译的 utility.cpp 则编译了命名空间 bar_ns 下的所有内容。当编译第二个 utility.cpp 时,编译器会覆盖 utility.obj 文件……等到链接器启动时,.obj 文件中只有 bar_ns 命名空间下的内容可用。 - Agnel Kurian
6个回答

13
右键单击两个/任意一个 .cpp 文件 > 属性 > C/C++ > 输出文件 > 对象文件名称 > 设置自定义名称。例如,如果两个文件都命名为 MyFile.cpp ,一个在文件夹 A 中,另一个在文件夹 B 中,您可以将输出设置为 AMyFileBMyFile
或者,您也可以使用宏来添加父文件夹的名称前缀到对象名称中(即使用 $(IntDir)\$(SafeParentName)$(SafeInputName))。 如果这还不够(例如,您有 A/B/MyFile.cppC/B/MyFile.cpp)并且您不介意在源树中有一些对象文件混杂,那么您还可以使用 $(InputDir)\,该选项会将对象文件放在与源文件相同的文件夹中。
然后将cpp文件编译成两个不同的对象文件...
祝您愉快!
针对VS2010的更新:在VS2010中有更好的解决方案,请在此处查看。感谢n1ck评论
顺便说一句,如果这些内容具有相同的名称,您是否使用不同的命名空间将它们分开?
namespace A { // in folder A
    class CMyFile {};
};

namespace B{ // in folder B
    class CMyFile {};
};

// client.cpp
#include "A/MyFile.h"
#include "B/MyFile.h"
int main() {
    A::CMyFile aMyFile;
    B::CMyFile bMyFile;
    return 0;
}

我不知道这是否重要,但对人类来说肯定更清晰:D


1
@afriza,AMyFile和BMyFile...看起来像是硬编码。有没有宏可以用来插入.cpp的相对路径作为.obj路径的一部分? - Agnel Kurian
@agnel-kurian $(SafeParentName)$(SafeInputName) 怎么样?因此,完整路径将是 $(IntDir)$(SafeParentName)$(SafeInputName)。但如果文件具有相同的 ParentName(即直接父文件夹名称),则此方法将无法正常工作。因此,如果您不介意混乱的源代码文件夹,可以使用 $(InputDir)$(SafeInputName) 代替,这将把对象文件放在与源文件相同的文件夹中。 - Afriza N. Arief
@afriza:当构建整个项目时,$(SafeParentName)修复似乎不起作用。当我一次只编译一个文件(ctrl+f7)时,它似乎运行良好,但是在构建整个项目时,它仅替换了整个编译过程中的1次而不是每个文件(因为它仅发送一次命令行,即构建.rsp文件时,它已经替换了$标识符)。我还没有找到解决这个问题的方法,但手动管理可能是一种选择(即$(IntDir)/A,$(IntDir)/B而不是自动处理)。 - n1ckp
@n1ck:$(InputDir)\怎么样?我现在没有我的电脑,但我认为文件名是可选的。不过这会使您的源树中出现更多的生成文件。 - Afriza N. Arief
2
@afriza:是的,我猜$(InputDir)在紧急情况下可能会起作用,但在我的情况下,这比手动操作更糟糕,因为它会在src/目录中污染大量对象文件。无论如何,在msvc2010中已经修复了这个问题(https://dev59.com/2XA65IYBdhLWcg3wrQh4#3731643),所以对我来说不是太大的问题。 - n1ckp
显示剩余3条评论

2
你可以尝试将另一个项目添加到你的解决方案中,该项目将从你的模块的 .cpp 和 .h 文件构建一个静态 mudule.lib 文件,然后将主项目与该库进行链接。这应该使 VS 在一个单独的目录中输出 .obj 文件,并且你应该能够无问题地进行链接。

1

最简单有效的方法是将冲突的.obj文件放入不同的子文件夹中(我曾在2003和2008年使用过此方法),这些子文件夹基于源目录。

例如:

对于src\gui\utils.cpp,将“对象文件名”设置为“.\Debug\gui/”,而对于src\database\utils.cpp,则将其设置为“.\Debug\database/”。

虽然我会在发现冲突时手动处理,但我可以想象编写一个脚本来更新每个.cpp文件的项目(或仅针对冲突的文件)将是一项非常简单的任务。


0
也许库(静态或动态)可以帮助您解决问题。但是,如果可执行文件或其他库中存在任何公共符号具有相同的名称,则仍然会出现问题。

0

我不知道 VS 的编译链。

然而,每个 .cpp 文件首先被编译成一个 .obj 文件。链接步骤将它们合并在一起。

很常见的做法是把所有的 .obj 文件放在同一个目录下。所以,正如你猜测的那样,在编译第二个文件时会覆盖第一个文件。因此,在编译过程中可能会缺少一些符号。

可能有一个选项(再次声明,我不用 VS),可以让 .obj 文件与 .cpp 文件在同一个目录下。但缺点是源代码树上会出现一些垃圾文件。

我的个人意见是重构代码。


0
你真的想在同一个项目中拥有两个名称相同但内容不同的文件吗?

6
可以的。子文件夹中的 utility.hutility.cpp 添加了与该文件夹实现的特定功能相关的功能。 - Agnel Kurian
5
如果您在构建中包含其他实用程序,通常情况下您是没有选择的。 - Martin Beckett

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接