C++ VisualStudio2010&;2008年可以';是否无法处理不同文件夹中同名的源文件?

C++ VisualStudio2010&;2008年可以';是否无法处理不同文件夹中同名的源文件?,c++,visual-studio-2008,visual-studio-2010,naming-conventions,projects-and-solutions,C++,Visual Studio 2008,Visual Studio 2010,Naming Conventions,Projects And Solutions,直接问题:如果我有两个同名文件(但在不同的目录中),似乎只有Visual Studio 2005可以透明地处理此问题??VS2008和2010需要一系列调整吗?除了我的命名惯例,我做错了什么吗 背景: 我正在开发C++统计库…我有两个文件夹: / Univariate Normal.cpp Normal.h Beta.cpp Beta.h Adaptive.cpp Adaptive.h / Multivariate Normal.cpp Normal.h Beta.cpp Beta.h A

直接问题:如果我有两个同名文件(但在不同的目录中),似乎只有Visual Studio 2005可以透明地处理此问题??VS2008和2010需要一系列调整吗?除了我的命名惯例,我做错了什么吗

背景:

我正在开发C++统计库…我有两个文件夹:

/ Univariate

Normal.cpp
Normal.h
Beta.cpp
Beta.h
Adaptive.cpp
Adaptive.h

/ Multivariate

Normal.cpp
Normal.h
Beta.cpp
Beta.h
Adaptive.cpp
Adaptive.h
我需要支持交叉编译——我正在使用g++/make将这些相同的文件编译到Linux中的库中。它们很好用

我一直在使用VisualStudio2005,但我需要升级到VisualStudio2008或2010(目前对nVidia的nsight工具垂涎三尺)。但是,如果我将文件添加到具有相同名称的项目中(即使它们位于不同的目录中),我会遇到问题。我愿意更改我的命名约定,但我很好奇其他人是否遇到过这个问题,是否找到了任何完善的文档化解决方案

如果我从2005年的项目升级到2010年的项目,那么VS 2010似乎能够正确处理不同目录中同名的两个源文件,这让我更加困惑;但是,如果我删除其中一个重复文件,然后将其添加回项目,我会收到以下警告:

Distributions\Release\Adaptive.obj:警告LNK4042:多次指定对象;多余的被忽略了

现在我将中间目录指定为$(ProjectName)\$(Configuration)——我需要将目标文件放在与源树不同的位置。因此,我可以理解为什么它会将对象文件相互复制,但当项目从2005年转换到2008年或2010年时,会添加一系列条件编译:

<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(Filename)1.obj</ObjectFileName>
<XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(Filename)1.xdc</XMLDocumentationFileName>
$(IntDir)%(文件名)1.obj
$(IntDir)%(文件名)1.xdc

可以从C/C++->Output Files->“对象文件名”和“XML文档文件名”中的源文件属性页访问这些文件。但是,如果我只是直接添加文件(或者删除并重新添加),VS在我尝试编译之前不会抱怨,但也不会添加条件指令——因此为了使事情正常工作,我必须为每个配置添加条件指令。我是在犯错误/错误的假设,还是在VS 2008/2010中发现了一个有效的错误?

你是对的,VS无法处理这个问题,而且永远也无法解决。根本问题是它为项目中的每个
.cpp
文件生成一个
.obj
文件,并且它们都放在同一个文件夹中。例如,在您的例子中,您最终得到了多个编译为
Adaptive.obj
.cpp
文件

至少链接器现在会为它生成一个警告。情况并非总是如此

您应该能够通过确保文件使用不同的中间目录路径来解决这一问题,但这是一种对一些应该是可能的事情的攻击


当然,您可以随时在IDE上提交错误报告或功能请求,这在IDE中很容易修复。单击文件夹中的第一个文件,按住Shift键并单击最后一个文件,以便选中所有文件。右击,属性,C++,输出文件。将对象文件名从
$(IntDir)\
更改为单变量\。您可以重复多变量文件组的操作,尽管这不是绝对必要的。

因此@Hans Passant指出了正确的方向,谢谢!!您不必列出文件,一个文件夹就足够了。然后,如果查看VS 2010列表底部的已定义宏,您将看到:

%(相对论)/单变量/

正如我所说,这个问题实际上是我正在研究的一个简化版本——在一个项目中有几个级别的文件夹,并且存在几个名称冲突。因此,我真的想找个方法来“修复”它

如果右键单击解决方案资源管理器中的项目,请选择C/C++->“输出文件”,并在“对象文件名”框中键入以下内容:

$(IntDir)/%(RelativeDir)/

注意,我还从下拉列表中选择了(所有配置、所有平台)。这将编译镜像源树的目录层次结构中的每个文件。VS2010将通过创建这些不存在的目录开始构建。此外,对于那些讨厌在目录名中使用空格的人来说,这个宏确实会删除所有空格,所以在使用它时不需要使用双引号


这正是我想要的——与我的Makefiles在Ubuntu端的工作方式相同,同时仍然保持源代码树的干净。

也可以在visual studio中创建一个.cpp文件,然后将其重命名为.h。虽然该文件已重命名,但visual studio仍将其编译为cpp文件,因此将创建两个obj文件并显示链接器警告。

使用配置属性>C/C++>Ouptut文件>$(IntDir)\%(RelativeDir)\%(文件名)


这将复制调试目录下的源文件结构,并将每个目录的目标文件存放在debug目录下同名的文件夹中。。问题以及必须在每个源文件上手动设置内容

更不用说,他们破坏了/MP。任何为%(ObjectFileName)指定精确的.obj的解决方案都会导致传递给CL.exe的每个.cpp文件(将其映射到特定的.obj文件)都有不同的/Fo,因此Visual Studio无法对其进行批处理。如果不批处理几个具有相同命令行(包括/Fo)的.cpp文件,/MP将无法工作

这里有一个新的方法。这至少适用于vs2010到vs2015。将此添加到


();
HashSet needdirectories=new
<!-- ================ UNDUPOBJ ================ -->
<!-- relevant topics -->
<!-- https://stackoverflow.com/questions/3729515/visual-studio-2010-2008-cant-handle-source-files-with-identical-names-in-diff/26935613 -->
<!-- https://stackoverflow.com/questions/7033855/msvc10-mp-builds-not-multicore-across-folders-in-a-project -->
<!-- https://stackoverflow.com/questions/18304911/how-can-one-modify-an-itemdefinitiongroup-from-an-msbuild-target -->
<!-- other maybe related info -->
<!-- https://stackoverflow.com/questions/841913/modify-msbuild-itemgroup-metadata -->
<UsingTask TaskName="UNDUPOBJ_TASK" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
  <ParameterGroup>
    <OutputDir ParameterType="System.String" Required="true" />
    <ItemList ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
    <OutputItemList ParameterType="Microsoft.Build.Framework.ITaskItem[]" Output="true" />
  </ParameterGroup>
  <Task>
    <Code><![CDATA[
            //general outline: for each item (in ClCompile) assign it to a subdirectory of $(IntDir) by allocating subdirectories 0,1,2, etc., as needed to prevent duplicate filenames from clobbering each other
            //this minimizes the number of batches that need to be run, since each subdirectory will necessarily be in a distinct batch due to /Fo specifying that output subdirectory

            var assignmentMap = new Dictionary<string,int>();
            HashSet<string> neededDirectories = new HashSet<string>();
            foreach( var item in ItemList )
            {
              //solve bug e.g. Checkbox.cpp vs CheckBox.cpp
              var filename = item.GetMetadata("Filename").ToUpperInvariant(); 

              //assign reused filenames to increasing numbers
              //assign previously unused filenames to 0
              int assignment = 0;
              if(assignmentMap.TryGetValue(filename, out assignment))
                assignmentMap[filename] = ++assignment;
              else
                assignmentMap[filename] = 0;

              var thisFileOutdir = Path.Combine(OutputDir,assignment.ToString()) + "/"; //take care it ends in / so /Fo knows it's a directory and not a filename
              item.SetMetadata( "ObjectFileName", thisFileOutdir );
            }

            foreach(var needed in neededDirectories)
              System.IO.Directory.CreateDirectory(needed);

            OutputItemList = ItemList;
            ItemList = new Microsoft.Build.Framework.ITaskItem[0];

        ]]></Code>
  </Task>
</UsingTask>

<Target Name="UNDUPOBJ">
  <!-- see stackoverflow topics for discussion on why we need to do some loopy copying stuff here -->
  <ItemGroup>
    <ClCompileCopy Include="@(ClCompile)"/>
    <ClCompile Remove="@(ClCompile)"/>
  </ItemGroup>
  <UNDUPOBJ_TASK OutputDir="$(IntDir)" ItemList="@(ClCompileCopy)" OutputItemList="@(ClCompile)">
    <Output ItemName="ClCompile" TaskParameter="OutputItemList"/>
  </UNDUPOBJ_TASK>
</Target>
<!-- ================ UNDUPOBJ ================ -->
<Project InitialTargets="UNDUPOBJ" ...
<PropertyGroup Label="Globals"><IgnoreWarnCompileDuplicatedFilename>true</IgnoreWarnCompileDuplicatedFilename></PropertyGroup>