簡單的概述
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大致的流程圖:
手寫的整個工程目標的依賴關係圖: