Pull to refresh

Comments 24

Вот спасибо. Всё самое интересное как всегда — to be continue… ждем.
«Любой проект Microsoft Visual Studio является скриптом MSBuild» — не совсем так. Все «коробочные» типы проектов в VS являются MSBuild-скриптами, это да. Но исторически это было не так (VC++ до VS2010 имел свой формат, и еще был Setup project), и в общем случае это некорректно, т.к. формат файла проекта отдается целиком на откуп проектной системе (project system — компоненту, отвечающему за загрузку и работу с данным конкретном типа проекта).
Вы правы. По поводу project system, то в будущих частях, я надеюсь, расскажу про создание своей системы проектов(это пункт 4й плана действий, если Вы не заметили), а пока я посчитал, что упоминание про это бессмысленно. По поводу истории — я прекрасно её знаю(сижу на студии с версии 5.0 — эта которая 97) поэтому и начал с 2010 т.к. между 2010 и 2012, 2013 — разница в проектных системах минимальна.
Описанный вами способ добавления свойств — это не MSBuild вообще, а конкретно те виды проектов, которые построены на Common Project System (это проектная система, изначально появившаяся в VS 2010 для C++-проектов, а на сегодня используется также для WinStore JavaScript проектов, и .NET vNext / Project K / .kproj). Для обычных C#/VB проектов, например, это работать не будет. Для F#, Python, Node.js, PHP — тоже. Тут та же проблема — каждая проектная система реализует эти штуки сама и по-своему; в CPS сделали такое вот декларативное описание пропертей, в других — что-то еще.

В C# добавить свои свойства вполне можно, но там придется еще рисовать руками property page для их редактирования, и в целом это все будет выглядеть совсем по-другому.
$(BlaBlaBla) — это не макрос, это способ адресации Свойства (Property) в MSBuild.

Вообще все остальное, включая ваши наборы свойств выглядит как мало относящееся к MSBuild. Props и Targets это просто «соглашения», можете именовать как угодно, но студия любит их и например может дать возможность редактировать ваши собственные props в окне свойств проекта.

int19h А в чем отличия этой Common Project System от стандартной системы сборки проектов в MSBuild? И почему декларативное описание свойств не будет работать? Мсбилд всегда так работает, ну или я не правильно понимаю ваше высказывание.
про $(BlaBlaBla) — я написал в терминологии студии, чтобы людям было привычнее. А в студии эти штуки как раз находятся под кнопкой «Macros». Мои наборы свойств включаются в проект студии, который является скриптом MSBuild и не упоминать его неправильно, понятно, что для сборки из консоли они не нужны, но ведь статья относится к MVS, а не чисто к MSBuild. К тому же в следующих частях я уже перейду уже к сборке — а это уже MSBuild в чистом виде.
Props и Targets это просто «соглашения» — Вы статью читали? Там про это написано.
То, что они где-то находятся в IDE — не определяет их предназначение. Вы такими выдуманными обозначениями запутаете читателей еще больше, а потом опять будем видеть жалобы на то, что кто-то потратил уйму времени (как автор) просматривая targets мсбилда и все равно ничего не понял.

Да, статью я читал. На соглашения я указал потому, что если им следовать — можно получить некоторые встроенные в msbuild(и поставляемые targets) ништяки. Если не следовать — можно сделать все то же самое, но руками и через «мучения».
Нет, тут как раз все правильно. Надо четко понимать, что свойства MSBuild и свойства проекта в VS — это две совершенно разные вещи, которые иногда пересекаются как деталь реализации данного конкретного типа проектов.
Ок. т.е. получается в данном случае они не только используют свойства как способ хранения, но и используют такой же синтаксис? Или все-таки они заимствуют синтаксис из мсбилда, потому что само строковое значение будет интерпретироваться\разворачиваться не студией, а мсбилдом? Кто их разворачивает, эти «макросы»? Если второе — то все-таки это сущность билда, а не макрос студии.
Конкретно $(BlaBlaBla) — на практике это сущность MSBuild, да, и разворачивает их он (если попросят).

Под капотом там создается экземпляр класса Project, а на нем дергается метод GetEvaluatedProperty, который и возвращает развернутое значение. При записи, соответственно, зовется SetProperty. Для редактирования же значение проперти обычно читается в исходном виде непосредственно из коллекции Properties, чтобы отобразить его точно в том виде, в котором оно было в файле проекта, со всеми $(...).

Про Macros я просто пропустил. Это (точнее — project macros) терминология, специфичная для C++-проектов, больше её никто не использует. Если мне не изменяет память, она осталась с тех времен, когда C++-проекты были не MSBuild. По факту на сегодня она просто отдается на откуп мсбилду, но в документации, тем не менее, она зачем-то описана как отдельная сущность.

