PX4 CMakeLists.txt分析

簡單的概述

make 和 cmake 是linux/UNIX系統下廣泛使用的構建編譯規則工具,面對複雜龐大的工程,各種源文件和工具文件分佈在工程目錄下,如何組織和有序地編譯和使用這些文件,顯然也是一項複雜的任務。Makefile是直接地定義編譯規則以及描述目標之間依賴關係。CMakeLists.txt雖然也是具有相同的功能,但是它是對Makefile的抽象化以便更容易地實現工程編譯規則的編寫。(想更具體瞭解cmake與make的關係,請google)

PX4下的Makefile

它只是對CMakeLists.txt的一個簡單封裝,真正定義PX4工程的編譯規則由CMakeList.txt文件實現。
這個文件主要完成:

檢查cmake版本3.2及以上和解析命令行參數

# Enforce the presence of the GIT repository
#
# We depend on our submodules, so we have to prevent attempts to
# compile without it being present.
ifeq ($(wildcard .git),)
    $(error YOU HAVE TO USE GIT TO DOWNLOAD THIS REPOSITORY. ABORTING.)
endif
#上面檢查.git文件是否存在

#若cmake版本3.2以下,將退出
CMAKE_VER := $(shell Tools/check_cmake.sh; echo $$?)
ifneq ($(CMAKE_VER),0)
    $(warning Not a valid CMake version or CMake not installed.)
    $(warning On Ubuntu 16.04, install or upgrade via:)
    $(warning )
    $(warning 3rd party PPA:)
    $(warning sudo add-apt-repository ppa:george-edison55/cmake-3.x -y)
    $(warning sudo apt-get update)
    $(warning sudo apt-get install cmake)
    $(warning )
    $(warning Official website:)
    $(warning wget https://cmake.org/files/v3.4/cmake-3.4.3-Linux-x86_64.sh)
    $(warning chmod +x cmake-3.4.3-Linux-x86_64.sh)
    $(warning sudo mkdir /opt/cmake-3.4.3)
    $(warning sudo ./cmake-3.4.3-Linux-x86_64.sh --prefix=/opt/cmake-3.4.3 --exclude-subdir)
    $(warning export PATH=/opt/cmake-3.4.3/bin:$$PATH)
    $(warning )
    $(error Fatal)
endif
...
...
# Parsing
# --------------------------------------------------------------------
# assume 1st argument passed is the main target, the
# rest are arguments to pass to the makefile generated
# by cmake in the subdirectory
FIRST_ARG := $(firstword $(MAKECMDGOALS))
ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
...
...

定義配置目標以及解析cmake編譯規則

# describe how to build a cmake config
define cmake-build
+@$(eval BUILD_DIR = $(SRC_DIR)/build_$@$(BUILD_DIR_SUFFIX))
+@if [ $(PX4_CMAKE_GENERATOR) = "Ninja" ] && [ -e $(BUILD_DIR)/Makefile ]; then rm -rf $(BUILD_DIR); fi
+@if [ ! -e $(BUILD_DIR)/CMakeCache.txt ]; then mkdir -p $(BUILD_DIR) && cd $(BUILD_DIR) && cmake .. -G$(PX4_CMAKE_GENERATOR) -DCONFIG=$(1) $(CMAKE_ARGS) || (cd .. && rm -rf $(BUILD_DIR)); fi
+@echo "PX4 CONFIG: $(BUILD_DIR)"
+@$(PX4_MAKE) -C "$(BUILD_DIR)" $(PX4_MAKE_ARGS) $(ARGS)
endef
...
...
#以make px4fmu-v2_default爲例,上面的-DCONFIG=$(1)展開後就是-DCONFIG=nuttx_px4fmu-v2_default
# Get a list of all config targets.
ALL_CONFIG_TARGETS := $(basename $(shell find "$(SRC_DIR)/cmake/configs" ! -name '*_common*' ! -name '*_sdflight_*' -name '*.cmake' -print | sed  -e 's:^.*/::' | sort))
# Strip off leading nuttx_
NUTTX_CONFIG_TARGETS := $(patsubst nuttx_%,%,$(filter nuttx_%,$(ALL_CONFIG_TARGETS)))
#上面sed  -e 's:^.*/::'把find獲得結果中目錄部分去除

# ADD CONFIGS HERE
# --------------------------------------------------------------------
#  Do not put any spaces between function arguments.

# All targets.
$(ALL_CONFIG_TARGETS):
    $(call cmake-build,$@)

# Abbreviated config targets.

#這裏定義了px4fmu-v2_default、px4fmu-v4_defaul等目標
# nuttx_ is left off by default; provide a rule to allow that.
$(NUTTX_CONFIG_TARGETS):
    $(call cmake-build,nuttx_$@)
...
...

進入工程根目錄,在終端輸入make px4fmu-v2_default時, 將在工程根目錄下創建build_px4fmu-v2_default目錄,然後進入此目錄執行cmake .. -G”Unix Makefiles” -DCONFIG=nuttx_px4fmu-v2_default命令來解析工程根目錄下的CMakeLists.txt文件,因此在build_px4fmu-v2_default下形成整個工程的編譯規則。

具體分析PX4工程的編譯規則CMakeList.txt(以make px4fmu-v2_default爲例)

設置基本變量與引入cmake模塊

set(PX4_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(PX4_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}")
...
#=============================================================================
# configuration
#
# must come before project to set toolchain

string(REPLACE "_" ";" config_args ${CONFIG})
list(GET config_args 0 OS)
list(GET config_args 1 BOARD)
list(GET config_args 2 LABEL)
set(target_name "${OS}-${BOARD}-${LABEL}")
#以make px4fmu-v2_default爲例,${CONFIG}=nuttx_px4fmu-v2_default, ${OS}=nuttx ${BOARD}=px4fmu-v2 ${LABEL}=default
...
list(APPEND CMAKE_MODULE_PATH "${PX4_SOURCE_DIR}/cmake")
message(STATUS "cmake module path: ${CMAKE_MODULE_PATH}")
set(config_module "configs/${CONFIG}")
include(${config_module})
#加載自定義的nuttx_px4fmu-v2_default.cmake模塊,其位於${PX4_SOURCE_DIR}/cmake/configs/目錄下
...

檢測自定義cmake函數有沒有實現,沒有的話輸出致命錯誤,退出cmake

#下面兩個必要接口函數在${PX4_SOURCE_DIR}/cmake/nuttx/px4_impl_nuttx.cmake模塊中實現
# require px4 module interface
set(px4_required_interface
    px4_os_prebuild_targets
    px4_os_add_flags
    )
foreach(cmd ${px4_required_interface})
    if(NOT COMMAND ${cmd})
        message(FATAL_ERROR "${config_module} must implement ${cmd}")
    endif()
endforeach()
#config_module_list變量在${PX4_SOURCE_DIR}/cmake/configs/nuttx_px4fmu-v2_default.camke中定義,很重要的一個變量。
#關乎PX4工程目錄下src目錄中的代碼能否編譯進燒入Pixhawk板子的固件中
set(px4_required_config
    config_module_list
    )
foreach(conf ${px4_required_config})
    if(NOT DEFINED ${conf})
        message(FATAL_ERROR "cmake/${config_module} must define ${conf}")
    endif()
endforeach()
...

#=============================================================================
#在${PX4_SOURCE_DIR}/cmake/configs/nuttx_px4fmu-v2_default.camke中定義了系統變量
#${CMAKE_TOOLCHAIN_FILE}=${PX4_SOURCE_DIR}/cmake/toolchains/Toolchain-arm-none-eabi.cmake
# 這便指定了交叉編譯所需的配置
# check required toolchain variables
#
set(required_variables
    CMAKE_C_COMPILER_ID
    )
foreach(var ${required_variables})
    if (NOT ${var})
        message(FATAL_ERROR "Toolchain/config must define ${var}")
    endif()
endforeach()
...

添加git submodule目標,其實沒有幹什麼具體事情。

#=============================================================================
# git
#
px4_add_git_submodule(TARGET git_genmsg PATH "Tools/genmsg")
px4_add_git_submodule(TARGET git_gencpp PATH "Tools/gencpp")
px4_add_git_submodule(TARGET git_mavlink PATH "mavlink/include/mavlink/v1.0")
px4_add_git_submodule(TARGET git_gtest PATH "unittests/gtest")
px4_add_git_submodule(TARGET git_uavcan PATH "src/modules/uavcan/libuavcan")
px4_add_git_submodule(TARGET git_nuttx PATH "NuttX")
px4_add_git_submodule(TARGET git_driverframework PATH "src/lib/DriverFramework")
px4_add_git_submodule(TARGET git_ecl PATH "src/lib/ecl")
px4_add_git_submodule(TARGET git_jmavsim PATH "Tools/jMAVSim")
px4_add_git_submodule(TARGET git_gazebo PATH "Tools/sitl_gazebo")
px4_add_git_submodule(TARGET git_matrix PATH "src/lib/matrix")
px4_add_git_submodule(TARGET git_cmake_hexagon PATH "cmake/cmake_hexagon")
...

nuttx系統源碼的配置及編譯(很重要),後面單獨地具體分析!

#=============================================================================
# external libraries
#
#定義了prebuild_targets目標,其依賴nuttx_export_px4fmu-v2目標
px4_os_prebuild_targets(OUT prebuild_targets
    BOARD ${BOARD}
    THREADS ${THREADS})

#=============================================================================
# build flags
#
px4_os_add_flags(
    BOARD ${BOARD}
    C_FLAGS c_flags
    CXX_FLAGS cxx_flags
    OPTIMIZATION_FLAGS optimization_flags
    EXE_LINKER_FLAGS exe_linker_flags
    INCLUDE_DIRS include_dirs
    LINK_DIRS link_dirs
    DEFINITIONS definitions)

px4_join(OUT CMAKE_EXE_LINKER_FLAGS LIST "${exe_linker_flags}" GLUE " ")
px4_join(OUT CMAKE_C_FLAGS LIST "${c_flags};${optimization_flags}" GLUE " ")
px4_join(OUT CMAKE_CXX_FLAGS LIST "${cxx_flags};${optimization_flags}" GLUE " ")

include_directories(${include_dirs})
#message("INCLUDE_DIRS=${include_dirs}")
link_directories(${link_dirs})
add_definitions(${definitions})
...

msg目錄下的ROS msg定義文件被處理成關於topic的C結構體和C++類定義與針對px4fmu-v2板子參數的處理

#=============================================================================
# source code generation
#
#msg目錄下的CMakeList.txt文件設置msg_files變量爲所有topic文件名
add_subdirectory(msg)
#主要生成${PX4_BINARY_DIR}/src/modules/uORB/topics目錄下所有topic頭文件(topic的C結構體聲明)
#和${PX4_BINARY_DIR}/topics_sources目錄下的所有topic源文件(topic的定義)
#和${PX4_BINARY_DIR}/src/platforms/${OS}/px4_messages目錄下所有C++-style topic 頭文件(topic的C++類聲明)
#msg_gen目標依賴prebuild_targets
px4_generate_messages(TARGET msg_gen
    MSG_FILES ${msg_files}
    OS ${OS}
    DEPENDS git_genmsg git_gencpp prebuild_targets
    )
px4_generate_parameters_xml(OUT parameters.xml BOARD ${BOARD})
px4_generate_airframes_xml(OUT airframes.xml BOARD ${BOARD})
add_custom_target(xml_gen
    DEPENDS parameters.xml airframes.xml)
...

處理src目錄下各個子目錄的CMakelist.txt,將生成各個子模塊以組件方式構建PX4固件

#=============================================================================
# subdirectories
#
set(module_libraries)
foreach(module ${config_module_list})
    string(REGEX MATCH "^[./]" external_module ${module})
    if(external_module)
        STRING(REGEX REPLACE "//" "/" EXT_MODULE ${module})
        STRING(REGEX REPLACE "/" "__" EXT_MODULE_PREFIX ${EXT_MODULE})
        add_subdirectory(${module} ${PX4_BINARY_DIR}/${EXT_MODULE_PREFIX})
    else()
        #處理各個子目錄的CMakeLists.txt文件,config_module_list變量指定了src目錄
        #下哪個子目錄被編譯成模塊庫的形式
        add_subdirectory(src/${module})
    endif()
    px4_mangle_name(${module} mangled_name)
    list(APPEND module_libraries ${mangled_name})
    #message(STATUS "adding module: ${module}")
endforeach()

# Keep track of external shared libs required for modules
set(module_external_libraries "${module_external_libraries}" CACHE INTERNAL "module_external_libraries")

#在src/firmware/nuttx/下的CMakeLists.txt定義了
#${fw_file}=${CMAKE_CURRENT_BINARY_DIR}/nuttx_px4fmu-v2_default.px4目標,
#即在build_px4fmu-v2_default/src/firmware/nuttx/下生成固件。
#Note:想詳細瞭解燒到pixhawk板子的固件到底如何生成的,看這個目錄下的CMakeLists.txt
#很很重要!!!!!
add_subdirectory(src/firmware/${OS})
...

px4io-v2的配置與編譯規則

#在cmake/configs/nuttx_px4fmu-v2_default.cmake文件中定義此變量
if (config_io_board)
    #處理這個目錄下CMakeLists.txt文件,將生成px4io-v2.bin
    add_subdirectory(src/modules/px4iofirmware)
endif()
...

手寫CMakeLists.txt大致的流程圖:

這裏寫圖片描述

手寫的整個工程目標的依賴關係圖:

這裏寫圖片描述
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章