简体   繁体   English

msbuild和Visual Studio项目配置问题

[英]msbuild and visual studio project configuration problem

I have a solution containing a lot of projects and installer projects. 我有一个包含很多项目和安装程序项目的解决方案。 One project uses a third party package. 一个项目使用第三方程序包。 The package comes with a native DLL and a .net wrapper DLL. 该软件包带有一个本机DLL和.net包装器DLL。 In order for the code to work, the .net wrapper DLL needs to find the native DLL in runtime. 为了使代码正常工作,.net包装器DLL需要在运行时查找本机DLL。 But the code never directly refers to the native DLL in compile time (the code talks to .net wrapper DLL in compile time). 但是代码在编译时从不直接引用本机DLL(代码在编译时与.net包装器DLL通信)。

Now I have to choose proper way to deploy the native DLL, during compile time on a programmer's machine and during installing time on a user machine. 现在,我必须在程序员的计算机上的编译期间以及在用户计算机上的安装期间选择适当的方法来部署本机DLL。

Basically I have two options, either to put the native DLL to Windows System folder or to put the native DLL in the local folder containing the exe file. 基本上,我有两个选择,要么将本机DLL放入Windows System文件夹,要么将本机DLL放入包含exe文件的本地文件夹。

To put the native DLL to system folder, I need a post-build script to xcopy the file to the directory after building the solution. 要将本机DLL放入系统文件夹,在构建解决方案后,我需要一个后构建脚本来将该文件xcopy到目录中。 I also need to create a System Folder output in installer project for installer to work on a client machine. 我还需要在安装程序项目中创建系统文件夹输出,以便安装程序在客户端计算机上工作。 I don't know whether copying files to system folder is a good idea or not. 我不知道将文件复制到系统文件夹是否是个好主意。 For this solution, every time someone (else in the big team) creates a new installer, he or she has to remember to create System Folder output and add the native DLL under the configuration otherwise his or her installer will not install a workable piece of software on a user machine. 对于此解决方案,每次(大团队中的其他人)创建新的安装程序时,他或她都必须记住创建系统文件夹输出并在配置下添加本机DLL,否则他或她的安装程序将无法安装用户计算机上的软件。

To put the native DLL to local folder, I have the following two ways: 1. Use a post-build script. 要将本机DLL放入本地文件夹,我有以下两种方式:1.使用后期生成脚本。 This solution, I have to find out every executable project in my big solution that has a reference to the project using the native DLL and link the post-build script to every such executable project. 此解决方案必须在我的大型解决方案中找出每个使用本机DLL对该项目进行引用的可执行项目,并将构建后脚本链接到每个此类可执行项目。 In the future, when someone (else in the big team) creates a new executable project with the same kind, he or she has to remember to link the same post-build script otherwise the executable wouldn't be able to find the native DLL. 将来,当某人(其他人在大团队中)创建相同类型的新可执行项目时,他(或她)必须记住链接相同的构建后脚本,否则可执行文件将无法找到本机DLL。 。 This is what I really don't like, people tend to forget. 这是我真正不喜欢的,人们往往会忘记。

  1. I can add the native DLL to the project that uses it and in the DLL's property configuration, set it to "Copy If Newer". 我可以将本机DLL添加到使用它的项目中,并在DLL的属性配置中将其设置为“ Copy If Newer”。 This way, the native DLL will be copied to the project's output folder and to every project that refers to the project. 这样,本机DLL将被复制到项目的输出文件夹以及引用该项目的每个项目中。 This way, I don't have to remember anything. 这样,我不必记住任何东西。 The native DLL will be copied to the local folder of every dependent project. 本机DLL将被复制到每个相关项目的本地文件夹中。

