Skip to main content

A python script to walk subdirectories of a C/C++ project of embedded system to generate CMakeLists.txt files for building the executable.

Project description

1. Introduction

cmWalk is a python script to walk the directory tree of a C/C++ project of embedded system to generate CMakeLists.txt files for building the executable.

2. Usage

usage: cmwalk.py [-h] input_dir

A python script to generate CMakeLists.txt of a C/C++ project - 0.0.7.

positional arguments: input_dir The base directory of C/C++ project.

optional arguments: -h, –help show this help message and exit

3. Configuration File

You can create a json file for each directory of project directory tree to configure how cmwalk to generate CMakeLists.txt. The configuration filename of cmwalk is cmwalk.json.

If there is no cmwalk.json in a directory of project directory tree, then all the files and subdirectories of that directory will be parsed for CMakeLists.txt generation.

3.1 Supported properties of cmwalk.json

  • cmakeToolchainFile

    Specifying the toolchain file of the used compiler for current project. You can also set the used toolchain file by invoking cmake with the command line parameter -DCMAKE_TOOLCHAIN_FILE=path/to/file.

    Refer cmake documentation cmake-toolchains(7) for the details.

    Example:

    {
        "cmakeToolchainFile": "gcc_arm_none_eabi_toolchain.cmake"
    }

    For above example, cmwalk will generate following command before project command to set the used toolchain.

    # set the toolchain file.
    # toolchain file should be set before "project" command.
    # the toolchain file can also be set via "cmake -DCMAKE_TOOLCHAIN_FILE=path/to/file".
    set(CMAKE_TOOLCHAIN_FILE gcc_arm_none_eabi_toolchain.cmake)

    An example of toolchain file:

    # refer https://cmake.org/Wiki/CMake_Cross_Compiling
    #include(CMakeForceCompiler)    # cmake_force_c_compiler and cmake_force_cxx_compiler are deprecated.
    
    set(CMAKE_SYSTEM_NAME Generic)
    set(CMAKE_SYSTEM_VERSION 1)
    set(CMAKE_SYSTEM_PROCESSOR "armv7-m")
    
    
    # refer https://cmake.org/pipermail/cmake-developers/2016-February/027871.html
    # about how to solve this problem: "arm-none-eabi-gcc.exe" is not able to compile a simple test program.
    set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
    
    # find the cross compiler and associated tools that we need:
    find_program(ARM_NONE_EABI_GCC arm-none-eabi-gcc)
    find_program(ARM_NONE_EABI_GPP arm-none-eabi-g++)
    find_program(ARM_NONE_EABI_OBJCOPY arm-none-eabi-objcopy)
    
    
    macro(gcc_program_notfound progname)
        message("**************************************************************************\n")
        message(" ERROR: the arm gcc program ${progname} could not be found\n")
        if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows" OR CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
            message(" you can install the ARM GCC embedded compiler tools from:")
            message(" https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads")
        elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
            message(" it is included in the arm-none-eabi-gcc package that you can install")
            message(" with homebrew:\n")
            message("   brew tap ARMmbed/homebrew-formulae")
            message("   brew install arm-none-eabi-gcc")
        endif()
        message("\n**************************************************************************")
        message(FATAL_ERROR "missing program prevents build")
        return()
    endmacro(gcc_program_notfound)
    
    if(NOT ARM_NONE_EABI_GCC)
        gcc_program_notfound("arm-none-eabi-gcc")
    endif()
    
    if(NOT ARM_NONE_EABI_GPP)
        gcc_program_notfound("arm-none-eabi-g++")
    endif()
    
    if(NOT ARM_NONE_EABI_OBJCOPY)
        gcc_program_notfound("arm-none-eabi-objcopy")
    endif()
    
    
    set(CMAKE_C_COMPILER arm-none-eabi-gcc)
    set(CMAKE_CXX_COMPILER arm-none-eabi-g++)
    
    set(C_FAMILY_FLAGS_INIT "-ffunction-sections -fdata-sections -g -fno-common -fmessage-length=0 --specs=nosys.specs --specs=nano.specs")
    set(CMAKE_C_FLAGS_INIT "${C_FAMILY_FLAGS_INIT} -std=c99")
    set(CMAKE_CXX_FLAGS_INIT "${C_FAMILY_FLAGS_INI} -std=c++11")
    set(CMAKE_ASM_FLAGS_INIT "-fno-exceptions -fno-unwind-tables -x assembler-with-cpp")
    set(CMAKE_EXE_LINKER_FLAGS_INIT "-Wl,-gc-sections,-print-memory-usage")
  • cmakeCompilerOptionsFile

    Specifying a file that contains the additional compiler settings to be included in the top-level CMakeLists.txt file.

    Example:

    {
        "cmakeCompilerOptionsFile": "gcc_arm_none_eabi_opts.cmake"
    }

    For above example, cmwalk will generate following command after project command to set the compiler options.

    # load and run the CMake code from the given file to specify project specific options.
    include(gcc_arm_none_eabi_opts.cmake)

    An example of compiler option files for GNU Arm Embedded Toolchain:

    set(EXTRA_COMMON_FLAGS "-mcpu=cortex-m4 -mthumb-interwork -mfloat-abi=hard -mfpu=fpv4-sp-d16 -DUSE_HAL_DRIVER -DSTM32F429xx")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_COMMON_FLAGS}")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_COMMON_FLAGS}")
    
    set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -mcpu=cortex-m4 -mthumb-interwork -mfloat-abi=hard -mfpu=fpv4-sp-d16")
    
    set(LINKER_SCRIPT ${CMAKE_SOURCE_DIR}/app/STM32F429ZITx_FLASH.ld)
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-Map=${CMAKE_BINARY_DIR}/${PROJECT_NAME}.map -T${LINKER_SCRIPT}")
  • addToCompilerIncludeDirectories

    A flag to control if current directory should be added to the include directories of compiler.

    The default option is true when addToCompilerIncludeDirectories does not exist.

    An example of not adding current directory to include directories of compiler.

    {
         "addToCompilerIncludeDirectories": false
    }
  • sourceDirectories

    A list of source directories.

    If sourceDirectories is specified in cmwalk.json, then only the specified directories will be included for parsing, other directories will be excluded. If sourceDirectories does not exist but ignoredDirectories exist, then all the directories except those specified by ignoredDirectories will be excluded.

    An example of specifying the source subdirectories for searching the source files:

    {
         "sourceDirectories": ["app", "libs"]
    }
  • ignoredDirectories - A list of ignored directories.

    sourceDirectories property has higher priority than ignoredDirectories property. If both of sourceDirectories and ignoredDirectories properties are specified in cmwalk.json, ignoredDirectories property has no effect.

    An example of excluding subdirectories for searching the source files:

    {
         "ignoredDirectories": ["docs"]
    }
  • ignoredFiles - A list of ignored files.

    An example of excluding a file from cmake build system:

    {
         "ignoredFiles": ["cfg.h.template"]
    }

