Перейти к содержимому

Сборка первой программы на C++ [1.4]

Сборка первой программы на C++ [1.4]

В этом уроке вы пройдете путь от пустого файла до запуска готовой программы на C++. Мы разберем виды целевых объектов (исполняемый файл, статическая и динамическая библиотеки), познакомимся с конфигурациями Debug/Release и шаг за шагом соберем проект с помощью CMake. В конце вас ждут практические задачи и чек-лист самопроверки.

Главная мысль урока: сборка -- это превращение исходного кода (.cpp) в машинный файл, который может быть исполняемым (.exe), статической (.lib / .a) или динамической (.dll / .so) библиотекой. Управлять этим процессом удобнее всего через CMakeLists.txt.

Содержание

1. Цели урока

  • Понять, как из исходного кода (.cpp) получаются целевые объекты.
  • Различать исполняемый файл, статическую и динамическую библиотеки.
  • Объяснить разницу между конфигурациями Debug и Release.
  • Самостоятельно написать CMakeLists.txt и собрать проект.
  • Переключать тип целевого объекта и конфигурацию сборки в CMake.
Что особенно важно запомнить: сборка -- это не одно действие, а конвейер исходный код -> компилятор -> целевой объект, и CMake позволяет описывать правила этого конвейера в одном файле.
^ К оглавлению

2. Что такое сборка программы

Сборка (build) -- это процесс превращения текстовых файлов с исходным кодом в машинные инструкции, которые процессор может выполнить напрямую. Общая схема выглядит так:

# Схема сборки (упрощенно)
#
# Исходный код (.cpp / .h)
#        |
#        v
#   Компилятор  (g++, clang++, MSVC)
#        |
#        v
# Целевой объект  (.exe / .lib / .dll)
Bash

Компилятор читает ваш .cpp-файл, проверяет синтаксис, преобразует конструкции языка в машинный код и записывает результат в целевой объект (target). Тип этого объекта зависит от настроек проекта.

Сборка и запуск -- не одно и то же

Запомните: сборка и запуск -- это два разных этапа. Сборка создает файл; запуск -- передает управление этому файлу. Если сборка прошла без ошибок, это еще не значит, что программа работает правильно -- логические ошибки обнаруживаются только при запуске или тестировании.
^ К оглавлению

3. Виды целевых объектов

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

3.1. Исполняемый файл (Executable)

Набор машинных инструкций, которые ОС может запустить напрямую. Это именно то, что вы запускаете, чтобы программа начала работать.

# CMake: создать исполняемый файл
add_executable(my_robot)
CMake
ПлатформаРасширениеПример
Windows .exe my_robot.exe
Linux без расширения my_robot
macOS без расширения / .app my_robot

3.2. Статическая библиотека (Static Library)

Набор подпрограмм, которые встраиваются в исполняемый файл на этапе компоновки (линковки). После сборки вашему .exe уже не нужен отдельный файл библиотеки -- весь ее код "вшит" внутрь.

# CMake: создать статическую библиотеку
add_library(my_math)          # по умолчанию -- STATIC
# или явно:
add_library(my_math STATIC)
CMake
Плюс: программа полностью самодостаточна -- не нужны внешние файлы.
Минус: размер итогового исполняемого файла увеличивается.

3.3. Динамическая библиотека (Shared / Dynamic Library)

Набор подпрограмм, которые подгружаются в программу при ее запуске (или по запросу). Библиотека остается отдельным файлом и не копируется внутрь исполняемого файла.

# CMake: создать динамическую библиотеку
add_library(my_sensors SHARED)
CMake
Плюс: исполняемый файл легче; несколько программ могут разделять одну библиотеку.
Минус: для работы программы файл .dll / .so должен быть доступен.

3.4. Сравнительная таблица

КритерийИсполняемый файлСтатическая библиотекаДинамическая библиотека
Можно запустить напрямую Да Нет Нет
Встраивается в .exe -- Да Нет
Загружается при запуске -- Нет Да
Размер итогового .exe Средний Большой Малый
Самодостаточность Да Да Нет
Расширение (Win / Linux) .exe / -- .lib / .a .dll / .so

3.5. Типичные ошибки

Ошибка 1: попытка "запустить" библиотеку

Начинающие иногда собирают проект как библиотеку (add_library), а затем пытаются запустить полученный .lib / .a-файл. Библиотека не является самостоятельной программой -- у нее нет точки входа main().

# [!] Не сработает:
./build/Debug/my_math.a
# bash: ./build/Debug/my_math.a: Permission denied  (или "не является исполняемым")

# [ok] Библиотеку нужно подключить к исполняемому файлу:
# target_link_libraries(my_robot PRIVATE my_math)
Bash