This seems a good solution. 这似乎是一个很好的解决方案。 But msbuild command seems not being able to handle this situation cleverly. 但是msbuild命令似乎不能巧妙地处理这种情况。 For example, suppose project A directly uses native DLL and I add the native DLL to project A. Project B refers to project A and project C refers to project B and project A. if using msbuild to build the solution, the native DLL will be copied repeatedly to the output folder of project C 3 times, one for reference to project A, one for reference to project B, one for reference of project B to project A. In my big solution, towards the end of the dependency link, the native DLL will be copied exponentially many times to the same output folder, regardless of the "Copy If Newer" setting. 例如,假设项目A直接使用本机DLL,并且我将本机DLL添加到项目A。项目B指代项目A,项目C指代项目B和项目A。如果使用msbuild生成解决方案,则本机DLL将是重复复制3次到项目C的输出文件夹,一次复制到项目A,一次复制到项目B,一次复制到项目B,复制到项目A。在我的大型解决方案中,依赖项链接的末尾无论“复制较新”设置如何,本机DLL都会以指数方式多次复制到同一输出文件夹。 This takes up tremendous amount of time to build the whole solution. 这将花费大量时间来构建整个解决方案。

Now I totally have no idea what is the best solution for my situation. 现在我完全不知道什么是最适合我的情况的解决方案。 For anyone who uses native DLLs, how do you deploy the DLL so 1. it is convenient for both deploying on developer machine (compile and run) and on user machine (install and run), 2. developers in big team don't have to remember anything when he or she adds new project/installer to the solution, 3. smart enough build manner that avoids unnecessary redundant actions. 对于使用本机DLL的任何人,您如何部署DLL,因此1.既方便在开发人员机器(编译并运行)和用户计算机(安装并运行)上进行部署,2.大型团队中的开发人员没有在他或她向解决方案添加新项目/安装程序时记住任何东西,3.足够聪明的构建方式,避免了不必要的重复操作。 Thank you for any hint, tutorial on Web, suggestion or clever teach in advance. 谢谢您的任何提示,网上教程,建议或提前的聪明教导。

What we've done in general is to make all \\bin directories into symlinks to a common directory. 通常,我们要做的是使所有\\ bin目录都成为指向公共目录的符号链接。 This avoids all the transitive copies that VS does for all references, and can speed up a clean build of a large solution up to a factor of 10-20. 这样可以避免VS对所有引用所做的所有传递副本,并且可以将大型解决方案的全新构建速度提高到10-20倍。

We use the following powershell script to set up the symlinks: 我们使用以下powershell脚本来设置符号链接:

param($linkTarget={throw "Link target must be specified"}, $rootDir=".")

ls $rootDir -Recurse -Include *.csproj | % { $_.DirectoryName } | % { Join-Path $_ -ChildPath "bin" } | % {

  Write-Host "Creating link from $_ to $linkTarget"
  if (Test-Path $_)
  {
    Remove-Item -Force -Recurse $_
    cmd /c rd $_
  }

  cmd /c mklink /D $_ $linkTarget
}

Symbolic links require Vista or Win7; 符号链接需要Vista或Win7。 if on XP, junctions can be used instead by replacing the call to mklink with a call to junction.exe. 如果在XP上,可以通过将对mklink的调用替换为对junction.exe的调用来代替使用结点。

By default, this must be run as administrator. 默认情况下,它必须以管理员身份运行。

For starters, avoid using post build events unless there's no other choice. 对于初学者,除非没有其他选择,否则避免使用构建后事件。 Post build events unmanaged nature tend to fail builds and have low maintainability. 生成后事件不受管理的性质往往会使生成失败并且可维护性较低。

"Copy If Newer" flag may have lame effectiveness, but it will assure you that: 1) the required dependencies will be copied to output 2) it won't fail the build 3) has virtually no maintainability. “如果较新则复制”标志可能有些la脚,但可以向您保证:1)所需的依赖项将被复制到输出2)它不会使构建失败3)实际上没有可维护性。

Secondly, you can reduce redundant copying by setting only the last project in the build chain with the "Copy If Newer" flag, eg: project A directly refers the DLL but does not copy it to output, project C refers indirectly to project A through project B, and has dummy reference to the DLL with "Copy If Newer" enabled. 其次,可以通过仅使用“ Copy If Newer”标志设置构建链中的最后一个项目来减少冗余复制,例如:项目A直接引用DLL但将其复制到输出,项目C通过以下方式间接指向项目A项目B,并且具有对DLL的虚拟引用,并启用了“如果更新则复制”。

Steve, 史蒂夫,

I add native dlls to my projects all the time and I haven't had a problem with adding the dll as content to the project. 我一直都将本机dll添加到我的项目中,而将dll作为内容添加到项目中并没有问题。 You can actually add the necessary dll as a project link rather than actual content. 您实际上可以将必要的dll添加为项目链接,而不是实际内容。 This way, the dll will not be copied into the project folder as well as into the target folder. 这样,dll将不会被复制到项目文件夹以及目标文件夹中。

Here's an explanation from devx: 这是devx的解释:

To add a shared file, open the dialog to select an existing file with the Project | 要添加共享文件,请打开对话框以使用“项目” |“选择”来选择现有文件。 Add Existing Item menu item and select the file you want to include. 添加现有项菜单项,然后选择要包括的文件。 Then, instead of clicking the Open button, click the arrow on the left of that button, and click Link File from the list that drops down. 然后,不要单击“打开”按钮,而是单击该按钮左侧的箭头,然后从下拉列表中单击“链接文件”。 This way you link to the original file, not to a local copy of it. 这样,您可以链接到原始文件,而不是其本地副本。

Do you build all the projects into a common solution target directory, ie ..\\bin\\debug? 您是否将所有项目都构建到公共解决方案目标目录中,即.. \\ bin \\ debug? This may curtail unnecessary copies. 这可能会减少不必要的副本。

Adding the project link to the dll is definitely easier to maintain than copying in a build event. 将项目链接添加到dll绝对比在构建事件中复制要容易维护。

There must be something "dodgy" in your project setup (like a circular reference) to cause an infinite copy loop - but finding it could be tricky and/or time consuming. 在项目设置中必须有一些“狡猾”的东西(例如循环引用)来引起无限的复制循环-但是找到它可能很棘手和/或很耗时。

