Это нормально баловать себя как разработчика. Я серьезно. Упростите себе задачу. Показательный пример: ограничьте количество вещей, которые вам нужно сделать в жизненном цикле разработки.
В этой статье я описываю, как настроить рабочий процесс C++/CMake, который будет автоматически создавать, компилировать и тестировать вашу программу, когда вы нажмете СОХРАНИТЬ.
Это будет окончательный результат:
Он не отображается, но я сохраняю файл (через vim) с помощью escape
+ :w
. Когда я это делаю, правая сторона начинает брызгать.
Сделать это проще
Я помню, как впервые увидел автоматическую сборку приложений React. Я думал, что это обман. Я внесу изменения, нажму «Сохранить» и сразу же увижу их в браузере. Более того, я мог написать модульные тесты, сохранить файл и сразу же посмотреть, пройден ли тест.
Итак, представьте 💡 момент, когда я начал разработку проекта C++. В колледже я, конечно, ничего не знал о системах сборки. тогда CMake даже не существовало, а до Docker оставалось еще пару лет, так что все приходилось делать по старинке: gcc program.c -o program
. К счастью, я был пользователем Linux, но я уверен, что студенты, изучающие Windows, разочаровываются больше.
Хватит дней Дикого Дикого Запада g++ 🤠. Приступим к самой интересной части автоматизации! 😝
Для нетерпеливых
Есть репозиторий с этим примером, который можно использовать как шаблонный код: https://github.com/src-r-r/cmake-automation-example.
Монтирование томов
Моей первой задачей было организовать оптимизированную сборку.
Я выбрал образ докера danger89/cmake, так как он уже имел CMake и казался довольно стабильным.
Затем мне нужен был способ построить мой проект в докере.
Это невозможно сделать в Dockerfile. Если вы скопируете свой проект с помощью COPY
, он будет скопирован в контейнер докера и не изменится. Должен быть способ обновить код в контейнере докеров, когда хост изменит его.
Итак, вместо этого проект должен быть смонтирован как том:
$ docker run -v ./my_project/my_project danger89/cmake
Или, поскольку мне лень, в файле компоновки:
Нам нужен собственный Dockerfile
Совсем маленький… в базовой сборке danger89/cmake
не установлено entr
. Если вы не хотите использовать файл dockerfile, включите некоторый код, чтобы проверить, установлен ли он в сценарии init.sh
(показан ниже), прежде чем запускать его.
Автоматизация сборки и тестирования
Теперь мы переходим к самой интересной части: запуск сборки (и тестирования) при сохранении файла.
Пока мы редактируем что-либо в каталоге ./my_project
, это возможно.
Если вы используете node, вы, вероятно, пересекались с инструментом под названием nodemon, который отслеживает изменения в файловой системе, а затем запускает команду при изменении любого отслеживаемого файла.
Я начал думать, что это был билет. Однако вскоре я обнаружил, что это не так.
Чтобы начать автоматическую сборку, мне нужно было сделать следующее:
- Следите за изменениями в
CMakeLists.txt
, затем запуститеcmake
. - Следите за изменениями под
src
, затем запустите make и тестовый исполняемый файл.
Nodemon отслеживает расширения пути, поэтому мне нужно следить за txt
и предоставлять команду для этого, затем отслеживать cpp
и предоставлять команду для этого, затем отслеживать hpp
и предоставлять команду для этого. Слишком много незавершенных вопросов и недостаточно детализации.
Введите ввод
Вместо этого есть утилита Linux под названием entr, которая позволяет вам следить за изменениями файловой системы и запускать команду.
Итак, чтобы отслеживать изменения для CMakeLists.txt
и любых файлов src
, выполните следующее:
$ ls ${PROJ_ROOT}/CMakeLists.txt ${PROJ_ROOT}/src/* | entr -d "/init.sh"
Где ${PROJ_ROOT}
— это (конечно) корень проекта.
Что в Инит?
В рамках init.sh
мы будем запускать cmake
, make
, а затем запускать тесты.
Теперь некоторые из вас, «экспертов», вероятно, будут ругать меня за сборку и компиляцию как на этапе сборки, так и на этапе компиляции. Правда, если бы мы делали это «правильно», мы бы наблюдали за CMakeLists.txt
и выполняли cmake
, затем наблюдали за src
(параллельно) и запускали make
.
Но заставить эти параллельные процессы работать — кошмар. Так что на данный момент этого достаточно.
Ну, почти…
Выход при ошибке
Прямо сейчас этот скрипт будет запускать cmake
, make
и test
, безоговорочно делая то, что ему сказано. Это то, чего мы хотим? Нет, мы хотим выйти из-за ошибки.
Мы делаем это, устанавливая set -e
вверху файла:
Таким образом, если какая-либо из этих команд завершится ошибкой, сценарий не будет работать.
И не беспокойтесь о enter
… он продолжит просмотр файлов и снова запустит /init.sh
, если что-то изменится.
Наводим порядок 🎁
До сих пор мы будем видеть МНОГО входных данных.
Мы беспокоимся только тогда, когда все идет хорошо… так почему бы просто не показать нам сцену, когда что-то пойдет не так?
Если вы использовали терминал, вы, несомненно, использовали clear
для очистки терминала или reset
для сброса сеанса терминала.
В сценариях BASH есть еще один менее известный протокол очистки, который делает это намного чище: printf "\033c"
. Это в основном делает жесткую очистку экрана терминала.
Итак, давайте включим его в наш скрипт инициализации:
И мы совершенно нормально делаем это… потому что, помните, мы используем set -e
, поэтому, например, если cmake
терпит неудачу, сценарий BASH завершается прямо здесь, поэтому строка printf
не затрагивается.
Интеграция в Докер
Теперь, куда мы поместим эти скрипты?
Приведенный выше сценарий инициализации я поместил в init.sh
, который смонтирован на томе докера /init.sh
.
Команду для enter
я поместил в скрипт под названием watch.sh
, который монтируется в /watch.sh
в докере.
Таким образом, файл компоновки с этими смонтированными файлами будет выглядеть так:
Убедитесь, что эти файлы имеют права на выполнение на хосте.
Теперь мы можем легко запустить контейнер my_project
и сразу начать просмотр файлов (помните, мы уже запускали docker-compose build
).
Если вы не запускали docker-compose build
, не волнуйтесь — вы получите тот же результат… просто это займет больше времени.
Таким образом, чтобы получить окончательную настройку запустить и забыть об этом, нам нужно выполнить скрипт watch
в качестве точки входа.
Теперь мы можем запустить docker compose:
$ docker-compose up
И теперь, как по волшебству, проект собирается, компилируется и запускает модульные тесты каждый раз, когда мы сохраняем файл!
Использование без докера
Если по какой-то причине вы не хотите использовать докер или хотите взять что-то из докера для отладки «в автономном режиме», скрипт будет работать точно так же.
Все, что вам нужно сделать, это изменить некоторые пути в watch.sh
и init.sh
. Одна вещь, которую я обычно люблю делать, — это получить текущий каталог скрипта и добавить его в начало скрипта BASH (благодаря легенде Dave Dopson at StackOverflow):
Убедитесь, что PROJ_DIR
назначено ${DIR}
в сценариях init.sh
и watch.sh
(убедитесь, что приведенный выше фрагмент находится в ОБОИХ), и вы должны быть золотыми.
Теперь запустите ./watch.sh
и (если вы все установили) проект должен автоматизировать сборку.
В этой статье я подробно описал, как настроить систему для автоматической сборки, компиляции и запуска проекта C++/CMake всякий раз, когда вы сохраняете файл.
Как указано выше, код примера доступен здесь: https://github.com/src-r-r/cmake-automation-example. Не стесняйтесь использовать его в своем собственном проекте
Если вам понравилась эта статья, пожалуйста, поделитесь ею с несколькими друзьями. Прокомментируйте, что вы нашли интересным, разочаровывающим или странным.
❤️❤️❤️
Если вы хотите получать больше статей (и получать их на 2 дня раньше!), рассмотрите возможность стать сторонником ko-fi:
https://ko-fi.com/damngood/tiers.
❤️❤️❤️