Наверное, каждому программисту, знакомому с системой построения проектов MsBuild, приходила в голову идея не заниматься расширением существующего процесса построения, а придумать его «с нуля». Иными словами, добавить в существующим типам проектов .csproj (проект на C#) и .vbproj (проект на VB.NET) еще один тип (например, .myproj или просто .proj). А кто-то, может быть, даже пытался эту идею реализовать.
По этой теме, казалось бы, полно информации, есть даже пошаговое руководство на MSDN. Но, после создания файла проекта по любому подобному руководству, становится понятно, что нас жестоко обманули — созданные таким образом проекты живут «сами по себе» и не могут быть ни включены в решение, ни открыты в Visual Studio.
В этой статье я представляю вам собственное исследование на эту тему.
В целях определения минимальных требований, налагаемых на «обычные» в понимании Visual Studio 2008 проекты, создать проект, который:
Процесс решения данной задачи довольно сложен, и потому выходит за рамки данной статьи. Скажу лишь, что в процессе решения использовались следующие инструменты:
Следующий файл проекта удовлетворяет всем требованиям (и пригоден к дальнейшему расширению):
В процессе работы над вышеприведенным файлом проекта выяснились следующие требования, накладываемые средой Visual Studio 2008 на все файлы проектов:
Я утверждаю, что любой проект, удовлетворяющий данным требованиям, может быть открыт в Visual Studio 2008, добавлен в решение к другим проектам, а также добавлен в список зависимостей другого проекта.
По этой теме, казалось бы, полно информации, есть даже пошаговое руководство на MSDN. Но, после создания файла проекта по любому подобному руководству, становится понятно, что нас жестоко обманули — созданные таким образом проекты живут «сами по себе» и не могут быть ни включены в решение, ни открыты в Visual Studio.
В этой статье я представляю вам собственное исследование на эту тему.
Постановка задачи
В целях определения минимальных требований, налагаемых на «обычные» в понимании Visual Studio 2008 проекты, создать проект, который:
- не выполняет никаких действий в процессе построения;
- корректно открывается и отображается в Visual Studio 2008;
- может быть добавлен в список зависимостей другим проектам;
- содержит в себе несколько файлов;
- все файлы проекта считаются выходными, т.е. должны копироваться в выходные директории зависимых проектов.
Процесс решения
Процесс решения данной задачи довольно сложен, и потому выходит за рамки данной статьи. Скажу лишь, что в процессе решения использовались следующие инструменты:
- MsBuild Reference на MSDN;
- текстовый редактор;
- содержимое файла %windir%\Microsoft.NET\Framework\v3.5\Microsoft.Common.targets;
- опции /v:d и /v:diag программы msbuild.exe;
- программа grep.exe из комплекта cygwin.
Решение
Следующий файл проекта удовлетворяет всем требованиям (и пригоден к дальнейшему расширению):
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{F4279D30-8B96-4217-B811-D2912FAD2C71}</ProjectGuid>
</PropertyGroup>
<ItemGroup>
<BuiltProjectOutputGroupKeyOutput Include="SuperLibrary.dll" />
</ItemGroup>
<ItemGroup>
<Content Include="logo.bmp" />
<Content Include="help.html" />
</ItemGroup>
<Target Name="Build" Outputs="" />
<Target Name="Rebuild" />
<Target Name="Clean" />
<Target Name="GetTargetPath" Outputs="" />
<Target Name="GetNativeManifest" Outputs="" />
<Target Name="GetCopyToOutputDirectoryItems" Outputs="@(_Content)">
<ItemGroup>
<Content Include="@(BuiltProjectOutputGroupKeyOutput)" />
<_Content Include="@(Content->'%(FullPath)')">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>%(Filename)%(Extension)</TargetPath>
</_Content>
</ItemGroup>
</Target>
</Project>
Выводы
В процессе работы над вышеприведенным файлом проекта выяснились следующие требования, накладываемые средой Visual Studio 2008 на все файлы проектов:
- файл проекта должен иметь расширение, ассоциированное с языков, использующим MsBuild, то есть .csproj или .vbproj, но никак не .myproj;
- в файле проекта обязано присутствовать свойство ProjectGuid;
- в проекте обязан присутствовать элемент BuiltProjectOutputGroupKeyOutput с расширением .dll или .exe (этот элемент может быть импортирован);
- все элементы, указанные в файле проекта (но не импортированные из других файлов!), отображаются в Solution Explorer и обязаны присутствовать на диске (элементы, импортированные из других файлов, в GUI не отображаются);
- в проекте обязаны быть цели Build, Rebuild и Clean, а также цели-функции GetTargetPath, GetNativeManifest и GetCopyToOutputDirectoryItem;
- цели Build и GetTargetPath должны указывать выходным первичный выходной файл проекта (но могут не возвращать ничего, если первичного файла нет);
- цель GetNativeManifest должна возвращать манифест проекта в том случае, когда у проекта есть этот самый манифест;
- цель GetCopyToOutputDirectoryItems должна возвращать список файлов, являющихся выходными для проекта;
- для всех элементов, возвращаемых целями-функциями (включая Build), нужно использовать исключительно полные пути (поскольку данные элементы передаются между проектами);
- для всех элементов, возвращаемых целью GetCopyToOutputDirectoryItems, должны быть указаны метаданные CopyToOutputDirectory со значением Always или PreserveNewest;
- для всех элементов, возвращаемых целью GetCopyToOutputDirectoryItems, должны быть указаны метаданные TargetPath, означающие относительно имя файла при копировании его в выходную директорию другого проекта (хорошим значением по умолчанию является %(Filename)%(Extension), то есть имя и расширение исходного элемента).
Я утверждаю, что любой проект, удовлетворяющий данным требованиям, может быть открыт в Visual Studio 2008, добавлен в решение к другим проектам, а также добавлен в список зависимостей другого проекта.