【问题标题】:Visual studio one project with several dlls as output?Visual Studio 一个项目有几个 dll 作为输出?
【发布时间】:2010-10-05 19:43:20
【问题描述】:

我正在编写一个支持插件的项目。 由于许多插件相对较小(只有一个源文件/类),我希望将它们全部放在 Visual Studio 的一个项目中,但要成功做到这一点,我需要将每个源文件/类编译成它的自己的dll文件,这可以使用Visual Studio吗?

如果 Visual Studio 无法做到这一点,是否可以使用另一个构建系统,同时仍使用 Visual Studio 进行编码和调试?

目前我已经将插件项目的输出类型设置为控制台,并编写了一个 main() 方法,它将源目录中的所有 .cs 文件编译为 dll 并将它们复制到正确的目录中。然后我将该控制台应用程序设置为插件项目的构建后事件。它有效,但它看起来像一个非常丑陋的黑客。

使用 Visual Studio 2010。

【问题讨论】:

    标签: c# visual-studio


    【解决方案1】:

    您可以为每个插件创建一个项目并将所有项目分组到一个解决方案中。

    如果您不想每个插件有一个项目,您可以使用 CSC task 使用 MSBuild 创建自定义构建

    如何为每个插件文件生成一个dll

    1. 在项目中添加所有插件文件

    2. 编辑项目文件以指定哪个类将生成插件库:

      <ItemGroup>
        <Compile Include="Class1.cs">
          <Plugin>true</Plugin>
        </Compile>
        <Compile Include="Class2.cs" />
        <Compile Include="Class3.cs">
          <Plugin>true</Plugin>
        </Compile>
        <Compile Include="Program.cs" />
        <Compile Include="Properties\AssemblyInfo.cs" />
      </ItemGroup>
      
    3. 在您的项目文件中添加一个新目标以生成插件库

      <Target Name="BuildPlugins">
        <CSC Condition="%(Compile.Plugin) == 'true'"
             Sources="%(Compile.FullPath)"
             TargetType="library"
             OutputAssembly="$(OutputPath)%(Compile.FileName).dll"
             EmitDebugInformation="true" />
      </Target>
      
    4. 如果您想在每次构建后创建插件库,请添加构建后目标:

      <Target Name="AfterBuild" DependsOnTargets="BuildPlugins">
      </Target>
      

    【讨论】:

    • 嘿,谢谢你的回答......它解决了我一半的问题。但我想要那些新生成的 DLL 的版本号和其他与组装相关的信息,并且还想将多个文件组合在一个 dll 中,而不是单个文件。如果有人知道同样的情况,请提供帮助......对我有很大帮助......
    • 简直太棒了,你从哪里得到所有这些知识?太好了,太好了,正是我想要的
    • 结果是否只是多文件汇编?我可以将任何结果 dll(没有清单)作为参考单独添加到另一个项目吗?
    • 这是很棒的逻辑,但如果我的项目有其他项目的参考,我会遇到困难。请提供我编译该项目的想法。
    • 正如其他人所提到的 - 当项目引用同一解决方案中的另一个项目时,这不起作用......
    【解决方案2】:

    您只需create a Solution,然后添加您想要的任意数量的项目。

    您可以拥有 5 个 Class Library 项目并编译它们,生成 5 个 DLL。

    【讨论】:

    • 是的,但是创建 10 个项目,每个项目都有一个源文件似乎是一种可怕的浪费,我希望有一种方法可以将一个项目中的所有源文件编译成单独的 dll。跨度>
    • Project 和 AssemblyInfo 文件可能浪费了几千字节?尊敬的,我们在这里谈论的是虚假经济。这就是项目 for 的目的,将源代码封装到程序集中。 :)
    • 所以没有适合你的方法!
    【解决方案3】:

    为了扩展 Julien Hoarau 的上述回答,这里有一个解决方案,允许您从单个项目中编译多个 DLL 文件,并从多个 CS 文件中编译这些 DLL 文件。只需打开您的 csproj 文件并将其添加到 标记之前:

      <!-- Plugin Building -->
      <!-- 1. Hardlink to NuGet References - CSC does not read HintPaths, so you will have to create these for all your packages -->
      <ItemGroup>
        <PluginReference Include="..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll" ><InProject>false</InProject></PluginReference>
        <PluginReference Include="..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll" ><InProject>false</InProject></PluginReference>
        <PluginReference Include="..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll" ><InProject>false</InProject></PluginReference>
        <PluginReference Include="..\packages\Microsoft.AspNet.Web.Optimization.1.1.3\lib\net40\System.Web.Optimization.dll" ><InProject>false</InProject></PluginReference>
        <PluginReference Include="..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll" ><InProject>false</InProject></PluginReference>       
      </ItemGroup>
      <!-- 2. Each Plugin CS Files -->
      <!-- You see that each tag in here has it's own name starting with Plugin -->
      <!-- We can reference that later e.g. as @(PluginBlue) to get an array list to pass to the CSC sources, allowing us to have multiple files -->
      <!-- Plugin.Blue\**\*.cs gets all the files in the "Plugin.Blue" folder -->
      <!-- Plugin.Green just has a specific file list -->
      <ItemGroup>
        <PluginBlue Include="Plugin.Blue\**\*.cs"><InProject>false</InProject></PluginBlue>
        <PluginGreen Include="Plugin.Green\File1.cs"><InProject>false</InProject></PluginGreen>
        <PluginGreen Include="Plugin.Green\File2.cs"><InProject>false</InProject></PluginGreen>
      </ItemGroup>
      <!-- 3. Build each Plugin -->
      <Target Name="BuildPlugins">
        <!-- Plugin Blue -->
        <CSC Sources="@(PluginBlue)" References="@(PluginReference)" TargetType="library" OutputAssembly="$(OutputPath)Plugin.Blue.dll" EmitDebugInformation="true" />
        <!-- Plugin Green -->
        <CSC Sources="@(PluginGreen)" References="@(PluginReference)" TargetType="library" OutputAssembly="$(OutputPath)Plugin.Green.dll" EmitDebugInformation="true" />
      </Target>
    
      <!-- 4. Require Build on Solution Compile -->
      <Target Name="AfterBuild" DependsOnTargets="BuildPlugins">
      </Target>
    

    这是我的方法 - 它可以让您将所有内容组织在底部,而不是分散在整个项目文件中。使用

    <InProject>false</InProject>
    

    允许我们从 SolutionExplorer 中隐藏文件,并拥有一个单独定义的文件列表,而不是简单地将插件标签添加到我们想要的文件中。在您的主解决方案中,请务必将您在插件中编译的所有文件的 Build Action 设置为“none”,这样主项目文件中就不会出现重复。

    更多关于 CSC 的阅读:

    https://msdn.microsoft.com/en-us/library/78f4aasd.aspx 使用 csc.exe 构建命令行

    https://msdn.microsoft.com/en-us/library/ms379563(v=vs.80).aspx 使用 C# 2.0 命令行编译器

    https://msdn.microsoft.com/en-us/library/s5c8athz.aspxCsc 任务

    https://msdn.microsoft.com/en-us/library/7szfhaft.aspx MSBuild 条件

    我希望这对某人有用。

    【讨论】:

    • 注册工具告诉我密钥文件不包含,当我尝试将密钥文件添加到项目文件时出现错误:无法打开元数据文件'mykey.snk' -- PE 映像不包含托管元数据。我该如何解决这个问题?
    【解决方案4】:

    一些诗歌:

    就我而言-我需要专门为unit test 项目构建插件dlls。如果您以“正常方式”为每个插件创建单独的项目,那么您最终将拥有更多与核心程序集相比,单元测试相关的项目。所以我认为在某些情况下,值得在同一个项目中进行多重构建。话虽如此 - 我想提供已接受答案的改进版本。

    新方法改进:

    • 支持新的 SDK 项目(用于 .net Core)
    • 支持构建引用解决方案中其他项目的程序集!

    新建一个空库项目,确保结构如下:

    <Project Sdk="Microsoft.NET.Sdk">
      <PropertyGroup>
        <TargetFramework>net472</TargetFramework>
      </PropertyGroup>
    </Project>
    

    提示:您可以创建 .Net core 项目并将目标更改为 net472,例如。

    如果需要,添加一个插件和一些参考,然后,根据以下文档,添加: https://docs.microsoft.com/en-us/dotnet/core/tools/csproj

    <EnableDefaultCompileItems>false</EnableDefaultCompileItems>
    

    这将使手动包含用于构建的文件成为可能。否则构建将默认包含所有文件。

    然后显式添加要编译的项:

    <ItemGroup>
    <Compile Include="TestApp1.cs">
      <Plugin>true</Plugin>
    </Compile>
    </ItemGroup>
    

    然后,如以下来源中所述 - 您可以将所有引用聚合到一个字符串中:How to get paths to all referenced DLLs in MSBuild?

      <Target Name="GatherReferences" DependsOnTargets="ResolveReferences">
        <ItemGroup>
          <MyReferencedAssemblies Include="@(ReferencePath)" />
        </ItemGroup>
      </Target>
    

    测试:

      <Target Name="TestMessage" AfterTargets="Build" >
        <Message Text="Referenced assemblies: @(ReferencePath)" Importance="high"/>
      </Target>
    

    然后你必须附加一个在 PostBuild 上触发的构建目标:

      <Target Name="BuildPlugins" AfterTargets="PostBuildEvent">
        <CSC Condition="%(Compile.Plugin) == 'true'"
             Sources="%(Compile.FullPath)"
             TargetType="library"
             References="@(ReferencePath)"
             OutputAssembly="$(OutputPath)%(Compile.FileName).dll"
             EmitDebugInformation="true" />
      </Target>
    

    您会注意到这里的区别是 References 属性,它基本上将值转换为 CSC 编译器的适当 -reference 参数:https://docs.microsoft.com/en-us/visualstudio/msbuild/csc-task?view=vs-2019

    奖励:您可以将此逻辑合并到您的项目中,即使无需明确定义 Plugin 属性..

    这里根据这个话题:MsBuild Condition Evaluate Property Contains

    可以在构建元数据上使用正则表达式:https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-well-known-item-metadata?view=vs-2019

    所以基本上,这样的事情是允许的:

    Condition="$([System.Text.RegularExpressions.Regex]::IsMatch('%(Compile.Filename)', 'Plugin'))"
    

    您可以这样做,如果类文件名包含特定关键字,那么您可以触发对此类文件的单独编译。或者如果文件位于特定位置文件夹!在上面的示例中,如果文件中包含单词“Plugin”,那么它将被 CSC 任务拾取。我建议检查元数据页面以查看所有选项。

    奖励:如果您像我一样喜欢能够进入代码并能够输出到Debug 输出窗口,您还可以定义:

      DefineConstants="DEBUG;TRACE"
      DebugType="full"
    

    我的最新配置如下:

      <Target Name="BuildPlugins" AfterTargets="PostBuildEvent">
        <CSC 
          Condition="$([System.Text.RegularExpressions.Regex]::IsMatch('%(Compile.FullPath)', '.*\\AppUnitTests\\Plugins\\.*.cs'))"
          Sources="%(Compile.FullPath)" 
          TargetType="library" 
          References="@(ReferencePath)"
          OutputAssembly="$(OutputPath)Plugins\%(Compile.FileName).dll" 
          EmitDebugInformation="true"
          DefineConstants="DEBUG;TRACE"
          DebugType="full" />
      </Target>
    

    希望它对某人有用;)

    附言感谢原作者提供了一个我可以改进的例子。

    【讨论】:

      【解决方案5】:

      如果您希望每个代码文件都是它自己的 DLL,那么您必须为每个代码文件创建一个新项目。但是您可以将多个项目文件 (.csproj) 放入一个大型解决方案中。

      如果这不适合您,那么您始终可以使用命令行编译您的项目。这将允许您自定义构建以满足您的需求。例如,您可以编写一个批处理脚本或一个将所有代码文件编译成单独的 DLL 的 powershell 脚本。

      【讨论】:

      • 请张贴示例和/或链接与您的答案,告诉人们该做什么,但不知道如何不是这个网站的目的。
      猜你喜欢
      • 2018-04-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-22
      • 1970-01-01
      • 1970-01-01
      • 2015-06-22
      相关资源
      最近更新 更多