«Сборка проекта должна быть отделена от IDE»

Главное преимущество перехода с GNU Make на CMake это получение кроссплатформенности. То есть вы сможете одними и теми же скриптами собирать прошивки как в окружении Windows, так и в окружении Linux. Буква С в слове CMake как раз это сокращение от Cross Platform. Если вы работаете только в Windows (или только на Mac), то смысла переходить на CMake просто нет.

Дело в том, что самостоятельно написанные скрипты Make как правило имеют специфические для конкретной ОС строки. Это пути, которые начинаются с диска С или название утилит с суффиксом exe. Скрипты написанные для Win вероятно не будут отрабатывать в Linux и наоборот. Хотя можно постараться написать Make максимально переносимым образом.

Поэтому для разработки в условиях кроcсплатформенности OS нужна какая‑то надсистема. Этой надсистемой и является утилита CMake (с 1999 года).

У CMake есть множество братьев по оружию. Тема называется meta build systems. Примерами выступают утилиты imake, premake, Autotools, Meson, GYP, WAF, SCons, qmake и прочее. Все они тоже могут генерировать makefile скрипты. Тем не менее, во всей теме build automation software чаще всего почему‑то вспоминают именно про CMake. Вот по этому я сейчас и сфокусировался именно на CMake.

Зачем нужна сборка из скриптов?

Вы можете спросить:

«А зачем запускать сборку из консоли? » или «Зачем в принципе командная строка?»

На то у меня есть два развернутых ответа в виде отдельных текстов:
1) Почему Сборка с Помощью GUI‑IDE — это Тупиковый Путь
2) Почему важно собирать код из скриптов

Если коротко, то GUI‑IDE не позволяют масштабироваться при увеличении ассортимента прошивок в организации. В то время как переход на скрипты сборки на порядки повышает производительность труда программиста. Вся суть любого программирования — это автоматизация чего‑либо. Даже автоматические построения самих проектов.

А сборку из скриптов очень легко автоматизировать. Достаточно в консоли выполнить скрипт и у вас инициируется процесс сборки, а через 3 мин в соседней папке будут лежать готовые артефакты. При сборке из скриптов у вас будет одна кнопка. Жмакнул на .bat скрипт — получил .hex прошивку. Жмакнул на другой *.bat скрипт — прошил плату. Ну что может быть еще проще?

Я сейчас поддерживаю на плаву примерно 150 прошивок. И меня это даже нисколько не утомляет, так как все они собираются из скриптов. У меня после каждой программной вставки все мои 150+ сборок в репозитории собрались пока я сплю.

Постановка задачи:

Написать на Си проект прошивки для микроконтроллера STM32F407VE. В качестве кросс компилятора выбрать ARM-GCC. Алогритм работы прошивки пока не так важен. Главное то, что в качестве системы сборки следует использовать CMake генерирующий GNU Make скрипты. В качестве HAL использовать фирменный HAL от STM и CMSIS от ARM. Собирать проект в Windows 10.

Компилятору следует передать пучок опций

 -MMD -MP -O0 -std=c11 -Wall -Werror -mcpu=cortex-m4 -march=armv7e-m -Werror=address 