Ошибка 2: одновременно add_executable и add_library с одним именем

Если в CMakeLists.txt указано и add_executable(lesson3), и add_library(lesson3), CMake выдаст ошибку: цель с именем lesson3 уже определена. Активной должна быть только одна команда.

# [!] Ошибка: дублирование цели
add_executable(lesson3)
add_library(lesson3)       # CMake Error: target "lesson3" already exists

# [ok] Оставьте только один вариант:
add_executable(lesson3)
# add_library(lesson3)
CMake
^ К оглавлению

4. Конфигурации сборки: Debug и Release

Один и тот же исходный код компилятор может превратить в машинный код по-разному в зависимости от выбранной конфигурации. Две основные конфигурации -- Debug и Release.

4.1. Режим Debug (Отладка)

Предназначен для разработки и поиска ошибок.

  • Оптимизация отключена -- код выполняется "как написан", без перестановок компилятором.
  • Генерируется отладочная информация -- можно ставить точки останова, видеть значения переменных и стек вызовов.
  • Итоговый файл больше по размеру и работает медленнее.
# Установка режима Debug в CMake
set(CMAKE_BUILD_TYPE Debug)
CMake

4.2. Режим Release (Релиз)

Предназначен для финальной версии программы.

  • Оптимизация включена -- компилятор перестраивает код для максимальной скорости.
  • Отладочная информация не генерируется -- файл меньше, код сложнее разобрать.
  • Итоговый файл меньше и работает быстрее.
# Установка режима Release в CMake
set(CMAKE_BUILD_TYPE Release)
CMake

4.3. Сравнение режимов

ПараметрDebugRelease
Оптимизация Отключена Максимальная
Отладочная информация Генерируется Отсутствует
Размер файла Большой Малый
Скорость работы Низкая Высокая
Назначение Разработка, тесты Продакшен
Практический вывод: используйте Debug, пока пишете и тестируете код робота, и переключайтесь на Release, когда загружаете финальную прошивку.

4.4. Типичные ошибки

Ошибка 1: отладка Release-сборки

Если вы собрали проект в режиме Release и пытаетесь поставить точку останова (breakpoint) в отладчике, он может "прыгать" по строкам или не останавливаться вовсе. Причина -- оптимизатор переставил и сократил код, а отладочные символы отсутствуют.

# [!] Собрали Release, а потом пытаемся отлаживать -- не работает
set(CMAKE_BUILD_TYPE Release)

# [ok] Для отладки нужен Debug
set(CMAKE_BUILD_TYPE Debug)
CMake

Ошибка 2: поставка Debug-сборки пользователю

Debug-версия содержит отладочные символы, работает медленнее и весит значительно больше. Для финальной поставки (на робота, заказчику и т.д.) всегда используйте Release.

^ К оглавлению

5. Система сборки CMake

CMake -- это кроссплатформенная система управления сборкой. Она не компилирует код сама, а генерирует файлы для выбранной системы сборки (Make, Ninja, Visual Studio и др.), которая уже вызывает компилятор.

# Как работает CMake (упрощенно):
#
# CMakeLists.txt  -->  CMake  -->  Makefile / .sln / ninja  -->  Целевой объект
# (ваши правила)                   (системные файлы)              (.exe / .lib / .dll)
Bash

Главное преимущество: один и тот же CMakeLists.txt работает на Windows, Linux и macOS. Вам не нужно писать отдельные скрипты сборки под каждую платформу.

5.1. Основные команды CMakeLists.txt

КомандаНазначение
cmake_minimum_required(VERSION X.Y) Минимально допустимая версия CMake
project(name ...) Метаданные проекта: имя, версия, язык
set(VAR value) Создает или изменяет переменную
add_executable(name) Объявляет цель типа "исполняемый файл"
add_library(name) Объявляет цель типа "статическая библиотека"
add_library(name SHARED) Объявляет цель типа "динамическая библиотека"
target_sources(name PRIVATE ...) Привязывает исходные файлы к целевому объекту
Запомните: ключевое слово PRIVATE в target_sources означает, что перечисленные файлы используются только для сборки данной цели и не передаются зависимым целям.

5.2. Типичные ошибки

Ошибка 1: файл называется не CMakeLists.txt

CMake ищет файл с точным именем CMakeLists.txt (регистр важен!). Варианты вроде cmakelists.txt, CMakeList.txt или cmake_lists.txt не будут найдены.

# [!] Файл назван неправильно
$ ls
cmake_lists.txt  main.cpp
$ cmake -B build
# CMake Error: The source directory "..." does not appear to contain CMakeLists.txt.

