10. Сборка кроссплатформенных программ
Программы для сборки
Для сборки под Windows потребуются инструменты Build Tools для Visual Studio 2019, которые можно найти на странице https://visualstudio.microsoft.com/ru/downloads/. Также потребуется программа для конфигурации сборки cmake. Для сборки в командной строке предварительно нужно запустить командный файл для Visual Studio Developer Command Prompt (в 2019 версии это команда C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\Common7\Tools\vsdevcmd
).
Для сборки под Linux рекомендуется запускать следующий контейнер docker:
sudo docker run -it -v 𝘴𝘩𝘢𝘳𝘦𝘥_𝘧𝘰𝘭𝘥𝘦𝘳:/usr/src/myapp rikorose/gcc-cmake
Пример программы
В общей папке для компьютеров с операционными системами Linux и Windows (один или оба компьютера – виртуальные машины) создайте папку с проектом и разместите в ней следующие исходные коды:
- в папке
src
файлыget_os_name.c
иmain.c
; - в папку
include
файлget_os_name.h
.
Содержимое файла get_os_name.c
:
#include "get_os_name.h"
char* get_os_name(){
#if defined(_WIN32)
return "windows";
#elif defined(__linux__)
return "linux";
#elif defined(__APPLE__)
return "Apple";
#elif defined(BSD)
return "BSD";
#endif
}
Содержимое файла get_os_name.h
:
#ifndef __GET_OS_NAME_H__
#define __GET_OS_NAME_H__
char* get_os_name();
#endif
Содержимое файла main.c
:
#include "stdio.h"
#include "get_os_name.h"
int main () {
printf("hello %s\n", get_os_name());
}
Соберите пример под Windows:
cl -I "include" src\main.c src\get_os_name.c
и под Linux:
gcc -I "include" src/main.c src/get_os_name.c
Проверьте его работоспособность в обеих системах.
Сборка с помощью cmake
Создайте новый каталог для изучения примера сборки с помощью cmake и скопируйте в него папки src
и include
вместе с файлами.
Добавьте в новый каталог файл CMakeLists.txt
:
cmake_minimum_required(VERSION 3.5)
project(print_os_name)
add_executable(print_os_target src/main.c src/get_os_name.c)
target_include_directories(print_os_target PRIVATE ${PROJECT_SOURCE_DIR}/include)
В первой строчке конфигурации (программы для cmake) мы задаем минимальную версию cmake. Во второй – имя проекта.
Функция add_executable
добавляет в проект задачу (target, цель) собрать исполняемый файл (программу). Первым аргументом этой функции является имя задачи, последующие аргументы – файлы исходных кодов.
Функция target_include_directories
задает для задачи каталог с включаемыми (include, заголовочными) файлами. Первый аргумент – задача. Далее указывается область действия этой функции (PRIVATE
– только указанная задача, PUBLIC
– весь проект). После чего указывается каталог.
В последней строке показано использование переменных cmake. Переменная PROJECT_SOURCE_DIR
равна пути к каталогу проекта.
Сборка под Windows
Создайте каталог wbuild
и перейдите в него.
Выполните в нем команду:
cmake ..
Программа cmake
при запуске требует один аргумент – каталог проекта, в котором должен находиться файл CMakeLists.txt
. Двоеточие как в Windows, так и в Linux означает родительский каталог по отношению к текущему.
При выполнении cmake пытается найти в операционной системе средства для сборки программ. После этого найденные средства для сборки тестируются. Далее генерируются конфигурационные файлы для сборки программы с помощью найденных средств сборки. Если на каком-либо этапе произойдет ошибка, то будет выдано соответствующее предупреждение.
При успешном выполнении cmake создаст в каталоге wbuild
файл с именем каждой задачи и расширением .vcxproj
. В терминах Visual Studio это называется проектом (project).
Также в этом каталоге будет создан файл с именем проекта и расширением .sln
. В Visual Studio это называется решением (solution). Оно содержит в себе все проекты, соответствующие задачам в cmake, а также некоторые дополнительные проекты.
Соберите программу с помощью программы:
msbuild 𝘱𝘳𝘰𝘫𝘦𝘤𝘵 или 𝘴𝘰𝘭𝘶𝘵𝘪𝘰𝘯
По умолчанию будет создана отладочная версия программы, которую можно найти в папке Debug
. Можно также создать рабочую версию, указав msbuild
ключ -p:Configuration=Release
(результат будет в папке Release
).
Сборка под Linux
Создайте каталог lbuild
и перейдите в него.
Выполните в нем команду:
cmake ..
Соберите программу с помощью программы:
make
Команда make собирает проект в текущей папки (понятие проекта в make и cmake совпадают). В результате получится готовая программа, имя которой совпадает с именем проекта. Запустите и проверьте правильность ее работы.
Статические библиотеки
Код функций из статической библиотеки помещается в файл программы во время ее сборки.
Создайте новый каталог для изучения примера со статической библиотекой и скопируйте в него папки src
и include
вместе с файлами.
Добавьте в новый каталог файл CMakeLists.txt
:
cmake_minimum_required(VERSION 3.5)
project(print_os_name)
# Create a library
add_library(get_os_library STATIC src/get_os_name.c)
target_include_directories(get_os_library PUBLIC ${PROJECT_SOURCE_DIR}/include)
# Create an executable
add_executable(print_os_name src/main.c)
target_link_libraries(print_os_name PRIVATE get_os_library)
В данном примере будет две задачи: создание библиотеки и готовой программы.
Задача создания библиотеки создается функцией add_library
. Первый ее аргумент – название задачи, обычно совпадающее с именем библиотеки. Далее указывается тип библиотеки (статическая), после чего указываются файлы исходных кодов.
Функция target_include_directories
, как и в предыдущем примере, задает каталоги с заголовочным файлами. В отличие от предыдущего примера указывается область действия PUBLIC, чтобы подключить эти заголовочные файлы и ко второй задаче (создание программы).
Функция add_executable
используется так же, как и в предыдущем примере.
Функция target_link_libraries
подключает ко второй задаче библиотеку, создаваемую в первой задаче.
Соберите пример под Windows и под Linux (используя те же команды, что и в предыдущем примере).
Проверьте правильность работы программ.
Определите, какие файлы получились в результате выполнения каждой задачи под каждой ОС.
Попробуйте удалить файлы, полученные в результате выполнения задач по созданию библиотеки, и запустить программы без этих файлов.
Динамические библиотеки
Код функций из динамической библиотеки помещается в отдельный от программы файл. Функции из таких библиотек компонуются к основной программе во время работы программы (поэтому и называются динамическими). Достоинством динамических библиотек является возможность использовать их одновременно из нескольких программ (отсюда второе название – разделяемые (shared) библиотеки). Их недостаток – необходимость контролировать их наличие в операционной системе и версию.
Создайте новый каталог для изучения примера со статической библиотекой и скопируйте в него папки src
и include
вместе с файлами.
Добавьте в новый каталог файл CMakeLists.txt
:
cmake_minimum_required(VERSION 3.5)
project(print_os_name)
# Extra lib files for WIN32
if(WIN32)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
endif()
# Create a library
add_library(get_os_library SHARED src/get_os_name.c)
target_include_directories(get_os_library PUBLIC ${PROJECT_SOURCE_DIR}/include)
# Create an executable
add_executable(print_os_name src/main.c)
target_link_libraries(print_os_name PRIVATE get_os_library)
Отличие конфигураций статически и динамически присоединяемых библиотек заключается в использовании ключевых слов STATIC
и SHARED
в функции add_library
. Для Linux отличия заканчиваются.
Если сборка ведется под Windows (что проверяется командой if(WIN32)
), переменную CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS
нужно установить в значение ON
с помощью функции set
. Это указывает cmake сгенерировать дополнительные файлы.
В Windows для создания программ, использующие динамические библиотеки, требуются дополнительные файлы для сборки программы. Код самих функций помещается в файлы с расширением .dll
, которые используются во время работы. Во время сборки требуются файлы с описанием функций в файле .dll
и кодом для доступа к этим функциям.
Соберите пример под Windows и под Linux (используя те же команды, что и в предыдущем примере).
Проверьте правильность работы программ.
Определите, какие файлы получились в результате выполнения каждой задачи под каждой ОС.
Определите, какие библиотечные файлы необходимы для запуска программ.