-Werror=address-of-packed-member -Werror=all -Werror=array-bounds=1 
-Werror=bool-compare -Werror=bool-operation -Werror=char-subscripts 
-Werror=clobbered -Werror=comment -Werror=div-by-zero -Werror=duplicate-decl-specifier
-Werror=duplicated-cond -Werror=empty-body -Werror=enum-compare -Werror=extra 
-Werror=float-equal -Werror=ignored-qualifiers -Werror=implicit -Werror=implicit-int
-Werror=incompatible-pointer-types -Werror=init-self -Werror=int-in-bool-context 
-Werror=int-to-pointer-cast -Werror=logical-not-parentheses -Werror=logical-op 
-Werror=maybe-uninitialized -Werror=memset-elt-size -Werror=memset-transposed-args
-Werror=misleading-indentation -Werror=missing -Werror=missing-braces 
-Werror=missing-parameter-type -Werror=multistatement-macros 
-Werror=old-style-declaration -Werror=overflow -Werror=override-init
-Werror=parentheses -Werror=pointer-arith -Werror=pointer-sign
-Werror=pointer-to-int-cast -Werror=return-local-addr -Werror=return-type 
-Werror=sequence-point -Werror=shadow -Werror=shift-count-overflow 
-Werror=shift-negative-value -Werror=sign-compare -Werror=sizeof-pointer-div
-Werror=sizeof-pointer-memaccess -Werror=strict-aliasing -Werror=strict-overflow=1
-Werror=switch -Werror=switch-default -Werror=tautological-compare -Werror=trigraphs
-Werror=type-limits -Werror=uninitialized -Werror=unused -Werror=unused
-Werror=unused-but-set-parameter -Werror=unused-but-set-variable -Werror=unused-value 
-Werror=unused-variable -Werror=unused-variable -g3 -Wextra -Wno -Wno-conversion 
-Wno-cpp -Wno-discarded-qualifiers -Wno-discarded-qualifiers -Wno-implicit
-Wno-int-conversion -Wno-nonnull-compare -Wno-redundant-decls -Wno-restrict
-Wno-sign-compare -Wno-stringop-truncation -Wno-switch-bool -Wno-unused-parameter
-fallthrough -fdata-sections -fdce -fdse -ffreestanding -ffunction-sections 
-field-initializers -finline -finline-small -fmax-errors=70 -fmessage-length=0
-fno-common -fno-move-loop-invariants -fno-printf-return-value -fomit -format 
-format-truncation -frame-pointer -fshort-enums -fsigned-char -fstack-usage
-function -function-declaration -functions -functions -g3 -fzero-initialized-in-bss 
-mfloat-abi=hard -mfpu=fpv4-sp-d16  -mthumb 


Компоновщику же следует передать вот эти ключи:

-specs=nosys.specs -Xlinker --gc-sections  -Xlinker --nmagic -Wl,--gc-sections 
-Xlinker --print-memory-usage  -t -Wl,--cref  -Wl,--gc-sections  --verbose 
-mcpu=cortex-m4  -march=armv7e-m -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16  -lm 

В чем проблема?
Трудность в том, что STMcubeMX не может сгенерировать CMake проект. В лучшем случае можно выбрать только GNU Make сборку.

Теория

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

Система сборки (build system) — это набор инструментов и процессов, которые автоматизируют преобразование исходного кода в исполняемые приложения или артефакты для развертывания. Такие системы обрабатывают различные задачи: компиляцию кода, разрешение зависимостей. Примерами систем сборки является GNU Make, Ninjia, Xcode, Visual Studio (Microsoft Windows), Android Studio , IAR Workbench.

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


Генераторы систем сборки (build system generator) - утилиты, которые генерируют код системы сборки. Это Autotools, Cmake, Meson.

в случае с СMake + GNU Make схема сборки выглядит как-то так:

Реализация

Скорее всего Cmake уже установлен на вашем PC. Это можно проверить набрав команду
where cmake

C:\Users\User>where cmake
C:\cygwin64\bin\cmake.exe
C:\Program Files\CMake\bin\cmake.exe

Скорее всего у вас уже есть какой-то проект прошивки собираемый через GNU Make скрипты и надо лишь на основе готовых make скриптов синтезировать аналогичные Cmake скрипты. Для этого можно применить вот эту подсказку.

Миграция с GNU Make на CMake

При наличии уже готовых GNU Make скриптов, миграция на CMake сводится к простой механической замене текстовых шаблонов кода согласно таблице подсказке ниже. С этой задачей справляется даже DeepSeek.

GNU Make

CMake

Пояснение

.mk

.cmake

Расширение файла

VAR += value

string(APPEND VAR " value")

пополнение переменной окружения

CRC=Y

set(CRC Y)

Определение переменной окружения

$( )

${ }

Вставка переменной окружения

endif

endif()

конец if

$(info text)