# [ok] Правильное имя (с точным регистром)
$ mv cmake_lists.txt CMakeLists.txt
$ cmake -B build
# -- Configuring done
Bash

Ошибка 2: пробел в ${ sources }

В CMake обращение к переменной пишется слитно: ${sources} . Если между скобками и именем есть пробелы (${ sources }), CMake может не найти переменную.

# [!] Пробелы внутри ${ } -- переменная не раскроется корректно
target_sources(lesson3 PRIVATE ${ sources })

# [ok] Без пробелов
target_sources(lesson3 PRIVATE ${sources})
CMake
^ К оглавлению

6. Пошаговая сборка проекта

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

Шаг 1. Структура директории

Создайте папку проекта с двумя файлами:

# Создаем директорию и переходим в нее
mkdir my_first_project
cd my_first_project

# Создаем два пустых файла
# Linux / macOS:
touch CMakeLists.txt main.cpp

# Windows (PowerShell):
# New-Item CMakeLists.txt, main.cpp
Bash

Итоговая структура:

my_first_project/
    CMakeLists.txt      # инструкции для системы сборки
    main.cpp            # исходный код программы
Bash
Важно: убедитесь, что разрядность компилятора (32/64 бит) совпадает с разрядностью вашей ОС.

Шаг 2. Исходный код main.cpp

Откройте main.cpp в редакторе и напишите простейшую программу:

// main.cpp -- первая программа на C++

#include <iostream>   // Подключаем библиотеку ввода-вывода

int main() {
    // Выводим приветствие в консоль
    std::cout << "Hello, Robotics World!" << std::endl;

    return 0;         // 0 -- программа завершилась успешно
}
C++
СтрокаЧто делает
#include <iostream> Подключает стандартную библиотеку для работы с вводом/выводом
int main() Объявляет главную функцию -- точку входа в программу
std::cout << "..." Выводит текст в стандартный поток (консоль)
std::endl Переводит строку и очищает буфер вывода
return 0; Сообщает ОС, что программа завершилась без ошибок

Шаг 3. Файл CMakeLists.txt

Это "рецепт" для системы сборки. Скопируйте код ниже и изучите комментарии:

# -- 1. Системные требования --
cmake_minimum_required(VERSION 3.18)

# -- 2. Описание проекта --
project(
    lesson3                       # Имя проекта
    VERSION 0.0.1                 # Версия (Major.Minor.Patch)
    DESCRIPTION "First project"   # Краткое описание
    LANGUAGES CXX                 # Язык: CXX = C++
)

# -- 3. Настройки компиляции --
set(CMAKE_CXX_STANDARD 17)           # Стандарт C++17
set(CMAKE_CXX_STANDARD_REQUIRED ON)  # Стандарт обязателен
set(CMAKE_BUILD_TYPE Debug)           # Конфигурация: Debug

# -- 4. Целевой объект --
# Вариант 1: Исполняемый файл (.exe)
add_executable(lesson3)

# Вариант 2: Статическая библиотека (.lib / .a)
# add_library(lesson3)

# Вариант 3: Динамическая библиотека (.dll / .so)
# add_library(lesson3 SHARED)

# -- 5. Исходные файлы --
set(sources
    main.cpp
)