4. Example of generated CMakeLists.txt

This is an example of generated top-level CMakeLists.txt:

cmake_minimum_required(VERSION 3.9)

# set the toolchain file.
# toolchain file should be set before "project" command.
# the toolchain file can also be set via "cmake -DCMAKE_TOOLCHAIN_FILE=path/to/file".
set(CMAKE_TOOLCHAIN_FILE gcc_arm_none_eabi_toolchain.cmake)

project(nucleo_f429zi_freertos_lwip)
enable_language(C CXX ASM)

# load and run the CMake code from the given file to specify project specific options.
include(gcc_arm_none_eabi_opts.cmake)


# export the executable target through a variable to CMakeLists.txt files in subdirectories.
# update the dependent sources.
add_executable(nucleo_f429zi_freertos_lwip.elf
    ""
)

if (${LINK_SCRIPT})
    set_target_properties(nucleo_f429zi_freertos_lwip.elf PROPERTIES LINK_DEPENDS ${LINKER_SCRIPT})
endif()


# export the name of executable target via a variable to CMakeLists.txt files in subdirectories.
set(CURRENT_EXE_NAME ${PROJECT_NAME}.elf)
# load and run the CMake code from subdirectories for current target.
include(app/CMakeLists.txt)
include(libs/CMakeLists.txt)

# if compiler is GNU gcc/g++, then generate *.bin & *.hex files.
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
    # generate the hex file from the built target.
    set(HEX_FILE ${PROJECT_NAME}.hex)
    add_custom_command(TARGET ${PROJECT_NAME}.elf POST_BUILD
        COMMAND ${CMAKE_OBJCOPY} -O ihex $<TARGET_FILE:${PROJECT_NAME}.elf> ${HEX_FILE}
        COMMENT "Building ${HEX_FILE}...")

    # generate the bin file from the built target.
    set(BIN_FILE ${PROJECT_NAME}.bin)
    add_custom_command(TARGET ${PROJECT_NAME}.elf POST_BUILD
        COMMAND ${CMAKE_OBJCOPY} -O binary $<TARGET_FILE:${PROJECT_NAME}.elf> ${BIN_FILE}
        COMMENT "Building ${BIN_FILE}...")
endif()

5. References

  1. Enhanced source file handling with target_sources() – Crascit

  2. CLion for embedded development | CLion Blog

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

cmwalk-0.1.0-py2.py3-none-any.whl (15.6 kB view hashes)

Uploaded Python 2 Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page