message(STATUS "text")

printf - отладка

$(error text)

message(FATAL_ERROR "text")

printf - отладка

ifeq ($(IAR),Y)

if(IAR STREQUAL Y)

Условный оператор

ifeq ($(A),Y)

if(A STREQUAL Y)

Условный оператор

ifeq ($(

if (

Условный оператор

COMPILE_GCC_OPT += -Wall

add_compile_options( -Wall)

пополнение переменной окружения

MCAL_OPT += -DHAS_ARM

set(MCAL_OPT “${MCAL_OPT} -DHAS_ARM”)

добавить в конец переменной окружения текст

ifneq ($(

if( NOT (

if not

@ECHO ${error Hello)

message( SEND_ERROR "Hello" )

printf - отладка

OPT += -D

target_compile_definitions(app PUBLIC

добавление ключей

OPT += -DHAS_CORTEX_M4

add_compile_definitions(-DHAS_CORTEX_M4)

добавление ключей

INCDIR += -I xxx/xxxx/xxx

target_include_directories(app PUBLIC xxx/xxx/xxx)

добавление путей

SOURCES_C += src/main.c

target_sources(app PRIVATE src/main.c)

добавление исходников

SOURCES_C += src/main.c

add_executable(Application src/main.c)

добавление исходников

LINKER_GCC_FLAGS += -u printffloat

add_link_options( -u_printf_float )

Добавление ключей компоновщику

Синтаксис GNU Make существенно лаконичнее и проще чем CMake.

было
LINKER_FLAGS += -u _printf_float

стало
target_link_options(app PRIVATE -u _printf_float)
-----------------------------------------------------
было
include $(WORKSPACE_LOC)/connectivity/connectivity.mk

стало
include(${WORKSPACE_LOC}/connectivity/connectivity.cmake)

------------------------------------------
было
SOURCES_THIRD_PARTY_C += $(STM32F4X_HAL_DRIVER_DIR)/stm32f4xx_hal_cortex.c

стало
string(APPEND SOURCES_THIRD_PARTY_C " ${STM32F4X_HAL_DRIVER_DIR}/stm32f4xx_hal_cortex.c")

------------------------------
было
MCAL_OPT += -DFLAG1

стало
string(APPEND MCAL_OPT " -DFLAG1")

--------------------
было
ifneq ($(CONNECTIVITY_MK_INC),Y)
endif

стало
if( NOT (CONNECTIVITY_MK_INC STREQUAL Y))
endif()

------------------
было
ifeq ($(AT_START_F413),Y)
endif

стало
if(AT_START_F413 STREQUAL Y)
endif()
--------------------
было
MCAL_OPT += -DUSE_HAL_DRIVER

стало
add_compile_definitions(USE_HAL_DRIVER)

Как видите, CMake заметно более многословный язык в сравнении с GNU Make.

Утилита CMake работает с файлом CMakeLists.txt. Его надо подвергать версионному контролю. Корневой CMakeLists.txt выглядеть может так:

cmake_minimum_required(VERSION 3.16)
project(jz_f407vet6_mbr_gcc_cmake)
set(PROJECT_NAME jz_f407vet6_mbr_gcc_cmake)
enable_language(C ASM)

set(CURRENT_CMAKELISTS_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(PROJECT_LOC ${CMAKE_CURRENT_SOURCE_DIR})
include_directories( ${PROJECT_LOC})

set(BUILD_DIR ${PROJECT_LOC}/build)
set(TARGET ${PROJECT_NAME})
set(EXECUTABLE ${TARGET})

get_filename_component(WORKSPACE_LOC "${PROJECT_LOC}/../.." ABSOLUTE)
include_directories(${WORKSPACE_LOC})

include(${PROJECT_LOC}/config.cmake)
include(${WORKSPACE_LOC}/cmake_scripts/code_base.cmake)
include(${WORKSPACE_LOC}/cmake_scripts/rules.cmake)

Каждая сборка уникальная. Уникальность программы формируется набором тех программных компонентов из которых она состоит. Выбрать набор программных компонентов, которые будут участвовать в построении можно при помощи переменных окружения. Достаточно просто определить эти переменные окружения в файле config.cmake. projects\jz_f407vet6_mbr_gcc_cmake\config.cmake


set(CONTROL Y)
set(DWT Y)
set(ARM_GCC Y)
set(CORTEX_M4 Y)
set(FLASH Y)
set(FPU Y)
set(GPIO Y)
set(INTERRUPT Y)
set(JZ_F407VET6 Y)
set(LED_MONO Y)
set(MBR Y)
set(MCAL_STM32 Y)
set(MICROCONTROLLER Y)
set(NVIC Y)
set(RCC Y)
set(SCHEDULER Y)
set(STM32F407VE Y)
set(STM32F4X_HAL_DRIVER Y)
set(SUPER_CYCLE Y)
set(SYSTEM Y)
set(SYSTICK Y)
set(SYS_INIT Y)
set(TIME Y)

Все программные компоненты надо добавить внутри code_base.cmake. Один за другим. Согласно активированным переменным окружения. Вот так может выглядеть CMake скрипт для программного компонента GPIO. Тут важно заметить, что к каждой папке, в которой лежат исходники, надо указать путь при помощи CMake функции include_directories

if(NOT (GPIO_DRV_MK_INC STREQUAL Y))
    set(GPIO_DRV_MK_INC Y)

    set(GPIO_DIR ${MCAL_CUSTOM_DIR}/gpio)
    include_directories( ${GPIO_DIR})

    string(APPEND MCAL_OPT " -DHAS_GPIO_CUSTOM")

    string(APPEND SOURCES_C " ${GPIO_DIR}/gpio_mcal.c")
    string(APPEND SOURCES_C " ${GPIO_DIR}/gpio_custom_isr.c")

    if(CLI STREQUAL Y)
        if(GPIO_COMMANDS STREQUAL Y)
            string(APPEND MCAL_OPT " -DHAS_GPIO_COMMANDS")
            string(APPEND SOURCES_C " ${GPIO_DIR}/gpio_custom_commands.c")
        endif()
    endif()

    if(DIAG STREQUAL Y)
        if(GPIO_DIAG STREQUAL Y)
            string(APPEND MCAL_OPT " -DHAS_GPIO_DIAG")
            string(APPEND SOURCES_DIAG_C " ${GPIO_DIR}/gpio_custom_diag.c")
        endif()
    endif()

endif()

CMake очень гибок в вопросах настройки того, что именно мы хотим собрать. Чтобы подключить файл к сборке надо прописать его путь в переменную окружения SOURCES_C_TOTAL и передать эту переменную в CMake функцию add_executable. Ключи компилятору тоже передаются через переменную окружения MCAL_OPT, которая передается в CMake функцию add_definitions.

set(CMAKE_C_STANDARD 11) 
add_definitions(${MCAL_OPT})

string(APPEND SOURCES_C_TOTAL "${SOURCES_ASM}")
string(APPEND SOURCES_C_TOTAL "${SOURCES_C}")
string(APPEND SOURCES_C_TOTAL "${SOURCES_DIAG_C}")
string(APPEND SOURCES_C_TOTAL "${SOURCES_THIRD_PARTY_C}")
string(APPEND SOURCES_C_TOTAL "${SOURCES_CONFIGURATION_C}")

message(STATUS "SOURCES_C_TOTAL=${SOURCES_C_TOTAL}")

separate_arguments(SOURCES_LIST UNIX_COMMAND ${SOURCES_C_TOTAL})

add_executable(${EXECUTABLE}   ${SOURCES_LIST})


include(${WORKSPACE_LOC}/cmake_scripts/toolchain.cmake)
include(${WORKSPACE_LOC}/cmake_scripts/compiler_gcc_options.cmake)
include(${WORKSPACE_LOC}/cmake_scripts/linker.cmake)

# Print executable size
add_custom_command(TARGET ${EXECUTABLE}
        POST_BUILD
        COMMAND arm-none-eabi-size ${EXECUTABLE}.elf)

# Create hex file
add_custom_command(TARGET ${EXECUTABLE}
        POST_BUILD
        COMMAND arm-none-eabi-objcopy -O ihex ${EXECUTABLE}.elf ${PROJECT_NAME}.hex
        COMMAND arm-none-eabi-objcopy -O binary ${EXECUTABLE}.elf ${PROJECT_NAME}.bin)

set_target_properties(${PROJECT_NAME} PROPERTIES  SUFFIX .elf )

set_target_properties(${EXECUTABLE} PROPERTIES
    LINK_FLAGS "-Wl,--no-undefined"
    WINDOWS_EXPORT_ALL_SYMBOLS OFF
)


set(CMAKE_EXECUTABLE_SUFFIX_ASM ".elf")
set(CMAKE_EXECUTABLE_SUFFIX_C ".elf")
set(CMAKE_EXECUTABLE_SUFFIX_CXX ".elf")

#set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)

Сборка прошивки это кросс компиляция. Это значит, что надо определить каким именно компилятором мы будем собирать Си код. Выбор компилятора происходит в файле скрипте toolchain.cmake


message(STATUS "WORKSPACE_LOC=${WORKSPACE_LOC}")

if(ARM_GCC STREQUAL Y)
    include( ${WORKSPACE_LOC}/cmake_scripts/toolchain_arm_gcc.cmake)
endif()

if(RISC_V_GCC STREQUAL Y)
    include( ${WORKSPACE_LOC}/cmake_scripts/toolchain_risc_v_gcc.cmake)
endif()

if(GHS STREQUAL Y)
    include( ${WORKSPACE_LOC}/cmake_scripts/toolchain_ghs.cmake)
endif()

if(CLANG STREQUAL Y)
    include( ${WORKSPACE_LOC}/cmake_scripts/toolchain_clang.cmake)
endif()

if(TCC STREQUAL Y)
    include( ${WORKSPACE_LOC}/cmake_scripts/toolchain_tcc.cmake)
endif()

if(MINGW STREQUAL Y)
    include( ${WORKSPACE_LOC}/cmake_scripts/toolchain_mingw.cmake)
endif()

if(IAR STREQUAL Y)
    include( ${WORKSPACE_LOC}/cmake_scripts/toolchain_iar.cmake)
endif()

в моем случае выбирается компилятор ARM GCC.


set(CMAKE_C_COMPILER arm-none-eabi-gcc)
set(CMAKE_CXX_COMPILER arm-none-eabi-g++)
set(CMAKE_ASM_COMPILER arm-none-eabi-gcc)
set(CMAKE_AR arm-none-eabi-ar)
set(CMAKE_OBJCOPY arm-none-eabi-objcopy)
set(CMAKE_OBJDUMP arm-none-eabi-objdump)
set(SIZE arm-none-eabi-size)
set(CMAKE_SIZE arm-none-eabi-size)

Компилятору можно передавать сотни разнообразных ключей, которые оказывают существенное влияние на результирующую программу. CMake позволяет передавать ключи компилятору через функцию target_compile_options()



target_compile_options(${EXECUTABLE} PRIVATE -Wall)
target_compile_options(${EXECUTABLE} PRIVATE -MD   )
target_compile_options(${EXECUTABLE} PRIVATE -ffreestanding   )
target_compile_options(${EXECUTABLE} PRIVATE -ffunction-sections   )
target_compile_options(${EXECUTABLE} PRIVATE -fdata-sections   )
target_compile_options(${EXECUTABLE} PRIVATE -fno-common   )
target_compile_options(${EXECUTABLE} PRIVATE -fno-printf-return-value  )
target_compile_options(${EXECUTABLE} PRIVATE -Werror=shadow  )
target_compile_options(${EXECUTABLE} PRIVATE -fshort-enums  )
target_compile_options(${EXECUTABLE} PRIVATE -fomit-frame-pointer  )
target_compile_options(${EXECUTABLE} PRIVATE -Werror=return-local-addr  )
target_compile_options(${EXECUTABLE} PRIVATE -Werror=missing-declarations  )
target_compile_options(${EXECUTABLE} PRIVATE -Werror=missing-prototypes  )
target_compile_options(${EXECUTABLE} PRIVATE -Werror=redundant-decls  )
target_compile_options(${EXECUTABLE} PRIVATE -Wno-nonnull-compare  )
target_compile_options(${EXECUTABLE} PRIVATE -Wall  )
target_compile_options(${EXECUTABLE} PRIVATE -fdse  )
target_compile_options(${EXECUTABLE} PRIVATE -Werror=address-of-packed-member  )
target_compile_options(${EXECUTABLE} PRIVATE -Werror=missing-field-initializers  )
target_compile_options(${EXECUTABLE} PRIVATE -Werror=unused-but-set-variable  )
target_compile_options(${EXECUTABLE} PRIVATE -Werror=unused-variable  )


if(DEBUG STREQUAL Y)
    target_compile_options(${EXECUTABLE} PRIVATE -O0  )
    target_compile_options(${EXECUTABLE} PRIVATE -g3   )
    #target_compile_options(${EXECUTABLE} PRIVATE -gdwarf-2  )
else()
    target_compile_options(${EXECUTABLE} PRIVATE -Os  )
endif()

if(HI_PERF STREQUAL Y)
    target_compile_options(${EXECUTABLE} PRIVATE -Ofast  )
endif()

if(PACK_PROGRAM STREQUAL Y)
    target_compile_options(${EXECUTABLE} PRIVATE -Os  )
    target_compile_options(${EXECUTABLE} PRIVATE -flto  )
endif()

target_compile_options(${EXECUTABLE} PRIVATE -Wno-cpp)
target_compile_options(${EXECUTABLE} PRIVATE ${OPTIMIZATION}  )
target_compile_options(${EXECUTABLE} PRIVATE ${CSTANDARD}  )
add_compile_options( ${MCAL_OPT}   )
add_compile_options( ${MICROPROCESSOR}    )

Скрипты сборки хороши тем, что вы можете очень гибко собирать пучок опций для компоновщика. Вот так может выглядеть файл linker.cmake для STM32F407x


target_link_options(${EXECUTABLE} PRIVATE  -specs=nano.specs)
target_link_options(${EXECUTABLE} PRIVATE  -specs=nosys.specs)
target_link_options(${EXECUTABLE} PRIVATE  -u_scanf_float)
target_link_options(${EXECUTABLE} PRIVATE  -u_printf_float)
target_link_options(${EXECUTABLE} PRIVATE  -Wl,--gc-sections)
target_link_options(${EXECUTABLE} PRIVATE  -T ${LDSCRIPT})
target_link_options(${EXECUTABLE} PRIVATE  -Wl,--print-memory-usage)
target_link_options(${EXECUTABLE} PRIVATE  -Wl,-Map=${BUILD_DIR}/${PROJECT_NAME}.map,--cref)

set(CMAKE_C_LINK_EXECUTABLE      
"<CMAKE_C_COMPILER> <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET>"
)

 

Инициировать процесс генерации и сборки можно всего двумя строками из bat файла.

echo off
cls

cmake -S . -B build --warn-uninitialized -G "Unix Makefiles"
cmake --build build/ -- VERBOSE=1

Вот с такими скриптами мне и удалось собрать свой проект первичного загрузчика MBR. И вот я собрал артефакты. Бинари оказались в папке build

Можно брать elf файл и прошивать его по интерфейсу JTAG программой Segger Ozone.

Недостатки сборки прошивок из-под CMake

--CMake подмешивает компоновщику ненужные ключи
--Бинарь разрастается в размере по непонятным причинам
--Финальный Makefile получается грязный. С душком

Достоинства сборки прошивок из-под CMake

++Можно выбирать систему сборки: Ninja, Make и пр.
++Вы можете писать код в абсолютно любом текстовом редакторе, как как система сборки больше не завязана на конкретную IDE
++Вы можете генерировать часть документации на проект в виде графа зависимостей, так как CMake поддерживает генерацию graphviz (как и ninjia).
++Если Вы не понимаете язык программирования GNU Make, то Вы можете попробовать выучить более простой язык - CMake, который всегда сгенерирует Вам в общем-то работоспособный Makefile для сборки микроконтроллерной прошивки. И уже по образу и подобию написать свой нормальный makefile вручную.
++CMake делает progress bar сборки проекта, который отображается в логе сборки на фазе отработки GNU Make скриптов.

CMake или GNU Make?

СMake (Сross-platform Make) был разработан для кросс-платформенности. Переводя на кухонный язык, это чтобы одну и ту же программу можно было собирать в разнообразных операционных системах Windows, Linux, MacOS, FreeBSD. Если же Вы все в своей организации работаете только в Windows 10, то вам CMake нужен как собаке бензобак. Вам много проще будет самим писать GNU Make скрипты, раз нужна только сборка по клику на *.bat файл.

Потом, если вы до этого никогда не писали никаких скриптов сборки, то сразу кидаться писать CMake пожалуй тоже нет резона. Дело в том, что CMake это даже не система сборки, а надстройка над всеми возможными системами сборки: Ninja, Make и проч. Как AutoTools. СMake, в зависимости от опций командной строки, сам генерирует скрипты сборки. СMake - это всего лишь кодогенератор. И вам с непривычки будет архи сложно разобраться с огромным калейдоскопом разнообразных и новых для себя расширений файлов: .сmake, СMakeList.txt. .c.in *.mk и прочие. CMake очень навороченная и переизбыточная система.

Если у вас цель - собирать код дергая скрипы в Jenkins, то лучше сосредоточиться на GNU Make. Тогда у вас в репозитории фактически будут только три типа файлов для версионного контроля: .c .h и *.mk файлы. Easy!

СMake же - это очень навороченная утилита и там много избыточного функционала. Много того, что вам никогда даже не пригодится. В случае выбора CMake вам, например, придется помимо ошибок компилятора чинить ещё ошибки отработки CMake скриптов, которые по логу порой даже понять трудно, потом чинить ошибки GNU Make, потом чинить ошибки компилятора, чинить ошибки компоновщика. Ещё CMake перед сборкой занимается тестированием компилятора. В результате долго отрабатывает скрипт. CMake работает в два прогона. Да и сами скрипты сборки make которые выращивает CMake получаются очень грязными. С душком.... Да они работают, но читать и отлаживать их человеку просто не-ре-аль-но....

Лучше, быстрее, надежнее и проще ликвидировать лишнюю стадию отработки CMake скриптов и просто самим взять и написать лаконичные скрипты сборки GNU Make. С точки зрения DevOps результат будет абсолютно тем же: сборка из скрипта, по клику. А раз так, то зачем платить больше? Не надо слишком сильно увлекаться FrameWork-о-строительством.

В GNU Make есть всё, что нужно для полноценной автоматизации: топологическая сортировка целей, регулярные выражения, выявление не поменявшихся файлов, функции, операторы. На GNU Make решаются 99,99% всех задач по DevOps(у).

Итоги

Удалось собрать прошивку для STM32 из-под самостоятельно написанных CMake скриптов. Это открывает дорогу для кросcплатформенной разработки прошивок для микроконтроллеров STM32 и интеграции проектов на сервера сборки.

Благодаря скриптам сборки вы можете не просто запрограммировать микроконтроллер, а можете также запрограммировать ещё и сам процесс сборки программы этой прошивки.

Источники

ссылка

URL

Прошивка и отладка STM32 в VSCode под Windows @lazbaphilipp

https://habr.com/ru/articles/713432/

Используем Cmake для автоматической генерации makefile в проектах
@romy4

https://habr.com/ru/articles/155397/

Как мы переводили проект на CMake
@missing_id

https://habr.com/ru/companies/swd_es/articles/773116/

CMake Reference Documentation

https://cmake.org/cmake/help/latest/index.html

CMake Reference Documentation

https://cmake.org/cmake/help/v3.20/

CMake Справочная документация

https://spec-zone.ru/cmake~3.19/

cmake(1) - Linux man page

https://linux.die.net/man/1/cmake

STM32 + Cmake + CubeMX

https://www.zenembed.com/ru/cmake-cubemx

CMake on STM32 | Episode 1: the beginning

https://dev.to/pgradot/cmake-on-stm32-the-beginning-3766

Почему важно собирать код из скриптов

https://habr.com/ru/articles/723054/

Настройка IDE Clion и Cmake для работы с STM32 и C++

@devslm

https://habr.com/ru/articles/336262/

CMake project for an ARM Cortex-M cross compilation project

https://github.com/feabhas/cmake-blog-1

How to use CMake in STM32CubeIDE

https://www.st.com/resource/en/application_note/an5952-how-to-use-cmake-in-stm32cubeide-stmicroelectronics.pdf

Сборка под stm32duino с помощью CMake 

https://www.pvsm.ru/arduino/254485

Сборка и отладка прошивки IoT-модуля: Python, make, апельсины и чёрная магия
@faruk_yussuf

https://habr.com/ru/companies/whoosh/articles/825330/

Why We Need Build Systems URL

https://blog.feabhas.com/2021/06/why-we-need-build-systems/

CMake Part 1 – The Dark Arts URL

https://blog.feabhas.com/2021/07/cmake-part-1-the-dark-arts/

CMake Part 2 – Release and Debug builds URL

https://blog.feabhas.com/2021/07/cmake-part-2-release-and-debug-builds/

CMake Part 3 – Source File Organisation URL

https://blog.feabhas.com/2021/08/cmake-part-3-source-file-organisation/

CMake Part 4 – Windows 10 Host

https://feabhasblog.wpengine.com/2021/09/cmake-part-4-windows-10-host/

STM32 CMake Template

https://jchisholm204.github.io/posts/stm32_cmake/

Используем CMake и GCC для программирования uC STM32 в линуксе.

https://we.easyelectronics.ru/STM32/ispolzuem-cmake-i-gcc-dlya-programmirovaniya-uc-stm32-v-linukse.html

STM32 without CubeIDE (Part 4): CMake, FPU and STM32 libraries

https://kleinembedded.com/stm32-without-cubeide-part-4-cmake-fpu-and-stm32-libraries/

CMake on STM32 | Episode 1: the beginning

https://dev.to/pgradot/cmake-on-stm32-the-beginning-3766

Вопросы

  • Что такое система сборки?

  • Назовите как можно больше способов передавать аргументы в консольную утилиту при старте.

  • Зачем использовать какую бы то ни было систему сборки (хоть GNU Make), если можно просто написать *.bat или *.sh скрипт, который передает компилятору gcc исходники? Ведь в cmd или bash скриптах же тоже есть переменные и условные операторы.

  • Как на языке CMake добавить в конец переменной окружения MCU_FLAGS строку -mcpu=cortex-m4 ? set(MCU_FLAGS "${MCU_FLAGS} -mcpu=cortex-m4")

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Вы собирали прошивки для STM32 через СMake?
33.33%да7
66.67%нет14
Проголосовал 21 пользователь. Воздержались 3 пользователя.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Вы программировали микроконтроллеры STM32?
95%да19
5%нет1
Проголосовали 20 пользователей. Воздержались 2 пользователя.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Какие скрипты сборки Вам кажутся проще для понимания?
52.94%СMake9
52.94%GNU Make9
11.76%Ninjia2
0%msbuild0
0%Jam0
0%SCons0
0%Ant0
0%AutoTools0
5.88%Gradle1
0%Meson0
0%nmake0
0%Rake0
5.88%другие скрипты сборки1
5.88%AutoTools1
0%Bazel0
0%Shake0
0%gyp0
Проголосовали 17 пользователей. Воздержались 9 пользователей.