target_sources(lesson3 PRIVATE ${sources})
CMake
Запомните: чтобы переключить тип целевого объекта, закомментируйте текущую строку (#) и раскомментируйте нужную. Одновременно активна только одна из трех команд.

Шаг 4. Генерация и компиляция

Откройте терминал в папке проекта и выполните две команды:

# 1. Генерируем файлы сборки в папку build
cmake -B build

# 2. Запускаем компиляцию
cmake --build build
Bash

После успешной сборки появится структура:

my_first_project/
    CMakeLists.txt
    main.cpp
    build/                    # создана автоматически
        Debug/                # или Release
            lesson3.exe       # ваш целевой объект
Bash

Шаг 5. Запуск результата

# Windows:
.\build\Debug\lesson3.exe

# Linux / macOS:
./build/lesson3
Bash

Ожидаемый вывод:

Hello, Robotics World!
Bash

Типичные ошибки при сборке

Ошибка: компилятор не найден

Если при команде cmake -B build появляется сообщение "No CMAKE_CXX_COMPILER could be found", значит, в системе не установлен или не настроен компилятор C++.

# Проверить наличие компилятора:
g++ --version       # Linux / macOS (GCC)
cl                  # Windows (MSVC, из Developer Command Prompt)

# Если не установлен -- установите:
# Ubuntu/Debian: sudo apt install g++
# macOS:         xcode-select --install
# Windows:       установите Visual Studio (с компонентом "Разработка на C++")
Bash

Ошибка: main не найдена при сборке библиотеки

Если вы выбрали add_library, но оставили main() в коде, сборка пройдет успешно (библиотеке не нужна точка входа). Однако запустить .lib-файл вы не сможете. И наоборот: если выбран add_executable, а функция main() отсутствует -- линковщик выдаст ошибку.

# [!] Ошибка линковщика при отсутствии main() в executable:
# undefined reference to `main'

# [ok] Убедитесь, что в main.cpp есть функция int main() { ... }
Bash
^ К оглавлению

7. Практика: типовые задачи (с решениями)

Базовые задачи

Задача 1: "Мое имя"

Измените программу так, чтобы она выводила ваше имя и специальность.

#include <iostream>

int main() {
    std::cout << "My name is Alex." << std::endl;
    std::cout << "I study robotics." << std::endl;
    return 0;
}

// Output:
// My name is Alex.
// I study robotics.
C++

Задача 2: Несколько строк через \n

Выведите три строки текста, используя символ \n вместо std::endl.

#include <iostream>

int main() {
    std::cout << "Line 1\nLine 2\nLine 3\n";
    return 0;
}

// Output:
// Line 1
// Line 2
// Line 3
C++

Задачи на CMake

Задача 3: Переключите конфигурацию на Release

Измените CMakeLists.txt так, чтобы проект собирался в режиме Release. Соберите и сравните размер файла с Debug-версией.

# Было:
set(CMAKE_BUILD_TYPE Debug)

# Стало:
set(CMAKE_BUILD_TYPE Release)

# Пересоберите:
# cmake -B build
# cmake --build build
CMake

Задача 4: Соберите проект как статическую библиотеку

Переключите целевой объект на статическую библиотеку. Убедитесь, что в папке build появился файл .lib (Windows) или .a (Linux).

# Закомментируйте executable:
# add_executable(lesson3)

# Раскомментируйте library:
add_library(lesson3)

# Пересоберите:
# cmake -B build
# cmake --build build

# Результат: build/Debug/lesson3.lib  (Windows)
#            build/liblesson3.a       (Linux)
CMake

Продвинутые задачи

Задача 5: Два исходных файла

Добавьте в проект файл greet.cpp с функцией, которая возвращает строку приветствия. Подключите его к сборке через переменную sources.

greet.h

#ifndef GREET_H
#define GREET_H

#include <string>

std::string getGreeting();

#endif
C++

greet.cpp

#include "greet.h"

std::string getGreeting() {
    return "Hello from greet module!";
}
C++

main.cpp

#include <iostream>
#include "greet.h"

int main() {
    std::cout << getGreeting() << std::endl;
    return 0;
}

// Output:
// Hello from greet module!
C++

CMakeLists.txt (изменения)

set(sources
    main.cpp
    greet.cpp
)

target_sources(lesson3 PRIVATE ${sources})
CMake

Задача 6: Динамическая библиотека

Соберите проект как динамическую библиотеку и найдите получившийся .dll / .so-файл в папке build.

# Закомментируйте executable:
# add_executable(lesson3)

# Раскомментируйте shared library:
add_library(lesson3 SHARED)

# Пересоберите:
# cmake -B build
# cmake --build build

# Результат: build/Debug/lesson3.dll  (Windows)
#            build/liblesson3.so      (Linux)
CMake
^ К оглавлению

8. Чек-лист самопроверки знаний

Отметьте пункты, которые вы действительно понимаете и можете применить без подсказок.

+/-НавыкПроверка
Понятие сборки Могу объяснить, что такое сборка и чем она отличается от запуска программы
Исполняемый файл Могу объяснить, что такое .exe и как его создать через CMake (add_executable)
Статическая библиотека Могу объяснить, чем .lib / .a отличается от .exe и когда ее использовать
Динамическая библиотека Могу объяснить, чем .dll / .so отличается от статической библиотеки
Конфигурация Debug Могу объяснить, почему Debug-сборка медленнее и тяжелее, но удобнее для отладки
Конфигурация Release Могу переключить проект на Release и объяснить, зачем это нужно
Структура CMakeLists.txt Могу написать CMakeLists.txt с нуля для простого проекта на C++17
Команды CMake в терминале Могу выполнить cmake -B build и cmake --build build и понимаю, что делает каждая
Переключение типа цели Могу переключить сборку между executable, static library и shared library
Многофайловый проект Могу добавить второй .cpp-файл в проект через переменную sources
Поиск ошибок сборки Могу прочитать ошибку компилятора/линковщика и понять, к какому файлу и строке она относится
Папка build Могу найти скомпилированный файл в папке build и запустить его из терминала
^ К оглавлению
Воскресенье, 15 февраля 2026
Сборка первой программы на C++ [1.4]