Это обзорная лекция без деталей, четыре части:
- Что можно сделать с помощью сторонних библиотек
- Кто компилирует C++, что откуда устанавливать.
- Как устроена компиляция и какие ошибки компиляции бывают.
- Конкретные примеры библиотек (Qt рулит, но есть ещё и другие).
Успеем пройтись по верхам и посмотреть на небольшие примеры.
Это всё проекты или домашки наших студентов
- Qt: графический интерфейс, мультимедиа, сеть...
- Игра (на самом деле разработка игр — отдельная вселенная и лучше движки)
- Аттракторы
- Dear ImGui: другой графический интерфейс
- Clang: внедряемся в компилятор C++
- Doctest: короткие и красивые тесты для отдельных функций
Стандарты: C++98/C++03, C++11 (C++0x), C++14, C++17, C++20... (это тексты)
- Язык: что такое
for
иint
- Стандартная библиотека (не только STL):
#include <algorithm>
Обязательное:
- Компилятор: gcc, Clang (LLVM), Visual C++, Apple Clang, Intel C++ Classic...
- Стандартная библиотека: libstdc++ (GNU), libc++, Microsoft STL...
- Динамические библиотеки: Visual C++ Redistributable
- Редактор кода: автодополнение, подсказки, подсветка синтаксиса
Опциональное:
- Отладчик: gdb, lldb...
- Система сборки: Makefile, проекты Visual Studio, проекты Code::Blocks
- CMake генерирует проекты для систем сборки (привет, CLion)
- Нестандартные библиотеки: GUI, мультимедиа, сеть...
Основная проблема: несовместимость ABI (Application Binary Interface).
- Один и тот же код можно скомпилировать по-разному
- Если библиотека и приложение используют разное ABI, они в лучшем случае не скомпилируются вместе
- У gcc/clang может быть множество несовместимых "сборок"
Особенности Linux и macOS: просто использовать:
- Есть "стандартный" компилятор и "стандартное" ABI: gcc в Ubuntu, Apple Clang в macOS
- Все популярные библиотеки уже скомпилированы, можно установить через
apt
в Ubuntu, HomeBrew в macOS - Можно поставить другие компиляторы (clang в Ubuntu, gcc в macOS) через
apt
/HomeBrew, должно работать
Под Windows:
- Есть много сборок gcc/clang с разным ABI, не всегда от Visual Studio
- Нет единого пакетного менеджера
Вещи в себе:
- Code::Blocks со встроенным gcc 8.1.0 из mingw-w64
- Qt Creator со встроенным gcc 8 из mingw-w64 и Qt (супер фреймворк!)
- CLion со встроенным gcc 9 из mingw-w64 (бесплатно для школьников и студентов)
Компиляторы с пакетными менеджерами:
- Visual Studio 2019 Community, использовать менеджер vcpkg
- mingw-w64, использовать менеджер
pacman
- Поставить Windows Subsystem for Linux (WSL) и Ubuntu 20.04 внутрь
Отдельно ставить среду разработки (CLion, Qt Creator, независимо от компилятора) или текстовый редактор и запускать через консоль.
- Если не хотите использовать нестандартные библиотеки, то ставьте что угодно.
- Если хотите Qt (рекомендую!), то Qt Creator.
- Под Linux используйте встроенный пакетный менеджер (
apt
/yum
/pacman
/emerge
)- Обычно библиотека
Foo
будет называтьсяlibFoo-dev
- Обычно библиотека
- Под macOS поставьте HomeBrew и используйте библиотеки из него
- Под Windows используйте либо Linux, либо mingw-w64 и gcc, либо Visual Studio и vcpkg
Чего не делать:
- Сборка библиотек из исходников (build from source): долго и нудно
- Особенно остерегайтесь
./configure && make && make install
- Особенно остерегайтесь
- Использование библиотек, которых нет в пакетных менеджерах
- Алхимия и переименование файлов:
libboost.a
иboost.lib
несовместимы!
Компиляция C++ сделана как в языке Си из 1970-х годов. Памяти было мало, прочитать все файлы сразу нельзя.
Два шага: компиляция и линковка (компоновка).
┌────────────────────┐ ┌─────────────────────┐
│ main.cpp │ │ say_hello.cpp │
│ │ │ │
│ Использует: │ │ Реализовано: │
│ * void say_hello() │ │ * void say_hello(); │
└──────────┬─────────┘ └──────────┬──────────┘
│ компиляция │
▼ ▼ Стандартные
main.o say_hello.o библиотеки
│ │ │
└──────►линковщик◄──────┘◄───────────────┘
│
▼
app.exe
- Системы сборки это от вас скрывают (и правильно!).
- Команда
g++
/clang++
/cl
умеет и компилировать, и линковать. - Продемонстрировать ключ
-c
дляg++
.
Чтобы main.cpp
мог использовать функцию say_hello()
, определённую в say_hello.cpp
,
ему надо про неё рассказать:
void say_hello(); // Объявление функции: нет {} с определением.
int main() { say_hello(); }
Ошибки на стадии линковки (не компиляции):
- Если забыть реализовать
say_hello()
или прилинковатьsay_hello.cpp
— undefined reference - Если дать две реализации
say_hello()
— multiple definition - Если слинковать командой
gcc
вместоg++
, то не будет стандартной библиотеки C++ — undefined reference
Ошибка на стадии запуска:
- Если запустить на "чистой" машине без нужных динамических библиотек — ошибка при запуске.
- У меня под Windows для mingw-w64 нужна
libstdc++-6.dll
- Под Linux бывает при переезде между дистрибутивами
- У меня под Windows для mingw-w64 нужна
#include <foo>
родом из 1970: просто копирует файл foo
в текущее место в коде.
- Где ищутся такие файлы — настройка компилятора, обычно есть текущая папка и стандартная библиотека.
- В заголовочных файлах пишут объявления функций и ещё кое-что
- Показать
-E
для стандартной библиотеки
Если ставите библиотеку — надо, чтобы компилятор видел её заголовочные файлы.
- Обычно можно добавить папку (include directory) в настройках проекта, ключом
-I
илиtarget_include_directories
в CMake. - Но лучше через пакетный менеджер или
find_package
/add_library
в CMake.
Бывают header-only библиотеки:
- Не надо ничего добавлять на этапе линковки
- Сильно увеличивается время компиляции, но возможны трюки
Но заголовочных файлов недостаточно:
- Для некоторых библиотек нужен скомпилированный код
- Обычно кладут не
.o
-файлы, а архив с именем вродеlibboost_filesystem-mt.a
. - Надо рассказать про этот архив линковщику (не компилятору!): в настройках проекта, ключ
-lboost_filesystem-mt
для gcc/clang,target_link_libraries
в CMake. - Где ищутся такие архивы — настройка линковщика, обычно есть стандартная библиотека
- Надо добавить папку с этим архимов (library directory): в настройках проекта, ключом
-L
для gcc/clang,target_link_directories
в CMake
Иногда библиотека на самом деле динамическая: подгружается при запуске программы, тогда несколько программ могут использовать одну библиотеку на диске.
Тогда надо ещё и при запуске подсказать ОС, где искать библиотеку (обычно ищется в PATH
).
При написании кода:
- Объявление и определение должны совпасть
- Имена глобальных переменных и функции по умолчанию пересекаются между всеми частями программы и всеми библиотеками
- Static Initialization Order Fiasco (пример кода)
- Порядок аргументов линковщика может влиять
- ODR violation и многие другие
Рекомедуется ставить через пакетный менеджер
- Boost.Asio
- Dear ImGui (потребовался SFML)
Общее:
- Поддержка популярных форматов, графика, звук — это обычно несколько сложных библиотек вместе или фреймворк
- Взаимодействие с ОС — обычно только сложные библиотеки, как минимум в нижнем слое