I'm part of a team that develops applications targeting ARM microcontrollers, the target is as you could guess by the post title bare-metal, we have been using STM32CubeIDE, which builds projects both on Windows and Linux, but are trying to move out of vendor provided software, by using VsCode and build scripts, on Linux I have managed to create a script that performs the build using CMake, make and the ARM provided toolchain, with addition to the nosys.specs file.
the script:
def build(self):
try:
os.makedirs(self.repo_root + "/build/" + self.output_dir)
except FileExistsError:
pass
output = self.repo_root + "/build/" + self.output_dir
stlib = subprocess.call(["/opt/ST-LIB/tools/build.py", "-bb", self.buildconfig, "-t" , self.target, "-eth",self.ethernet])
if stlib != 0:
raise Exception("STLIB build failed")
if self.buildconfig == "Release":
if self.target == "BOARD":
subprocess.call(["cmake", self.repo_root, "-B", output, "-DRELEASE=TRUE","-DNUCLEO=FALSE"])
else:
subprocess.call(["cmake", self.repo_root, "-B", output, "-DRELEASE=TRUE","-DNUCLEO=TRUE"])
else:
if self.target == "BOARD":
subprocess.call(["cmake", self.repo_root, "-B", output, "-DRELEASE=FALSE", "-DNUCLEO=FALSE"])
else:
subprocess.call(["cmake", self.repo_root, "-B", output, "-DRELEASE=FALSE", "-DNUCLEO=TRUE"])
threads = os.cpu_count()
print( Fore.BLUE + "\n\nCalling make with {} threads\n\n".format(threads))
retval = subprocess.call(["make","-j",str(threads),"-C", output])
if retval != 0:
print(Fore.RED + "ERRORS OCCURED\n")
raise Exception("error invoking make")
print(Fore.GREEN + "\nBuild completed successfully!!\n" + Fore.YELLOW)
try:
os.makedirs(self.repo_root + "/build/" + self.output_dir + "/bin")
except FileExistsError:
pass
elf_ori = self.repo_root + "/build/" + self.output_dir + "/" + self.find_file(self.repo_root + "/build/" + self.output_dir)
elf_dir = self.repo_root + "/build/" + self.output_dir + "/bin"
subprocess.call(["mv",elf_ori,elf_dir])
The CMakeLists.txt
cmake_minimum_required (VERSION 3.4)
include(arm-none-eabi.cmake)
project (template-project ASM C CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(EXECUTABLE ${PROJECT_NAME}.elf)
file(GLOB_RECURSE SOURCE_C ${CMAKE_SOURCE_DIR}/Core/*.c ${CMAKE_SOURCE_DIR}/Drivers/*.c ${CMAKE_SOURCE_DIR}/Middlewares/*.c ${CMAKE_SOURCE_DIR}/LWIP/*.c)
file(GLOB_RECURSE SOURCE_CPP ${CMAKE_SOURCE_DIR}/Core/*.cpp ${CMAKE_SOURCE_DIR}/Drivers/*.cpp ${CMAKE_SOURCE_DIR}/Middlewares/*.cpp ${CMAKE_SOURCE_DIR}/LWIP/*.cpp)
file(GLOB_RECURSE SOURCE_H ${CMAKE_SOURCE_DIR}/Core/*.h ${CMAKE_SOURCE_DIR}/Drivers/*.h ${CMAKE_SOURCE_DIR}/Middlewares/*.h ${CMAKE_SOURCE_DIR}/LWIP/*.h)
file(GLOB_RECURSE SOURCE_HPP ${CMAKE_SOURCE_DIR}/Core/*.hpp ${CMAKE_SOURCE_DIR}/Drivers/*.hpp ${CMAKE_SOURCE_DIR}/Middlewares/*.hpp ${CMAKE_SOURCE_DIR}/LWIP/*.hpp)
set(STLIB_DIR "/opt/ST-LIB")
if(${NUCLEO})
add_definitions(-DNUCLEO)
add_definitions(-DHSE_VALUE=8000000)
else()
add_definitions(-DBOARD)
add_definitions(-DHSE_VALUE=25000000)
endif()
if(${RELEASE})
set(OPTIMIZATION -O3)
set(DEBUG_CONFIGURATION -g0)
set(STLIB_LIBRARY ${STLIB_DIR}/build/Release/lib)
else()
set(OPTIMIZATION -O0)
set(DEBUG_CONFIGURATION -g3)
set(STLIB_LIBRARY ${STLIB_DIR}/build/Debug/lib)
endif()
add_executable(${EXECUTABLE}
${SOURCE_C}
${SOURCE_CPP}
${SOURCE_H}
${SOURCE_HPP}
Core/Startup/startup_stm32h723zgtx.s
)
target_link_libraries(${EXECUTABLE} PUBLIC ${STLIB_LIBRARY}/libst-lib.a)
target_compile_definitions(${EXECUTABLE} PUBLIC
-DUSE_HAL_DRIVER
-DSTM32H723xx
-DDATA_IN_D2_SRAM
)
message("\n\nCMAKE:\n")
message(STATUS "[DEBUG, RELEASE]: RELEASE: " ${RELEASE})
message(STATUS "Optimization value: " ${OPTIMIZATION})
message(STATUS "Debug configuration value: " ${DEBUG_CONFIGURATION})
message(STATUS "[BOARD, NUCLEO] Config: NUCLEO: " ${NUCLEO})
target_compile_options(${EXECUTABLE} PUBLIC
-mcpu=cortex-m7
-mfpu=fpv5-d16
-mfloat-abi=hard
-mthumb
${OPTIMIZATION}
${DEBUG_CONFIGURATION}
-ffunction-sections
-fdata-sections
-fno-exceptions
$<$<COMPILE_LANGUAGE:CXX>:-fno-use-cxa-atexit>
$<$<COMPILE_LANGUAGE:CXX>:-fno-rtti>
-Wall
-specs=/usr/lib/arm-none-eabi/lib/nosys.specs
)
target_include_directories(${EXECUTABLE} PUBLIC
## includes
)
target_link_options(${EXECUTABLE} PUBLIC
-T${CMAKE_SOURCE_DIR}/STM32H723ZGTX_FLASH.ld
-mcpu=cortex-m7
-mthumb
-mfpu=fpv5-d16
-mfloat-abi=hard
-specs=nosys.specs
-lc
-lm
-lnosys
-Wl,-Map=${PROJECT_NAME}.map,--cref
-Wl,--gc-sections
)
Lastly the arm-none-eabi.cmake
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR ARM)
if(MINGW OR CYGWIN OR WIN32)
set(UTIL_SEARCH_CMD where)
elseif(UNIX OR APPLE)
set(UTIL_SEARCH_CMD which)
endif()
set(TOOLCHAIN_PREFIX arm-none-eabi-)
set(ASM_OPTIONS "-x assembler-with-cpp")
set(CMAKE_ASM_FLAGS "${CFLAGS} ${ASM_OPTIONS}")
execute_process(
COMMAND ${UTIL_SEARCH_CMD} ${TOOLCHAIN_PREFIX}gcc
OUTPUT_VARIABLE BINUTILS_PATH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}gcc)
set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER})
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}g++)
get_filename_component(ARM_TOOLCHAIN_DIR ${BINUTILS_PATH} DIRECTORY)
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
set(CMAKE_OBJCOPY ${ARM_TOOLCHAIN_DIR}/${TOOLCHAIN_PREFIX}objcopy CACHE INTERNAL "objcopy tool")
set(CMAKE_SIZE_UTIL ${ARM_TOOLCHAIN_DIR}/${TOOLCHAIN_PREFIX}size CACHE INTERNAL "size tool")
set(CMAKE_FIND_ROOT_PATH ${BINUTILS_PATH})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
The build process works well on several Linux distros, Ubuntu, Arch and I'm interested in seeing if this could be possible in Windows
I know utils like make are OS dependant, and in theory the gcc compiler is also OS dependant, that's why on Windows there is MinGW or for applications targeting x86_64 MSVC, but there is itself a compiler that's available on Windows per the ARM website: https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads
Maybe checking in CMakeLists.txt current OS could allow to use make via cygwin on Windows and using "normal" make in Linux?
Just spitballing here.