C++ VisualStudio2010&;2008年可以';是否无法处理不同文件夹中同名的源文件?
直接问题:如果我有两个同名文件(但在不同的目录中),似乎只有Visual Studio 2005可以透明地处理此问题??VS2008和2010需要一系列调整吗?除了我的命名惯例,我做错了什么吗 背景: 我正在开发C++统计库…我有两个文件夹: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
/ 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>