Java, CI/CD Makefile сборка
В данном разделе рассмотрен пример CI/CD сборки java проекта через Makefile.
Смотрите также раздел CI/CD сборки Maven проекта.
Для проверки данного примера подготовлена ветка makefile-build в репозитории gitverse_tutorials/CICD_building_projects.
Подготовительные действия
-
Создайте репозиторий, например, CICD_building_projects.
-
Обновите список доступных пакетов:
sudo apt update- Установите JDK-пакет по умолчанию, который включает в себя компилятор Java:
sudo apt install default-jdkПроверьте, что компилятор установлен:
javac -version- Скачайте раннер и сделайте его исполняемым:
chmod +x act_runner-
Включите CI/CD в настройках вашего репозитория:

Main.java
Создайте файл Main.java с кодом:
public class Main {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}Проверьте, что программа исполняется
Запустите файл Main.java без предварительной компиляции, используя интерпретатор Java (java).
Пример успешного выполнения:
$ java Main.java
Hello, World!Makefile
Создайте Makefile, который содержит инструкции для сборки проекта или программы с помощью утилиты make:
# Define compiler
CC = javac
# Define target directory
TARGET_DIR = target
# Define target
TARGET = $(TARGET_DIR)/Main
all: $(TARGET)
$(TARGET): Main.java
mkdir -p $(TARGET_DIR)
$(CC) -d $(TARGET_DIR) Main.java
clean:
rm -rf $(TARGET_DIR)В Makefile обычно определяются зависимости между различными частями проекта и команды для их сборки. Утилита make использует Makefile для автоматизации процесса компиляции и сборки программного обеспечения.
Структура Makefile
CC = javac— определяет переменную CC и устанавливает ее значение равнымjavac, что указывает на компилятор Java.TARGET_DIR = target— здесь определяется переменнаяTARGET_DIRи устанавливается в значениеtarget, указывающее на директорию, где будут храниться скомпилированные файлы.TARGET = $(TARGET_DIR)/Main— определяет переменнуюTARGET, которая представляет собой путь к главному исполняемому файлу Main.all: $(TARGET)— это цельall, которая зависит от цели$(TARGET), что означает, что при запускеmake allбудет собран целевой файл Main.$(TARGET): Main.java— указывает, что цель$(TARGET)зависит от файла Main.java.mkdir -p $(TARGET_DIR)— создает директорию$(TARGET_DIR)с ключом -p, который создает все промежуточные директории в пути, если они отсутствуют.$(CC) -d $(TARGET_DIR) Main.java— использует переменнуюCC(компилятор javac) для компиляции файла Main.java и помещает скомпилированный файл в директорию$(TARGET_DIR).clean: rm -rf $(TARGET_DIR)— удаляет директорию$(TARGET_DIR)и все ее содержимое рекурсивно.
Проверьте, что Makefile исполняется
Пример:
$ make
javac Main.javaВ результате должен появиться файл Main.class.
Когда вы выполнили команду make, она вызвала правило all, которое зависит от цели $(TARGET), в данном случае Main. Это правило указывает, что для создания цели Main необходимо выполнить команду javac Main.java, которая компилирует файл Main.java с использованием Java компилятора (javac). Таким образом, при выполнении make была автоматически вызвана команда компиляции Java файла.
Проверьте скомпилированный файл
Пример успешного выполнения:
$ java Main
Hello, World!Когда вы выполняете java Main, Java ВМ ожидает, что имя класса будет указано после слова java, без расширения файла. Таким образом, Main будет рассматриваться как имя класса для запуска.
С другой стороны, когда вы используете java Main.java, вы указываете Java ВМ запустить файл Main.java, который не является допустимым способом для запуска Java программы. Java ВМ ожидает имя класса, а не имени файла .java.
javaMakefileBuildDemo.yaml
name: Сборка проекта через Makefile
on:
push:
jobs:
build-test:
name: javaMakefileBuildDemo
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3 # Checkout the repository code
- name: Install jdk
run: |
apt-get update
apt-get -y install default-jdk
- name: build project through Makefile
run: |
make
- name: Set Git user email
run: |
git config --local user.email "author@gitverse.com"
- name: Set Git user name
run: |
git config --local user.name "author"
- name: Create new makefile-build-branch
run: |
git checkout -b makefile-build-branch
git add .
git commit -m "a project through Makefile is built"
- name: Push to remote branch
run: |
git push -u origin makefile-build-branch --forceСтруктура javaMakefileBuildDemo.yaml:
name: Сборка проекта через Makefile— название работы (job), которая отвечает за сборку проекта через Makefile.on: push:— этот job будет запускаться при каждом push’е в репозиторий.jobs: build-test:— начало описания работы с именем build-test.name: javaMakefileBuildDemo— название этой конкретной задачи сборки проекта через Makefile.runs-on: ubuntu-latest— указание о том, что задача будет выполняться на последней версии Ubuntu.steps:— начало списка шагов, необходимых для выполнения этой задачи.- uses: actions/checkout@v3— используется для клонирования кода репозитория.- name: Install jdk— название шага, устанавливающего JDK.run: |— начало блока команд для выполнения.apt-get update— обновление пакетов.apt-get -y install default-jdk— установка JDK.
- name: build project through Makefile— название шага, собирающего проект через Makefile.run: |— начало блока команд для выполнения.make— вызов команды make для сборки проекта.
- name: Set Git user email— название шага, устанавливающего email пользователя Git.run: |— начало блока команд для выполнения.git config --local user.email "author@gitverse.com"— установка email пользователя Git.
- name: Set Git user name— название шага, устанавливающего имя пользователя Git.run: | — начало блока команд для выполнения.git config --local user.name "author"— установка имени пользователя Git.
- name: Create new makefile-build-branch— название шага, создающего новую ветку для сборки через Makefile.run: |: Начало блока команд для выполнения.git branch -d makefile-build-branch— удаление ветки локально.git checkout -b makefile-build-branch— создание новой ветки.git add .— добавление изменений для коммита.git commit -m "a project through Makefile is built"— коммит изменений с сообщением.
- name: Push to remote branch— название шага, отправляющего изменения на удаленную ветку.run: |— начало блока команд для выполнения.git push -u origin makefile-build-branch --force— отправка изменений на удаленную ветку.
CI/CD Сборка
Получите токен раннера
Создайте токен раннера в профиле репозитория во вкладке Настройки > Раннеры > Добавить раннер > пиктограмма копирования раннера:

