Проблема конфигурации проекта msbuild и visual studio - PullRequest
2 голосов
/ 27 ноября 2009

У меня есть решение, содержащее множество проектов и инсталляторов. Один проект использует сторонний пакет. Пакет поставляется с собственной DLL и DLL-оболочкой .net. Чтобы код работал, DLL-оболочке .net необходимо найти собственную DLL во время выполнения. Но код никогда не ссылается непосредственно на нативную DLL во время компиляции (код обращается к DLL-оболочке .net во время компиляции).

Теперь мне нужно выбрать правильный способ развертывания собственной библиотеки DLL во время компиляции на компьютере программиста и во время установки на компьютере пользователя.

По сути, у меня есть два варианта: поместить собственную DLL в системную папку Windows или поместить собственную DLL в локальную папку, содержащую exe-файл.

Чтобы поместить собственную DLL в системную папку, мне нужен сценарий после сборки, чтобы скопировать файл в каталог после построения решения. Мне также нужно создать системную папку в проекте установщика, чтобы установщик мог работать на клиентском компьютере. Я не знаю, является ли копирование файлов в системную папку хорошей идеей или нет. Для этого решения каждый раз, когда кто-то (еще в большой команде) создает новый установщик, он или она должны помнить, что нужно создать выход системной папки и добавить собственную DLL в конфигурацию, в противном случае его установщик не установит работоспособную часть программное обеспечение на компьютере пользователя.

Чтобы поместить собственную DLL в локальную папку, у меня есть два следующих способа: 1. Используйте сценарий после сборки. В этом решении я должен найти каждый исполняемый проект в моем большом решении, в котором есть ссылка на проект с использованием собственной библиотеки DLL, и связать сценарий после сборки с каждым таким исполняемым проектом. В будущем, когда кто-то (еще в большой команде) создаст новый исполняемый проект того же типа, он или она должны помнить, чтобы связать тот же сценарий после сборки, иначе исполняемый файл не сможет найти нативную DLL , Это то, что мне действительно не нравится, люди склонны забывать.

  1. Я могу добавить собственную DLL в проект, который ее использует, и в конфигурации свойств библиотеки DLL установить «Копировать, если новее». Таким образом, нативная DLL будет скопирована в выходную папку проекта и в каждый проект, который ссылается на проект. Таким образом, мне не нужно ничего запоминать. Собственная DLL будет скопирована в локальную папку каждого зависимого проекта.

Это кажется хорошим решением. Но команда msbuild, похоже, не в состоянии справиться с этой ситуацией. Например, предположим, что проект A напрямую использует нативную DLL, и я добавляю нативную DLL в проект A. Проект B ссылается на проект A, а проект C ссылается на проект B и проект A. Если для построения решения используется msbuild, нативная DLL будет 3 раза копировал в выходную папку проекта C, один для ссылки на проект A, один для ссылки на проект B, один для ссылки на проект B на проект A. В моем большом решении, к концу ссылки зависимости, Собственная DLL будет многократно копироваться в одну и ту же выходную папку, независимо от значения параметра «Копировать, если новее». На создание решения в целом уходит огромное количество времени.

Теперь я совершенно не представляю, как лучше всего решить мою ситуацию. Для тех, кто использует собственные библиотеки DLL, как вы развертываете DLL, чтобы: 1. это удобно как для развертывания на компьютере разработчика (компиляция и запуск), так и на компьютере пользователя (установка и запуск), 2. разработчики в большой команде не имеют помнить что-либо, когда он или она добавляет новый проект / установщик в решение; 3. достаточно умный способ сборки, позволяющий избежать ненужных лишних действий. Спасибо за любую подсказку, учебник в Интернете, предложение или умное обучение заранее.

Ответы [ 6 ]

3 голосов
/ 08 декабря 2009

В общем, мы сделали все каталоги \ bin символическими ссылками на общий каталог. Это позволяет избежать всех транзитивных копий, которые VS делает для всех ссылок, и может ускорить чистую сборку большого решения с коэффициентом 10-20.

Мы используем следующий скрипт 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
}

Символьные ссылки требуют Vista или Win7; если в XP вместо этого можно использовать переходы, заменив вызов mklink вызовом junction.exe.

По умолчанию это должно быть выполнено от имени администратора.

1 голос
/ 07 декабря 2009

Стив,

Я постоянно добавляю нативные dll в свои проекты, и у меня не было проблем с добавлением dll в качестве контента в проект. На самом деле вы можете добавить необходимую DLL в качестве ссылки на проект, а не фактическое содержание. Таким образом, dll не будет скопирована ни в папку проекта, ни в целевую папку.

Вот объяснение от devx:

