-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCMakeLists.txt
209 lines (180 loc) · 8.14 KB
/
CMakeLists.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# This CMakeLists.txt file is a parser for Makefile generated by STM32CubeMX.
# It reads the Makefile and extracts the necessary flags and variables to build the project.
# Please add other needed files and libraries to the project manually in the CMakeLists.txt
# file instead of the Makefile to avoid being overwritten by STM32CubeMX.
cmake_minimum_required(VERSION 3.23)
# --------------------------------- Toolchain -------------------------------- #
# Specify gcc-arm-none-eabi toolchain
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_VERSION 1)
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_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
# ------------------------------ Makefile parser ----------------------------- #
if (NOT EXISTS "${CMAKE_SOURCE_DIR}/Makefile")
message(FATAL_ERROR "Makefile not found. Please run STM32CubeMX to generate the Makefile.")
endif()
# Read Makefile generated by STM32CubeMX
file(READ "${CMAKE_SOURCE_DIR}/Makefile" STM32CUBEMX_MAKEFILE)
# Strip line continuations
string(REGEX REPLACE "\\\\\\\n" "" STM32CUBEMX_MAKEFILE ${STM32CUBEMX_MAKEFILE})
# Function to extract a variable from the Makefile
function(extract_makefile_variable var_name out_var)
string(REGEX MATCH "${var_name} = ([^\n]*)" match ${STM32CUBEMX_MAKEFILE})
if (match)
string(STRIP "${CMAKE_MATCH_1}" match)
set(${out_var} ${match} PARENT_SCOPE)
else()
set(${out_var} "" PARENT_SCOPE)
endif()
endfunction()
# Function to extract a list of variables from the Makefile.
# Only keep items that start with `leading`, and remove the leading text if `remove_leading` is set.
function(extract_makefile_list var_name out_list leading remove_leading)
extract_makefile_variable(${var_name} temp)
# Split the list into items by spaces
string(REPLACE " " ";" temp "${temp}")
# Filter out items that don't start with `leading`
set(output "")
foreach(item ${temp})
if (item)
if (item MATCHES "^${leading}")
if (remove_leading)
string(REGEX REPLACE "^${leading}" "" item ${item})
endif()
list(APPEND output ${item})
endif()
endif()
endforeach()
set(${out_list} ${output} PARENT_SCOPE)
endfunction()
function(print_var var_name)
message(STATUS "${var_name}: ${${var_name}}")
endfunction()
function(print_list list_name)
message(STATUS "${list_name}:")
foreach(item ${${list_name}})
message(STATUS " ${item}")
endforeach()
endfunction()
# ------------------------------- Project Name ------------------------------- #
extract_makefile_variable("TARGET" project_name)
print_var(project_name)
project(${project_name} C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
# ---------------------------------- C Flags --------------------------------- #
extract_makefile_variable("CPU" cpu)
extract_makefile_variable("FPU" fpu)
extract_makefile_variable("FLOAT-ABI" float_abi)
add_compile_options(${cpu} -mthumb ${fpu} ${float_abi})
add_compile_options(-Wall -fdata-sections -ffunction-sections)
extract_makefile_list("C_DEFS" c_defs "-D" TRUE)
print_list(c_defs)
add_compile_definitions(${c_defs})
# Add extra definitions here
# Enable assembler files preprocessing
add_compile_options($<$<COMPILE_LANGUAGE:ASM>:-x$<SEMICOLON>assembler-with-cpp>)
# --------------------------------- LD Flags --------------------------------- #
extract_makefile_variable("LDSCRIPT" ld_script)
print_var(ld_script)
set(ld_script "${CMAKE_SOURCE_DIR}/${ld_script}")
add_link_options(-Wl,-gc-sections,--print-memory-usage,-Map=${PROJECT_BINARY_DIR}/${PROJECT_NAME}.map)
add_link_options(${cpu} -mthumb ${fpu} ${float_abi})
add_link_options(-specs=nano.specs)
add_link_options(-T${ld_script})
if (fpu)
add_link_options(-u _printf_float)
endif()
extract_makefile_list("LIBS" libs "-l" TRUE)
print_list(libs)
extract_makefile_list("LIBDIR" libdirs "-L" TRUE)
print_list(libdirs)
# --------------------------------- CMSIS-DSP -------------------------------- #
# Example of using CMSIS-DSP library on CM7 devices. Uncomment the following lines to use CMSIS-DSP.
# include_directories(
# Drivers/CMSIS/Include
# Drivers/CMSIS/DSP/Include/
# )
# link_directories(
# Drivers/CMSIS/DSP/Lib/ARM
# Drivers/CMSIS/DSP/Lib/GCC
# )
# add_compile_definitions(
# ARM_MATH_CM7
# )
# list(APPEND libs arm_cortexM7lfdp_math)
# ------------------------------- Source Files ------------------------------- #
extract_makefile_list("C_SOURCES" c_sources "" FALSE)
extract_makefile_list("ASM_SOURCES" asm_sources "" FALSE)
# Add extra source files here
file(GLOB_RECURSE extra_sources
"Core/Src/*.c"
"Core/Src/*.cpp"
"Core/Src/*.s"
)
list(FILTER extra_sources EXCLUDE REGEX ".*Templates.*")
list(APPEND c_sources ${extra_sources})
list(APPEND all_sources ${c_sources} ${asm_sources} ${extra_sources})
list(REMOVE_DUPLICATES all_sources)
print_list(all_sources)
# ------------------------------- Include Paths ------------------------------ #
extract_makefile_list("C_INCLUDES" c_includes "-I" TRUE)
print_list(c_includes)
include_directories(${c_includes})
# Add extra include paths here
# ------------------------------- Executable --------------------------------- #
link_directories(${libdirs})
link_libraries(${libs})
add_executable(${project_name}.elf ${all_sources} ${ld_script})
set(hex_file ${PROJECT_BINARY_DIR}/${project_name}.hex)
set(bin_file ${PROJECT_BINARY_DIR}/${project_name}.bin)
add_custom_command(TARGET ${project_name}.elf POST_BUILD
COMMAND ${CMAKE_OBJCOPY} -Oihex $<TARGET_FILE:${project_name}.elf> ${hex_file}
COMMAND ${CMAKE_OBJCOPY} -Obinary $<TARGET_FILE:${project_name}.elf> ${bin_file}
COMMENT "Exporting ${hex_file} \nExporting ${bin_file}"
)
# ---------------------------------- Clangd ---------------------------------- #
# Generate .clangd file for clangd language server
if (CMAKE_HOST_WIN32)
execute_process(COMMAND where arm-none-eabi-gcc OUTPUT_VARIABLE compiler_path OUTPUT_STRIP_TRAILING_WHITESPACE)
if (NOT compiler_path)
message(FATAL_ERROR "arm-none-eabi-gcc not found")
endif()
# Note that clangd has a bug on Windows where it doesn't handle spaces in the path correctly
# The best solution is to install the toolchain in a path without spaces. Using scoop is a good option.
# If you have to use a path with spaces, the following code can convert the path to DOS 8.3 format as a workaround.
if (compiler_path MATCHES " ")
execute_process(COMMAND cmd /c for %A in ("${compiler_path}") do @echo %~sA OUTPUT_VARIABLE compiler_path OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()
string(REPLACE "\\" "\\\\" compiler_path ${compiler_path})
else()
execute_process(COMMAND which arm-none-eabi-gcc OUTPUT_VARIABLE compiler_path OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()
print_var(compiler_path)
# If exists .clangd-template, copy it to .clangd, replace %COMPILER% with the actual compiler path
if (EXISTS ${CMAKE_SOURCE_DIR}/.clangd-template)
file(READ ${CMAKE_SOURCE_DIR}/.clangd-template clangd_template)
string(REPLACE "%COMPILER%" ${compiler_path} clangd_template ${clangd_template})
file(WRITE ${CMAKE_SOURCE_DIR}/.clangd ${clangd_template})
else()
file(WRITE ${CMAKE_SOURCE_DIR}/.clangd "CompileFlags:\n Compiler: ${compiler_path}\n")
endif()
# ---------------------------------- OpenOCD --------------------------------- #
# Generate openocd.cfg file for OpenOCD
# Comment out the following lines if you want to use custom OpenOCD configuration
# Infer the target device from the ld_script
string(REGEX MATCH "STM32[A-Z][0-9]" target_device ${ld_script})
print_var(target_device)
if (NOT target_device)
message(WARNING "Cannot generate openocd.cfg, failed to detect target device type.")
else()
string(TOLOWER ${target_device} target_device)
set(openocd_target "target/${target_device}x.cfg")
file(WRITE ${CMAKE_SOURCE_DIR}/openocd.cfg "source [find interface/stlink.cfg]\ntransport select hla_swd\nsource [find ${openocd_target}]\n")
endif()