2009-11-27 3 views
2

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

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

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

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

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

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

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

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

ответ

3

В общем, мы сделали все каталоги \ 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.

По умолчанию это должно запускаться как администратор.

+0

Одно предостережение: никогда не запускайте этот скрипт с относительным путем в качестве цели ссылки. Боль будет следовать. – ArildF

0

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

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

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

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

+0

Пост-сборка определенно может помочь. Но таким образом, каждый раз, когда я добавляю новый проект в решение, зависящее от проекта, содержащего родную DLL, мне нужно добавить новую копию в сценарий пост-сборки. Более того, даже сейчас у меня более десятка проектов, создание такого скрипта уже достаточно утомительно. – Steve

1

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

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

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

1

Стив,

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

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

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

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

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

+0

Hi Soctt, я никогда не пытаюсь связать родную DLL. Я попробую. Когда вы создаете установщик своего программного обеспечения, я думаю, вы должны поместить dll в проект установщика. Затем местоположение dll может быть изменено между временем разработки и временем установки. Как вы держите ссылку, указывающую на правильное местоположение? – Steve

+0

Steve. Если я понимаю ваш вопрос, я думаю, что если вы связали dll в своем проекте, он должен быть скопирован в проект развертывания как зависимость. Вам не нужно перемещать dll в system32, если вы этого не хотите. Если вы этого захотите, вам нужно будет изменить проект развертывания. Я мог бы отключиться от этого, поскольку я обычно использую Installshield и явно определяю все файлы, которые будут установлены, и их целевые местоположения ... –

0

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

Например, у меня есть файл Library.msbuild, который запускает задачу MsBuild источника .csproj как мою цель сборки. Цель My Deploy использует задачу копирования для копирования DLL из библиотеки \ Library \ LibraryName \ bin \ Configuration * .dll в библиотеку \ 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 скопировать задачу PreBuild или удалить его полностью зависит от метода Add Existing переписывающей DLL. Цель состоит в том, что при запуске \ debug вашего проекта все будет относиться к бину. У вас может даже быть bin \ win32, если вы отделяете родные от .NET DLL.

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

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

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

0

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

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

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

Смежные вопросы