(гипотетически, если MSBuild завтра внезапно умрет, то макросы его переживут, поэтому какой-то смысл в том, чтобы говорить о них в отдельности, наверное есть)
и да, проект становится проектом «студии» если у него соответствующий ProjectGuid, а не невинные импорты
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
Собственно я об этом упомянул — когда сказал, что если их удалить — то проект остается валидным.
>> А в чем отличия этой Common Project System от стандартной системы сборки проектов в MSBuild? И почему декларативное описание свойств не будет работать? Мсбилд всегда так работает, ну или я не правильно понимаю ваше высказывание.

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

С точки зрения MSBuild, «проект» — это просто корневой скрипт системы сборки, точка входа в неё. Никакого другого смысла в него не вкладывается, и обычные VS-термины вроде «файлов проекта» или там «выходной сборки» на этом уровне смысла не имеют. Есть просто набор properties (по сути, скалярных переменных), items (коллекций), и targets (функций), который выполняется. Все.

С точки зрения VS, «проект» — это отнюдь не MSBuild-скрипт, и даже вообще не обязательно файл. Это просто некоторый COM-объект в памяти, реализующий интерфейсы IVsProject и IVsHierarchy, и ряд связанных с ними. Соответственно, «проектная система» (project system) — это реализация конкретной фабрики (IVsProjectFactory) для создания таких объектов, и реализации этих самых объектов для этой конкретной фабрики. Вся эта система очень абстрактна, и то, как именно реализован проект под капотом, может сильно варьироваться, в т.ч. и откуда грузится при открытии проекта, и куда пишется при сохранении. На практике постепенно пришли к единому знаменателю в виде MSBuild-скриптов, чтобы логика билда, по крайней мере, у всех проектных систем была одна.

