3

我们有一个使用多个.sln 文件的代码项目,每个文件都包含项目(一些项目由不同的解决方案共享,即存在于多个解决方案中)。

我们的问题是,当使用项目引用时,实际项目也必须驻留在同一个解决方案中。

所有这些项目都是在构建服务器上使用 MSBuild 构建的。

我想知道是否可以创建一个 MSBuild 脚本,以某种方式将所有项目“导入”到单个 MSBuild 项目中,这样就好像所有项目实际上位于同一个 Visual Studio .sln 文件下一样?

例如,我想要类似于以下脚本的内容:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

    <!-- Builds all *.sln files under this repository. -->
    <ItemGroup>
        <SolutionFiles Include="**/*.sln" />
    </ItemGroup>

    <Target Name="Build">
        <MSBuild Projects="@(SolutionFiles)" Targets="Rebuild" />
    </Target>

</Project>

这是否意味着 MSBuild 将构建所有项目的内存中“主项目”,从而克服项目引用问题?

4

5 回答 5

2

为什么不直接使用上面的语法来构建 csprojs?

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

<!-- Builds all *.*proj files under this repository. -->
<ItemGroup>
    <!--SolutionFiles Include="**/*.sln" /-->
    <ProjectFiles Include="**/*.*proj"/>

</ItemGroup>

<Target Name="Build">
    <MSBuild Projects="@(ProjectFiles)" Targets="Rebuild" />
</Target>

</Project>

默认情况下,即使您在命令行模式下没有 sln 文件,MSBuild 也会构建项目引用。如果您想省略项目引用(即您正在按顺序连续构建事物),您可以使用 /p:BuildProjectReferences=false...

于 2012-12-31T20:30:56.553 回答
1

我做了类似的事情,只是在同一个文件夹中有多个 .sln 文件,所有这些文件都引用了部分或全部项目。就我而言,我为每种构建风格(CI、nightly、release 等)都有 .sln 文件。

因此,例如,您可能总共有以下项目:

  • 网站
  • 网站单元测试
  • 公共图书馆
  • 公共库单元测试
  • 数据访问库
  • 数据访问库单元测试
  • 网站验收测试(例如 Selenium webdriver 测试)
  • 压力测试

您可以有以下解决方案:

  1. CI 解决方案(在提交时运行)。这将引用单元测试项目及其目标

  2. 每晚解决方案(每晚运行)。这将参考压力和验收测试项目

  3. 发布解决方案(按需发布)。这将引用网站、通用和数据访问项目(即没有测试项目)

这只是一个简单的例子,但希望有所帮助。一旦设置了这个解决方案/项目结构,我不会看到太多要求它改变的呼声,但是如果添加了一个新项目,那么只需添加到相关的解决方案中就可以快速完成工作。

于 2012-12-30T08:20:19.050 回答
0

您可以编写小型控制台应用程序,该应用程序将找到所有解决方案文件并构建它们。它甚至会选择正确的 MSBuild 版本:

创建 c# 控制台应用程序

添加对 Microsoft.Build 的引用并使用以下代码

  static void Main(string[] args)
  {
     string[] files = Directory.GetFiles(args[0], "*.sln", SearchOption.AllDirectories);

     foreach (string path in files)
     {
        RunMsBuild(path);
     }
  }

  public static void RunMsBuild(string SrcDir)
  {
     ProjectCollection pc = new ProjectCollection();
     Dictionary<string, string> GlobalProperty = new Dictionary<string, string>();

     //GlobalProperty.Add("Configuration", "Debug");
     //GlobalProperty.Add("Platform", "x86");
     //GlobalProperty.Add("OutputPath", "c:\\src");

     BuildRequestData buidlRequest = new BuildRequestData(SrcDir, GlobalProperty, null, new string[] { "Build" }, null);
     BuildResult buildResult = BuildManager.DefaultBuildManager.Build(new BuildParameters(pc), buidlRequest);
     if (buildResult["Build"].ResultCode == TargetResultCode.Success)
     {
        Console.WriteLine("Build Success");
     }
     else
     {
        Console.WriteLine("Build Fail");
     }
  }

之后,您可以从控制台或脚本运行它,并将搜索解决方案文件的路径作为参数传递

于 2012-12-30T17:55:07.297 回答
0

**没关系,我错过了下面的答案,项目包括命令行模式**

这将是不容易或漂亮。但是,如果您真的想像您所要求的那样采用更“全面”的构建自动化和管理路线,那么下面的#4 是如何开始变得更好的。