Two things I would try: 我会尝试两件事:

  • Turn off the "newer" flag and see if it has any effect on your problem. 关闭“较新”标志,看看它是否对您的问题有影响。 Copying a single dll is unlikely to impact build times very much, and problems can come about with this option when file datestamps get confused. 复制单个dll不太可能极大地影响构建时间,并且当文件的日期戳不清时,使用此选项可能会出现问题。 (I wouldn't expect this to cause repeated copy attempts though) (我不希望这会导致重复的复制尝试)

  • Try using a post-build event with xcopy to copy the file instead of relying on the automatic system. 尝试对xcopy使用构建后事件来复制文件,而不要依赖自动系统。 Then you'll be in full control of a simple system instead of wondering why a clever system doesn't work. 然后,您将完全控制一个简单的系统,而不用担心为什么一个聪明的系统不起作用。

Personally, I'd treat the native DLL and assembly DLL as one entity. 我个人将本机DLL和程序集DLL视为一个实体。 Adding a Link to the file is one way. 将链接添加到文件是一种方法。 Alternatively, you could have a separate main build script that massages your project and installer. 或者,您可以有一个单独的主构建脚本,以完善您的项目和安装程序。

For instance, I have a Library.msbuild file that runs a MsBuild task of a source .csproj as my Build target. 例如,我有一个Library.msbuild文件,该文件运行源.csproj的MsBuild任务作为构建目标。 My Deploy target uses a copy task to copy the dlls from source\\library\\LibraryName\\bin\\Configuration*.dll to library\\LibraryName. 我的部署目标使用复制任务将dll从source \\ library \\ LibraryName \\ bin \\ Configuration * .dll复制到library \\ LibraryName。 I have one library location for all the source files I need to build and the other is all the bins that my main project references. 对于我需要构建的所有源文件,我都有一个库位置,另一个是主项目引用的所有bin。

Here's the entire Library.msbuild script:` 这是整个Library.msbuild脚本:

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup>
        <Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
        <ProjectDirectory>library\AspNetMvc\DataAnnotationsModelBinder\src</ProjectDirectory>
        <LibraryDirectory>..\library\AspNetMvc</LibraryDirectory>
    </PropertyGroup>
    <ItemGroup>
       <CompiledBinaries Include="$(ProjectDirectory)\bin\$(Configuration)\*.dll" />
    </ItemGroup>

    <Target Name="Clean">
        <MSBuild Projects="$(ProjectDirectory)\Microsoft.Web.Mvc.DataAnnotations.csproj"
        Targets="Clean" Properties="Configuration=$(Configuration)" />
    </Target>

    <Target Name="PreBuild" DependsOnTargets="Clean">
    </Target>

    <Target Name="Build" DependsOnTargets="PreBuild">
        <MSBuild Projects="$(ProjectDirectory)\Microsoft.Web.Mvc.DataAnnotations.csproj"
        Targets="Build" Properties="Configuration=$(Configuration)" />
    </Target>

    <Target Name="Deploy" DependsOnTargets="Build">
        <Copy SourceFiles="@(CompiledBinaries)" DestinationFolder="$(LibraryDirectory)"/>
    </Target>
</Project>  

` In your instance, I would move the Deploy copy task to PreBuild or remove it entirely to depend on the Add Existing method copying the dll. 在您的实例中,我将Deploy复制任务移至PreBuild或完全删除它,以依赖于复制dll的Add Existing方法。 The goal is that when you run\\debug your project that everything will be bin relative. 目的是当您运行\\调试项目时,所有内容都是相对于bin的。 You could even have bin\\win32 if you're separating native from .NET DLLs. 如果要从.NET DLL中分离本机,甚至可以使用bin \\ win32。

Every build is now done from a .build.cmd batch file (1-click build) that is simply this: C:\\Windows\\Microsoft.NET\\Framework\\v3.5\\MSBuild Library.msbuild /t:Deploy . 现在,每个构建都是通过.build.cmd批处理文件(一键生成)完成的,该文件就是这样: C:\\Windows\\Microsoft.NET\\Framework\\v3.5\\MSBuild Library.msbuild /t:Deploy You're free to add more targets in the chain like test after build but before deploy. 您可以自由地在构建后但部署之前在测试中添加更多目标,例如测试。

If you are using WiX or any other type of installer, you should be able to use relative paths for the files themselves. 如果您使用的是WiX或任何其他类型的安装程序,则应该能够为文件本身使用相对路径。 I have a top-level staging\\ directory that I have no problem getting into from source\\install\\ (..\\..\\staging\\ icky, yes but works). 我有一个顶级的staging \\目录,从source \\ install \\(.. \\ .. \\ staging \\ icky,是的,没问题,但是可以使用)进入。 Worst case you can place your staging directory somewhere inside the install path. 最坏的情况是,您可以将登台目录放置在安装路径内的某个位置。

In most instances you can get away with not having to abstract MsBuild further than your .csproj or .wixproj files. 在大多数情况下,您不必摆脱.csproj或.wixproj文件的抽象MsBuild所困扰。 There's a very low ceiling that Before/AfterBuild runs into but I find myself opting for this approach in almost every situation now. 之前/之后构建遇到一个非常低的上限,但是我发现自己现在几乎在每种情况下都选择这种方法。

See this post: http://blog.alexyakunin.com/2009/09/making-msbuild-visual-studio-to.html 看到这个职位: http : //blog.alexyakunin.com/2009/09/making-msbuild-visual-studio-to.html

It explains how to automatize copying of N-th level dependencies into Bin folder. 它说明了如何自动将第N级依赖项复制到Bin文件夹中。

If you have some assembly, that isn't referenced even indirectly, you can create another one (eg MyProject.ThirdPartyMagnet ), reference this assembly from this project and reference MyProject.ThirdPartyMagnet from the project you need to copy all the assemblies to. 如果您有一些甚至没有间接引用的程序集,则可以创建另一个程序集(例如MyProject.ThirdPartyMagnet ),从该项目中引用该程序集,并从需要将所有程序集复制到其中的项目中引用MyProject.ThirdPartyMagnet

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM