Начало работы: git, gcc и make

В прошлой статье вы подняли окружение для разработки и компиляции gcc под Windows (или установили виртуальную машину с Ubuntu/Debian), а так же зарегистрировались на GitHub. Сейчас мы напишем простейшую программу на C и научимся простейшему использованию git и make.

Для начала вы должны выбрать текстовый редактор, в котором будете писать код. Под Linux-ом это может быть консольный редактор nano или vim (оба предустановлены в Debian и Ubuntu), графический gedit или sublime_text (предустановлен в Debian).

В окружении Windows для того, чтобы удобно использовать текстовый редактор из консоли bash нужно немного исправить его конфигурацию. Для этого открываем вашим любимым текстовым редактором файл C:\MinGW\msys\1.0\etc\profile и в самый конец файла на новой строчке добавляем следующее:

alias editor='"<путь к exe-файлу вашего любимого редактора>"'

Например, для Notepad++ со стандартным путем установки это выглядит так:

alias editor='"C:\Program Files (x86)\Notepad++\notepad++.exe"'

Команда alias задает псевдоним какой-то команды в bash. В данном случае, вы дали знать оболочке, что хотите, чтобы при обращении к команде “editor” у вас вызывалась программа, расположеная по пути “C:\Program Files (x86)\Notepad++\notepad++.exe”.

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

Написание первого кода

Откроем консоль bash и создадим новую директорию с именем test1 в нашей домашней директории. Для этого введем команду:

mkdir test1

Теперь войдем в нее. Аналогично,

cd test1

Заголовок окна и строка приглашения (та, что на строку выше “$” в Windows, в той же строке перед символов “$” в Linux) должна измениться и отображать текущий путь. Нетрудно заметить, что он начинается с символа“~”. В Unix-системах этот символ означает домашнюю директорию.

Так выглядит окно консоли под Windows
А вот так под Ubuntu

Теперь же приступим непосредственно к редактированию кода.

В консоли bash выполним следующую команду (если вы используете Sublime Text 3 под Linux, то вместо editor используйте sublime_text):

editor main.c

Тем самым мы откроем текстовый редактор для файла main.c в текущей директории. Эта команда удобна тем, что сработает и в Windows, и в Linux с любым текстовым редактором (кроме Sublime Text, если это не было настроено вручную). Если такого файла не существовало ранее, то этот файл будет создан.

Введем в него следующий код:

И сохраним файл. Теперь этот исходный код необходимо скомпилировать. Введем команду:

gcc -o main -Wall -Werror main.c

В результате у нас получится файл main (или main.exe под Windows). Но давайте сначала разберем саму команду.

И так, команда состоит из 2 частей: собственно команды и ее параметров. В качестве команды здесь у нас выступает имя компилятора — gcc, а вот параметры рассмотрим подробнее.

Параметр -o задает имя выходного файла скомпилированой программы. Если его не указывать, то выходной файл компилятора будет называться a.out (таким образом, этот параметр необязательный).

Далее следуют необязательные параметры -Wall и -Werror. Легко заметить, что оба начинаются с “-W”, что означает, что они относятся к обработке предупреждений (Warning-и). “-Wall” включает вывод всех сообщений warningов, а “-Werror” заставляет компилятор обрабатывать их как ошибки, то есть прерывать компиляцию, когда такой warning встречается.

Далее следует последний и обязательный параметр — имя компилируемого файла. Тут все просто. Этот параметр нельзя опускать (иначе компилятор не узнает, что надо компилировать).

Можем проверить работу нашей программы, введя в консоли:

./main

Если на экране вывелась строка “Hello, world!”, то вы все сделали правильно.

Начало работы с Git

Git — это такая система контроля версий. Это значит, что она используется для хранения всей истории изменения проекта, быстрого перехода между версиями проекта, а так же для удобства командной разработки. Основной объект оперирования (то, с чем вы будете работать) — это репозиторий. Для человека он выглядит как обычная директория с файлами, в которой также есть и скрытая папка .git, в которой хранится история изменений и другая служебная информация.

Начнем работу. Для того, чтобы создать пустой репозиторий в текущей папке, введем команду:

git init

(для создания новой пустой папки и репозитория в нем нужно ввести имя папки после “init”). В данный момент все изменения (а на данный момент для git-а файл main.c, который мы создали ранее, это “изменение”) еще не добавлены в репозиторий (т.н. “unstaged changes”). Мы можем просмотреть текущее состояние репозитория (т.е. все неизмененные, измененные и недобавленные файлы) с помощью команды

git status
Так выглядит вывод команды git status под Windows

Видим, что файлы, которые создали мы и компилятор находятся в списке “Untracked files”. Это означает, что они еще не добавлены в репозиторий или не добавлены в текущий коммит.

Коммитом называется операция фиксации всех изменений, сделанных в репозитории и добавленых к коммиту. Также к коммиту обычно прилагается комментарий, описывающий что именно изменилось во время данной фиксации. На практике очень важно писать осмысленные и правильные комментарии к коммиту.

Давайте добавим наш файл к коммиту и зафиксируем изменения.

git add main.c
git commit -m'main.c: file created, hello world code added'

После этого должен создасться первый коммит, а в выводе команды “git status” файл main.c должен исчезнуть из списка “Untracked files”. С помощью команды “git log” можно просмотреть список коммитов.

Обратите внимание, мы не просто так добавили в репозиторий только файл с исходным кодом. За редким исключением в репозиторий добавляются только plaintext-файлы, т.е. файлы, которые содержат человекочитаемый текст. Binary-файлы в репозиторий добавлять не нужно (в git существует даже специальный файл, в который можно записать список или маску всех бинарных файлов проекта, чтобы случайно не добавить их).

Давайте теперь внесем изменения в наш код.

Для начала об изменениях в коде. Выше, при компиляции, вы уже познакомились с понятием параметра командной строки. Функция main принимает 2 параметра — argc и argv. Так вот, argc — это количество параметров, а argv — это массив, содержащий в элементах каждый из параметров. Теперь наша программа проверяет, больше ли 1 количество параметров (потому что сама команда на всех системах тоже считается за параметр и хранится в argv[0] — это важно!) и если это так, то выводит сообщение “Hello, <тут первый параметр>!”, в противном случае выводит “Hello, <имя программы, оно же нулевой параметр>!”.

Скомпилируем программу заново (используя ту же команду, что и в прошлый раз) и проверим результат ее выполнения, введя:

./main User
./main
Примерно так выглядит результат работы программы под Windows и не сильно отличается под Linux.

Вместо самой команды вывелся полный путь к вызываемому файлу, потому что оболочка командной строки автоматически раскрывает команду в полный путь к файлу.

Теперь нужно добавить измененный файл к текущему коммиту. Делается это той же командой “git add” (как и добавление нового файла).

git add main.c
git commit -m'main.c: added greeting with command line parameter'

И так, теперь в списке коммитов отображается 2 коммита. Для самого git коммиты — это специальные файлы в формате patch, которые позволяют на уровне строк (т.е. даже если в строке будет отличаться всего один символ, будет полностью удалена старая строка и добавлена измененная) находить разницу между файлами. Чтобы посмотреть, как выглядит коммит, использутся команда “git show”.

Наш коммит выглядит так. Коммиты нумеруются длинной уникальной строкой-идентификатором (строка №3 на скриншоте).

Теперь рассмотрим, как отправлять код на удаленный репозиторий (например GitHub). Переходим по этой ссылке и создаем репозиторий с названием “test1". Настройки должны выглядеть как на скриншоте ниже.

Создаем репозиторий. После этого GitHub выдает нам страницу с некоторым набором действий, которые именуются “Quick setup”. На странице будет переключатель “HTTPS | SSH”, по умолчанию установленый в HTTPS. Если вы создавали ssh-ключ с помощью ssh-keygen, то можете выбрать SSH (как я писал ранее, тогда вам не придется вводить пароль при отправке изменений). В противном случае ничего не трогайте.

Из всех команд, которые предлагает нам GitHub, нас интересует только та, которая начинается с “git remote add”. Копируем ее и выполняем в консоли. Эта команда добавляет удаленный адрес репозитория, в который git сможет отправлять все сделаные вами изменения.

git remote add origin git@github.com:group453502/test1.git

(это пример команды). Здесь “origin” — это имя источника (удаленного репозитория). “origin” — это имя для основного источника (их может быть несколько). После этого введем:

git push origin master

Как видим, в этой команде указывается имя источника, а так же название ветки “master”. Дело в том, что у репозитория git может быть несколько ответвлений, которые после могут сливаться в главное. Но это мы пока рассматривать не будем.

Если вы выбрали HTTPS-режим, то у вас запросится логин и пароль. После этого изменения отправятся на сервер и мы сможем их увидеть на странице репозитория GitHub.

Написание сценариев make

GNU make — это система сборки проектов. Сейчас наш проект состоит из одного файла и собирали мы его одной командой, однако на практике файлов могут быть сотни и тысячи, и для того, чтобы не компилировать каждый файл вручную и нужна система сборки.

make имеет очень простой синтаксис. У make есть так называемые “цели”, т.е. задачи, которые система сборки будет выполнять. Цели задаются таким образом: “<имя_цели>:”. Имя цели — строчные английские символы и цифры. Команды внутри цели — это обычные консольные команды bash. Они должны быть отделены от начала строки одним символом табуляции (нажатие кнопки Tab, таким образом make понимаем, что это именно команда, а не цель). Сам файл с целями и командами make должен называться “Makefile” (обязательно с большой буквы). Цель по умолчанию называется “all”.

Рассмотрим пример простейшего Makefile:

(если будете копировать здесь и далее, то отступы сделаны с помощью пробелов, но надо их сделать с помощью клавиши Tab).

Здесь задана только одна цель — “all” и одна команда, которой мы и раньше компилировали наш исходник. Добавим еще две цели, одну для очистки директории от мусора (за мусор примем скомпилированый файл) и тестирования нашего проекта.

Мы добавили две цели: в цели test — команды для тестирования, которые мы использовали ранее, а в цели clean — команда для удаления скомпилированного файла “main” (“main.exe” для Windows).

Протестируем полученный файл:

make
make test
make clean

После этого у вас должен скомпилироваться код main.c, вывестись 2 результата запуска (с параметром и без), а потом удалиться исполняемый файл (“make clean” завершится с ошибкой, т.к. одного из файлов в зависимости от ОС у вас не будет)

Как видно, в файле часто используется название “main”. Для того, чтобы вынести его, в make есть поддержка переменных. Переменные задаются вне целей: “<имя переменной>:=<значение>”, каждая на новой строке. В командах значение переменной можно использовать с помощью конструкции “$(<имя переменной>)”. Добавим переменную target в наш Makefile:

Протестируйте этот файл еще раз.

Самостоятельное задание: добавьте Makefile в репозиторий и отправьте изменения на GitHub.

На этом пока все.

Show your support

Clapping shows how much you appreciated Alexander Pasukhov’s story.