Какова наилучшая практика для совместного использования проекта Visual Studio (сборка) среди решений

Предположим, у меня есть проект "MyFramework", который имеет некоторый код, который используется во множестве решений. Каждое решение имеет свое собственное управление контролем источника (SVN).

MyFramework является внутренним продуктом и не имеет официального расписания релизов, а также для решений.

Я бы предпочел не создавать и копировать библиотеки DLL во все 12 проектов, т.е. новые разработчики должны были бы просто выполнить svn-checkout, и приступайте к работе.

Каков наилучший способ поделиться MyFramework со всеми этими решениями?

Ответ 1

Поскольку вы упоминаете SVN, вы можете использовать externals для "импорта" проекта framework в рабочую копию каждого используемого решения, Это приведет к созданию такого макета:

C:\Projects
  MyFramework
    MyFramework.csproj
    <MyFramework files>

  SolutionA
    SolutionA.sln
    ProjectA1
      <ProjectA1 files>
    MyFramework   <-- this is a svn:externals definition to "import" MyFramework
      MyFramework.csproj
      <MyFramework files>

С помощью этого решения у вас есть исходный код MyFramework, доступный в каждом решении, которое его использует. Преимущество состоит в том, что вы можете изменить исходный код MyFramework из каждого из этих решений (без необходимости переключения на другой проект).

НО: в то же время это также является огромным недостатком, так как очень легко разбить MyFramwork для некоторых решений при модификации его для другого.

По этой причине я недавно отказался от этого подхода, и теперь рассматриваю наши инфраструктурные проекты как совершенно отдельный продукт/решение (с их собственным расписанием). Затем все другие решения включают в себя конкретную версию двоичных файлов проектов инфраструктуры.

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

Ответ 2

Это звучит как катастрофа... как вы справляетесь с тем, что разработчики уничтожают/нарушают работу других...

Если бы я был вами, я бы поставил MyFrameWork в совершенно отдельное решение. Когда разработчик хочет разработать один из 12 проектов, он открывает это проектное решение в одной среде IDE и открывает MyFrameWork в отдельной среде IDE.

Если вы сильно назовете свою сборку MyFramework и ее GAC и ссылаетесь на нее в других проектах, то "Копирование DLL" не будет проблемой.

Вы просто создаете MyFrameWork (и событие PostBuild может запускать GacUtil, чтобы поместить его в кеш сборщика), а затем создать другой проект.

Ответ 3

"Лучший способ" будет зависеть от вашей среды. Я работал в среде непрерывной интеграции на основе TFS, где ночная сборка развернула двоичные файлы для общего ресурса. Все зависимые проекты касались доли. Когда это стало медленным, я создал некоторые инструменты, позволяющие разработчикам иметь локальную копию общих двоичных файлов без изменения файлов проекта.

Ответ 4

Работает ли в любом из 12 решений, регулярно требующих изменений в коде "framework"?

Если это ваша инфраструктура, вероятно, новая и просто созданная, поэтому я бы включил проект framework во все решения. В конце концов, если работа требует, чтобы вы изменили код рамки, это должно быть легко сделать.

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

Как только вам редко приходится менять структуру при работе в решениях (это должно быть вашей целью), тогда я бы включил ссылку на dll framework и обновлял dll в каждом решении только по мере необходимости.

Ответ 5

svn: externals позаботится об этом, если вы выполните несколько правил.

Во-первых, это безопаснее, если вы используете относительные URI (начиная с символа ^) для определения svn: externals и по возможности ставьте проекты в один и тот же репозиторий. Таким образом, определения останутся в силе, даже если сервер подчинения перенесен на новый URL.

Во-вторых, убедитесь, что вы следуете следующему намеку из книги SVN. Используйте PEG-REV в определениях svn: externals, чтобы избежать случайных поломки и нестабильных тегов:

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

Ответ 6

Я согласен с другим плакатом - это звучит как неприятность. Но если вы не можете сделать это "правильно", я могу подумать о двух других способах этого. Мы использовали что-то похожее на номер 1 ниже. (для собственного приложения на С++)

  • a script или командный файл или другой выполняемый процесс, который выполняет сборку и сборку зависимости. (только один раз). Он создается/выполняется только в том случае, если в репо нет изменений. Вам нужно будет знать, какой тег/ветвь/версия получить. Вы можете использовать файл bat как шаг предварительной сборки в ваших файлах проекта.

  • Держите двоичные файлы в репо (не очень хорошая идея). Даже в этом случае зависимые проекты должны сделать и получить информацию о том, какую версию получить.

В конечном итоге то, что мы пытались сделать для наших проектов, было имитирующим, как мы используем и обращаемся к сторонним библиотекам.

Что вы можете сделать, так это создать пакет выпуска для зависимостей, который настраивает переменную env для себя. Я бы разрешил использовать несколько версий этого устройства на машине, а затем зависимые проекты связывают/ссылаются на конкретные версии.

Что-то вроде

$(PROJ_A_ROOT) = c:\mystuff\libraryA

$(PROJ_A_VER_X) = %PROJ_A_ROOT%\VER_X

а затем ссылайтесь на нужную версию в зависимых решениях либо по определенному имени, либо с помощью версии env var.

Не очень, но он работает.

Ответ 7

Масштабируемое решение состоит в том, чтобы сделать svn-external в каталоге решений, чтобы ваши импортированные проекты выглядели параллельными ваши другие проекты. Причины этого приведены ниже.

Использование отдельной подкаталога для "импортированных" проектов, например. externals, через svn-external кажется хорошей идеей, пока у вас нет нетривиальных зависимостей между проектами. Например, предположим, что проект A зависит от проекта по проекту B и проекта B от проекта C. Если вы тогда есть решение S с проектом A, вы получите следующую структуру каталогов:

# BAD SOLUTION #
S
+---S.sln
+---A
|   \---A.csproj
\---externals
    +---B     <--- A dependency
    |   \---B.csproj
    \---externals
        \---C     <--- B dependency
            \---C.csproj

Используя этот метод, , вы даже можете получить несколько копий одного проекта в своем дереве. Это явно не то, что вы хотите.

Кроме того, если ваши проекты используют NuGet зависимости, они обычно загружаются в каталог packages верхнего уровня. Это означает, что ссылки NuGet проектов в подкаталоге externals будут разбиты.

Кроме того, если вы используете Git в дополнение к SVN, рекомендуемым способом отслеживания изменений является наличие отдельного репозитория Git для каждого проекта, а затем отдельный репозиторий Git для решения, использующего git submodule для проектов внутри. Если подмодуль Git не является непосредственным подкаталогом родительского модуля, то команда Git subodule сделает клон, который является непосредственным подкаталогом.

Еще одно преимущество того, что все проекты на одном уровне - это то, что вы можете создать "супер-решение", которое содержит проекты из всех ваших решений (отслеживаемых через Git или svn-external), что, в свою очередь, позволяет вы проверяете с помощью одного решения-перестройки, что любое изменение, внесенное вами в один проект, согласуется со всеми другими проектами.

# GOOD SOLUTION #
S
+---S.sln
+---A
|   \---A.csproj
+---B     <--- A dependency
|   \---B.csproj
\---C     <--- B dependency
    \---C.csproj