从 .sln en-masse 构建通配符驱动的项目组到它们各自的输出目录

Build wildcard-fueled group of projects from .sln en-masse to their respective output directories

我们有一个通过 VisualStudio2017 创建和维护的解决方案,其中我们的 .csprojs 放置在 virtual-folders 中,如下所示:

Solution.sln
  \- VirtualFolder1
       \- Foo.Common.Bar.csproj -> Bar\bin
       \- Foo.Common.Ping.csproj -> Ping\bin
       \- Foo.Common.Pong.csproj -> Pong\bin
  \- VirtualFolder2
       \- Foo.Utils.Bar.csproj -> Utils.Bar\bin
       \- Foo.Utils.Ping.csproj -> Utils.Ping\bin
       \- Foo.Utils.Pong.csproj -> Utils.Pong\bin

正如预期的那样,每个 .csproj 文件都已经包含一个定义输出路径的部分:

  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <PlatformTarget>AnyCPU</PlatformTarget>
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>[Bar/bin or Ping/bin etc]</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
    <LangVersion>7.1</LangVersion>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <PlatformTarget>AnyCPU</PlatformTarget>
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>[Bar/bin or Ping/bin etc]</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
    <LangVersion>7.1</LangVersion>
  </PropertyGroup>

我们要构建所有 .Common .csproj.Utils .csproj 项目en-masse 到它们各自的输出文件夹中 而无需 必须在我们的 msbuild-script(由 JenkinsCI btw 调用)中一一指定它们。为了实现这一点,我们已经尝试过:

<ItemGroup>      
  <ALL_PROJECTS_IN_SOLUTION_EXCEPT_TESTS
    Include="$(_codeFolderpath)\**\*.csproj"
  />
</ItemGroup>

<MSBuild
  Projects="@(ALL_PROJECTS_IN_SOLUTION_EXCEPT_TESTS)"
  Properties="Platform=$(Platform);Configuration=$(Configuration)"
  BuildInParallel="true"
/>

然而,这会导致我们所有的 .csproj 出现以下错误:

The OutputPath property is not set for project [...].csproj

鉴于 OutputPath 是在我们的 .csproj 文件中定义的(如上所示),这很奇怪。

如果我们指定 'Output' 属性 那么问题当然会消失,但我们真正想要的是这些项目将它们自己输出到各自适当的输出目录(如上所示)。如何实现这一目标?

看起来您有一个单独的项目(Build Project)用于构建 .Common .csproj 和 .Utils .csproj 项目。而你上面写的脚本是在Build Project中的一个target中定义的。 (希望我没有误会。)

根据你的错误信息The OutputPath property is not set... Common..csproj 或 Utils..csproj.[=31 中没有定义 OutputPath 属性 =]

如果是这样,我建议您使用这样的文件夹结构:

Solution.sln
  \- VirtualFolder1
       \- Foo.Common.Bar.csproj -> Foo.Common.Bar\bin
       \- Foo.Common.Ping.csproj -> Foo.Common.Ping\bin
       \- Foo.Common.Pong.csproj -> Foo.Common.Pong\bin
  \- VirtualFolder2
       \- Foo.Utils.Bar.csproj -> Foo.Utils.Bar\bin
       \- Foo.Utils.Ping.csproj -> Foo.Utils.Ping\bin
       \- Foo.Utils.Pong.csproj -> Foo.Utils.Pong\bin

因为要得到你想要的相同结构我想也许还有更复杂的工作:

1.With.csproj文件中没有OutputPath,我们可以在其路径上方的Directory中创建一个Directory.Build.props文件来控制输出路径。

2.Pass MSBuild 任务中的 OutputPath 属性。在这种情况下,您需要获取 .common.csproj 和 .utils.csproj 项目的第二个名称并添加如下条件:

<MSBuild
      Projects="@(ALL_PROJECTS_IN_SOLUTION_EXCEPT_TESTS)"
      Properties="Platform=$(Platform);Configuration=$(Configuration);OutputPath=xxx\ThirdName\bin"
      BuildInParallel="true"
      Condition="judge if the common.csproj files"
    />
    <MSBuild
      Projects="@(ALL_PROJECTS_IN_SOLUTION_EXCEPT_TESTS)" 
      Properties="Platform=$(Platform);Configuration=$(Configuration);OutputPath=xxx\SecondName.ThirdName\bin"
      BuildInParallel="true"
      Condition="judge if the utils.csproj files"
    />

所以这两个方向都可能有助于实现您的特定目标,但工作量会比我们预期的要多得多。

解决方法: 为什么必须将它们放在 Utils.Bar\bin 文件夹而不是 Foo.Utils.Bar\bin 文件夹中?后一个是 pre-defined 属性 用于 Foo.Utils.Bar.csproj 文件。所以我们可以轻松地使用 $(ProjectDir) 或 $(ProjectName) 来表示它。您可以创建一个 Directory.Build.props 文件,添加以下脚本:

<Project>
 <PropertyGroup>
  <OutputPath>$(ProjectDir)bin$(Configuration)</OutputPath>
</PropertyGroup>
</Project>

这样,在VS中加载工程文件时,需要做的就是build the solution。您将不再需要构建 Build 项目。并且由于您使用的是我没有尝试过的 virtual-path,也许您可​​以使用 <OutputPath>AbsolutePathOfMyOutput$(ProjectName)bin$(Configuration)</OutputPath>

更新:(直到今天才注意到您的编辑。)

根据您的编辑,您已经在 .csproj 中设置了输出路径。

这里有两个建议:

1.If 你在 VS ID 中构建它们:每次你在 VS IDE 之外通过记事本或其他方式对 xx.csproj 进行一些修改后,我建议你 right-click在构建它们之前将项目 unload and reload the project file

2.Please 检查您收到的整个错误消息是否如下所示:

error : The OutputPath property is not set for project 'ConsoleApp1.csproj'.  Please check to make sure that
 you have specified a valid combination of Configuration and Platform for this project.  Configuration=''  Platform='An
yCPU'.

由于你的OutputPath propertyPropertyGroup中定义了Debug|AnyCPURelease|AnyCPU。如果你没有将相应的参数传递给msbuild.exe,则进程无法从这些 ProppertyGroup 中读取 OutPutPath 属性。

例如:您在 Debug|AnyCPURelease|AnyCPU 中定义了 OutPutPath。那么你传递的Configuration and Platform的实际值为Debug|X86, or Null|AnyCPU or CustomDebug|AnyCPU,而你在这种Combination(PropertyGroup)中没有定义OutPutPath,你会得到错误消息xxx not set.

要解决此问题:确保您通过正确的配置和平台组合可以解决它。或者在你实际使用的Combination中定义OutPutPath。