Что такое cmake visual studio
На первом шаге проект нужно сконфигурировать, то есть создать финальный скрипт сборки, запустив cmake <параметры> <путь-к-каталогу> в будущем каталоге сборки.
На втором шаге нужно запустить финальный скрипт. Не вызывайте make ! Утилита cmake сделает это сама:
Структура CMakeLists.txt
В начале главного файла CMakeLists.txt ставят метаинформацию о минимальной версии CMake и названии проекта:
Затем следует список инструкций, служащих для вычисления различных переменных, создания целей сборки, подключения проектов из подкаталогов и так далее. Например, подключить дополнительный CMakeLists.txt из подкаталога можно так:
Целью может стать исполняемый файл, собираемый из исходного кода
Целью также может быть библиотека, статическая или динамическая.
Автогенерация проекта для Visual Studio (Windows)
Если используется Visual C++, то путь немного другой: на шаге конфигурирования создаётся проект для Visual Studio, который затем можно собрать из IDE либо так же из командной строки.
Созданный проект Visual Studio нельзя изменять и использовать постоянно, потому что при генерации проекта используются абсолютные пути и другие неприемлемые для постоянной работы вещи.
Если проект был сконфигурирован успешно, то в каталоге ../myapp-build появятся автоматически сгенерированный BUILD_ALL.sln и проекты для Visual Studio. Их можно открыть к IDE, либо собрать из командной строки с помощью cmake. Названия опций говорят сами за себя:
Зависимости между библиотеками и приложениями
Не используйте директивы include_directories , add_definitions , add_compile_options ! Они меняют глобальные настройки для всех целей, это создаёт проблемы при масштабировании.
- Используйте target_link_libraries для добавления статических и динамических библиотек, от которых зависит цель
- Используйте target_include_directories вместо include_directories для добавления путей поиска заголовков, от которых зависит цель
- Используйте target_compile_definitions вместо add_definitions для добавления макросов, с которыми собирается цель
- Используйте target_compile_options для добавления специфичных флагов компилятора, с которыми собирается цель
Вы можете выбирать область видимости настройки:
- PUBLIC делает настройку видимой для текущей цели и для всех зависящих от неё целей
- PRIVATE делает настройку видимой только для текущей цели
- INTERFACE делает настройку видимой только для всех зависящих от неё целей
Пример использования областей видимости:
Схема зависимостей условного проекта:
Выбор стандарта и диалекта C++
Для настройки стандарта и флагов языка C++ не добавляйте флаги напрямую!
В CMake версии 3.8+ вы можете прямо потребовать включить нужный стандарт:
В CMake версии до 3.7 включительно можно использовать set_target_properties (если не работает, то у вас слишком старый CMake):
Для разработчиков библиотек есть более тонкий контроль над возможностями языка:
Функции в CMake
CMake позволяет объявлять функции командами function(name) / endfunction() и макросы командами macro(name) / endmacro() . Предпочитайте функции, а не макросы, т.к. у функций есть своя область видимости переменных, а у макросов - нет.
Добавление исходников к цели с target_sources
Лучше добавлять специфичные исходники с помощью target_sources, а не с помощью дополнительных переменных.
Интерфейс к утилитам командной строки
Функция find_package
Функция find_package принимает имя библиотеки как аргумент и обращается к CMake, чтобы найти скрипт для настройки переменных данной библиотеки. В итоге при сборке либо возникает ошибка из-за того что пакет не найден, либо добавляются переменные, хранящие пути поиска заголовков, имена библиотек для компоновщика и другие параметры.
Пример подключения Boost, вызывающего встроенный в CMake скрипт FindBoost:
Пример подключения библиотеки Bullet с помощью встроенного скрипта FindBullet и компоновки с приложением my_app:
Разработка Visual Studio C и C++ теперь подходит не только для Windows. В этом руководстве показано, как использовать Visual Studio для C++ межплатформенной разработки в Windows и Linux. Он основан на CMake, поэтому вам не нужно создавать или генерировать проекты Visual Studio. При открытии папки с файлом CMakeLists.txt Visual Studio настраивает IntelliSense и параметры сборки автоматически. Вы можете быстро приступить к редактированию, сборке и отладке кода локально в Windows. Затем можно переключить конфигурацию для того, чтобы сделать то же самое в Linux, в Visual Studio.
В этом руководстве вы узнаете, как:
- Клонировать проект CMake с открытым кодом с сайта GitHub.
- Открывать проект в Visual Studio.
- Собирать и отлаживать исполняемый целевой объект на Windows.
- Добавлять подключение к компьютеру Linux.
- Собирать и отлаживать тот же целевой объект в Linux.
Предварительные требования
Настройка Visual Studio для кроссплатформенной разработки на C++
- Сначала установите Visual Studio и выберите Разработка классических приложений на C++ и Разработка для Linux на C++ . Для минимальной установки требуется всего 3 ГБ свободного места на диске. В зависимости от скорости загрузки установка не должна занять более 10 минут.
Настройка компьютера Linux для кроссплатформенной разработки на C++
Visual Studio не требует конкретный дистрибутив Linux. Операционная система может работать на физическом компьютере, на виртуальной машине или в облаке. Также можно использовать подсистему Windows для Linux (WSL). Однако в рамках этого руководства требуется графическая среда. WSL не рекомендуется использовать здесь, поскольку она предназначена в основном для операций командной строки.
На компьютере Linux должны быть установлены следующие средства Visual Studio: компиляторы C++, gdb, ssh, rsync, make и zip. В системах на основе Debian эти зависимости можно установить с помощью следующей команды:
Visual Studio требует наличия на компьютере Linux последней версии CMake с включенным режимом сервера (не ниже 3.8). Корпорация Майкрософт предлагает универсальную сборку CMake, которую можно установить на любой дистрибутив Linux. Мы рекомендуем использовать эту сборку, чтобы у вас были самые новые функции. Вы можете получить двоичные файлы CMake из вилки Майкрософт репозитория CMake на сайте GitHub. Перейдите на эту страницу и загрузите версию, соответствующую архитектуре вашей системы на компьютере Linux, а затем пометьте ее как исполняемый файл:
Вы увидите параметры для запуска скрипта с -–help . Рекомендуется использовать параметр –prefix , чтобы указать установку по пути /usr, потому что это расположение по умолчанию Visual Studio выполняет поиск CMake в каталоге /usr/bin. В следующем примере показан скрипт Linux x86_64. Измените этот параметр на нужный, если вы используете другую целевую платформу.
Git для Windows, установленный на компьютере Windows.
Учетная запись GitHub.
Клонирование проекта CMake с открытым кодом с сайта GitHub
В этом руководстве используется пакет SDK Bullet Physics на сайте GitHub. Он обеспечивает обнаружение столкновений и физическое моделирование для многих приложений. Пакет SDK включает примеры исполняемых программ, которые компилируются и запускаются без дополнительного кода. В этом учебнике не изменяются исходный код или скрипты сборки. Для начала клонируйте репозиторий bullet3 из GitHub на компьютер, где установлена среда Visual Studio.
В главном меню Visual Studio выберите Файл > Открыть > CMake. Перейдите к файлу CMakeLists. txt в корне только что скачанного репозитория bullet3.
Когда вы откроете эту папку, структура папок отобразится в обозревателе решений.
В этом представлении показано, что фактически находится на диске. Это не логическое или отфильтрованное представление. По умолчанию оно не показывает скрытые файлы.
Выберите Показать все файлы, чтобы просмотреть полный список файлов в папке.
Переключение на представление целевых объектов
Когда вы откроете папку, которая использует CMake, Visual Studio автоматически создаст кэш CMake. Эта операция может занять некоторое время в зависимости от размера проекта.
В окне вывода выберите Показать выходные данные из и выберите CMake для отслеживания состояния процесса создания кэша. По завершении операции отображается надпись: "Извлечение сведений о целевом объекте выполнено".
После завершения этой операции будет настроена технология IntelliSense. Можно выполнить сборку проекта и отладить приложение. В Visual Studio теперь отображается логическое представление решения, основанное на целевых объектах, заданных в файлах CMakeLists.
Вот как это представление выглядит для пакета SDK Bullet:
Представление целевых объектов обеспечивает более интуитивное отображение содержимого исходной базы. Вы увидите, что некоторые целевые объекты являются библиотеками, а другие — исполняемыми файлами.
Разверните узел в представлении целевых объектов CMake, чтобы просмотреть его файлы исходного кода, где бы эти файлы ни находились на диске.
Добавление явной конфигурации Windows x64-Debug
Visual Studio создает конфигурацию x64-Debug по умолчанию для Windows. Конфигурации указывают Visual Studio, какую платформу она будет использовать для CMake. Конфигурация по умолчанию не представлена на диске. При явном добавлении конфигурации Visual Studio создает файл с именем CMakeSettings.json. Он заполняется параметрами для всех указанных конфигураций.
Добавьте новую конфигурацию. На панели инструментов откройте раскрывающийся список Конфигурация и выберите Управление конфигурациями.
Откроется редактор параметров CMake. Щелкните зеленый значок плюса в левой части редактора, чтобы добавить новую конфигурацию. Откроется диалоговое окно Добавление конфигурации в CMakeSettings.
В этом диалоговом окне представлены все конфигурации, которые входят в состав Visual Studio, а также все созданные вами настраиваемые конфигурации. Если вы хотите продолжать использовать конфигурацию x64-Debug, добавьте ее в первую очередь. Выберите x64-Debug, а затем нажмите кнопку Выбрать. Visual Studio создает файл CMakeSettings.json с конфигурацией для x64-Debug и сохраняет ее на диске. Вы можете назвать конфигурацию как угодно, изменив параметр имени непосредственно в CMakeSettings.json.
Установка точки останова, сборка и запуск в Windows
На этом шаге нам предстоит отладить пример программы, демонстрирующий библиотеку Bullet Physics.
В обозревателе решений выберите AppBasicExampleGui и разверните его.
Откройте файл BasicExample.cpp .
Задайте точку останова, которая будет выполняться при щелчке кнопки в работающем приложении. Событие щелчка обрабатывается в методе внутри вспомогательного класса. Для быстрого перехода:
Выберите CommonRigidBodyBase , из которого происходит структура BasicExample , около строки 30.
Щелкните правой кнопкой мыши и выберите Перейти к определению. Вы находитесь в заголовке CommonRigidBodyBase.h.
В представлении браузера выше вы увидите, что находитесь в CommonRigidBodyBase . Справа можно выбрать элементы для проверки. Щелкните раскрывающийся список и выберите mouseButtonCallback , чтобы перейти к определению функции в заголовке.
Поместите точку останова на первой строке в этой функции. Она будет выполняться при нажатии кнопки мыши в окне приложения при запуске в отладчике Visual Studio.
Чтобы запустить приложение, выберите на панели инструментов раскрывающийся список запуска. Это зеленый значок воспроизведения с текстом "Выбрать элемент запуска". В раскрывающемся списке выберите AppBasicExampleGui.exe. Имя исполняемого файла теперь отображается на кнопке запуска:
Переместите указатель мыши в окно приложения, а затем нажмите кнопку для вызова точки останова. Точка останова снова выведет Visual Studio на передний план, а в редакторе отобразится строка, где выполнение приостановлено. Можно проверить переменные, объекты, потоки и память приложения, а также пошагово выполнить код. Выберите Продолжить, чтобы позволить приложению возобновить работу, и закройте его в обычном режиме. Или остановите выполнение в Visual Studio с помощью кнопки "Остановить".
Добавление конфигурации Linux и подключение к удаленному компьютеру
Добавьте конфигурацию Linux. Щелкните правой кнопкой мыши файл CMakeSettings.json в обозревателе решений и выберите Добавить конфигурацию. Вы увидите то же диалоговое окно "Добавление конфигурации в CMakeSettings", что и раньше. На этот раз выберите Linux-Debug, а затем сохраните файл CMakeSettings.json (CTRL+S).
Visual Studio 2019 версии 16.6 или более поздней версии: прокрутите вниз в редакторе параметров CMake и выберите Показать дополнительные параметры. В качестве генератора CMake выберите Unix Makefiles, а затем сохраните файл CMakeSettings.json (CTRL+S).
В раскрывающемся списке конфигураций выберите Linux-Debug.
Если это первое подключение к системе Linux, откроется диалоговое окно Подключение к удаленной системе.
Если вы уже добавили удаленное подключение, вы можете открыть это окно в разделе Сервис > Параметры > Кроссплатформенный > Диспетчер подключений.
Установка точки останова, сборка и запуск в Linux
Так как это классическое приложение, необходимо предоставить некоторые дополнительные сведения о конфигурации для конфигурации отладки.
В представлении целевых объектов CMake щелкните правой кнопкой мыши AppBasicExampleGui и выберите Параметры отладки и запуска, чтобы открыть файл launch.vs.json, который находится в скрытой вложенной папке .vs. Этот локальный файл для среды разработки. Вы можете переместить его в корень проекта, если хотите проверить его и сохранить для своей команды. В этот файл была добавлена конфигурация для AppBasicExampleGui. Эти параметры по умолчанию работают в большинстве случаев, но не здесь. Поскольку это классическое приложение, необходимо предоставить некоторые дополнительные сведения, чтобы запустить программу и увидеть ее на компьютере Linux.
Чтобы найти значение переменной среды DISPLAY на компьютере Linux, выполните следующую команду:
В конфигурации для AppBasicExampleGui существует массив параметров "pipeArgs". В нем есть строка "$". Это команда, которая запускает gdb на удаленном компьютере. Visual Studio необходимо экспортировать соответствующие элементы в этот контекст перед выполнением этой команды. Например, если значение экрана — :1 , измените эту строку следующим образом:
Запустите приложение и выполните его отладку. На панели инструментов откройте раскрывающийся список Выбрать элемент запуска и выберите AppBasicExampleGui. Затем либо выберите зеленый значок воспроизведения на панели инструментов, либо нажмите клавишу F5. Приложение и его зависимости будут собраны на удаленном компьютере Linux. После чего приложение будет запущено с подключенным отладчиком Visual Studio. На удаленном компьютере Linux вы увидите окно приложения.
Переместите указатель мыши в окно приложения, а затем нажмите кнопку. Сработает точка останова. Выполнение программы приостанавливается, Visual Studio возвращается на передний план, вы увидите точку останова. Кроме того, вы увидите окно консоли Linux в Visual Studio. В этом окне предоставлены выходные данные с удаленного компьютера Linux, а также оно может принимать входные данные для stdin . Как и любое окно Visual Studio, вы можете закрепить его в предпочтительном месте. Его расположение сохраняется в будущих сеансах.
Вы можете проверить переменные, объекты, потоки и память приложения и пошагово выполнить код с помощью Visual Studio. Но на этот раз вы выполняете все это на удаленном компьютере Linux вместо локальной среды Windows. Выберите Продолжить, чтобы приложение возобновило работу, выйдите из него обычным образом или нажмите кнопку остановки, как и при локальном выполнении.
Посмотрите на окно стека вызовов и увидите вызовы к x11OpenGLWindow , поскольку среда Visual Studio запустила приложение в Linux.
Чему вы научились
В этом руководстве вы клонировали базу кода непосредственно из GitHub. Вы создали, запустили и отладили его в Windows без изменений. Затем вы использовали эту же самую базу кода, с незначительными изменениями конфигурации, для сборки, запуска и отладки на удаленном компьютере Linux.
Следующие шаги
Дополнительные сведения о настройке и отладке проектов CMake в Visual Studio:
CMake (от англ. cross-platform make) — это кроссплатформенная система автоматизации сборки программного обеспечения из исходного кода. CMake не занимается непосредственно сборкой, а лишь генерирует файлы управления сборкой из файлов CMakeLists.txt. Первый выпуск программы состоялся в 2000 году. Для сравнения, статический анализатор PVS-Studio появился только в 2008 году. Тогда он был ориентирован на поиск ошибок портирования программ с 32-х битных систем на 64-битные, а в 2010 году появился первый набор диагностик общего назначения (V501-V545). Кстати, на коде CMake есть несколько предупреждений из этого первого набора.
Непростительные ошибки
V1040 Possible typo in the spelling of a pre-defined macro name. The '__MINGW32_' macro is similar to '__MINGW32__'. winapi.h 4112
Диагностика V1040 только недавно была реализована. На момент публикации статьи, скорее всего, ещё не будет релиза с ней, но с помощью этой диагностики уже удалось найти крутую ошибку.
Здесь допустили опечатку в имени __MINGW32_. В конце не хватает одного символа подчёркивания. Если сделать поиск по коду с этим именем, то можно убедиться, что в проекте действительно используют версию именно с двумя подчёркиваниями с двух сторон:
V531 It is odd that a sizeof() operator is multiplied by sizeof(). cmGlobalVisualStudioGenerator.cxx 558
Когда массив объявлен статически, то оператор sizeof посчитает его размер в байтах с учётом и количества элементов, и размера элементов. При вычислении значения переменной cch_subkeyname программист не учёл этого и получил значение в 4 раза больше запланированного. Поясним откуда это «в 4 раза».
Массив и его неправильный размер передаётся в функцию RegEnumKeyExW:
Указатель lpcchName должен указывать на переменную, содержащую размер буфера в символах: «A pointer to a variable that specifies the size of the buffer specified by the lpClass parameter, in characters». Размер массива subkeyname составляет 512 байт и он способен хранить 256 символов типа wchar_t (в Windows wchar_t это 2 байта). Именно это значение в 256 и должно быть передано в функцию. Вместо этого 512 ещё раз умножается на 2 и получается 1024.
Кстати, точно такая же ошибка происходит и при вычислении значения переменной cch_keyclass.
- V531 It is odd that a sizeof() operator is multiplied by sizeof(). cmGlobalVisualStudioGenerator.cxx 556
- V531 It is odd that a sizeof() operator is multiplied by sizeof(). cmGlobalVisualStudioGenerator.cxx 572
- V531 It is odd that a sizeof() operator is multiplied by sizeof(). cmGlobalVisualStudioGenerator.cxx 621
- V531 It is odd that a sizeof() operator is multiplied by sizeof(). cmGlobalVisualStudioGenerator.cxx 622
- V531 It is odd that a sizeof() operator is multiplied by sizeof(). cmGlobalVisualStudioGenerator.cxx 649
Указатель this->BuildFileStream разыменовывается прямо перед проверкой на валидность. Неужели это ни у кого не вызывало проблем? Ниже ещё один пример такого места. Оно сделано прямо под копирку. Но на самом деле, предупреждений V595 очень много и большинство из них не такие очевидные. По опыту могу сказать, что исправлять предупреждения этой диагностики дольше всего.
- V595 The 'this->FlagFileStream' pointer was utilized before it was verified against nullptr. Check lines: 303, 304. cmMakefileTargetGenerator.cxx 303
Анализатор обнаружил использование неинициализированного указателя str. А возникло это из-за обычной опечатки. При вызове функции SysAllocStringByteLen надо было использовать указатель src.str.
V557 Array overrun is possible. The value of 'lensymbol' index could reach 28. archive_read_support_format_rar.c 2749
Сразу несколько проблем обнаружено в этом фрагменте кода. При обращении к массивам lengthbases и lengthbits возможен выход за границу массива, потому что выше по коду разработчики написали оператор '>' вместо '>='. Такая проверка стала пропускать одно недопустимое значение. Перед нами не что иное, как классический паттерн ошибки под названием Off-by-one Error.
Весь список мест обращений к массивам по невалидному индексу:
- V557 Array overrun is possible. The value of 'lensymbol' index could reach 28. archive_read_support_format_rar.c 2750
- V557 Array overrun is possible. The value of 'lensymbol' index could reach 28. archive_read_support_format_rar.c 2751
- V557 Array overrun is possible. The value of 'lensymbol' index could reach 28. archive_read_support_format_rar.c 2753
- V557 Array overrun is possible. The value of 'lensymbol' index could reach 28. archive_read_support_format_rar.c 2754
- V557 Array overrun is possible. The value of 'offssymbol' index could reach 60. archive_read_support_format_rar.c 2797
Утечка памяти
V773 The function was exited without releasing the 'testRun' pointer. A memory leak is possible. cmCTestMultiProcessHandler.cxx 193
Анализатор обнаружил утечку памяти. Память по указателю testRun не освобождается, если функция testRun->StartTest возвращает true. При выполнении другой ветви кода память по указателю testRun освобождается в функции this-> FinishTestProcess.
Утечка ресурсов
V773 The function was exited without closing the file referenced by the 'fd' handle. A resource leak is possible. rhash.c 450
Странная логика в условиях
V590 Consider inspecting the '* s != '\0' && * s == ' '' expression. The expression is excessive or contains a misprint. archive_cmdline.c 76
Сравнение символа *s с терминальным нулём является лишним. Условие цикла while зависит только от того, равен символ пробелу или нет. Это не ошибка, но лишнее усложнение кода.
V592 The expression was enclosed by parentheses twice: ((expression)). One pair of parentheses is unnecessary or misprint is present. cmCTestTestHandler.cxx 899
Анализатор предупреждает, что, возможно, отрицание должно быть вынесено за скобки. Вроде, такой ошибки тут нет — просто лишние двойные скобки. Но, скорее всего, в этом условии присутствует логическая ошибка.
Оператор continue выполняется в том случае, если список тестов this->TestsToRun не пуст и cnt в нём отсутствует. Логично предположить, что если список тестов пуст, то необходимо выполнить то же самое действие. Скорее всего, условие должно быть таким:
V592 The expression was enclosed by parentheses twice: ((expression)). One pair of parentheses is unnecessary or misprint is present. cmMessageCommand.cxx 73
Похожий пример, но тут я больше уверен в наличии ошибки. Функция IsSet(«CMAKE_WARN_DEPRECATED») проверяет, что значение CMAKE_WARN_DEPRECATED задано глобально, а функция IsOn(«CMAKE_WARN_DEPRECATED») проверяет, что значение задано в конфигурации проекта. Скорее всего, оператор отрицания является лишним, т.к. в обоих случаях корректно задать одинаковые значения type и level.
V728 An excessive check can be simplified. The '(A && !B) || (!A && B)' expression is equivalent to the 'bool(A) != bool(B)' expression. cmCTestRunTest.cxx 151
Такой код можно сильно упростить, если переписать условное выражение таким образом:
Ещё несколько мест, которые можно упростить:
- V728 An excessive check can be simplified. The '(A && B) || (!A && !B)' expression is equivalent to the 'bool(A) == bool(B)' expression. cmCTestTestHandler.cxx 702
- V728 An excessive check can be simplified. The '(A && !B) || (!A && B)' expression is equivalent to the 'bool(A) != bool(B)' expression. digest_sspi.c 443
- V728 An excessive check can be simplified. The '(A && !B) || (!A && B)' expression is equivalent to the 'bool(A) != bool(B)' expression. tcp.c 1295
- V728 An excessive check can be simplified. The '(A && !B) || (!A && B)' expression is equivalent to the 'bool(A) != bool(B)' expression. testDynamicLoader.cxx 58
- V728 An excessive check can be simplified. The '(A && !B) || (!A && B)' expression is equivalent to the 'bool(A) != bool(B)' expression. testDynamicLoader.cxx 65
- V728 An excessive check can be simplified. The '(A && !B) || (!A && B)' expression is equivalent to the 'bool(A) != bool(B)' expression. testDynamicLoader.cxx 72
Разные предупреждения
V523 The 'then' statement is equivalent to the subsequent code fragment. archive_read_support_format_ar.c 415
V535 The variable 'i' is being used for this loop and for the outer loop. Check lines: 2220, 2241. multi.c 2241
Переменная i используется как счётчик цикла во внешнем и вложенном циклах. При этом значение счётчика снова начинает отсчитываться от нуля во вложенном. Возможно, здесь это не ошибка, но код подозрительный.
V519 The 'tagString' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 84, 86. cmCPackLog.cxx 86
Переменная tagString перетирается новым значением во всех местах. Сложно сказать, в чём ошибка, или зачем так сделали. Возможно, перепутали операторы '=' и '+='.
Весь список таких мест:
- V519 The 'tagString' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 94, 96. cmCPackLog.cxx 96
- V519 The 'tagString' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 104, 106. cmCPackLog.cxx 106
- V519 The 'tagString' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 114, 116. cmCPackLog.cxx 116
- V519 The 'tagString' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 125, 127. cmCPackLog.cxx 127
Принудительная установка значения AES_SET_UTF8 выглядит подозрительно. Я думаю, такой код введёт в заблуждение любого разработчика, который столкнётся с доработкой этого места.
Такой код скопировали ещё в одно место:
- V519 The 'aes->aes_set' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 4066, 4068. archive_string.c 4068
Как найти ошибки в проекте на CMake
В этом разделе я немного расскажу, как легко и просто проверять проекты на CMake с помощью PVS-Studio.
Windows/Visual Studio
Для Visual Studio можно сгенерировать проектный файл с помощью CMake GUI или следующей команды:
Далее можно открыть .sln файл и проверять проект с помощью плагина для Visual Studio.
На этих системах для проверки проекта используется файл compile_commands.json. Кстати, его можно сгенерировать в разных сборочных системах. В CMake это делается так:
Осталось запустить анализатор в каталоге с .json файлом:
Также мы разработали модуль для CMake-проектов. Некоторым нравится использовать его. CMake-модуль и примеры его использования можно найти в нашем репозитории на GitHub: pvs-studio-cmake-examples.
Заключение
Огромная аудитория пользователей CMake является хорошими тестировщиками проекта, но многие проблемы можно было и не допускать до релиза, применяя такие инструменты статического анализа кода, как PVS-Studio.
Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Svyatoslav Razmyslov. CMake: the Case when the Project's Quality is Unforgivable.
CMake — кроcсплатформенная утилита для автоматической сборки программы из исходного кода. При этом сама CMake непосредственно сборкой не занимается, а представляет из себя front-end. В качестве back-end`a могут выступать различные версии make и Ninja. Так же CMake позволяет создавать проекты для CodeBlocks, Eclipse, KDevelop3, MS VC++ и Xcode. Стоит отметить, что большинство проектов создаются не нативных, а всё с теми же back-end`ами.
Для того что бы собрать проект средствами CMake, необходимо в корне дерева исходников разместить файл CMakeLists.txt, хранящий правила и цели сборки, и произвести несколько простых шагов.
Разберёмся на примерах.
Пример 1. Hello, World:
Для начала напишем простейший хеловорлд и создадим структуру проекта:
Создадим пустую директорию для временных файлов и перейдём туда.
$ mkdir tmp
fshp@panica-desktop:
$ cd tmp/
fshp@panica-desktop:
Теперь запустим команду cmake, передав ей в качестве параметра путь к папке с исходниками:
/cmake/example_1/
…
— Build files have been written to: /home/fshp/tmp
fshp@panica-desktop:
/tmp$ ls
CMakeCache.txt CMakeFiles cmake_install.cmake Makefile
fshp@panica-desktop:
Видим, что в папке появилось несколько временных файлов, необходимых для сборки проекта.
Теперь можно запустить непосредственно make:
/tmp$ make
Scanning dependencies of target main
[100%] Building CXX object CMakeFiles/main.dir/main.cpp.o
Linking CXX executable main
[100%] Built target main
fshp@panica-desktop:
/tmp$ ./main
Hello, World!
fshp@panica-desktop:
Итак, наша программа собралась.
Папку tmp можно очищать\удалять без риска поломать исходники. Если CMakeLists.txt был изменен, то вызов make автоматически запустит cmake. Если исходники были перемещены, то нужно очистить временную директорию и запустить cmake вручную.
Пример 2. Библиотеки:
Если ваш проект содержит библиотеку, то CMake соберет ее без проблем.
Для этого усложним пример.
Переменные могут хранить списки значений, разделённых пробелами\табуляциями\переносами:
Оба варианта правильные
Что бы получить значение переменной ипользуем конструкцию:
Итак, эта версия нашего проекта включает в себя одну статическую библиотеку, собираемую из исходников. Если заменить «STATIC» на «SHARED», то получим библиотеку динамическую. Если тип библиотеки не указать, по умолчанию она соберётся как статическая.
При линковке указываются все необходимые библиотеки:
Как и при ручной компиляции, имена библиотек указываются без стандартного префикса «lib».
Итак, сборка библиотек с CMake не вызывает проблем, при этом тип библиотеки статическая\динамическая меняется лишь одним параметром.
Пример 3. Подпроекты:
Подпроекты очень удобны, если ваша программа разбита на несколько библиотек или же проект состоит из нескольких программ.
Каждый подпроект является по сути полноценным проектом и может использоваться самостоятельно.
Теперь у нас «foo» находится в субдирректории и там же находится CMakeLists.txt подпроекта.
В файле подпроекта ничего нового для вас нет. А вот в основном файле новые команды:
main.cpp мы не меняли, а foo.h перенесли. Команда указывает компилятору, где искать заголовочные файлы. Может быть вызвана несколько раз. Хидеры будут искаться во всех указаных директориях.
Указываем директорию с подпроектом, который будет собран как самостоятельный.
Вывод: проекты на CMake можно объединять в довольно сложные иерархические структуры, причем каждый подпроект в реальности является самостоятельным проектом, который в свою очередь может сам состоять из подпроектов. Это позволяет легко разбить вашу программу на необходимое количество отдельных модулей. Примером такого подхода может служить KDE.
Пример 4. Поиск библиотек:
CMake обладает достаточно развитыми средствами поиска установленых библиотек, правда они не встроеные, а реализованы в виде отдельных модулей. В стандартной поставке довольно много модулей, но некоторые проекты (например Ogre) поставляют свои. Они позволяют системе автоматически определить наличие необходимых для линковки проекта библиотек.
На debian модули располагаются в /usr/share/cmake-2.8/Modules/ (у вас версия может отличаться). За поиск библиотек отвечают модули, называющиеся FindNAME.cmake, где NAME — имя библиотеки.
Пример 5. Внешние библиотеки и объектные файлы:
Если вы пишите для «дяди», а злой «дядя» любит самописные библиотеки и делиться исходниками не желает, поэтому присылает готовую библиотеку, то вы по адресу.
Объектные файлы в CMake стоят на ряду с исходниками — достаточно включить объектник в список файлов для компиляции.
С библиотеками потуже. Как известно, статическая библиотека это не что иное, как ar-архив, внутри которого лежат обычные объектники, никак не связаные между собой. Вы, наверное, уже догадались, как я поступал сначала. Да, просто потрошил библиотеку. Но потом был найден способ поэлегантнее:
Слово «IMPORTED», указывает, что библиотека берётся извне.
В CMake каждая цель имеет параметры, а set_property позволяет их изменять.
Линкуется такая библиотека стандартно:
Для динамических библиотек все аналогично, только тип «SHARED», расширение — ".so".
К сожалению, поддержка несистемных библиотек реализована немного костыльно. Возможно, я просто не знаю правильного варианта, поэтому буду рад, если «ткнете мордочкой». С другой стороны это не навороченый экзоскелет с системой жизнеобеспечения, а простейший костыль из двух строк.
Генераторы:
Как было сказано в начале, CMake умеет генерировать множество различных видов проектов. Это удобно и позволяет использовать CMake для практически любой популярной IDE.
Если запустить cmake без параметров, в конце будут описаны доступные генераторы. Пользоваться так:
/cmake/example_3/ -G "KDevelop3 — Unix Makefiles"
Заключение:
Это не перевод мануала, а результат использования CMake в одном коммерческом проекте. Буду рад, если статья поможет хотя бы одному человеку — на русском языке подобной документации довольно мало.
Читайте также: