CMAKE

CMake is a tool to generate the makefile for different platforms.
CMake generates the makefiles by interpreting CMakeLists.txt. The CMakeList.txt shall be created in each sub-folder. The CMakeLists.txt is a text script file with specified rules.

 ----

add cmake to system path to enable it globally in windows.

C:\Program Files\CMake\bin

=======================================================================

# a block comment

if(FALSE) # fake a block comment

endif()

#The useful commands/tips:

CMAKE_EXPORT_COMPILE_COMMANDS
Enable/Disable output of compile commands during generation
example: set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

 

generate command during make

option 1: cmake -G "Unix Makefile" -DCMAKE_VERBOSE_MAKEFILE:BOOL = ON

option 2: set(CMAKE_VERBOSE_MAKEFILE ON CACHE BOOL "ON")

 

release or debug

CMAKE_BUILD_TYPE = Debug or Release




========================================================================
I list some examples in my projects or learn from internet.
========================================================================


#minimun version required

cmake_minimum_required(VERSION 3.10)
as the first line of CMakeLists.txt


#A simple exmaple 

cmake_minimum_required(VERSION 3.10) 

Project(yourprojectname)

add_executable(${PROJECT_NAME}  main.c)

 

in command window, 

cmake -G"Eclipse CDT4 - Unix Makefiles" .

The makefile will be generated.

 

#out-of-source build

The cmake will generate some files which will store your project folder, and there is no cmake -clean method to remove all temp files.

A good solution is out-of-source build, you can write a batch file to generate the makefile

mkdir build

cd build

cmake ..

make

An Exmaple is shown below.

#!/bin/sh

if [ x"$1" = release ]
then
   echo "generate release makefiles"
   rm -fr release
   mkdir release
   cmake --trace \
         -G "Eclipse CDT4 - Unix Makefiles" \
         -DCMAKE_BUILD_TYPE=Release \
         -DCMAKE_SYSTEM_NAME=Linux \
         -DUNIT_TESTS=FALSE \
         ..
else
   echo "generate debug makefiles"
   rm -fr debug
   mkdir debug
   cd debug
   cmake --trace \
         -G "Eclipse CDT4 - Unix Makefiles" \
         -DCMAKE_BUILD_TYPE=Debug \
         -DCMAKE_SYSTEM_NAME=Linux \
         -DUNIT_TESTS=FALSE \
         ..
fi

 

#Override the CFLAGS

for example, to generate the makefile for old compiler or speicific compiler like IAR

In the top level CMakeLists.txt,
set(CMAKE_USER_MAKE_RULES_OVERRIDE  ${CMAKE_CURRENT_SOURCE_DIR}/c_flag_overrides.cmake)
set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX  ${CMAKE_CURRENT_SOURCE_DIR}/cxx_flag_overrides.cmake)

a new file name c_flag_overrides.cmake, which has follow as example.

# override the default paramters
set(CMAKE_C_FLAGS_DEBUG "-D DEBUG=1 -D USE_FULL_ASSERT --no_unroll --no_inline --no_tbaa --no_scheduling --endian=little --cpu=Cortex-M3 --fpu=None -Om --debug --dlib_config \"${DLIB_FILE}\"")
set(CMAKE_C_FLAGS_RELEASE "--no_unroll --no_inline --no_tbaa --no_scheduling --endian=little --cpu=Cortex-M3 --fpu=None -Om --dlib_config \"${DLIB_FILE}\"")
set(CMAKE_ASM_FLAGS "-s+ -M<> -w+ --cpu Cortex-M3 --fpu None")
set(CMAKE_DEPFILE_FLAGS_C "")
set(CMAKE_DEPFILE_FLAGS_CXX "")

 

#define variables in top level CMakeLists.txt

set(STMLibHeader ${CMAKE_HOME_DIRECTORY}/STMLib/inc)
set(CMSISHeader ${CMAKE_HOME_DIRECTORY}/STMLib/CMSIS)

later, you can use in the sub-folder CMakeLists.txt, example

# include directory
include_directories(
core/inc
input/inc
output/inc
${STMLibHeader}
${IARHeader}
${CMSISHeader}
${applicationHeader}
${inputsHeader}
${driverHeader}
)

The STMLibHeader,embOSHeader, etc. are defined in top level CMakeLists.txt

 

#add sub-folder as lib

in top level CMakeLists.txt

cmake_minimum_required(VERSION 3.10)

set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR ARM)
set(CMAKE_C_COMPILER_ARCHITECTURE_ID ARM)
set(CMAKE_CXX_COMPILER_ARCHITECTURE_ID ARM)

#set up IAR root dir
set(EWARM_ROOT_DIR "C:/Program\ Files\ (x86)/IAR\ Systems/Embedded\ Workbench\ 5.4/arm")
set(DLIB_FILE "${EWARM_ROOT_DIR}/INC/DLib_Config_Normal.h")