Чтобы добавить общий файл, откройте диалоговое окно выбрать существующий файл с Проект | Элемент меню Добавить существующий элемент и выберите файл, который вы хотите включают. Затем вместо нажатия Открыть кнопку, нажмите на стрелку на слева от этой кнопки, и нажмите ссылку Файл из списка, который выпадает. Таким образом, вы ссылаетесь на оригинал файл, а не его локальная копия.

Собираете ли вы все проекты в единую целевую директорию решения, т.е. \ bin \ debug? Это может сократить ненужные копии.

Добавление ссылки на проект в DLL определенно проще поддерживать, чем копирование в событии сборки.

1 голос
/ 02 декабря 2009

Для начала, избегайте использования событий после сборки, если нет другого выбора. События после сборки неуправляемой природы, как правило, дают сбой при сборке и имеют низкую ремонтопригодность.

Флаг «Копировать, если новее» может быть неэффективным, но он гарантирует, что: 1) требуемые зависимости будут скопированы в вывод 2) он не потерпит неудачу при сборке 3) практически не имеет возможности сопровождения.

Во-вторых, вы можете уменьшить избыточное копирование, установив только последний проект в цепочке сборки с флагом «Копировать, если новее», например: проект А напрямую ссылается на DLL, но не не копирует ее в вывод проект C косвенно ссылается на проект A через проект B и имеет фиктивную ссылку на библиотеку DLL с включенной функцией «Копировать, если новее».

0 голосов
/ 08 декабря 2009

Смотрите это сообщение: http://blog.alexyakunin.com/2009/09/making-msbuild-visual-studio-to.html

В нем объясняется, как автоматизировать копирование зависимостей N-го уровня в папку Bin.

Если у вас есть какая-то сборка, на которую нет ссылок даже косвенно, вы можете создать другую (например, MyProject.ThirdPartyMagnet), сослаться на эту сборку из этого проекта и сослаться на MyProject.ThirdPartyMagnet из проекта, который вам необходим для копирования всех сборок. к.

0 голосов
/ 08 декабря 2009

Лично я бы рассматривал собственную DLL и сборочную DLL как один объект. Добавление ссылки на файл является одним из способов. В качестве альтернативы вы можете использовать отдельный основной скрипт сборки, который массирует ваш проект и установщик.

Например, у меня есть файл Library.msbuild, который выполняет задачу MsBuild из источника .csproj в качестве цели Build. Моя цель Deploy использует задачу копирования, чтобы скопировать dll-файлы из source \ library \ LibraryName \ bin \ Configuration * .dll в library \ LibraryName. У меня есть одно расположение библиотеки для всех исходных файлов, которые мне нужно собрать, а другое - все бункеры, на которые ссылается мой основной проект.

Вот весь скрипт 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>  

` В вашем случае я бы переместил задачу Deploy copy в PreBuild или удалил ее полностью, чтобы зависеть от метода Add Existing, копирующего dll. Цель в том, чтобы при запуске \ отладке вашего проекта все было относительно. Вы даже можете иметь bin \ win32, если вы отделяете нативные от .NET DLL.

Каждая сборка теперь выполняется из пакетного файла .build.cmd (сборка в один клик), который просто так: C:\Windows\Microsoft.NET\Framework\v3.5\MSBuild Library.msbuild /t:Deploy. Вы можете добавлять больше целей в цепочку, например, тест после сборки, но перед развертыванием.

Если вы используете WiX или инсталлятор любого другого типа, вы должны иметь возможность использовать относительные пути для самих файлов. У меня есть каталог промежуточного уровня \, в который я без проблем могу войти из source \ install \ (.. \ .. \ staging \ icky, да, но работает). В худшем случае вы можете разместить свой промежуточный каталог где-нибудь внутри пути установки.

В большинстве случаев вы можете избежать необходимости абстрагировать MsBuild дальше, чем ваши файлы .csproj или .wixproj. Существует очень низкий потолок, с которым сталкивается Before / AfterBuild, но теперь я выбираю этот подход практически в любой ситуации.

0 голосов
/ 27 ноября 2009

В настройках вашего проекта должно быть что-то «изворотливое» (например, циклическая ссылка), чтобы вызвать бесконечный цикл копирования, но его обнаружение может быть сложным и / или трудоемким.

Две вещи, которые я бы попробовал:

  • Отключите «новый» флаг и посмотрите, как он повлияет на вашу проблему. Копирование одной dll вряд ли сильно повлияет на время сборки, и с этой опцией могут возникнуть проблемы, когда метки даты файла перепутаны. (Я не ожидаю, что это вызовет повторные попытки копирования)

  • Попробуйте использовать событие после сборки с xcopy, чтобы скопировать файл, а не полагаться на автоматическую систему. Тогда вы будете полностью контролировать простую систему, а не удивляться, почему умная система не работает.

...