Skip to main content

05. Первое приложение

Чтобы начать работать с теорией, вам нужно создать выполнить эту инструкцию.

В итоге у вас должен быть создан такой репозиторий:

idea

В нём должно быть три коммита:

  1. Initial commit - содержит три файла: .gitignore, CMakeLists.txt и main.cpp. Причём при загрузке он должен корректно собираться в бинарник
  2. gitignore changed - в файле .gitignore добавить строчку /.idea/
  3. readme added - добавьте readme.md файл
## Тестовый репозиторий

Он создан для проверки работы `.gitignore`.

А сам проект в clion должен выглядеть так:

idea

Все задания можно выполнять в удобной вам среде разработки. Хотя я советую Clion. Для альтернативных сред будут даваться консольные команды. Если вы работаете в Clion, просто игнорируйте их.

CMake

Чтобы собирать сложные приложения на C++, которые используют сторонние библиотеки, используется специальная консольная программа cmake.

Инструкции для неё пишутся в файле CMakeLists.txt

idea

Первая строка указывает, какая минимальная версия cmake может собирать проект по инструкциям в этом файле

cmake_minimum_required(VERSION 3.21)

Вторая строка указывает название проекта

project(test_cmake)

Следующая строка указывает версию стандарта(языка) cmake

set(CMAKE_CXX_STANDARD 14)

Последняя добавляет сборку бинарника

add_executable(test_cmake main.cpp)

где test_cmake - название бинарника, main.cpp - исходники

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

К тому же, модули могут вообще собираться из удалённых репозиториев. Об этом будет рассказано ниже.

Пока что мы создадим только один модуль с нашим исходником, который просто выводит на экран Hello, World!.

Для этого создайте папку src, переместите (можно перетащить) в него файл main.cpp и создайте в этой папке файл CMakeList.txt. Для каждого модуля нужно указывать свой список команд сборки.

idea

Теперь нам нужно поменять главный CMakeList.txt так, чтобы он просто подключал модуль src:

cmake_minimum_required(VERSION 3.21)
project(test_cmake)

set(CMAKE_CXX_STANDARD 14)

add_subdirectory(src)

В созданном нами новом CMakeList.txt нужно написать всего одну строчку

add_executable(example main.cpp)

Теперь снова откройте главный файл CMakeList.txt. Clion предложит автоматически обрабатывать его изменения. Вам нужно это разрешить. Для этого кликните Enable Auto-Reload.

idea

После того, как clion обработает изменения, название приложения должно поменяться на example:

idea

Запустите приложение. У вас снова должна вывестись фраза Hello, World!:

idea

Теперь вам нужно создать новый коммит и отправить его на сервер.

Для этого нажмите Ctrl+K, введите название коммита main.cpp moved to module и нажмите Commit and Push...

idea

В следующем окне нажмите Push.

idea

Теперь ваш репозиторий должен будет выглядеть так:

idea

Если перейти в папку src, то её содержимое будет таким:

idea

Сборка в консоли*

Если вы используете clion, то можете пропустить этот раздел и переходить к следующему.

Чтобы собрать проект с помощью cmake через консоль, вам нужно создать папку для сборки, обычно её называют build.

idea

Перейдите в папку build и, зажав Shift клинките правой кнопкой мыши по свободной области внутри открытой папки и в контекстном меню выберите Открыть окно PowerShell здесь

idea

Выполните команду:

cmake ../

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

idea

Дождитесь, пока закончится подготовка файлов закончится

idea

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

cmake --build .

idea

Теперь можно запустить собранную нами программу

.\src\Debug\example.exe

idea

Бинарник собирается в папке src\Debug\example.exe

Зависимости

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

Чтобы добавить зависимость, создадим ещё одну папку dependencies,

idea

а в ней создадим файл CMakeList.txt:

idea

Первой зависимость, которую мы так подключим, будет sfml.

Для этого сам файл нужно заполнить следующими строками:

include(FetchContent)

# SFML
FetchContent_Declare(
sfml
URL https://github.com/SFML/SFML/archive/refs/tags/2.5.1.zip
URL_MD5 2c4438b3e5b2d81a6e626ecf72bf75be
)

add_subdirectory(sfml)

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

include(FetchContent)

выполняет импорт FetchContent.

Вторая команда иммет несколько аругментов:

# SFML
FetchContent_Declare(
sfml
URL https://github.com/SFML/SFML/archive/refs/tags/2.5.1.zip
URL_MD5 2c4438b3e5b2d81a6e626ecf72bf75be
)

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

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