1)在 OP 示例中,使用 MSBuild 作为脚本:在您的示例中,这更像是一种自动化,就像使用 shell 或批处理文件一样,而不是真正让您获得任何 MSBuild 项目技巧。请参阅关于 .sln 规则的#2,以及关于我认为您希望这样做更多的事情的#3,但这会起到其他作用。

2)关于“仅记忆” .sln 问题:从根本上说,我相信如果您希望 MSBuild 使用 .sln 来解决基于 .sln 的项目引用,那么它不能处于“零影响”或“仅内存”状态,并且必须被刷新或保存到磁盘。即使您拥有项目系统本身也是如此,因为 MSBuild 将查看文件本身以获取解析引用,并期望它在文件系统中,因为它在单独的进程中运行,并且有自己的想法。因此,如果您想使用 .sln 文件,则必须有实际的 .sln 文件。因此,对没有 .sln 文件的 .sln 方法的希望是正确的。如果您运行 VS 来运行 msbuild,它将生成这些,并且需要在 MSBuild 启动之前将它们刷新到磁盘,在那里它们将保持“零影响”状态直到构建......只是为了完全详细和清晰。

3)关于“import .proj”问题:我知道的一个类似的选项,<Import Project="my/proj/path/mine.csproj"/>就像是文件的批量包含,它将这些文件视为外部项目的一部分并编译为那个大会。经常被 microsft 内部使用。以这种方式使用的导入忽略了导入的 .proj 文件中的大部分内容,并且基本上是在寻找要包含的文件,就像外部项目中包含的任何其他文件一样。所以我认为这不会让你走得更远,除非你打算在同一个程序集中构建所有这些。如果你这样做,你将不得不以这种意图来构建包含的 .proj 文件,并滥用/构建外部以包含一切所需的引用等等。

4)它的参考定义。关于引用有很多选项,它们是否被复制,将被假定放置在 GAC 中,或者“只是不做任何事情,相信我他们会在运行时出现在应用程序域搜索路径中”。您可以关闭大部分 cr*p,然后您唯一的依赖是构建和语言编译器能够解析其类型和 whatnbot 的引用程序集,以便编译您当时尝试编译的依赖程序集. 如果您考虑一下,您会发现很多其他参考资料不是您自己构建的,而是构建时会拾取并用于编译的。所以真正的问题可能是,“我如何让我的自动化构建处于我编译依赖项的状态,并且看起来像任何其他参考?”

由于您控制构建,因此您可以控制 dll 的放置,并且可以负责构建顺序。而且...您可以控制引用。

这是剩下的经典问题:在设计时,如果引用指向 .sln 项目,那么您无需构建即可从外部程序集中获得类型的设计时查找,如果您将项目更改为不可知论,那么您将拥有编译。您可以在许多方面做一些棘手的事情,包括条件性 .proj 文件,这会给开发人员带来负担,并且可能需要手动编辑以保持同步,或者通过脚本预先构建 .proj 文件过滤器以修复引用,或制作它们是非 sln 引用并强制开发人员构建依赖项以解析类型,他们必须确保他们使用的环境与构建保持一致。


所以问题归结为引用是如何定义的,是的,MSBuild 所需的任何内容都需要写入磁盘以供 MSBuild 运行,而与 VS 本身无关。你必须选择你的毒药,因为问题是你不能同时定义两种方式的引用。这是一个经典的构建管理问题,你并不孤单。

于 2013-01-03T21:05:01.927 回答
0

我们需要在 TFS (Azure DevOps) 中组合几个 .csproj 文件,但在我们的标准构建/部署中排除其他文件。我最终得到了以下 .proj 文件。重要的是

  • 在 Microsoft 的示例中,目标使用<MSBuild ...而不是like<CSC
  • 我需要包含Targets="..."每个构建操作(构建、重建、清理、恢复)

我最终得到了一个看起来像的文件

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <ProjectReference Include="one.csproj" />
    <ProjectReference Include="two.csproj" />
    <ProjectReference Include="three.csproj" />
  </ItemGroup>
  <Target Name="Build">
    <MSBuild Projects="@(ProjectReference)" Targets="Build" />
  </Target>
  <Target Name="Clean">
    <MSBuild Projects="@(ProjectReference)" Targets="Clean" />
  </Target>
  <Target Name="Rebuild">
    <MSBuild Projects="@(ProjectReference)" Targets="Rebuild" />
  </Target>
  <Target Name="Restore">
    <MSBuild Projects="@(ProjectReference)" Targets="Restore" />
  </Target>
</Project>
于 2020-04-23T15:17:35.123 回答