#see, the space shall started by "\"

#set the user rules to override the cflags,cxxflags
set(CMAKE_USER_MAKE_RULES_OVERRIDE ${CMAKE_CURRENT_SOURCE_DIR}/c_flag_overrides.cmake)

#setup ninja path if it is not in system path
set(CMAKE_MAKE_PROGRAM "directory/ninja-win/ninja.exe")

 

#set up the compiler and assembler

set(CMAKE_C_COMPILER "${EWARM_ROOT_DIR}/bin/iccarm.exe")
set(CMAKE_CXX_COMPILER "${EWARM_ROOT_DIR}/bin/iccarm.exe")
set(CMAKE_ASM_COMPILER "${EWARM_ROOT_DIR}/bin/iasmarm.exe")
set(ELF2BIN "${EWARM_ROOT_DIR}/bin/ielftool.exe")

#set up the linker
set(LINKER_SCRIPT "${CMAKE_SOURCE_DIR}/embOS/setup/FLASH.icf")

set(CMAKE_VERBOSE_MAKEFILE ON CACHE BOOL "ON")

enable_language(C ASM)

# project information/name
project(YourProjectName)

#the global header files
set(STMLibHeader ${CMAKE_HOME_DIRECTORY}/STMLib/inc)
set(CMSISHeader ${CMAKE_HOME_DIRECTORY}/STMLib/CMSIS)
set(driverHeader ${CMAKE_HOME_DIRECTORY}/driver/include)
set(applicationHeader ${CMAKE_HOME_DIRECTORY}/application/include)
set(inputsHeader ${CMAKE_HOME_DIRECTORY}/application/inputs/inc)
set(IARHeader ${EWARM_ROOT_DIR}/inc)
set(USBHeader ${CMAKE_HOME_DIRECTORY}/STMUSB/inc)

# the sub dirs
add_subdirectory(application)
add_subdirectory(STMLib)
add_subdirectory(driver)
add_subdirectory(STMUSB)

#include directory

include_directories(
${STMLibHeader}
${driverHeader}
${applicationHeader}
${IARHeader}
${CMSISHeader}
${CMAKE_HOME_DIRECTORY}/application/core/inc
)


#set the source to build execute binary
set(MAIN_SRC "application/main.c")

# firmware output file
add_executable(${PROJECT_NAME} ${MAIN_SRC})

 

#set the cflags for release and debug

set_target_properties(${PROJECT_NAME}
PROPERTIES
LINK_FLAGS_DEBUG "--redirect _Printf=_PrintfSmall --redirect _Scanf=_ScanfSmall --map \"${PROJECT_BINARY_DIR}/${PROJECT_NAME}Out.map\" --config \"${LINKER_SCRIPT}\" --semihosting --entry __iar_program_start --redirect __iar_sh_stdout=__iar_sh_stdout_swo"
LINK_FLAGS_RELEASE "--redirect _Printf=_PrintfSmall --redirect _Scanf=_ScanfSmall --map \"${PROJECT_BINARY_DIR}/${PROJECT_NAME}Out.map\" --strip --config \"${LINKER_SCRIPT}\" --entry __iar_program_start"
)

#link by libs
target_link_libraries(${PROJECT_NAME} application STMLib driver STMUSB)

#add the custom build to generate the .bin file after building
add_custom_target (custom ALL DEPENDS "${PROJECT_NAME}")

add_custom_command (TARGET custom POST_BUILD
COMMAND "${ELF2BIN}" --bin --verbose ${PROJECT_NAME}.elf ${PROJECT_NAME}.bin)

in sub folder CMakeLists.txt

# The minimun CMAKE version
cmake_minimum_required(VERSION 3.10)

# add the source code to compile
aux_source_directory(core CORE_DIR_LIB_SRCS)
aux_source_directory(datastorage DATASORAGE_DIR_LIB_SRCS)
aux_source_directory(inputs INPUTS_DIR_LIB_SRCS)
aux_source_directory(outputs OUTPUTS_DIR_LIB_SRCS)

add_library(application ${CORE_DIR_LIB_SRCS} ${DATASORAGE_DIR_LIB_SRCS} ${INPUTS_DIR_LIB_SRCS} ${OUTPUTS_DIR_LIB_SRCS})


# include directory
include_directories(
core/inc
input/inc
output/inc
${STMLibHeader}
${IARHeader}
${CMSISHeader}
${applicationHeader}
${inputsHeader}
${driverHeader}
)

#Pass a path with space

for example  D:/FMOD SoundSystem/FMOD Programmers API Win32/api

using D:/FMOD\ SoundSystem/FMOD\ Programmers API Win32/api

#Enable ninja verbose of makefile 

in top level CMakeLists.txt