При этом реализация всего остального в проектной системе (т.е. собственно IVsProject и IVsHierarchy — интерфейсы, ответственные за наполнение Solution Explorer, открытие редакторов для документов etc) по прежнему различается. В частности, если взять тот же VS 2010, то в нем C++ — это одна реализация (что забавно, написанная на C#), C# и VB — совершенно другая (что еще более забавно, написанная на C++), F# — третья (форк MPF — примера по написанию проектной системы из VS SDK), Setup project — четвертая. Если ставить расширения, то, например, Python Tools и Node.js Tools — это будет пятая (тоже форк MPF, но не имеет родства с C#), PHP Tools — шестая (форк PTVS), RemObjects Oxygene — седьмая (что-то свое, но, кажется, тоже форк MPF). Плюс есть всякие мелкие вспомогательные проектные системы, не привязанные к языкам, и не имеющие смысла сами по себе — например, Cloud Service Project в Azure SDK.

Понятно, что подобный зоопарк приводит к головной боли в виде необходимости реализовывать одни и те же фичи по десять раз. Поэтому периодически предпринимаются попытки написать одну универсальную проектную систему, которая покроет все требования, и может быть использована и кастомизирована всеми языками под свои нужды. Как правило, это работало примерно так, как описано в xkcd про стандарты (например, проектная система C#/VB была именно такой попыткой, но в итоге её никто больше использовать не стал). К VS 2010 очередной попыткой стал CPS, который вырос из переписывания проектной системы C++ (старая не использовала MSBuild, поэтому её все равно надо было переделывать). Попыткой, похоже, успешной, потому как его подхватали JS, и теперь вот .NET Core.

Возвращаясь к терминологии — с точки зрения VS самой по себе (не включая стандартные проектные системы), понятия «свойства проекта» в общем случае не существует. Есть фиксированный набор свойств у корневой иерархии проекта (IVsHierarchy), есть понятие «конфигурация» (IVsCfg) и «платформа», и, в общем-то, все. Все остальное — это штуки, специфичные для каждой проектной системы, и какие они вообще есть (и есть ли!), и где и как хранятся — решает именно она. На практике, опять же, есть некоторые общие вещи вроде выходного файла, но даже для них в общем случае нет одного универсального интерфейса, через который их можно получить из любого произвольного проекта. Есть IVsBuildPropertyStorage (который появился одновременно с MSBuild и проектной системой для С#/VB на его основе), который поддерживают все MSBuild-based проектные системы — но, в принципе, они это делать не обязаны.

Графический интерфейс для редактирования этих свойств тоже реализуется проектной системой. VS здесь предоставляет костыли в виде реализации COM property pages, но каждая конкретная страница целиком и полностью на откупе у проектной системы.

Для систем, которые в качестве файлового формата для проекта используют MSBuild, наиболее очевидный маппинг свойств на файл — это MSBuild properties (а для файлов проекта — соответственно, MSBuild items). Обратное неверно, т.е. далеко не каждое свойство в MSBuild является свойством проекта в данной системе, и не каждый item является файлом проекта. Собственно, если сделать дамп свойств после чтения какого-нибудь шарпного или плюсового проекта, их там будет с пару сотен, и из них только несколько десятков видны в VS как свойства проекта. Остальное — по сути, просто временные переменные. Что есть что, решает опять же проектная система.

Так вот, в случае с CPS, это решение не зашито в код системы, как во всех остальных случаях, а вынесено в декларативные описания в сам MSBuild-скрипт. Т.е. файл проекта, а точнее, импортируемые им .targets и .props файлы, описывают, как его надо интерпретировать, и в частности, какие именно MSBuild-свойства должны быть отображены в UI, и каким именно образом. Это как раз и есть PropertyPageSchema, и используемые им XML-файлы (которые на самом деле XAML). И вся эта машинерия — специфична именно для CPS, и работает только с его проектами. К MSBuild она прямого отношения не имеет, и последний рассматривает её просто как обычный набор свойств и items, никак ни с чем не связанный и не имеющий никакого сакрального смысла. В сборке, соответственно, она тоже не участвует.
Классно, спасибо за пояснения, как работает мсбилд я знаю неплохо, а вот такие детали про проектные системы и их проекции на систему сборки — очень полезны.
Кстати такой технический вопрос — можно ли убедить студию что ей нужно отрисовать содержимое файла Х как набор свойств проекта в GUI (т.е. убедить ее в том, что «проектная система — C#, но вот тут отрисуй пожалуйста используя другой компонент, из CPS» ), или это все жестко связано с расширениями и внутренними Guid? А то я сейчас покопался — и обнаружил что куда-то пропал графический редактор свойств в С#, похоже раньше это мне какое-то расширение делало… Не то что бы очень надо, просто любопытно, можно ли так обмануть систему…
Можно, понятие редактора не привязано к проектной системе — ассоциация идет обычно по типу файла (т.е. расширению). Проектная система может перехватить открытие файла и насильно заставить открыть какой-то редактор по умолчанию для данного типа, отличный от глобального умолчания (например, PTVS перехватывает открытие .html в Django-проектах, чтобы открыть их в своем редакторе, который понимает синтаксис Django). Но в любом случае остается вариант в виде Open With в контекстном меню файла — там будут вообще все зарегистрированные в VS редакторы, и можно выбрать любой. Вполне вероятно, что ваш редактор где-то там :)
Спасибо! А про написание аддинов к Студии не будет ничего?
Возможно будет — я сейчас сам в этом во всем разбираюсь. Если забегать вперед и прикручивать XC8 полностью, то необходимо реализовать карту памяти микроконтроллера — подумываю сделать это как раз в виде добавления своего инструментального окна. Так что вполне вероятно, что напишу об этом.
Автору конечно спасибо за проделанный труд, но тут стоило бы заметить что MSBuild так же покрыт огромным слоем пыли и пепла. Для людей, кто ищет современные средства построения (build) могу посоветовать FAKE или PSAKE, они оба в той или иной мере используют, под капотом, MSBuild, но они просто северное сияние по сравнению с бараньими тестикулами обычным MSBuild.
А еще есть TFS — вообще гуй есть и можно в workflow в drag-and-drop стиле редактировать, не то что ваши тестикулярные скриптовые языки. Типа ура…

Обычно, необходимость в скриптовых и императивных языках возникает когда в команде многие не способны ( в силу ограниченности кругозора) понимать XML мсбилда и его декларативность. Ну это в общем проблемы команды, а не мсбилда. Хоть на batch пишите, только все эти обвязки — как забивать гвозди микроскопом — от непонимания.
Так же наверное как и потребность в использовании языков высокого уровня возникает когда в команде многие не способны(в силу ограниченности кругозора) понимать всей красоты и мощи Assembler. И это тоже не проблемы Assembler.

MSBuild недружествен к восприятию, хотите продуктивности используйте высокоуровневые DSL как FAKE, любите хардкор и хотите им обременять всю команду спускайтесь на MSBuild.

Насчет TFS и его workflow, он обречен в его современном виде, что есть хорошо, посмотрите какова тенденция TFS 2015 и поймете о чем речь.

Мое мнение в том что не нужно тратить время и нервы на MSBuild, лучше брать высокоуровневые билд-системы. Как FAKE, sbt (из стана врагов), gulp (из стана неприятеля).
Эти системы (я про fake &psake) направлены на другое — это просто обертка, которая прячет от вас функциональную часть сборки. Мсбилд — возможность заглянуть и понять что происходит под капотом. Просто не понимая что внутри — невозможно модифицировать систему чтобы она делала что нужно вам, всегда будут ритуальные пляски — а вот такой плагин добавим, а вот такой модуль, а еще их надо вызвать в строгом порядке, а между вызовами очистить вот эту папку. Это называется культ карго.

Да, мсбилд использует не самый дружественный синтаксис, да, весь каскад импортов и переопределенных свойств может вызвать мигрень, да, половина таргетов для не основных продуктов написана криворукими идиотами, но понимание самой системы сборки дает вам знание о том, что происходит когда вы вызываете msbuild ./mylib.csproj. А также вы знаете как повлиять на это, в любой билд системе. И это кстати совсем не хардкор 8-)

PS про TFS — ппкс, и спасибо за наводку, как то пропустил что появились детали 2015…
Спасибо, статья действительно полезная.
Сам, в своё время, пытался разбираться в системе MSBuild для этого.
Ничего путного не нашёл в сети — делал по аналогии с примерами.
Sign up to leave a comment.

Articles