IAR + Clion = дружба


    Доброго здравия всем!


    Карантин заставил меня проводить все свое время дома, в том числе и свободное время, и хотя дома есть куча дел, я умело спихнул их на сына, а сам решил наконец-то доизучать среду разработки Clion от JetBrains, тем более, что в релизе 2020.1 появилась поддержка IAR toolchain.


    Все кому интересен пошаговый гайд и куча картинок велком...


    Введение


    В своей работе, для разработки программного обеспечения различных датчиков я использую C++ IAR Workbench компилятор. У него есть свои недостатки, например поздняя поддержка новых стандартов С++, у него есть несколько критичных багов, которые не позволяют создавать удобные конструкции и оптимальные вещи, но в целом я люблю его.


    Всегда можно обратиться за поддержкой к IAR, попросить добавить какую-нибудь функциональность или сделать улучшения, а также, что немаловажно, компилятор имеет сертификат безопасности, а это означает, что я могу положиться на этот компилятор и во время сертификации ПО к нему не будет претензий.


    Последние мои исследования (когда я вызвал внутренний assert у IAR компилятора и он выдал мне простыню из отладочной информации) говорят о том, что собственно этот компилятор сделан на основе Clang, что радует своей перспективой.


    Но есть у IAR одна очень напрягающая вещь — это редактор. Он конечно развивается, в него добавился кривенький интелисенс, подсветка синтаксиса и другие фишки из прошлого, но в целом редактор можно описать фразой — "Powered by notepad".


    Поэтому для работы и для студентов я искал что-то более современное, модное, молодежное, недорогое (а для студентов и подавно бесплатное).


    Мой выбор пал на Clion от JetBrains.


    Общая информация


    Clion это среда для разработки на С/С++. Но я не буду описывать все его прелести, они довольно хорошо описаны в руководстве. Вместо этого, я покажу, как подключить IAR компилятор и как проводить отладку. Описать словами как все это настроить очень сложно, поэтому я просто буду вставлять картинки с небольшими пояснениями.


    Как я уже сказал, в версии 2020.1 была добавлена поддержка IAR компилятора. Огромное спасибо за это Илье Моторному ака Elmot, потому что до версии 2020.1 работа с IAR была немного загадочной и не совсем понятной.


    Он уже выкладывал здесь статью про свой плугин для поддержки разработки встроенного ПО с использованием ST Cube, а сейчас еще приложил руку и голову к поддержке IAR. Он также вкратце описал, как подружить Cube, IAR и Clion здесь.


    Создание проекта


    В основе работы Clion лежит система сборки CMAKE, и любой проект настраивается на основе файлов настроек дя CMAKE. Поэтому чтобы создать проект, достаточно просто указать папку где будут лежать ваши исходники. Можно создать проект уже из существующих исходников, в таком случае, Clion автоматически прошерстит указанную папку с исходниками, найдет все c и cpp файлы и добавит их в список (CMAKELIST) для сборки.


    Но давайте создадим проект с нуля, чтобы было понятно, как оно настраивается руками. Для этого необходимо выбрать пункт меню File->NewProject



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


    Нас интересует С++17 и тип выходного файла C++ Executable. На данном этапе ничего больше не надо.



    Если вы заметили в настройках проектах уже сть опция Embedded->STM32CubeMX, она позволяет вам создать файл .ioc, в который затем можно добавить настройки из STM32CubeIDE. А поскольку Clion может работать с .ioc файлом, то все изменения в нем экспортируется в проект Clion.


    Но это не наш вариант, мы хотим работать с IAR компилятором и микроконтроллерами по брутальному без всяких там Cubов. Итак, мы создали пустой проект, который содержит только один исходных файл main.cpp.



    Как я уже говорил, вся концепция сборки с Clion построена на использовании CMAKE, поэтому основным файлом сборки будет являться CMakeList.txt, содержащий настройки целей для сборки, списки подключаемых директорий, списки исходных файлов и многие другие вещи, необходимы для сборки.


    На данный момент файл выглядит вот так:



    Как видите в нем указана только минимально требуемая версия CMAKE +
    Собственно имя проекта +
    Стандарт С++, который мы выбрали при настройке+
    И единственный исходный файл для сборки — main.cpp


    Скоро мы добавим сюда немного настроек, а пока необходимо установить toolchain


    Выбор и установка Toolchain


    Clion в теории может работать с любым toolchain.


    Для тех кто не в курсе

    Toolchain — это набор инструментов для сборки программ из исходного кода. Обычно туда входит, стандартные библиотеки, компилятор, линковщик, ассемблер, отладчик и другие полезные вещи.


    Но стандартно Clion поддерживает популярные тулчейны — MinGW, CygWin, Visual Studio


    В списке нет IAR toolchain, но это не беда, можно установить любой стандартный, я пробовал с MinGW и Visual Studio с обоими работает прекрасно.


    Поэтому для начала необходимо установить один из стандартных toolchain, которые поддерживает Clion.


    C Visual Studio все понятно, нужно просто скачать установщик у Microsoft и установить С++ пакет (поставить галочку, потому что по умолчанию устанавливается только C#).


    Поэтому сразу давайте разберемся с MinGW, скачать его можно отсюда http://www.mingw.org/.
    Для полного понимания: нужен installer, его можно обнаружить справа на ссылках Popular или All time:



    На всякий случай, прямая ссылка.


    Далее запускаем MinGW и указываем путь, куда это все дело поставить:



    После копирования файлов, жмем Continue, запуститься Менеджер Инсталляции. Все что нам нужно это GNU C++ Compiler (собственно и он то не нужен, но нужно, чтобы, что-то было установлено) и Базовая инсталляция. Выбрали — жмем ApplyChanges.



    Все это дело превосходно установится в течении минуты. Установка MinGW toolchain завершена. Перейдем теперь к настройкам.


    Настройка


    Сразу скажу, настроек в Clion немерено, я не будут рассказывать про все, цель статьи показать, как работать с IAR toolchain.


    Итак, для начала идем в настройку Clion — File->Settings->Build, Execution, Deployment -> Toolchain и жмем на плюсик.



    Выбираем из списка стандартных toolchain MinGW, ну или Visual Studio, если вы установили его. И ждём пока Clion сам определит местоположение компилятора, make утилиты, и отладчика.
    Вообще ждать не обязательно, мы все равно это заменим своим :)



    Теперь заменим все на нужный нам компилятор и отладчик. Для компиляции С и С++ файлов IAR использует тот же самый компилятор, поэтому просто в обоих случаях указываем один и тот же компилятор.


    А вот отладчик нужно поменять либо на поставляемый (Bundled) с Clion, либо на отладчик из комплекта GNU ARM (можно скачать отсюда https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads)


    Самое простое использовать отладчик поставляемый с Clion:



    Можно сразу переименовать ваш toolchain в IAR, чтобы отличать его от стандартного MinGW.



    Утилиту make можно использовать из комплекта MinGW, но если очень хочется, то можно поменять её на любую другую, например, я использую clearmake, поставляемый с системой контроля версий ClearCase (не спрашивайте, почему — так исторически сложилось)


    Вы также можете поменять make сборку на какую-нибудь другую, например на ninja, более подробно об этом можно прочитать здесь.


    Базовая Настройка CMAKE


    Перед тем как собирать проект, необходимо выполнить базовые настройки CMAKE, для различных вариантов сборок, например, Release или Debug. Создадим обе.


    Для этого идем в File->Settings->Build, Executiion, Deployment -> CMake



    И жмем на "+" плюсик



    Автоматически у вас создастся конфигурация сборки для Debug. Здесь можно добавить кое какие опции для CMake, поменять папку для сборки, и добавить опции для make или другого сборщика (Build Options). По умолчанию, стоит ключ -j 16( у вас может быть и больше), что означает задействовать все 16 ядер для параллельной компиляции модулей. Такой параллелизм хорошо работает, кода весь код лежит на локальной машине, но если он лежит где-нибудь в сети или удалённой системе контроля версии (моя история) и этот доступ осуществляется медленно, через VPN, то лучше поставить компиляцию на одно ядро.


    Для выбора типа сборки Debug или Release нужно использовать выпадающий список Build Type.


    Точно также создаём еще один тип сборки Release.


    После нажатия на кнопку Apply Clion должен будет пересобрать проект CMAKE, и если вы нигде не допустили ошибок, то после пересборки у вас должен появиться вот такой выбор в списке возможных сборок:



    В принципе уже сейчас можно компилировать, жмем на молоток и видим что компиляция происходит успешно, а вот линковка нет, требуется метод __write(), который вызывается оператором вывода в main.cpp.



    Все потому что мы не настроили ключи для компилятора и линковщика. Переходим к настройку CMake.


    IAR выложил пример с настройками для CMake, он лежит здесь.


    Немного подредактируем его
    ### BEGIN CMAKE_TOOLCHAIN_FILE
    # "Generic" is used when cross compiling
    set(CMAKE_SYSTEM_NAME Generic)
    
    # Set the EW installation root directory
    set(EW_ROOT_DIR "C:/Program Files (x86)/IAR Systems/Embedded Workbench 8.3/arm")
    
    # set common compiler flags for all build types
    set(CMAKE_CXX_FLAGS  "--no_cse --no_unroll --no_code_motion --no_tbaa --no_clustering --no_scheduling --endian=little --cpu=Cortex-M4 -e --fpu=VFPv4_sp --c++ --no_exceptions --no_rtti")
    
    set(CMAKE_C_FLAGS  "--no_cse --no_unroll --no_code_motion --no_tbaa --no_clustering --no_scheduling --endian=little --cpu=Cortex-M4 -e --fpu=VFPv4_sp ")
    
    set(CMAKE_ASM_FLAGS "-s+ -r -t8 --cpu Cortex-M4 --fpu VFPv4_sp ")
    
    # Set up the CMake asm compilers
    set(CMAKE_C_COMPILER "${EW_ROOT_DIR}/bin/iccarm.exe")
    set(CMAKE_CXX_COMPILER "${EW_ROOT_DIR}/bin/iccarm.exe" )
    set(CMAKE_ASM_COMPILER "${EW_ROOT_DIR}/bin/iasmarm.exe")
    
    #set output file extentation to .elf
    set(CMAKE_EXECUTABLE_SUFFIX ".elf")
    
    # Set up the linker configuration script
    set(LINKER_SCRIPT "${CMAKE_SOURCE_DIR}/stm32f411xE.icf")
    
    #Set IAR setting for bedug build
    if (CMAKE_BUILD_TYPE  MATCHES Debug)
    message ("IAR Debug")
    # set a preprocessor symbol "DEBUG"
    add_compile_definitions( DEBUG=1 )
    # set up the CMake variables for the compiler for DEBUG
    set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --dlib_config=normal --no_inline")
    set (CMAKE_ASM_FLAGS  "${CMAKE_ASM_FLAGS} ")
    set (CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} --dlib_config=normal --no_inline")
    set(CMAKE_CXX_LINK_FLAGS "--semihosting --config ${LINKER_SCRIPT}")
    
    else(CMAKE_BUILD_TYPE MATCHES Release)
    message ("IAR Release")
    # set up the CMake variables for the compiler for Release
    set (CMAKE_C_FLAGS  "${CMAKE_C_FLAGS} --dlib_config=normal")
    set (CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} ")
    set (CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS}  --dlib_config=normal")
    set(CMAKE_CXX_LINK_FLAGS "--config ${LINKER_SCRIPT}")
    endif()
    ### END CMAKE_TOOLCHAIN_FILE

    Все что я сделал, это добавил две ветки настроек для двух типов сборок Debug и Release.
    Да еще поменял имя выходного файла на *.elf установив переменную set(CMAKE_EXECUTABLE_SUFFIX ".elf")


    Осталось добавить нашу настройку в CMakelist.txt:


    cmake_minimum_required(VERSION 3.16)
    project(MyFirstProject)
    
    # enable C and assembler source
    enable_language(C ASM CXX)
    set(CMAKE_CXX_STANDARD 17)
    
    include(iarconfig.cmake)
    
    add_executable(MyFirstProject main.cpp)

    Каждый раз когда вы меняете Cmakelist.txt или настройку toolchanin необходимо запускать пересборку Cmake проекта. Можно настроить, чтобы она делалась автоматически, но лучше просто руками нажимать на кнопку Reload Cmake, а вот для того, чтобы жестко пересобрать Cmake проект, лучше пойти в toolbox Cmake и выбрать там пункт Reset Cache and Reload Project



    Теперь можно снова попробовать пересобрать проект, нажав на молоток. Если вы опять все сделали правильно — ваш простой проект должен собраться.


    Настройка отладчика


    Для отладки я буду использовать OpenOCD gdb сервер, но вы можете использовать Jlink gdb сервер или ST-Link gdb сервер.


    Скачаем стабильную версию, на момент написания статьи это была версия 0.10.0: https://sourceforge.net/projects/openocd/files/openocd/0.10.0/ можно её собрать самому. Но если лень с этим возиться, то можно использовать неофициальную сборку под Windows: http://www.freddiechopin.info/en/download/category/4-openocd.


    Итак, для настройки отладчика нужно сделать следующие шаги:


    • Убедитесь, что в настройках стоит gdb клиент из поставки File->Settings->Build,Execution,Deployment->Toolchains->Debugger: Bundled GDB


    • Переходим в настройки отладчика Run -> Edit Configurations -> Templates
      И находим там Embedded GDB Server




    В шаблоне нет настроек и можно для каждого проекта использовать пустой шаблон и каждый раз его настраивать, а можно сразу настроить шаблон, чтобы в следующем проекте переиспользовать настройки.


    Настроим сразу шаблон:


    • В опции Download executable поставим галочку, на Update Only — позволит загружать в микроконтроллер образ программы только в том случае, если были были какие-то изменения, в противном случае прошивки не будет.


    • OpenOCD по умолчанию работает по tcp протоколу, т.е. вы можете подключаться к серверу удалённо по IP адресу и порту по умолчанию 3333 (порт можно менять, но нам это не нужно). Так как запускаться OpenOCD будет на локальном компьютере, то и в опции target remote args нужно установить в значение tcp:127.0.0.1:3333


    • В опции GDB Server прописываем путь к OpenOCD, туда куда вы уже его скопировали на предыдущих шагах.


    • В GDB Server args прописываем строку запуска OpenOCD сервера с аргументами. Так как я использую китайский клон Nucleo, который называется XNucleo, то я немного подредактировал конфигурацию st_nucelo, прописав идентификационный номер вендора китайского отладчика (hla_vid_pid — The vendor ID and product ID of the adapter) и поменял имя файла настроек. В итоге моя строка для аргументов OpenOcd выглядит следующим образом:
      -f ../scripts/board/st_xnucleo_f4.cfg -c "reset_config none separate" -c "init" -c "reset halt"



    Здесь ключ -f задаёт имя конфигурационного файла, вместо моего st_xnucleo_f4.cfg, поставьте вашу плату, либо если у вас нет платы, то прописать нужно конфигурацию для процессора и для отладчика в отдельном файле и уже подключить этот файл.


    Ключ -с задаёт команду, которая следуют за ключем в кавычках.


    • -c "reset_config none separate" — означает, что сброс производится через SWD без использования отдельной ножки сброса (а у меня как раз такой китайский отладчик).


    • -c "init" — запускает команду "init", которая запускает загрузочные OpenOCD скрипты под ваш целевой процессор


    • -c "reset halt"_ — выполняет немедленный сброс микроконтроллера после инициализации



    В принципе все. Больше ничего не нужно. У вас должен получиться вот такой шаблон



    Осталось на основе этого шаблона создать конфигурацию:


    • Снова переходим в Run -> Edit Configurations
    • Жмем на "+"


    и выбираем наш Template. Переименовываем как-то по человечьи



    И собственно теперь можно запускать на проверку, жмем на жука и смотрим, как все работает.



    В опциях Advanced GDB Server options можно дополнительно установить команды выполняющиеся после загрузки кода. Я поставил перезагрузку и перенаправление потока вывода через отладочный интерфейс — monitor arm semihosting enable. Только не забудьте поставить галочку Download executable: Always иначе загрузки не будет и команды не выполнятся.


    Теперь все обращения к потоку вывода будут отражаться у вас в окне Debug: Console. Выводиться будет медленно, но для отладки пойдет.


    Залипающая картинка


    Также вы можете просмотреть все регистры для вашего микроконтроллера но нужно будет их подключить, используя .svd файл.


    Еще одна залипающая картинка


    Завершающий этап


    Чтобы наш проект заработал вообще как надо, добавим в него файл startup.cpp, в котором будет происходить инициализация стека, инициализация статических переменных, fpu и храниться таблица векторов прерывания и собственно переход на точку входа программы main().


    Для этого нам достаточно скопировать файл startup.cpp в папку проекта и добавить его в сборку.



    Теперь наш проект готов и вы можете скачать его здесь: Постой проект с настройками для IAR
    Для открытия в Clion достаточно зайти в меню File->Open и выбрать папку в которую вы его разархивировали.


    Да остался один момент:


    Статический анализатор, проверяющий код на лету, на основе Clang пока не работает для IAR, так как не понимает ключи компилятора, поэтому его придется отключить, через меню File->Settings -> Languages&Frameworks -> C/C++ -> Clangd.


    Убрать галочку Enable clangd server.



    Заключение


    В качестве заключения хотелось бы сказать, что работать в IAR IDE после Clion как то не очень хочется. Хотя для детальной отладки все таки придется использовать IAR, так как средства отладки там явно обширнее. С другой стороны к отладке я вообще редко обращаюсь, разве что проверить код студентов, когда он не работает.


    Clion бесплатен для студентов и поэтому проблем с его установкой у них быть не должно, но и в принципе лицензия тоже не дорогая. Думаю, что студентам Clion серьезно облегчит жизнь и привнесет песчинку радости в их угрюмую жизнь, потому что сейчас больно смотреть на их муки написания кода. Да, что таить и на работе тоже.


    А еще работать в Clion приятно, потому что все в одном. Например, эту статью я пишу тоже в Clion и сразу вижу её отображение.



    А ведь есть еще куча всяких других плюшек, про которые я рассказывать не буду, они описаны на сайте JetBrains. Просто завершающий гифчик, показывающий скорость работы:


    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 13

    • НЛО прилетело и опубликовало эту надпись здесь
        +2
        Вообще имхо выглядит несколько костыльно. Необходимость ставить левый (MSVC/MinGW) компилятор, плюс завязывать проектный CMakeLists.txt на то, что нравится CLion.
        У меня один из проектов делается на CMake, тулчейн указывается в отдельном cmake файле. Так вот, в такой конфигурации CLion вскидывает лапки со словами «я не знаю такого тулчейна» и отказывается дальше индексировать проект.
        Приходится тупо `File->New CMake project from sources`, и делать это снова и снова при добавлении нового файла в проект.

        А вот работать в ней действительно удобно. Индекс у них лучший (если не глючит и нормально отрабатывает на весь проект)
          0
          Строго говоря, «левый» компилятор не нужен. Нужно GNU окружение и gdb.
            0
            Так и чего, зачем GNU окружение, к примеру, мне, компилирующему исключительно в Tasking/Diab (или, как в статье — IAR)?
              0
              Diab не поддерживается. Gnu окружение для make/cmake. Увы, пока так, но мы работаем над улучшением.
          0
          AFAIK, Qt Creator должен работать с IAR «из коробки» в связке в Qbs.
            +1
            Отличная статья, спасибо!
            Пара вопросов:
            1) Почему вы студентам не предлагаете Кейл? Я не похоливарить сейчас хочу на тему «Великой Тройки», а конкретно про студентов. Сертифицированность компилятора для них вряд ли имеет значение, а в части удобства работы с МК у него конкурентов нет ИМХО (с IAR-ом все понятно, а Atollic True Studio и аналоги мало того что тормозные, так еще и в gdb приходится макаться). Ну и он бесплатный до 32кБ, ИХМО достаточно. Ну и вероятность поработать с ним в отрасли весьма высокая.
            2) Поясните убогим — файл startup.cpp откуда берется? Понятно, что его можно и самому при наличии знаний написать (оглядываясь на готовые примеры), но вот конкретно тут он откуда?
            3) И еще вопрос от убогих — не очень понял из поста, где и как вы переопределили _write, очевидно ITM_SendChar должен быть в основе всего, а как дальше настраивается вывод вот туда вниз?
              0

              Спасибо, рад что полезная статья.


              1) Почему вы студентам не предлагаете Кейл?

              Исторически так сложилось, что мы всегда на работали на IAR, в связи с тем, что это хороший, надежный проверенный временем компилятор, имеющий сертификат безопасности. Еще работали с GreenHill, по той же причине, но потом остановились на одном IAR. Поэтому просто проще было давать студентам IAR, который я знаю и использую, тем более, что 32 кБайтной бесплатной версии им за глаза хватает.
              Но мое мнение в приницпе без разницы какой компилятор можно и с GCC тоже самое сделать. Если не использовать расширения неподдерживаемые стандартом, а сейчас мы так и стараемся делать, то точно без разницы. Код можно запускать хоть на каком компиляторе, там все отличия в основном в этом startup, где используются как раз трюки компиляторов, типа инициализации стека или __weak директивы. Весь остальной код к компилятору не привязан вообще.


              За границей, по моему ощущению, IAR довольно популярный, у нас не очень потому что платный, но в Европах и Америках очень распространен, особенно в разработке для промышленных применений, автомобильной, медицинской, — там где надежность нужна.


              2) Поясните убогим — файл startup.cpp откуда берется? Понятно, что его можно и самому при наличии знаний написать (оглядываясь на готовые примеры), но вот конкретно тут он откуда?

              Файл startup.cpp, самописный (за основу взят Сишный из IAR примеров) Но можно использовать startup сишний или ассемблеровский, который есть в CMSIS для IAR или Cube — не важно какой, главное стек проинициализировать, таблицу векторов, инициализацию глобальных и статических переменных, fpu ну и main() вызвать. Просто раз уж все на С++, то и стартап тоже :), хотя там используется соглашение об вызовах сишное, но зато компилятор С++ его компилирует, а не Сишный.


              3) И еще вопрос от убогих — не очень понял из поста, где и как вы переопределили _write, очевидно ITM_SendChar должен быть в основе всего, а как дальше настраивается вывод вот туда вниз?

              функция __write() определяется в библиотеке dlib, без ключей компилятора она не подключается и соответственно нет и её имплементации. Когда добавляешь ключ к строке компилятора --dlib_config=normal, ну или full — появляется и её имплементация. См строчку
              set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --dlib_config=normal --no_inline")


              PS. Да добавлю с помощью semihosting вы перенаправляете вывод в отладочный интерфейс, вначале в настройках линкера, чтобы он подключил нужную реализацию


              set(CMAKE_CXX_LINK_FLAGS "--semihosting --config ${LINKER_SCRIPT}")


              а затем еще и OpenOCD, чтобы он активировал эту функцию у отладчика:


              monitor arm semihosting enable

                0
                Исторически так сложилось, что мы всегда на работали на IAR


                Этой практики вероятно и следовало придерживаться, просто если вы решили взять что-то более красивое, то кажется Кейла было бы достаточно, и это все еще было бы отраслевое решение. Но это сугубо ИМХО.

                функция __write() определяется в библиотеке dlib, без ключей компилятора она не подключается и соответственно нет и её имплементации


                Ну ок, а внутри нее-то какая реализация?
                  0
                  Ну ок, а внутри нее-то какая реализация?

                  Реализация от IAR из dlib в зависимости от ключей, линкер может подрубить нужную.
                  Вы в принципе и сами можете её переопределить, если хотите. Но я не стал :)


                  PS. Да добавлю с помощью semihosting вы перенаправляете вывод в отладочный интерфейс, вначале в настройках линкера, чтобы он подключил нужную реализацию
                  set(CMAKE_CXX_LINK_FLAGS "--semihosting --config ${LINKER_SCRIPT}")
                  а затем еще и OpenOCD, чтобы он активировал эту функцию у отладчика:
                  monitor arm semihosting enable
                    0
                    Вот, я это и спрашивал — что там под капотом, оказалось семихостинг. Да, в этом случае вывод сам по себе идет в консоль отладчика. В этом смысле с выводом через ITM больше тонкостей, он как-то в ATS у меня вообще отказался работать, приходилось отладочную консоль в Link Utility запускать.
                • НЛО прилетело и опубликовало эту надпись здесь
                0
                Не рекламы ради, но в QtCreator это все делается быстрее и проще. ;)

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

                Самое читаемое