我本质上是一个 make(1) 人。我想做的是相当于这个 make 片段:
FILES = generated.cs
app.exe : $(FILES)
csc -out:$@ $(FILES)
generated.cs :
echo "// generated file" > $@
即,
$(FILES)
包含文件列表,其中一些文件可能由 Makefile 中的其他目标生成。这行得通。我想用 MSBuild 做同样的事情。不幸的是,我的尝试失败了:
<Target Name="BuildGenerated"
Outputs="Generated.cs"
>
<WriteLinesToFile
File="Generated.cs"
Lines="// generated file"
Overwrite="True"
/>
</Target>
<ItemGroup>
<Compile Include="Generated.cs" />
</ItemGroup>
即,使用
<Compile/>
包含生成的文件并让 MSBuild 推断出自 Generated.cs
不存在,它应该找到一些 <Target/>
这将生成该文件,然后执行它。看起来做这样的事情的唯一方法是添加预构建步骤,但这似乎是一个黑客。预构建步骤是唯一的方法吗?或者有什么方法可以让 MSBuild 表现得像有大脑一样?
更新 1 :作为引用,这将是使其工作所需的预构建咒语,并且(再次)这是我宁愿尽可能避免的事情:
<PropertyGroup>
<CompileDependsOn>
BuildGenerated;$(CompileDependsOn)
</CompileDependsOn>
</PropertyGroup>
这需要在
<Import Project="..." />
之后发生定义 <CompileDependsOn/>
的元素.
最佳答案
问题是您的文件是生成的文件,并且 MsBuild 仅解析项目和属性组一次(在构建开始时)。因此,当 MsBuild 尝试包含生成的.cs 文件时,它尚未创建,而且 MsBuild 根本不包含任何内容。
正确的做法是在 BuildGenerated 目标中执行包含部分 这将导致它被动态评估。
<Target Name="BuildGenerated"
Outputs="Generated.cs"
>
<WriteLinesToFile
File="Generated.cs"
Lines="// generated file"
Overwrite="True"
/>
<ItemGroup>
<Compile Include="Generated.cs" />
</ItemGroup>
</Target>
我对这个问题的回答中的更多信息:Bin folder not being copied with MSBuild, Teamcity
编辑
抱歉,我没有正确阅读您的问题。在您的 makefile 中,在 app.exe 目标(默认目标)中,您明确调用了 generate.cs 目标。你可以用 MsBuild 做同样的事情。
默认情况下,MsBuild 会搜索 Build 目标(makefile 中的“all”),如果您的主要目标是“app.exe”,则必须使用以下选项之一调用 BuildGenerated 目标:
<Target Name="app.exe" DependsOnTargets="BuildGenerated>
<!-- Stuff here -->
</Target>
或者
<Target Name="app.exe">
<CallTarget Targets="BuildGenerated"/>
<!-- Stuff here -->
</Target>
如果您没有设置默认目标,您可以通过带有/t 参数的命令行或在项目声明中进行设置:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="app.exe">
关于msbuild - 如何隐式使用 Target 生成包含文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4338564/