diff --git a/2019-2020-informatics.md b/2019-2020-informatics.md index 2cdcb79..b6a5c09 100644 --- a/2019-2020-informatics.md +++ b/2019-2020-informatics.md @@ -9,8 +9,7 @@ ### Осень 2019 1. [Введение в Linux](practice/linux_basics/intro.md) - 2. [Часть 1: Инструменты разработки в UNIX](practice/linux_basics/devtools.md) - [Часть 2: CMake TODO: вынести в отдельный ридинг](practice/linux_basics/cmake.md) + 2. [Инструменты разработки в UNIX](practice/linux_basics/devtools.md) 3. [Часть 1: Целочисленная арифметика](practice/integers/) [Часть 2: Вещественная арифметика](practice/ieee754/) 4. [Часть 1: Инструменты для ARM](practice/arm/) @@ -38,7 +37,7 @@ 7. [Указатели на функции и динамические библиотеки](practice/function-pointers/) 8. [Сокеты UDP и AF_PACKET](practice/sockets-udp/) 9. [Berkley Packet Filter](practice/bpf/) - 10. Неделя с 6 по 11 апреля: [Протокол HTTP/1.1. Сборка с помощью CMake](practice/http-cmake/) + 10. Неделя с 6 по 11 апреля: [Часть 1: Протокол HTTP/1.1 и cURL](practice/http-curl/) [Часть 2: Сборка с помощью CMake](practice/linux_basics/cmake.md) 11. Неделя с 13 по 18 апреля: [Шифрование с использованием OpenSSL/LibreSSL](practice/openssl/) 12. Неделя с 20 по 25 апреля: Файловые системы в POSIX. Файловые системы FUSE 13. Неделя с 27 апреля по 9 мая: **новых тем не будет, только прием задач** diff --git a/practice/http-cmake/README.md b/practice/http-curl/README.md similarity index 56% rename from practice/http-cmake/README.md rename to practice/http-curl/README.md index 6d776c4..89a97bc 100644 --- a/practice/http-cmake/README.md +++ b/practice/http-curl/README.md @@ -1,4 +1,4 @@ -# Протокол HTTP, библиотека cURL и система сборки CMake +# Протокол HTTP и библиотека cURL ## Протокол HTTP @@ -93,12 +93,12 @@ API состоит из двух частей: полнофункциональ ``` #include -CURL *curl = curl_easy_init(); -if(curl) { - CURLcode res; - curl_easy_setopt(curl, CURLOPT_URL, "http://example.com"); - res = curl_easy_perform(curl); - curl_easy_cleanup(curl); +CURL *curl = curl_easy_init(); +if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "http://example.com"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); } ``` @@ -167,93 +167,3 @@ int main(int argc, char *argv[]) { ``` -## Система сборки `cmake` - -Использование сторонних библиотек усложняет процесс воспроизводимости сборки. В случае, когда целевая операционная система одна, это не доставляет особых проблем и достаточно простого `Makefile`, но если предполагается разработка кросс-платформенного продукта, то возникают неоднозначности: - * какой компилятор используется для сборки (gcc, clang, cl.exe); - * расположение include-файлов библиотек для компиляции; - * рссположение файлов библиотек для компоновки. - -По этой причине часто практикуется не распространение `Makefile`, написанного для конкретного стека инструментов, а его генерация по декларативному описанию в процессе сборки: `./configure`, `qmake`, или `cmake`. - -Наиболее гибкой системой сборки, и при этом относительно простой, является [CMake](https://cmake.org/cmake/help/v3.2/), которая реализована с поддержкой не только UNIX-подобных систем, но и Windows. - -Описание проекта находится в файле `CMakeLists.txt` и имеет примерно следующий вид: - -``` -# признак того, что это файл для cmake -# номер версии - это минимально требуемый для сборки проекта -# не стоит злоупотребять указанием самой свежей версии -# CMake, поскольку в консервативных Linux-дистрибутивах -# может быть что-то более старое -cmake_minimum_required(VERSION 3.2) - -# имя проекта - не обязательно, обычно используется IDE -project(my_great_project) - -# команда `set` устанавливает значение переменной -# некоторые переменные (их имена начинаются с CMAKE_) -# имеют специальное значение - -# дополнительные опции компилятора Си -set(CMAKE_C_FLAGS "-std=gnu11") - -# дополнительные опции компилятора C++ -set(CMAKE_CXX_FLAGS "-std=gnu14") - -# в переменной SOURCES будет храниться список файлов; -# если файлов не много, то можно этого не делать, -# но некоторым IDE это требуется для навигации по проекту -set(SOURCES - file1.c - file2.cpp - file3.cpp -) - -# добавление цели для сборки - бинарного файла; -# синтаксис ${...} означает использование значения -# переменной, которая в данном примере будет раскрыта -# в список файлов, из которых собирается программа -add_executable(my_cool_program ${SOURCES}) -``` - -Для сборки CMake-проекта необходимо выполнить две стадии: - 1. Сгенерировать `Makefile`из `CMakeLists.txt` - 2. Собрать проект обычнычным инструментом `make`. - -Обычно в процессе генерации `Makefile` и при сборке проекта создается много временных файлов. По этой причине сборку принято проводить в отдельном каталоге, - чтобы не засорять каталог с исходными текстами. - -``` -$ mkdir build # создаем каталог для сборки -$ cd build # переходим в него -$ cmake ../ # генерируем Makefile - # аргумент cmake - это каталог, который - # содержит файл CMakeLists.txt -$ make # запуск компиляции -``` - -Для многих OpenSource библиотек в стандартной поставке CMake уже готовы модули поддержки, которые выполняют поиск библиотеки. В случае c UNIX этот поиск осуществляется с помощью запуска команд конфигурации, либо проверки различных вариантов написания имен файлов в `/usr/include` и `/usr/lib`. Для Windows просматривается системный реестр. - -Список поддерживаемых библиотек можно найти в поставке CMake, для Linux это может быть каталог (в разных дистрибутивах они разные) `/usr/share/cmake/Modules`. Все файлы модулей имеют название `FindИМЯБИБЛИОТЕКИ.cmake`. - -Подключение библиотеки, которая поддерживается "из коробки", осуществляется с помощью команды `find_package`. В случае, если необходимые файлы присутствуют, то определяются переменные `ИМЯБИБЛИОТЕКИ_INCLUDE_DIRS` и `ИМЯБИБЛИОТЕКИ_LIBRARIES`. - -Пример для curl: -``` -# найти библиотеку CURL; опция REQUIRED означает, -# что библиотека является обязательной для сборки проекта, -# и если необходимые файлы не будут найдены, cmake -# завершит работу с ошибкой -find_package(CURL REQUIRED) - -# добавляет в список каталогов, которые превратятся в -# опции -I компилятора все каталоги, которые перечислены -# в переменной CURL_INCLUDE_DIRECTORIES -include_directories(${CURL_INCLUDE_DIRECTORIES}) - -add_executable(my_cool_program ${SOURCES}) - -# для цели my_cool_program указываем библиотеки, с которыми -# программа будет слинкована -target_link_libraries(my_cool_program ${CURL_LIBRARIES}) -``` diff --git a/practice/linux_basics/cmake.md b/practice/linux_basics/cmake.md new file mode 100644 index 0000000..53cb319 --- /dev/null +++ b/practice/linux_basics/cmake.md @@ -0,0 +1,157 @@ +# Система сборки `cmake` + +Использование сторонних библиотек усложняет процесс воспроизводимости сборки. В случае, когда целевая операционная система одна, это не доставляет особых проблем и достаточно простого `Makefile`, но если предполагается разработка кросс-платформенного продукта, то возникают неоднозначности: + * какой компилятор используется для сборки (gcc, clang, cl.exe); + * расположение include-файлов библиотек для компиляции; + * рссположение файлов библиотек для компоновки. + +По этой причине часто практикуется не распространение `Makefile`, написанного для конкретного стека инструментов, а его генерация по декларативному описанию в процессе сборки: `./configure`, `qmake`, или `cmake`. + +Наиболее гибкой системой сборки, и при этом относительно простой, является [CMake](https://cmake.org/cmake/help/v3.2/), которая реализована с поддержкой не только UNIX-подобных систем, но и Windows. + +## Проект CMake и его сборка + +Описание проекта находится в файле `CMakeLists.txt` и имеет примерно следующий вид: + +```cmake +# признак того, что это файл для cmake +# номер версии - это минимально требуемый для сборки проекта +# не стоит злоупотребять указанием самой свежей версии +# CMake, поскольку в консервативных Linux-дистрибутивах +# может быть что-то более старое +cmake_minimum_required(VERSION 3.2) + +# имя проекта - не обязательно, обычно используется IDE +project(my_great_project) + +# команда `set` устанавливает значение переменной +# некоторые переменные (их имена начинаются с CMAKE_) +# имеют специальное значение + +# дополнительные опции компилятора Си +set(CMAKE_C_FLAGS "-std=gnu11") + +# дополнительные опции компилятора C++ +set(CMAKE_CXX_FLAGS "-std=gnu14") + +# в переменной SOURCES будет храниться список файлов; +# если файлов не много, то можно этого не делать, +# но некоторым IDE это требуется для навигации по проекту +set(SOURCES + file1.c + file2.cpp + file3.cpp +) + +# добавление цели для сборки - бинарного файла; +# синтаксис ${...} означает использование значения +# переменной, которая в данном примере будет раскрыта +# в список файлов, из которых собирается программа +add_executable(my_cool_program ${SOURCES}) +``` + +Для сборки CMake-проекта необходимо выполнить две стадии: + 1. Сгенерировать `Makefile`из `CMakeLists.txt` + 2. Собрать проект обычнычным инструментом `make`. + +Обычно в процессе генерации `Makefile` и при сборке проекта создается много временных файлов. По этой причине сборку принято проводить в отдельном каталоге, - чтобы не засорять каталог с исходными текстами. + +```bash +$ mkdir build # создаем каталог для сборки +$ cd build # переходим в него +$ cmake ../ # генерируем Makefile + # аргумент cmake - это каталог, который + # содержит файл CMakeLists.txt +$ make # запуск компиляции +``` + +## Использование сторонних библиотек, для который есть готовое описание CMake + +Для многих OpenSource библиотек в стандартной поставке CMake уже готовы модули поддержки, которые выполняют поиск библиотеки. В случае c UNIX этот поиск осуществляется с помощью запуска команд конфигурации, либо проверки различных вариантов написания имен файлов в `/usr/include` и `/usr/lib`. Для Windows просматривается системный реестр. + +Список поддерживаемых библиотек можно найти в поставке CMake, для Linux это может быть каталог (в разных дистрибутивах они разные) `/usr/share/cmake/Modules`. Все файлы модулей имеют название `FindИМЯБИБЛИОТЕКИ.cmake`. + +Подключение библиотеки, которая поддерживается "из коробки", осуществляется с помощью команды `find_package`. В случае, если необходимые файлы присутствуют, то определяются переменные: + +* `ИМЯБИБЛИОТЕКИ_FOUND` - переменная, значение которой устанавливается в `1`, если библиотека не отмечена как `REQUIRED`; +* `ИМЯБИБЛИОТЕКИ_INCLUDE_DIRS` - список дополнительных каталогов, в которых нужно искать заголовочные файлы (опции компилятора `-I...`); +* `ИМЯБИБЛИОТЕКИ_LIBRARIES` - список дополнительных библиотек и каталоги к ним (опции компилятора `-l...` и `-L...`); + +Пример для curl: +```cmake +# найти библиотеку CURL; опция REQUIRED означает, +# что библиотека является обязательной для сборки проекта, +# и если необходимые файлы не будут найдены, cmake +# завершит работу с ошибкой +find_package(CURL REQUIRED) + +add_executable(my_cool_program ${SOURCES}) + +# добавляет в список каталогов для цели my_cool_program, +# которые превратятся в опции -I компилятора для всех +# каталоги, которые перечислены в переменной CURL_INCLUDE_DIRECTORIES +target_include_directories(my_cool_program ${CURL_INCLUDE_DIRECTORIES}) + +# для цели my_cool_program указываем библиотеки, с которыми +# программа будет слинкована +target_link_libraries(my_cool_program ${CURL_LIBRARIES}) +``` + +Если необходимо использовать библиотеку для всех целей проекта, а не для отдельных, то можно использовать команды `include_directories` и `link_libraries`. + +## Использование сторонних библиотек, для которых есть описания `pkg-config` + +Для многих GNU-библиотек существуют описания их использования, которые можно использовать утилитой [`pkg-config(1)`](https://linux.die.net/man/1/pkg-config). Эти описания можно использовать в проектах CMake в том случае, если для них не реализованы описания CMake, но существуют описания pkg-config. Обычно эти файлы `*.pc` располагаются в каталоге `/usr/lib[64]/pkgconfig`. + +Пример для fuse3: + +```cmake +# подключаем модуль интеграции с pkg-config +find_package(PkgConfig REQUIRED) + +pkg_check_modules( + FUSE # имя префикса для названий выходных переменных + REQUIRED # если библиотека является обязательной + fuse3 # имя библиотеки, должен существовать файл fuse3.pc +) + +# можно использовать переменные FUSE_INCLUDE_DIRECTORIES +# и FUSE_LIBRARIES +target_include_directories(my_cool_program ${FUSE_INCLUDE_DIRECTORIES}) +target_link_libraries(my_cool_program ${FUSE_LIBRARIES}) + +# дополнительные флаги компиляции, например определения -D..., +# которые не указывают на каталоги для поиска заголовочных файлов, +# перечислены в переменной FUSE_CFLAGS_OTHER +target_compile_options(my_cool_program ${FUSE_CFLAGS_OTHER}) +``` + +## Использование сторонних библиотек, для которых вообще ничего нет + +В случае, если для библиотеки не подготовлено никаких описаний, то можно попытаться найти необходимые файлы, используя перебор различных комбинаций имен и стандартных каталогов: + +```cmake +# поиск файла динамической библиотеки +find_library( + SOME_LIBRARY # переменная, в которую будет записан результат + NAMES # перечисляются различные варианты имен для поиска + some + something + somelib0 +) + +# поиск пути к заголовочным файлам +find_path( + SOME_INCLUDE_DIRECTORY # переменная, в которую будет записан результат + NAMES # имена файлов, которые могут содержаться в каталоге + somelib.h + somelib_common.h + PATH_SUFFIXES # возможные имена подкаталогов в .../include/ + somelib + somelib-1.0 +) + +target_include_directories(my_cool_program ${SOME_INCLUDE_DIRECTORY}) +target_link_libraries(my_cool_program ${SOME_LIBRARY}) +``` +