Зарегистрируйте раннер
$ sudo ./act_runner register
INFO Registering runner, arch=amd64, os=linux, version=40a6fce.
INFO Enter the runner token:
qbTVGAj5pZrLtYTjAR3SSHoWu3Qy6dgBkSkyJAwo
INFO Enter the runner name (if set empty, use hostname: DESKTOP-VOTMM9Q):
makefile-build-demo
INFO Enter the runner labels, leave blank to use the default labels (comma-separated, for example, ubuntu-20.04:docker://node:16-bullseye,ubuntu-18.04:docker://node:16-buster,linux_arm:host):
INFO Registering runner, name=makefile-build-demo, instance=https://gitverse.ru/sc, labels=[ubuntu-latest:docker://node:16-bullseye ubuntu-22.04:docker://node:16-bullseye ubuntu-20.04:docker://node:16-bullseye ubuntu-18.04:docker://node:16-buster].
DEBU Successfully pinged the GitVerse instance server
INFO Runner registered successfully.
Сохраните и отправьте изменения в удаленный репозиторий
git add .
git commit -m "ваш комментарий"
git push -u origin makefile-buildЗапустите раннер
sudo ./act_runner daemonРаннер сработает на ранее отправленное изменение (событие push) и через некоторое время отправит в репозиторий новую ветку makefile-build-branch с собранным проектом:
![]()
Проверка сборки
Через некоторое время раннер выполнит задачи.
Пример:
![]()
Пример:

После успешной сборки обновите ваш локальный репозиторий, сохраните изменения в текущей ветке (если они были сделаны) и перейдите в ветку makefile-build-branch:
git pull
git add .
git commit -m "ваш комментарий"
git switch makefile-build-branchЗапустите проект:
$ java /target/Main
Hello, World!Когда вы используете java Main, Java виртуальная машина ожидает, что имя класса будет указано после слова java, без расширения файла. Таким образом, Main будет рассматриваться как имя класса для запуска.
С другой стороны, когда вы используете java Main.java, вы указываете Java виртуальной машине запустить файл Main.java, который не является допустимым способом для запуска Java-программы.
Таким образом Java виртуальная машина ожидает имя класса, а имя файла .java.