Чтобы это сделать, создаёте папку sfml в папке dependencies, а внутри папки sfml создайте новый CMakeList.txt файл.

idea

Сам файл заполните следующими строками:

message(STATUS "Fetching SFML...")

# No need to build audio and network modules
set(SFML_BUILD_AUDIO FALSE)
set(SFML_BUILD_NETWORK FALSE)

FetchContent_MakeAvailable(sfml)

Первая команда выводит сообщение в лог сборки уровня STATUS строку, которая указана в кавычках. В нашем случае - это Fetching SFML...

message(STATUS "Fetching SFML...")

Вторая и третья команда - это просто флаги, говорящие CMake, что не нужно собирать аудио и сетевые модули

# No need to build audio and network modules
set(SFML_BUILD_AUDIO FALSE)
set(SFML_BUILD_NETWORK FALSE)

Последняя команда - это просто связывание удалённого репозитория с нашим CMake проектом

FetchContent_MakeAvailable(sfml)

Т.к. мы собираем библиотеку, то нам нужно связать её заголовочные файлы с объектными.

Для этого используется команда

target_link_libraries(example PRIVATE sfml-graphics)

Также нужно прописать для Windows автоматическое копирование собранных DLL библиотек в папку с бинарником. В этой команде просто перечисляется, что и куда скопировать после сборки бинарника example

# Copy DLLs needed for runtime on Windows
if(WIN32)
if (BUILD_SHARED_LIBS)
add_custom_command(TARGET example POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:sfml-graphics>
$<TARGET_FILE:sfml-window>
$<TARGET_FILE:sfml-system>
$<TARGET_FILE_DIR:example>)
endif()
endif()

Если эту команду не дописать, то на Windows мы получим такую ошибку:

idea

Весь файл src/CMakeList.txt теперь будет таким:

add_executable(example main.cpp)
target_link_libraries(example PRIVATE sfml-graphics)

# Copy DLLs needed for runtime on Windows
if(WIN32)
if (BUILD_SHARED_LIBS)
add_custom_command(TARGET example POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:sfml-graphics>
$<TARGET_FILE:sfml-window>
$<TARGET_FILE:sfml-system>
$<TARGET_FILE_DIR:example>)
endif()
endif()

В главном файле CMakeList.txt нужно добавить строчку

add_subdirectory(dependencies)

Весь файл будет теперь таким:

cmake_minimum_required(VERSION 3.21)
project(test_cmake)

set(CMAKE_CXX_STANDARD 14)

add_subdirectory(dependencies)
add_subdirectory(src)
Соблюдайте порядок подключения

Сначала должно идти подключение папкиdependencies и только потом - src. В противном случае приложение у вас запустится с ошибкой.

Если после сохранения главного файла у вас не началась автоматическая пересборка, то вам нужно вручную пересобрать проект. Для этого в верхнем меню выберите Build->Rebuild Project.

idea

Начнётся сборка

idea

Когда сборка закончится, Clion выдаст сообщение Build finished

idea

Теперь запустите снова ваше приложение, чтобы удостовериться в корректности настроек

idea

Программа снова должна вывести Hello, World!

Замените теперь код main.cpp:

#include <SFML/Graphics.hpp>

int main() {
sf::RenderWindow window(sf::VideoMode(200, 200), "SFML works!");
sf::CircleShape shape(100.f);
shape.setFillColor(sf::Color::Green);

while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed)
window.close();
}

window.clear();
window.draw(shape);
window.display();
}

return 0;
}

Запустите приложение, оно должно нарисовать зелёный круг:

idea

Если программа всё ещё выводит Hello, World, значит, вам нужно пересобрать проект Build->Rebuild project.

После успешного запуска кода sfml вам нужно создать новый коммит sfml connected и отправить его на сервер.

idea

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

idea

Dear ImGui

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

Чтобы её подключить, нужно переписать dependencies/CMakeLists.txt:

include(FetchContent)


# SFML
FetchContent_Declare(
sfml
URL https://github.com/SFML/SFML/archive/refs/tags/2.5.1.zip
URL_MD5 2c4438b3e5b2d81a6e626ecf72bf75be
)

add_subdirectory(sfml)

# Dear ImGui
FetchContent_Declare(
imgui
GIT_REPOSITORY https://github.com/ocornut/imgui
GIT_TAG 35b1148efb839381b84de9290d9caf0b66ad7d03 # 1.82
)

FetchContent_MakeAvailable(imgui)

