#c #git #visual-studio #gitlab
#c #git #visual-studio #gitlab
Вопрос:
У моей компании есть репозиторий для большого клиент-серверного приложения CPP. В нашей сети есть дополнительный диск, содержащий последние скомпилированные проекты для всего приложения, поэтому каждому разработчику остается только вносить свои изменения (сборка всего приложения занимает несколько часов).
- Эти проекты предварительной компиляции обновляются каждый день и могут быть скопированы на ваш локальный диск.
- Мы используем Visual Studio для разработки, и проекты настроены так, чтобы сначала искать скомпилированные файлы на вашем локальном диске, а затем искать их на сетевом диске.
Это создает проблему для разработчиков, которые обновляют (извлекают) свои ветви и не обновляют сетевой диск (потому что они скопировали его на свой локальный диск). Или наоборот, разработчики, которые не обновляют свой репозиторий, но поддерживают диск в актуальном состоянии.
Объяснение:
Есть два важных типа файлов: заголовочные и CPP-файлы. При запуске приложения Visual Studio сначала искала файлы заголовков на вашем локальном диске, а затем на сетевом диске и делает то же самое для скомпилированных проектов. Итак, проблема в том, что у вас всегда есть все файлы заголовков на вашем локальном диске, потому что у вас, очевидно, есть весь проект, клонированный, но у вас не весь проект, скомпилированный на вашем диске. Это может привести к несоответствию между вашим скомпилированным проектом и файлами заголовков, используемыми для запуска приложения.
Пример:
Проект 1: интерфейс.h, реализация.h, implementation.cpp Проект 2: dependency.cpp
Итак dependeny.cpp использует интерфейс Project 1 .h . Теперь у нас есть два разработчика, и разработчик 1 вносит изменения в интерфейс.h и расширяет структуру и отправляет ее в репозиторий, находящийся выше по потоку. Разработчик 2 НЕ извлекает изменения, но получает последние скомпилированные проекты с сетевого диска. Итак, теперь Visual Studio использует вашу СТАРУЮ реализацию интерфейса.загружается с вашего локального диска И использует НОВУЮ скомпилированную версию Project 1. Это приводит к очень запутанным ошибкам во время выполнения (нарушениям доступа для чтения), поскольку структуры, которые передаются методам, имеют разные размеры.
Итак, в основном: предварительно скомпилированные проекты всегда должны быть скомпилированы с той же версией ( фиксацией), на которой основаны ваши изменения. (Не всегда, поскольку не все изменения вносят изменения в заголовочные файлы, но, как правило, всегда полезно вносить локальные изменения на основе коммита, на котором был скомпилирован сетевой диск).
Теперь актуальный вопрос:
Мы переходим на GitLab, который заставляет пользователей использовать ветки для получения обзора кода. Филиалам не очень нравится двигаться вперед в истории, но скомпилированные проекты будут обновляться каждый день. Таким образом, чем дольше существует ваша ветка, тем выше вероятность того, что вы столкнетесь со странными ошибками во время выполнения. Как вы могли бы предотвратить это?
Мои первые идеи были бы:
- Каждая ветвь получает свою собственную версию скомпилированных проектов на сетевом диске. (Дополнительные затраты на хранение. Руководству не нравится платить деньги за хранилище)
- Каждая ветвь перебазируется на коммит, используемый сетевым диском. Это либо должен делать каждый разработчик, поэтому каждый несет ответственность за свои собственные ветви. Или после сборки запускается процесс, который автоматически переносит каждую ветвь в этот коммит (обработка ошибок необходима для конфликтов слияния с уведомлениями по электронной почте). Также ветви должны быть —принудительно нажаты, поскольку мы переписываем историю, и это дает возможность разработчику случайно удалить чьи-либо изменения случайно, если несколько разработчиков работают над одной веткой.
Я не могу представить, что мы единственная компания с подобными проблемами, и для этого должно быть какое-то хорошее решение, где разработчикам не нужно каждый день перебазировать ветки и — принудительно вносить изменения.
Комментарии:
1. Являются ли эти внешние проекты, которые находятся в другом репозитории, или частью проектов в той же кодовой базе?
2. Это похоже на фундаментальную проблему, возникающую при управлении версиями артефактов объектов на сетевом диске независимо от исходного кода. Это именно то, для чего существуют менеджеры пакетов для синхронизации
3. Возможно, вы захотите взглянуть на книгу, такую как Шаблоны управления конфигурацией программного обеспечения . Это может, по крайней мере, помочь вам продумать, чего вы пытаетесь достичь, и некоторые из доступных вариантов (с точки зрения практики — он не рекомендует какое-либо конкретное программное обеспечение).
4. @bk2204 Проекты в рамках одной и той же базы кода, которые превращены в библиотеки и связаны с программой.
Ответ №1:
Итак dependeny.cpp использует интерфейс Project 1 .h . Теперь у нас есть два разработчика, и разработчик 1 вносит изменения в интерфейс.h и расширяет структуру и отправляет ее в вышестоящий репозиторий. Разработчик 2 НЕ извлекает изменения, но получает последние скомпилированные проекты с сетевого диска. Итак, теперь Visual Studio использует вашу СТАРУЮ реализацию интерфейса.загружается с вашего локального диска И использует НОВУЮ скомпилированную версию Project 1.
Поздравляем! Что вы делаете? К сожалению, ваш рабочий процесс полностью нарушен, и общая проблема сокращения длительного времени сборки должна быть исправлена в целом. Для меня совершенно бессмысленно иметь только сборку за ночь, и многие ветки не являются ее частью.
Моя подсказка:
-
Используйте более сложную цепочку инструментов сборки! Это означает, что вы компилируете только те части кода, которые зависят от изменений ваших рабочих ветвей. Обычно нет необходимости выполнять полную перестройку каждый раз.
-
Используйте серверы распределенной сборки. Такие инструменты, как
distcc
, хорошо справляются с работой, если доступно много машин для сборки. Я не могу говорить за среду MS, но я полагаю, что вы можете настроить что-то подобное и для MS. -
вы можете объединить этот инструмент с чем-то вроде
ccache
tools. Эти инструменты кэшируют объектные файлы. Если хэш исходного кода не изменился, они на самом деле не создают заново, а возвращают уже доступные объектные файлы, даже если это необходимо для другой ветки. -
проверьте, почему время сборки у вас такое большое. Часто проекты, которые растут с течением времени, имеют больше зависимостей по мере необходимости. Всегда полезно потратить некоторое время на рефакторинг кодовой базы и поиск частей кода, которые можно изолировать. Создавайте отдельные библиотеки / компоненты, которые создаются полностью самостоятельно или имеют строгое иерархическое дерево зависимостей.
-
если у вас все еще есть время сборки, превышающее часы, вам следует подумать о покупке нескольких простых КОМПЬЮТЕРОВ в качестве подчиненных устройств для компиляции. Если вы настроите 10 компьютеров для кластера с
distcc
, чтобы получить полную сборку и сократить время сборки, скажем, в 9 раз, вы получите больший эффект, предоставляя некоторые двоичные файлы ночной сборки, которые не поддаются управлению.
В моей последней компании у нас также было большое время сборки на очень толстых серверах (24 сервера с процессорами, каждый многоядерный процессор, массивные параллельные карты ввода-вывода и так далее. ). После настройки distcc для каждого ПК разработчика (~ 200 ПК на сайте) мы сокращаем время сборки в 20 раз! Это не уменьшало линейность, поскольку у вас всегда есть задержка в сети, большее время ввода-вывода в сети, как на локальном SSD и так далее, Но эффект достаточно большой. Начиная примерно с 5 часов, мы смогли перейти к 15 минутам для полной сборки. С помощью ccache
мы «находим» уже скомпилированные двоичные файлы и можем выполнять локальные сборки за несколько секунд. Но для всего этого нужны хорошие сценарии сборки, а также техническое обслуживание и настройка goo для управления филиалом. Это не работает из коробки!
Как уже говорилось, мы не настраивали структуру каталогов или какое-либо другое хранилище данных, связанное с репозиторием, для хранения уже созданных двоичных файлов. Эта работа была просто выполнена путем кэширования двоичных файлов с помощью ccache
. С другой стороны, мы храним локальные двоичные файлы сборки в структуре каталогов, которая отражает локальное ветвление. Это может привести к наличию нескольких идентичных двоичных файлов в структуре сборки, но упрощает поддержку сценариев сборки на ПК разработчика.
Нет общей концепции готовности к использованию. Но я надеюсь, что вы сможете уловить некоторые идеи, которые мы успешно использовали.
Комментарии:
1. Спасибо за ваш отличный ответ. Итак, по вашему мнению, нет разумного способа перенести этот старый рабочий процесс в git. И настоящая проблема заключается в нашем способе создания приложения для каждого разработчика, и мы должны попытаться сократить время сборки для всех, чтобы разработчики могли без проблем создавать все приложение и, наконец, удалять сетевой диск (сборка по ночам).
2. @JustinS: Чтобы сказать спасибо, у нас есть кнопка «Поддержать». И если вы считаете, что ответ — это то, что вам нужно, вы можете принять его. Сегодня Git не имеет ничего общего с вашим рабочим процессом сборки. Git хранит файлы с историей версий. Ничего больше! Остальное зависит от вас. Вы должны организовать цепочку инструментов сборки. И да, вам следует сократить время сборки за счет общего кэширования объектов и распределить процессы сборки по всем хостам разработчика и сервера.
3. За ваш ответ уже проголосовали, однако у меня самого меньше 15 представителей, так что это не считается.
4. @JustinS: Спасибо! Желаю вам удачи и надеюсь, что вы сможете решить свои проблемы!
Ответ №2:
(не ответ, это форматированный комментарий)
Я не получил весь ваш рабочий процесс :
- как обновлять «изменения, на которых он основан»?
- как вашей системе сборки удается выполнять поэтапную сборку? проверяет ли он
git diff master HEAD
? - сколько копий артефактов хранится на внешнем диске? одна единственная копия для «сборки этой ночью»?
Комментарии:
1. 1. Извините за запутанное объяснение. Обновление ваших изменений в основном означает продвижение вперед в истории ветки разработки. Итак, ночная сборка основана на ветке разработки, и если ваша функциональная ветка не перемещается вместе с веткой разработки (ночная сборка ), исходный код начинает слишком сильно расходиться, и вы начинаете получать ошибки во время выполнения. 2. К сожалению, я недостаточно знаю о нашем конвейере ночной сборки. Я могу задать вопрос и ответить на moday. 3. Существует единственная копия последней ночной сборки, и я верю в последние несколько выпусков, которые довольно старые.
Ответ №3:
Это можно решить довольно легко с помощью make
и некоторых скриптов. Как вы будете интегрировать это с Visual Studio — это другой вопрос, на который я, как пользователь Unix, не имею права отвечать.
Процесс состоит из трех этапов:
- Проверьте фиксацию, из которой создаются артефакты сборки.
- Скопируйте артефакты сборки с сетевого диска на место, как если бы они были собраны на локальном компьютере.
- Проверьте коммит, который вы хотите создать, а затем создайте с помощью
make
.
Это работает, потому что make
просматривает временные метки при принятии решения о том, какие файлы изменились, а Git проверяет только файлы, которые изменились. Как следствие, make
вы заметите, что продукты сборки новее всех, кроме измененных файлов, поэтому требуется перестроить только измененные файлы и файлы, которые зависят от них.
Также возможно решить эту проблему с помощью аналогичного менеджера сборки на основе зависимостей и хорошего хэша, такого как SHA-256 (или, для скорости, BLAKE2b): вы можете загрузить манифест хэшей исходных файлов вместе с продуктами сборки, а затем создать только файлы, хэши зависимостей которых изменились. Это избавляет вас от необходимости проверять более старую версию, но я не знаю ни о каких встроенных инструментах, которые это делают.
Я принял последний подход для системы сборки на основе Perl, и он работал довольно хорошо. Нашей целью никогда не было перестраивать двоичные файлы, если это не требовалось, чтобы пользователи могли загружать минимально возможные частичные обновления, и это сработало.
Все, что вы делаете, чтобы заставить текущую систему работать, потребует какого-либо пользовательского инструментария для сборки. Это легко с make
или набором сценариев оболочки, но будет сложнее в Windows.