set(CMAKE_VERBOSE_MAKEFILE ON CACHE BOOL "ON")

and run ninja -v

ninja  clean : ninja.exe -t clean

 

#a good example for custom command and custom target

# References:

# https://cmake.org/cmake/help/latest/command/add_custom_target.html

# https://samthursfield.wordpress.com/2015/11/21/cmake-dependencies-between-targets-and-files-and-custom-commands/

# https://gist.github.com/socantre/7ee63133a0a3a08f3990

# https://stackoverflow.com/questions/24163778/how-to-add-custom-target-that-depends-on-make-install

# https://stackoverflow.com/questions/30719275/add-custom-command-is-not-generating-a-target

# https://stackoverflow.com/questions/26024235/how-to-call-a-cmake-function-from-add-custom-target-command

# https://blog.csdn.net/gubenpeiyuan/article/details/51096777

 

cmake_minimum_required(VERSION 3.10)

project(foo)

 

set(TEST_FILE "log.txt")

 

# add_custom_command does not create a new target. You have to define targets explicitly

# by add_executable, add_library or add_custom_target in order to make them visible to make

add_custom_command(OUTPUT ${TEST_FILE}

    COMMAND touch ${TEST_FILE}

 

    # Display the given message before the commands are executed at build time

    COMMENT "Creating ${TEST_FILE}"

)

 

# target zoo is always built

add_custom_target(zoo ALL

    COMMAND echo "This is ALL target 'zoo', and it depends on ${TEST_FILE}"

    # If the file exists, then commands related to that file won't be executed

    # DONOT let other target depends on the same OUTPUT as current target,

    #   or it may be bad when doing parallel make

    DEPENDS ${TEST_FILE}

 

    # to make quotes printable,for example

    VERBATIM

)

 

# target bar is only build when `make bar` is issued

add_custom_target(bar

    # cmake -E support copy/env/echo and so on. use cmake -E to see

    # COMMAND/COMMENT must be upper case

    COMMAND ${CMAKE_COMMAND} -E echo bar:hello

    #COMMAND ${CMAKE_COMMAND} -E environment

 

    COMMENT "testing add_custom_target 'bar'..."

    WORKING_DIRECTORY ${CMAKE_BINARY_DIR}

 

    #DEPENDS zoo

)

# It seems to be same as `DEPENDS zoo` above

add_dependencies(bar zoo)

 

# This is the second signature of add_custom_command, which adds a custom command to a target such as a library or executable. This is useful for performing an operation before or after building the target. The command becomes part of the target and will only execute when the target itself is built. If the target is already built, the command will not execute

add_custom_command(TARGET bar

    # On Visual Studio Generators, run before any other rules are executed within the target. On other generators, run just before PRE_LINK commands

    PRE_BUILD

    COMMAND echo -e "\texecuting a PRE_BUILD command"

    COMMENT "This command will be executed before building bar"

    VERBATIM # to support \t for example

)

 

add_custom_command(TARGET bar

    # Run after sources have been compiled but before linking the binary or running the librarian or archiver tool of a static library. This is not defined for targets created by the add_custom_target() command

    PRE_LINK

    COMMAND echo -e "\texecuting a PRE_LINK command"

    COMMENT "This command will be executed after building bar"

    VERBATIM

)

 

add_custom_command(TARGET bar

    # Run after all other rules within the target have been executed

    POST_BUILD

    COMMAND echo -e "\texecuting a POST_BUILD command"

    COMMENT "This command will be executed after building bar"

    VERBATIM

)

 

#CMake Error: CMake was unable to find a build program corresponding to "Ninja"

in CMakeLists.txt

set(CMAKE_MAKE_PROGRAM "${CMAKE_SOURCE_DIR}/../Tools/ninja-win/ninja.exe" CACHE INTERNAL "ninja" FORCE )

the old method, set(CMAKE_MAKE_PROGRAM "${CMAKE_SOURCE_DIR}/../Tools/ninja-win/ninja.exe" , you can see it is not in CMakeCache.txt

 

#CMake Error: The source directory "" does not exist.

The root cause is that the shell script did not define the source code folder.

#!/bin/sh

if [ x"$1" = debug ]
then
echo "generate debug makefiles"
rm -fr debug
mkdir debug
cmake --trace -Bdebug -G "Ninja" -DCMAKE_BUILD_TYPE=Debug -DCMAKE_SYSTEM_NAME=Linux .
else
echo "generate release makefiles"
rm -fr release
mkdir release
cmake --trace -Brelease -G "Ninja" -DCMAKE_BUILD_TYPE=Release -DCMAKE_SYSTEM_NAME=Linux .
fi

mkdir build
cd build
cmake ..
make

posted on 2019-04-02 11:37  荷树栋  阅读(426)  评论(0编辑  收藏  举报

导航