从.sln en-asse到通配符构建的项目组到其各自的输出目录 [英] Build wildcard-fueled group of projects from .sln en-masse to their respective output directories

查看:88
本文介绍了从.sln en-asse到通配符构建的项目组到其各自的输出目录的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们有一个通过VisualStudio2017创建和维护的解决方案,其中,我们的 .csprojs 放置在虚拟文件夹内,如下所示:

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 项目都构建到各自的输出文件夹无需在我们的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'属性,那么问题当然就解决了,但是我们真正想要的是这些项目将自己输出到各自的适当输出目录中(如上所示).如何实现这一目标?

解决方案

似乎您有一个单独的项目(构建项目),用于构建.Common .csproj和.Utils .csproj项目.您上面编写的脚本是在Build Project的目标中定义的. (希望我没有误会.)

根据您的错误消息The OutputPath property is not set...,在Common. .csproj或Utils. .csproj中没有定义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..csproj文件中没有OutputPath,我们可以创建

因此,这两个方向都可能有助于实现您的特定目标,但是这项工作将比我们期望的要多得多.

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

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

这样,在VS中加载项目文件时,您要做的是build the solution.您将不再需要构建Build项目.并且由于您使用的是我尚未尝试过的虚拟路径,因此也许您可以使用<OutputPath>AbsolutePathOfMyOutput\$(ProjectName)bin\$(Configuration)</OutputPath>

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

根据您的修改,您已在.csproj中设置了输出路径.

这里有两个建议:

1.如果使用VS ID构建它们:每次在VS IDE外部通过记事本或其他方式对xx.csproj进行一些修改后,建议您在构建它们之前右键单击unload and reload the project file项目. >

2.请检查您收到的整个错误消息是否看起来像这样:

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'.

由于在PropertyGroup中为Debug|AnyCPURelease|AnyCPU定义了OutputPath property.如果尚未将相应的参数传递给msbuild.exe,则该进程无法从这些ProppertyGroups中读取OutPutPath属性.

例如:您在Debug|AnyCPURelease|AnyCPU中定义OutPutPath.那么您传递的Configuration and Platform的实际值是Debug|X86, or Null|AnyCPU or CustomDebug|AnyCPU,并且尚未在这种Combination(PropertyGroup)中定义OutPutPath,则会收到错误信息xxx not set.

要解决此问题:请确保您通过正确的配置,并且平台组合可以解决该问题.或在您实际使用的组合中定义OutPutPath.

We have a solution created and maintained via VisualStudio2017 in which our .csprojs are placed inside virtual-folders like so:

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

As expected each and every .csproj file already contains a section which defines where the output path should be:

  <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>

We want to build all .Common .csproj and .Utils .csproj projects en-masse into their respective output folders without having to specify them in our msbuild-script (which is invoked by JenkinsCI btw) one by one. To achieve that we have tried:

<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"
/>

This however results in the following errors for all our .csproj:

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

This is strange given the fact that the OutputPath is defined in our .csproj files (as shown above).

If we specify the 'Output' property then the problem goes away of course however what we really want is these projects to output themselves into their respective appropriate output directories (shown above). How can one go about achieving this?

解决方案

Looks like you have one separate project(Build Project) used to build the .Common .csproj and .Utils .csproj projects. And the script you write above is defined in a target in the Build Project. (Hope I didn't misunderstand.)

According to your error message The OutputPath property is not set... There is no OutputPath property defined in the Common..csproj or Utils..csproj.

If so, I suggest you use a folder structure like this:

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

Because to get the same structure you want I think maybe there has much more complex work:

1.With no OutputPath in .csproj file, we can create a Directory.Build.props file in the Directory above its path to control the output path.

2.Pass the OutputPath property in your MSBuild Task. In this situation you need to get the second name for .common.csproj and .utils.csproj projects and add conditions like:

<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"
    />

So both of these two directions may help achieve your particular goal, but the work would be much more than we expect.

As a workaround: What's reason you must put them in Utils.Bar\bin folder instead of Foo.Utils.Bar\bin folder? The latter one is pre-defined property for the Foo.Utils.Bar.csproj file. SO we can easily use the $(ProjectDir) or $(ProjectName) to represent it. You can Create a Directory.Build.props file, add the script below:

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

In this way, when loading the project files in VS, what you need to do is to build the solution. You won't need to build the Build project any more. And since you're using the virtual-path which I haven't tried, maybe you can use <OutputPath>AbsolutePathOfMyOutput\$(ProjectName)bin\$(Configuration)</OutputPath>

Update:(Haven't noticed your edit until today.)

According to your edit, you've set the output path in the .csproj.

Here are two suggestions:

1.If you build them in VS ID: Every time after you do some modify to xx.csproj outside VS IDE by notepad or what, I suggest you right-click the project to unload and reload the project file before you build them

2.Please check if the entire error message you get looks like this:

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'.

Since your OutputPath property are defined in PropertyGroup for Debug|AnyCPU and Release|AnyCPU.If you haven't passed the corresponding parameters to msbuild.exe, the process can't read the OutPutPath property from these ProppertyGroups.

For example: You define the OutPutPath in Debug|AnyCPU and Release|AnyCPU. Then the real value of Configuration and Platform you pass is Debug|X86, or Null|AnyCPU or CustomDebug|AnyCPU, and you haven't defined OutPutPath in this kind of Combination(PropertyGroup), you'll get the error messgae xxx not set.

To resolve this: Make sure you pass the correct Configuration and Platform combination can resolve it. Or define OutPutPath in the Combination you actually use.

这篇关于从.sln en-asse到通配符构建的项目组到其各自的输出目录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