По этой теме, казалось бы, полно информации, есть даже пошаговое руководство на 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, добавлен в решение к другим проектам, а также добавлен в список зависимостей другого проекта.