Using CMake, make and arm-none-eabi-gcc in Windows

268 views Asked by At

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.

0

There are 0 answers