You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MSBuild技术问题:如何将%(Compile.Identity)转换为obj文件名?

Fix MSBuild Error When Generating .obj List for Linker

Priority Solution: Fix Metadata Reference & Use Transform Syntax

The MSB4095 error you're hitting happens because your metadata reference is ambiguous. In your original Transform expression %(Compile.Identity->'%(Filename).obj'), the inner %(Filename) isn't tied to the Compile item collection—MSBuild can't tell which item's filename you're referring to.

1. Correct the Exec Command

If you want to stick with the Exec task, explicitly specify the Compile item's Filename metadata in the Transform, and use @ to reference the entire transformed list (this avoids running echo once per file, which is inefficient):

<Exec Command="echo @(Compile->'%(Compile.Filename).obj', '&#x0D;&#x0A;') &gt; $(OutputPath)\$(ExecutableName).link" />
  • @(Compile->'%(Compile.Filename).obj', '&#x0D;&#x0A;'): Converts each Compile item to filename.obj, using a carriage return + line feed (XML-escaped as &#x0D;&#x0A;) to separate entries
  • Use > to overwrite the file (prevents duplicate entries on re-runs); keep >> if you need to append instead

2. More Efficient Native MSBuild Approach: Use WriteLinesToFile

Instead of spawning a cmd process with Exec, use MSBuild's built-in WriteLinesToFile task—it's cleaner and faster:

<WriteLinesToFile File="$(OutputPath)\$(ExecutableName).link" 
                  Lines="@(Compile->'%(Filename).obj')" 
                  Overwrite="true" 
                  Encoding="UTF-8" />
  • Lines="@(Compile->'%(Filename).obj'): Directly uses the transformed .obj paths as the file content
  • Overwrite="true" replaces the file on each run; set to false if you need to append

Pure MSBuild Implementation (No Dependency on Microsoft.Cpp.targets)

If you want a fully self-contained build script without relying on C++-specific Targets files, here's a complete framework:

1. Define Base Properties & Item Collections

<PropertyGroup>
  <OutputPath>bin\$(Configuration)</OutputPath>
  <ExecutableName>HelloWorld</ExecutableName>
  <!-- Update these paths to match your MSVC installation if they're not in PATH -->
  <CLPath>cl.exe</CLPath>
  <LinkPath>link.exe</LinkPath>
</PropertyGroup>

<ItemGroup>
  <Compile Include="src\*.cpp" /> <!-- Your C++ source files -->
</ItemGroup>

2. Compile Target: Generate .obj Files

<Target Name="Compile">
  <!-- Create output directory if it doesn't exist -->
  <MakeDir Directories="$(OutputPath)" />
  
  <!-- Compile each .cpp file to .obj -->
  <Exec Command="$(CLPath) /c %(Compile.Identity) /Fo$(OutputPath)\%(Compile.Filename).obj" />
  
  <!-- Generate the linker input file (using the recommended WriteLinesToFile) -->
  <WriteLinesToFile File="$(OutputPath)\$(ExecutableName).link" 
                    Lines="@(Compile->'$(OutputPath)\%(Filename).obj')" 
                    Overwrite="true" />
</Target>
<Target Name="Link" DependsOnTargets="Compile">
  <!-- Use the generated link file to pass .obj list to linker -->
  <Exec Command="$(LinkPath) @$(OutputPath)\$(ExecutableName).link /OUT:$(OutputPath)\$(ExecutableName).exe" />
</Target>

<!-- Default build target -->
<Target Name="Build" DependsOnTargets="Link" />

Notes

  • This script manually calls cl.exe and link.exe—no external Targets files required
  • Ensure MSVC's toolchain is in your system PATH, or specify full paths for CLPath and LinkPath
  • The @filename syntax is natively supported by link.exe to read input files from a text list

内容的提问来源于stack exchange,提问作者dmitry_bond

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:06:46