# ImGui-SFML
FetchContent_Declare(
imgui-sfml
GIT_REPOSITORY https://github.com/eliasdaler/imgui-sfml
GIT_TAG 82dc2033e51b8323857c3ae1cf1f458b3a933c35 # 2.3
)
add_subdirectory(imgui-sfml)

Также нужно создать папку imgui-sfml, а в ней файл CMakeLists.txt

idea

Его заполните следующими строками:

message(STATUS "Fetching ImGui-SFML...")

set(IMGUI_DIR ${imgui_SOURCE_DIR})
set(IMGUI_SFML_FIND_SFML OFF)
set(IMGUI_SFML_IMGUI_DEMO ON)

FetchContent_MakeAvailable(imgui-sfml)

Также нужно добавить копирование DLL

add_executable(example main.cpp)
target_link_libraries(example PRIVATE ImGui-SFML::ImGui-SFML)


# Copy DLLs needed for runtime on Windows
if(WIN32)
if (BUILD_SHARED_LIBS)
add_custom_command(TARGET example POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:ImGui-SFML::ImGui-SFML>
$<TARGET_FILE:sfml-graphics>
$<TARGET_FILE:sfml-window>
$<TARGET_FILE:sfml-system>
$<TARGET_FILE_DIR:example>)
endif()
endif()

Замените теперь код main.cpp:

#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/System/Clock.hpp>
#include <SFML/Window/Event.hpp>

#include <imgui-SFML.h>
#include <imgui.h>

// главный метод
int main() {
// создаём окно для рисования
sf::RenderWindow window(sf::VideoMode(1280, 720), "ImGui + SFML = <3");
// задаём частоту перерисовки окна
window.setFramerateLimit(60);
// инициализация imgui+sfml
ImGui::SFML::Init(window);

// переменная таймера
sf::Clock deltaClock;
// пока окно открыто, запускаем бесконечный цикл
while (window.isOpen()) {
// создаём событие sfml
sf::Event event;
// пока окно принимает события
while (window.pollEvent(event)) {
// отправляем события на обработку sfml
ImGui::SFML::ProcessEvent(event);

// если событие - это закрытие окна
if (event.type == sf::Event::Closed) {
// закрываем окно
window.close();
}
}

// запускаем обновление окна по таймеру с заданной частотой
ImGui::SFML::Update(window, deltaClock.restart());

// рисуем демонстрационное окно
ImGui::ShowDemoWindow();

// очищаем окно
window.clear();
// рисуем по окну средствами imgui+sfml
ImGui::SFML::Render(window);
// отображаем изменения на окне
window.display();
}

// завершаем работу imgui+sfml
ImGui::SFML::Shutdown();

return 0;
}

Перезапустите сборку проекта и запустите программу example. У вас должно запуститься демонстрационное окно ImGui

idea

Создайте новый коммит с названием imgui connected и отправьте его на сервер.

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

idea

Теперь поменяйте readme, как показано в образце, создайте новый коммит readme changed и отправьте на сервер.

## Шаблон проекта SFML+ImGui

Этот репозиторий - прототип программ для создания графических приложений средствами `SFML` и
`ImGui`.

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

idea

Задание

Оценивание

Это задание выдаётся только на урок, оно оценивается по последнему коммиту, сделанному во время урока. Если вы выполнили все блоки теории в этой главе, то вам останется только опубликовать ваш локальный репозиторий на сервере github.

Вам необходимо создать свой репозиторий, в котором добавлены следующие коммиты (для каждого сначала указывается название, потом требования):

В нём должно быть три коммита:

  1. Initial commit - содержит три файла: .gitignore, CMakeLists.txt и main.cpp. Причём при загрузке он должен корректно собираться в бинарник
  2. gitignore changed - в файле .gitignore добавить строчку /.idea/
  3. readme added - добавьте readme.md файл
## Тестовый репозиторий

Он создан для проверки работы `.gitignore`.
  1. main.cpp moved to module - переделайте проект под сборку модуля src (один CMakeLists.txt для всего проекта, один - для модуля src)
  2. sfml connected - создайте папку зависимостей dependencies, а внутри неё модуль sfml, который собирает библиотеку из git-репозитория, перепишите файл main.cpp, а также CMakeLists.txt так, чтобы средствами sfml в окне рисовался зелёный круг.
  3. imgui connected - подключите библиотеку imgui таким же образом, как и sfml, перепишите main.cpp так, чтобы рисовалось демонстрационное окно ImGui.

Ссылку на github-репозиторий необходимо отправить в поле ввода задания на сайте mdl.

Ссылка на контест.