Chinaunix首页 | 论坛 | 博客
  • 博客访问: 86915
  • 博文数量: 44
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 582
  • 用 户 组: 普通用户
  • 注册时间: 2014-08-05 15:21
个人简介

读圣人书,明圣人志,遵圣人训。

文章分类

全部博文(44)

文章存档

2017年(23)

2016年(19)

2014年(2)

我的朋友

分类: 嵌入式

2016-11-16 00:15:23

PX4编译脚本

                                                                             -------- 转载请注明出处
-------- 2014-11-25.冷月追风
                                                                             -------- emailmerafour@163.com

参考网站: http://dev.ardupilot.com/wiki/table-of-contents/
           http://dev.ardupilot.com/wiki/building-with-eclipse/
           http://dev.ardupilot.com/wiki/building-px4-for-linux-with-make/
           http://dev.ardupilot.com/wiki/building-px4-with-make/
           http://dev.ardupilot.com/wiki/building-px4-for-linux-with-make/
           https://pixhawk.org/dev/start
编译环境:xubuntu
    在这里我不特别区分 APM, ArduCopter, pixhawk, PX4, PIX。
    实际上 pixhawk可以在 Windows, Linux, MAC上编译。这里选择 xubuntu作为开发环境为个人意愿,个人比较钟情与 Linux中简单而高效的命令行。有人做过测试,MAC编译代码只需几分钟,但是我毕竟没有 MAC也就只好退而求其次。
    但其实我编译源码使用的也只是虚拟机而已。但即便是虚拟机也比在 Windows编译要高效得多。
1. 编译源码
    源码编译参考 APM网站 http://dev.ardupilot.com/wiki/building-the-code/ 即可,根据自己的系统选择相应的编译教程。我用的是 Linux系统,因此参考 http://dev.ardupilot.com/wiki/building-px4-for-linux-with-make/ 进行编译。
    现将其编译过程简单摘录如下:
Quick start
For Ubuntu, follow these steps to build the code. For other distributions, see the advanced instructions below.
1 Setup
Install git:
    sudo apt-get -qq -y install git
Clone the source:
    git clone https://github.com/diydrones/ardupilot.git
Run the install-prereqs-ubuntu.sh script:
    ardupilot/Tools/scripts/install-prereqs-ubuntu.sh -y
Reload the path (log-out and log-in to make permanent):
    . ~/.profile
2 Build
Build for ArduCopter:
    cd ardupilot/ArduCopter
    make configure
    make px4-v2
Build for ArduPlane:
    cd ardupilot/ArduPlane
    make configure
    make px4-v2


2. 脚本分析
    我们始终需要记住一件事,那就是我们在哪个目录编译,以及我们的编译命令。编译目录为: ardupilot/ArduCopter,编译命令我们用的是 “make px4”,但我们也可以改变命令编译我们需要的。
    下面是我们的 Makefile:

include ../mk/apm.mk
实际上这是调用了外部的 mk文件来进行编译,内容为:
# find the mk/ directory, which is where this makefile fragment
# lives. (patsubst strips the trailing slash.)
SYSTYPE   := $(shell uname)
ifneq ($(findstring CYGWIN, $(SYSTYPE)),)
  MK_DIR := $(shell cygpath -m ../mk)
else
  MK_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))
endif
include $(MK_DIR)/environ.mk
# short-circuit build for the configure target
ifeq ($(MAKECMDGOALS),configure)
include $(MK_DIR)/configure.mk
else
# common makefile components
include $(MK_DIR)/targets.mk
include $(MK_DIR)/sketch_sources.mk
ifneq ($(MAKECMDGOALS),clean)
# board specific includes
ifeq ($(HAL_BOARD),HAL_BOARD_APM1)
include $(MK_DIR)/board_avr.mk
endif
ifeq ($(HAL_BOARD),HAL_BOARD_APM2)
include $(MK_DIR)/board_avr.mk
endif
ifeq ($(HAL_BOARD),HAL_BOARD_AVR_SITL)
include $(MK_DIR)/board_native.mk
endif
ifeq ($(HAL_BOARD),HAL_BOARD_LINUX)
include $(MK_DIR)/board_linux.mk
endif
ifeq ($(HAL_BOARD),HAL_BOARD_PX4)
include $(MK_DIR)/board_px4.mk
endif
ifeq ($(HAL_BOARD),HAL_BOARD_VRBRAIN)
include $(MK_DIR)/board_vrbrain.mk
endif
ifeq ($(HAL_BOARD),HAL_BOARD_FLYMAPLE)
include $(MK_DIR)/board_flymaple.mk
endif
endif
endif
这个时候可能我们会很迷惑, $(HAL_BOARD)的值到底是多少?
    但其实我们在执行 “make px4”命令编译的时候会有一行信息:
HAL_BOARD=HAL_BOARD_PX4 HAL_BOARD_SUBTYPE= TOOLCHAIN=NATIVE EXTRAFLAGS=-DGIT_VERSION="b6d361a3" -DNUTTX_GIT_VERSION="eba6b56f" -DPX4_GIT_VERSION="cf208916"
这行信息非常清楚地告诉了我们用的是 “$(MK_DIR)/board_px4.mk”文件。但这个 mk文件内容其实也不多:
TOOLCHAIN = NATIVE
include $(MK_DIR)/find_tools.mk
include $(MK_DIR)/px4_targets.mk
所以最终将是有 “$(MK_DIR)/px4_targets.mk”中的脚本进行编译:
px4-v1: showflags $(PX4_ROOT)/Archives/px4fmu-v1.export $(SKETCHCPP) module_mk px4-io-v1
$(RULEHDR)
$(v) rm -f $(PX4_ROOT)/makefiles/$(PX4_V1_CONFIG_FILE)
$(v) cp $(PWD)/$(PX4_V1_CONFIG_FILE) $(PX4_ROOT)/makefiles/
$(v) $(PX4_MAKE) px4fmu-v1_APM
$(v) /bin/rm -f $(SKETCH)-v1.px4
$(v) cp $(PX4_ROOT)/Images/px4fmu-v1_APM.px4 $(SKETCH)-v1.px4
$(v) echo "PX4 $(SKETCH) Firmware is in $(SKETCH)-v1.px4"
px4-v2: showflags $(PX4_ROOT)/Archives/px4fmu-v2.export $(SKETCHCPP) module_mk px4-io-v2
$(RULEHDR)
$(v) rm -f $(PX4_ROOT)/makefiles/$(PX4_V2_CONFIG_FILE)
$(v) cp $(PWD)/$(PX4_V2_CONFIG_FILE) $(PX4_ROOT)/makefiles/
$(PX4_MAKE) px4fmu-v2_APM
$(v) /bin/rm -f $(SKETCH)-v2.px4
$(v) cp $(PX4_ROOT)/Images/px4fmu-v2_APM.px4 $(SKETCH)-v2.px4
$(v) echo "PX4 $(SKETCH) Firmware is in $(SKETCH)-v2.px4"
px4: px4-v1 px4-v2
px4-io-v1: $(PX4_ROOT)/Archives/px4io-v1.export
$(v) make -C $(PX4_ROOT) px4io-v1_default
$(v) /bin/rm -f px4io-v1.bin
$(v) cp $(PX4_ROOT)/Images/px4io-v1_default.bin px4io-v1.bin
$(v) cp $(PX4_ROOT)/Build/px4io-v1_default.build/firmware.elf px4io-v1.elf
$(v) mkdir -p $(MK_DIR)/PX4/ROMFS/px4io/
$(v) rm -f $(MK_DIR)/PX4/ROMFS/px4io/px4io.bin
$(v) cp px4io-v1.bin $(MK_DIR)/PX4/ROMFS/px4io/px4io.bin
$(v) mkdir -p $(MK_DIR)/PX4/ROMFS/bootloader/
$(v) rm -f $(MK_DIR)/PX4/ROMFS/bootloader/fmu_bl.bin
$(v) cp $(SKETCHBOOK)/mk/PX4/bootloader/px4fmu_bl.bin $(MK_DIR)/PX4/ROMFS/bootloader/fmu_bl.bin
$(v) echo "PX4IOv1 Firmware is in px4io-v1.bin"
px4-io-v2: $(PX4_ROOT)/Archives/px4io-v2.export
$(v) make -C $(PX4_ROOT) px4io-v2_default
$(v) /bin/rm -f px4io-v2.bin
$(v) cp $(PX4_ROOT)/Build/px4io-v2_default.build/firmware.bin px4io-v2.bin
$(v) cp $(PX4_ROOT)/Images/px4io-v2_default.bin px4io-v2.bin
$(v) cp $(PX4_ROOT)/Build/px4io-v2_default.build/firmware.elf px4io-v2.elf
$(v) mkdir -p $(MK_DIR)/PX4/ROMFS/px4io/
$(v) rm -f $(MK_DIR)/PX4/ROMFS/px4io/px4io.bin
$(v) cp px4io-v2.bin $(MK_DIR)/PX4/ROMFS/px4io/px4io.bin
$(v) mkdir -p $(MK_DIR)/PX4/ROMFS/bootloader/
$(v) rm -f $(MK_DIR)/PX4/ROMFS/bootloader/fmu_bl.bin
$(v) cp $(SKETCHBOOK)/mk/PX4/bootloader/px4fmuv2_bl.bin $(MK_DIR)/PX4/ROMFS/bootloader/fmu_bl.bin
$(v) echo "PX4IOv2 Firmware is in px4io-v2.bin"

当然这只是其中的部分内容。告诉我们 px4是怎样的一个目标。V1,V2是两个不同的版本,这里我就不分别进行分析了,主要以我所使用的 V2来分析。

3. px4-io-v2
    为了帮助分析,我增加了下面的目标:
px4-io-v3: $(PX4_ROOT)/Archives/px4io-v2.export
echo "$(v) make -C $(PX4_ROOT) px4io-v2_default"
$(v) make -C $(PX4_ROOT) px4io-v2_default
$(v) /bin/rm -f px4io-v2.bin
得到下面这样一串信息:
echo "@ make -C /home/bitcraze/apm/PX4Firmware px4io-v2_default"
@ make -C /home/bitcraze/apm/PX4Firmware px4io-v2_default
这样我就知道了下面 make所在的目录,知道了目录就可以找到 Makefile,就可以继续往下分析。
    但到了 “PX4Firmware”目录,打开 Makefile却找不到 “px4io-v2_default”这样一个目标。说明目标被处理过了。于是我只好去看编译输出信息了:
make[1]: Entering directory `/home/bitcraze/apm/PX4Firmware'
%%%%
%%%% Building px4io-v2_default in /home/bitcraze/apm/PX4Firmware/Build/px4io-v2_default.build/
%%%%

这里需要说明的是我的源码是编译过的。
    通过这串信息,我匹配到了这样一个目标:

$(FIRMWARES): $(BUILD_DIR)%.build/firmware.px4:
$(ECHO) "hello" $(FIRMWARES)
@$(ECHO) %%%%
@$(ECHO) %%%% Building $(config) in $(work_dir)
@$(ECHO) %%%%
$(Q) $(MKDIR) -p $(work_dir)
$(ECHO) "hello2" $(PX4_MK_DIR)
$(Q) $(MAKE) -r -C $(work_dir) \
  -f $(PX4_MK_DIR)firmware.mk \
  CONFIG=$(config) \
  WORK_DIR=$(work_dir) \
  $(FIRMWARE_GOAL)
“hello”是我后来加的。通过 hello我就确定了 “$(FIRMWARES)”实际上就是我们编译的 “px4io-v2_default”。但这究竟是怎么回事呢?不妨先看看我们加了 hello之后的输出:
echo "hello" /home/bitcraze/apm/PX4Firmware/Build/px4fmu-v1_APM.build/firmware.px4 /home/bitcraze/apm/PX4Firmware/Build/px4fmu-v1_default.build/firmware.px4/home/bitcraze/apm/PX4Firmware/Build/px4fmu-v2_APM.build/firmware.px4 /home/bitcraze/apm/PX4Firmware/Build/px4fmu-v2_default.build/firmware.px4/home/bitcraze/apm/PX4Firmware/Build/px4fmu-v2_test.build/firmware.px4 /home/bitcraze/apm/PX4Firmware/Build/px4io-v1_default.build/firmware.px4/home/bitcraze/apm/PX4Firmware/Build/px4io-v2_default.build/firmware.px4
hello /home/bitcraze/apm/PX4Firmware/Build/px4fmu-v1_APM.build/firmware.px4 /home/bitcraze/apm/PX4Firmware/Build/px4fmu-v1_default.build/firmware.px4/home/bitcraze/apm/PX4Firmware/Build/px4fmu-v2_APM.build/firmware.px4 /home/bitcraze/apm/PX4Firmware/Build/px4fmu-v2_default.build/firmware.px4/home/bitcraze/apm/PX4Firmware/Build/px4fmu-v2_test.build/firmware.px4 /home/bitcraze/apm/PX4Firmware/Build/px4io-v1_default.build/firmware.px4/home/bitcraze/apm/PX4Firmware/Build/px4io-v2_default.build/firmware.px4
在 Makefile中有这样一段内容:
FIRMWARES   = $(foreach config,$(KNOWN_CONFIGS),$(BUILD_DIR)$(config).build/firmware.px4)
因为就是最后我们实际上编译的是 “/home/bitcraze/apm/PX4Firmware/Build/px4io-v2_default.build/firmware.px4”目标。
    而通过 hello2那一串信息我知道下一个 mk是 “/home/bitcraze/apm/PX4Firmware/makefiles/firmware.mk ”。但我们这里看到并没有指定编译哪个目标,也就是说编译第一个目标,通常是 all。
#
# Set a default target so that included makefiles or errors here don't
# cause confusion.
#
# XXX We could do something cute here with $(DEFAULT_GOAL) if it'
s not one
#     of the maintenance targets and set CONFIG based on it.
#
all:  firmware
.PHONY:   firmware
firmware:  $(PRODUCT_BUNDLE)
#
# Built product rules
#
$(PRODUCT_BUNDLE): $(PRODUCT_BIN)
@$(ECHO) %% Generating $@
$(Q) $(MKFW) --prototype $(IMAGE_DIR)/$(BOARD).prototype \
  --git_identity $(PX4_BASE) \
  --image $< > $@
$(PRODUCT_BIN):  $(PRODUCT_ELF)
$(call SYM_TO_BIN,$<,$@)
$(PRODUCT_ELF):  $(OBJS) $(MODULE_OBJS) $(LIBRARY_LIBS) $(GLOBAL_DEPS) $(LINK_DEPS) $(MODULE_MKFILES)
$(call LINK,$@,$(OBJS) $(MODULE_OBJS) $(LIBRARY_LIBS))
    这一段 Makefile我是自己整理了顺序的。这段 Makefile大致告诉了我们最终我们的程序是怎么编译出来的。那么现在剩下的就是这些 “OBJS”是怎么编译的问题了。通常都是有对应的源文件编译出来的。

4. 目标编译
    这里所说的目标编译就是 “$(PRODUCT_ELF)”所依赖的这些目标。我们先来看看 “$(OBJS)”。
#
# Object files we will generate from sources
#
OBJS   := $(foreach src,$(SRCS),$(WORK_DIR)$(src).o)
#
# SRCS -> OBJS rules
#
$(OBJS):  $(GLOBAL_DEPS)
$(filter %.c.o,$(OBJS)): $(WORK_DIR)%.c.o: %.c $(GLOBAL_DEPS)
$(call COMPILE,$<,$@)
$(filter %.cpp.o,$(OBJS)): $(WORK_DIR)%.cpp.o: %.cpp $(GLOBAL_DEPS)
$(call COMPILEXX,$<,$@)
$(filter %.S.o,$(OBJS)): $(WORK_DIR)%.S.o: %.S $(GLOBAL_DEPS)
$(call ASSEMBLE,$<,$@)
这个时候如果我们试图去查看 “$(OBJS)”或是 “$(SRCS)”的值或许会得到一个让自己觉得莫名其妙的结果: “/home/bitcraze/apm/PX4Firmware/Build/px4io-v2_default.build//home/bitcraze/apm/PX4Firmware/Build/px4io-v2_default.build/empty.c.o”, 而且你去查看文件 “empty.c”的内容你会看到内容为:
/* this is an empty file */
这可能让人有点费解。为什么会这样呢?如果我们去阅读 Makefile我们就会发现:
BUILTIN_CSRC   = $(WORK_DIR)builtin_commands.c
# command definitions from modules (may be empty at Makefile parsing time...)
MODULE_COMMANDS   = $(subst COMMAND.,,$(notdir $(wildcard $(WORK_DIR)builtin_commands/COMMAND.*)))
# We must have at least one pre-defined builtin command in order to generate
# any of this.
#
ifneq ($(BUILTIN_COMMANDS),)
# (BUILTIN_PROTO,<cmdspec>,<outputfile>)
define BUILTIN_PROTO
$(ECHO) 'extern int $(word 4,$1)(int argc, char *argv[]);' >> $2;
endef
# (BUILTIN_DEF,<cmdspec>,<outputfile>)
define BUILTIN_DEF
$(ECHO) '    {"$(word 1,$1)", $(word 2,$1), $(word 3,$1), $(word 4,$1)},' >> $2;
endef
# Don't generate until modules have updated their command files
$(BUILTIN_CSRC): $(GLOBAL_DEPS) $(MODULE_OBJS) $(MODULE_MKFILES) $(BUILTIN_COMMAND_FILES)
# @$(ECHO) "CMDS:    $@"
$(ECHO) "CMDS:    $@"
$(Q) $(ECHO) '
/* builtin command list - automatically generated, do not edit */' > $@
$(Q) $(ECHO) '
#include <nuttx/config.h>' >> $@
$(Q) $(ECHO) '
#include <nuttx/binfmt/builtin.h>' >> $@
$(Q) $(foreach spec,$(BUILTIN_COMMANDS),$(call BUILTIN_PROTO,$(subst ., ,$(spec)),$@))
$(Q) $(foreach spec,$(MODULE_COMMANDS),$(call BUILTIN_PROTO,$(subst ., ,$(spec)),$@))
$(Q) $(ECHO) '
const struct builtin_s g_builtins[] = {' >> $@
$(Q) $(foreach spec,$(BUILTIN_COMMANDS),$(call BUILTIN_DEF,$(subst ., ,$(spec)),$@))
$(Q) $(foreach spec,$(MODULE_COMMANDS),$(call BUILTIN_DEF,$(subst ., ,$(spec)),$@))
$(Q) $(ECHO) '
    {NULL, 0, 0, NULL}' >> $@
$(Q) $(ECHO) '
};' >> $@
$(Q) $(ECHO) '
const int g_builtin_count = $(words $(BUILTIN_COMMANDS) $(MODULE_COMMANDS));' >> $@
SRCS   += $(BUILTIN_CSRC)
EXTRA_CLEANS  += $(BUILTIN_CSRC)
endif
################################################################################
# Default SRCS generation
################################################################################
#
# If there are no SRCS, the build will fail; in that case, generate an empty
# source file.
#
ifeq ($(SRCS),)
EMPTY_SRC   = $(WORK_DIR)empty.c
$(EMPTY_SRC):
$(Q) $(ECHO) '
/* this is an empty file */' > $@
SRCS   += $(EMPTY_SRC)
endif

这样我们就知道,如果 “$(SRCS)”值为空,就会往文件 “empty.c”中写入“/* this is an empty file */”,并且给 “SRCS”赋值为 “$(WORK_DIR)empty.c”。这样我们就知道 “$(BUILTIN_COMMANDS)”值必须也为空,这样就跟我们观察到的现象是一致的。
    通过搜索我们发现,
bitcraze@bitcraze-vm:~/apm/ardupilot/ArduCopter$ grep -nr BUILTIN_COMMANDS ../../
../../PX4Firmware/makefiles/config_px4fmu-v1_APM.mk:81:BUILTIN_COMMANDS := \
../../PX4Firmware/makefiles/config_px4fmu-v2_APM.mk:80:BUILTIN_COMMANDS := \
../../PX4Firmware/makefiles/config_px4fmu-v2_test.mk:62:BUILTIN_COMMANDS := \
../../PX4Firmware/makefiles/config_px4fmu-v1_default.mk:156:BUILTIN_COMMANDS := \
../../PX4Firmware/makefiles/config_px4fmu-v2_default.mk:164:BUILTIN_COMMANDS := \
../../PX4Firmware/makefiles/README.txt:59: ROMFS_ROOT to build a ROMFS and BUILTIN_COMMANDS to include non-module
../../PX4Firmware/makefiles/firmware.mk:57:# BUILTIN_COMMANDS
../../PX4Firmware/makefiles/firmware.mk:393:# The configuration supplies builtin command information in the BUILTIN_COMMANDS
../../PX4Firmware/makefiles/firmware.mk:409:ifneq ($(BUILTIN_COMMANDS),)
../../PX4Firmware/makefiles/firmware.mk:428: $(Q) $(foreach spec,$(BUILTIN_COMMANDS),$(call BUILTIN_PROTO,$(subst ., ,$(spec)),$@))
../../PX4Firmware/makefiles/firmware.mk:431: $(Q) $(foreach spec,$(BUILTIN_COMMANDS),$(call BUILTIN_DEF,$(subst ., ,$(spec)),$@))
../../PX4Firmware/makefiles/firmware.mk:435: $(Q) $(ECHO) 'const int g_builtin_count = $(words $(BUILTIN_COMMANDS) $(MODULE_COMMANDS));' >> $@
../../linux/PX4Firmware/makefiles/config_px4fmu-v1_APM.mk:81:BUILTIN_COMMANDS := \
../../linux/PX4Firmware/makefiles/config_px4fmu-v2_APM.mk:80:BUILTIN_COMMANDS := \
../../linux/PX4Firmware/makefiles/config_px4fmu-v2_test.mk:62:BUILTIN_COMMANDS := \
../../linux/PX4Firmware/makefiles/config_px4fmu-v1_default.mk:156:BUILTIN_COMMANDS := \
../../linux/PX4Firmware/makefiles/config_px4fmu-v2_default.mk:164:BUILTIN_COMMANDS := \
../../linux/PX4Firmware/makefiles/README.txt:59: ROMFS_ROOT to build a ROMFS and BUILTIN_COMMANDS to include non-module
../../linux/PX4Firmware/makefiles/firmware.mk:57:# BUILTIN_COMMANDS
../../linux/PX4Firmware/makefiles/firmware.mk:393:# The configuration supplies builtin command information in the BUILTIN_COMMANDS
../../linux/PX4Firmware/makefiles/firmware.mk:409:ifneq ($(BUILTIN_COMMANDS),)
../../linux/PX4Firmware/makefiles/firmware.mk:427: $(Q) $(foreach spec,$(BUILTIN_COMMANDS),$(call BUILTIN_PROTO,$(subst ., ,$(spec)),$@))
../../linux/PX4Firmware/makefiles/firmware.mk:430: $(Q) $(foreach spec,$(BUILTIN_COMMANDS),$(call BUILTIN_DEF,$(subst ., ,$(spec)),$@))
../../linux/PX4Firmware/makefiles/firmware.mk:434: $(Q) $(ECHO) 'const int g_builtin_count = $(words $(BUILTIN_COMMANDS) $(MODULE_COMMANDS));' >> $@
../../linux/ardupilot/mk/VRBRAIN/config_vrbrain-v51_APM.mk:167:BUILTIN_COMMANDS := \
../../linux/ardupilot/mk/VRBRAIN/config_vrbrain-v45_APM.mk:167:BUILTIN_COMMANDS := \
../../linux/ardupilot/mk/VRBRAIN/config_vrubrain-v51_APM.mk:167:BUILTIN_COMMANDS := \
../../linux/ardupilot/mk/PX4/config_px4fmu-v1_APM.mk:81:BUILTIN_COMMANDS := \
../../linux/ardupilot/mk/PX4/config_px4fmu-v2_APM.mk:80:BUILTIN_COMMANDS := \
../../ardupilot/mk/VRBRAIN/config_vrbrain-v51_APM.mk:167:BUILTIN_COMMANDS := \
../../ardupilot/mk/VRBRAIN/config_vrbrain-v45_APM.mk:167:BUILTIN_COMMANDS := \
../../ardupilot/mk/VRBRAIN/config_vrubrain-v51_APM.mk:167:BUILTIN_COMMANDS := \
../../ardupilot/mk/PX4/config_px4fmu-v1_APM.mk:81:BUILTIN_COMMANDS := \
../../ardupilot/mk/PX4/config_px4fmu-v2_APM.mk:80:BUILTIN_COMMANDS := \
bitcraze@bitcraze-vm:~/apm/ardupilot/ArduCopter$
那么我们就知道 IO板编译的时候不会去创建 “$(BUILTIN_CSRC)”目标,这个目标会生成一个源文件,就是 builtin_commands.c。我们不妨到核心板的相应目录下去查看下该文件的内容:
bitcraze@bitcraze-vm:~/apm/ardupilot/ArduCopter$ cat ../../PX4Firmware/Build/px4fmu-v2_APM.build/builtin_commands.c
/* builtin command list - automatically generated, do not edit */
#include <nuttx/config.h>
#include <nuttx/binfmt/builtin.h>
extern int sercon_main(int argc, char *argv[]);
extern int serdis_main(int argc, char *argv[]);
extern int ArduPilot_main(int argc, char *argv[]);
extern int adc_main(int argc, char *argv[]);
extern int auth_main(int argc, char *argv[]);
extern int bl_update_main(int argc, char *argv[]);
extern int blinkm_main(int argc, char *argv[]);
extern int boardinfo_main(int argc, char *argv[]);
extern int ets_airspeed_main(int argc, char *argv[]);
extern int fmu_main(int argc, char *argv[]);
extern int gps_main(int argc, char *argv[]);
extern int hil_main(int argc, char *argv[]);
extern int hmc5883_main(int argc, char *argv[]);
extern int l3gd20_main(int argc, char *argv[]);
extern int ll40ls_main(int argc, char *argv[]);
extern int lsm303d_main(int argc, char *argv[]);
extern int mb12xx_main(int argc, char *argv[]);
extern int meas_airspeed_main(int argc, char *argv[]);
extern int mixer_main(int argc, char *argv[]);
extern int mkblctrl_main(int argc, char *argv[]);
extern int mpu6000_main(int argc, char *argv[]);
extern int ms5611_main(int argc, char *argv[]);
extern int mtd_main(int argc, char *argv[]);
extern int nshterm_main(int argc, char *argv[]);
extern int perf_main(int argc, char *argv[]);
extern int pwm_main(int argc, char *argv[]);
extern int px4io_main(int argc, char *argv[]);
extern int reboot_main(int argc, char *argv[]);
extern int rgbled_main(int argc, char *argv[]);
extern int tests_main(int argc, char *argv[]);
extern int tone_alarm_main(int argc, char *argv[]);
extern int top_main(int argc, char *argv[]);
extern int uorb_main(int argc, char *argv[]);
const struct builtin_s g_builtins[] = {
    {"sercon", SCHED_PRIORITY_DEFAULT, 2048, sercon_main},
    {"serdis", SCHED_PRIORITY_DEFAULT, 2048, serdis_main},
    {"ArduPilot", SCHED_PRIORITY_DEFAULT, 4096, ArduPilot_main},
    {"adc", SCHED_PRIORITY_DEFAULT, CONFIG_PTHREAD_STACK_DEFAULT, adc_main},
    {"auth", SCHED_PRIORITY_DEFAULT, 64000, auth_main},
    {"bl_update", SCHED_PRIORITY_DEFAULT, 4096, bl_update_main},
    {"blinkm", SCHED_PRIORITY_DEFAULT, CONFIG_PTHREAD_STACK_DEFAULT, blinkm_main},
    {"boardinfo", SCHED_PRIORITY_DEFAULT, CONFIG_PTHREAD_STACK_DEFAULT, boardinfo_main},
    {"ets_airspeed", SCHED_PRIORITY_DEFAULT, 2048, ets_airspeed_main},
    {"fmu", SCHED_PRIORITY_DEFAULT, CONFIG_PTHREAD_STACK_DEFAULT, fmu_main},
    {"gps", SCHED_PRIORITY_DEFAULT, CONFIG_PTHREAD_STACK_DEFAULT, gps_main},
    {"hil", SCHED_PRIORITY_DEFAULT, CONFIG_PTHREAD_STACK_DEFAULT, hil_main},
    {"hmc5883", SCHED_PRIORITY_DEFAULT, 4096, hmc5883_main},
    {"l3gd20", SCHED_PRIORITY_DEFAULT, CONFIG_PTHREAD_STACK_DEFAULT, l3gd20_main},
    {"ll40ls", SCHED_PRIORITY_DEFAULT, CONFIG_PTHREAD_STACK_DEFAULT, ll40ls_main},
    {"lsm303d", SCHED_PRIORITY_DEFAULT, CONFIG_PTHREAD_STACK_DEFAULT, lsm303d_main},
    {"mb12xx", SCHED_PRIORITY_DEFAULT, CONFIG_PTHREAD_STACK_DEFAULT, mb12xx_main},
    {"meas_airspeed", SCHED_PRIORITY_DEFAULT, 2048, meas_airspeed_main},
    {"mixer", SCHED_PRIORITY_DEFAULT, 4096, mixer_main},
    {"mkblctrl", SCHED_PRIORITY_DEFAULT, CONFIG_PTHREAD_STACK_DEFAULT, mkblctrl_main},
    {"mpu6000", SCHED_PRIORITY_DEFAULT, 4096, mpu6000_main},
    {"ms5611", SCHED_PRIORITY_DEFAULT, CONFIG_PTHREAD_STACK_DEFAULT, ms5611_main},
    {"mtd", SCHED_PRIORITY_DEFAULT, CONFIG_PTHREAD_STACK_DEFAULT, mtd_main},
    {"nshterm", SCHED_PRIORITY_DEFAULT, 3000, nshterm_main},
    {"perf", SCHED_PRIORITY_DEFAULT, CONFIG_PTHREAD_STACK_DEFAULT, perf_main},
    {"pwm", SCHED_PRIORITY_DEFAULT, 4096, pwm_main},
    {"px4io", SCHED_PRIORITY_DEFAULT, CONFIG_PTHREAD_STACK_DEFAULT, px4io_main},
    {"reboot", SCHED_PRIORITY_DEFAULT, CONFIG_PTHREAD_STACK_DEFAULT, reboot_main},
    {"rgbled", SCHED_PRIORITY_DEFAULT, CONFIG_PTHREAD_STACK_DEFAULT, rgbled_main},
    {"tests", SCHED_PRIORITY_DEFAULT, 12000, tests_main},
    {"tone_alarm", SCHED_PRIORITY_DEFAULT, CONFIG_PTHREAD_STACK_DEFAULT, tone_alarm_main},
    {"top", SCHED_PRIORITY_DEFAULT, 3000, top_main},
    {"uorb", SCHED_PRIORITY_DEFAULT, 4096, uorb_main},
    {NULL, 0, 0, NULL}
};
const int g_builtin_count = 33;
bitcraze@bitcraze-vm:~/apm/ardupilot/ArduCopter$
我们看到头文件用的是 nuttx的,源文件里有一个数组,放的全是入口函数。显然这是给 nuttx系统用的。那么这些入口函数也就来自 nuttx系统。而且我们可以进一步确定,这些入口是应用程序的,而非驱动的。
    看到这里我就在想,从这段 Makefile中我们是不是可以认为 IO板是以裸机的方式在运行?我认为应该是可以的。
    如果我们继续修改 Makefile进行调试,我们会发现:
define LINK
@$(ECHO) "LINK:    $1"
@$(MKDIR) -p $(dir $1)
$(ECHO) "LINK1"
# $(Q) $(LD) $(LDFLAGS) -Map $1.map -o $1 --start-group $2 $(LIBS) $(EXTRA_LIBS) $(LIBGCC) --end-group
$(LD) $(LDFLAGS) -Map $1.map -o $1 --start-group $2 $(LIBS) $(EXTRA_LIBS) $(LIBGCC) --end-group
$(ECHO) "LINK2"
endef
# Convert $1 from a linked object to a raw binary in $2
#
define SYM_TO_BIN
@$(ECHO) "BIN:     $2"
# @$(MKDIR) -p $(dir $2)
# $(Q) $(OBJCOPY) -O binary $1 $2
$(MKDIR) -p $(dir $2)
$(OBJCOPY) -O binary $1 $2
endef
LINK:    /home/bitcraze/apm/PX4Firmware/Build/px4io-v2_default.build/firmware.elf
LINK1
arm-none-eabi-ld --warn-common --gc-sections  -T/home/bitcraze/apm/PX4Firmware/Build/px4io-v2_default.build/nuttx-export/build/ld.script -L/home/bitcraze/apm/PX4Firmware/Build/px4io-v2_default.build/nuttx-export/libs -Map /home/bitcraze/apm/PX4Firmware/Build/px4io-v2_default.build/firmware.elf.map -o /home/bitcraze/apm/PX4Firmware/Build/px4io-v2_default.build/firmware.elf --start-group /home/bitcraze/apm/PX4Firmware/Build/px4io-v2_default.build//home/bitcraze/apm/PX4Firmware/Build/px4io-v2_default.build/empty.c.o /home/bitcraze/apm/PX4Firmware/Build/px4io-v2_default.build//home/bitcraze/apm/PX4Firmware/src/drivers/boards/px4io-v2/module.pre.o /home/bitcraze/apm/PX4Firmware/Build/px4io-v2_default.build//home/bitcraze/apm/PX4Firmware/src/drivers/stm32/module.pre.o /home/bitcraze/apm/PX4Firmware/Build/px4io-v2_default.build//home/bitcraze/apm/PX4Firmware/src/modules/px4iofirmware/module.pre.o  -lapps -lnuttx /home/bitcraze/bin/gcc-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7-m/libm.a /home/bitcraze/bin/gcc-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/4.7.3/armv7-m/libgcc.a --end-group
LINK2
BIN:     /home/bitcraze/apm/PX4Firmware/Build/px4io-v2_default.build/firmware.bin
mkdir -p /home/bitcraze/apm/PX4Firmware/Build/px4io-v2_default.build/
arm-none-eabi-objcopy -O binary /home/bitcraze/apm/PX4Firmware/Build/px4io-v2_default.build/firmware.elf /home/bitcraze/apm/PX4Firmware/Build/px4io-v2_default.build/firmware.bin
%% Generating /home/bitcraze/apm/PX4Firmware/Build/px4io-v2_default.build/firmware.px4
make[2]: Leaving directory `/home/bitcraze/apm/PX4Firmware/Build/px4io-v2_default.build'
%% Copying /home/bitcraze/apm/PX4Firmware/Images/px4io-v2_default.px4
make[1]: Leaving directory `/home/bitcraze/apm/PX4Firmware'

这样我们就可以大概知道编译我们的 elf文件用到了那些源码。其中用到了几个库,最显眼的应该是 nuttx这个库,因为这个库很清楚地告诉了我我们的 IO板是跑系统的,而不是裸机运行。所以现在我有个疑问就是:“为什么运行在 Nuttx系统却不提供应用程序入口”?我想这也只有到源码中去寻找答案了。由于这里我们主要讨论的是 Makefile,暂时就不去深究了。
    另外一个是 apps库,剩下的两个都是编译器的库,对于编译器的库,我是直接掠过的。我们的这两个库是由 $(LIBS)指定的,都源自 Nuttx系统。那么他们是怎么来的呢?我们继续到 Makefile中去寻找答案。
################################################################################
# NuttX libraries and paths
################################################################################
include $(PX4_MK_DIR)/nuttx.mk
这还是 firmware.mk中的内容,引用了外部的 mk文件 nuttx.mk。其中有这样一段内容:
#
# Use the linker script from the NuttX export
#
LDSCRIPT  += $(NUTTX_EXPORT_DIR)build/ld.script
#
# Add directories from the NuttX export to the relevant search paths
#
INCLUDE_DIRS  += $(NUTTX_EXPORT_DIR)include \
      $(NUTTX_EXPORT_DIR)arch/chip \
      $(NUTTX_EXPORT_DIR)arch/common
LIB_DIRS  += $(NUTTX_EXPORT_DIR)libs
LIBS   += -lapps -lnuttx
NUTTX_LIBS   = $(NUTTX_EXPORT_DIR)libs/libapps.a \
      $(NUTTX_EXPORT_DIR)libs/libnuttx.a
LINK_DEPS  += $(NUTTX_LIBS)
$(NUTTX_CONFIG_HEADER): $(NUTTX_ARCHIVE)
@$(ECHO) %% Unpacking $(NUTTX_ARCHIVE)
$(Q) $(UNZIP_CMD) -q -o -d $(WORK_DIR) $(NUTTX_ARCHIVE)
$(Q) $(TOUCH) $@
$(LDSCRIPT): $(NUTTX_CONFIG_HEADER)
$(NUTTX_LIBS): $(NUTTX_CONFIG_HEADER)
但是当我尝试去获取这两个库编译的细节的时候却失败了,具体原因不明。

5. px4-v2
    现在我们来看下 px4-v2的编译。
    核心板与 IO板在编译上存在一定的相似性。这里我们同样也可以构造一个目标 px4-v3来进行测试。
px4-v3: showflags $(PX4_ROOT)/Archives/px4fmu-v2.export $(SKETCHCPP) module_mk
$(RULEHDR)
$(v) rm -f $(PX4_ROOT)/makefiles/$(PX4_V2_CONFIG_FILE)
$(v) cp $(PWD)/$(PX4_V2_CONFIG_FILE) $(PX4_ROOT)/makefiles/
$(PX4_MAKE) px4fmu-v2_APM
$(v) /bin/rm -f $(SKETCH)-v2.px4
$(v) cp $(PX4_ROOT)/Images/px4fmu-v2_APM.px4 $(SKETCH)-v2.px4
$(v) echo "PX4 $(SKETCH) Firmware is in $(SKETCH)-v2.px4"  
showflags:
@echo "HAL_BOARD=$(HAL_BOARD) HAL_BOARD_SUBTYPE=$(HAL_BOARD_SUBTYPE) TOOLCHAIN=$(TOOLCHAIN) EXTRAFLAGS=$(EXTRAFLAGS)"
$(PX4_ROOT)/Archives/px4fmu-v2.export:
$(v) $(PX4_MAKE_ARCHIVES)
.PHONY: module_mk
#
# Build the sketch.cpp file
$(SKETCHCPP): showflags $(SKETCHCPP_SRC)
@echo "building $(SKETCHCPP)"
$(RULEHDR)
$(v)$(AWK) -v mode=header '$(SKETCH_SPLITTER)'   $(SKETCHCPP_SRC) >  
$(v)echo "#line 1 \"autogenerated\""                              >>
$(v)$(AWK)                '$(SKETCH_PROTOTYPER)' $(SKETCHCPP_SRC) >>
$(v)$(AWK) -v mode=body   '$(SKETCH_SPLITTER)'   $(SKETCHCPP_SRC) >>
$(v)cmp $@ > /dev/null 2>&1 || mv $@
$(v)rm -f
module_mk:
$(RULEHDR)
$(v) echo "# Auto-generated file - do not edit" > $(SKETCHBOOK)/module.mk.new
$(v) echo "MODULE_COMMAND = ArduPilot" >> $(SKETCHBOOK)/module.mk.new
$(v) echo "SRCS = Build.$(SKETCH)/$(SKETCH).cpp $(SKETCHLIBSRCSRELATIVE)" >> $(SKETCHBOOK)/module.mk.new
$(v) echo "MODULE_STACKSIZE = 4096" >> $(SKETCHBOOK)/module.mk.new
$(v) cmp $(SKETCHBOOK)/module.mk $(SKETCHBOOK)/module.mk.new 2>/dev/null || mv $(SKETCHBOOK)/module.mk.new $(SKETCHBOOK)/module.mk
$(v) rm -f $(SKETCHBOOK)/module.mk.new
其中,我们裁掉了对 IO板的依赖。
    那么这几个一来都分别做了哪些事情呢?第一个最明显,打印了编译的相关信息。其它的我们都需要经过一些测试。通过测试我们知道 “$(PX4_ROOT)/Archives/px4fmu-v2.export”是用来编译 Nuttx系统的,编译命令为 “make -C /home/bitcraze/apm/PX4Firmware NUTTX_SRC=/home/bitcraze/apm/PX4NuttX/nuttx/ archives MAXOPTIMIZATION="-Os"”,也就是编译 archives目标; “$(SKETCHCPP)”用于生成源文件 “ardupilot/Build.ArduCopter/ArduCopter.cpp”,这部分 Makefile在 sketch_sources.mk文件中。是在 apm.mk中 include进来的。 “module_mk”则是用来生成 “ardupilot/module.mk”文件。该文件定义了三个变量:MODULE_COMMAND, SRCS, MODULE_STACKSIZE。从字面上看分别是模块命令、源文件和模块的堆栈大小。关于这几个变量的作用,我们后面会看到。
    当所有的这些依赖都被满足,便通过 “$(PX4_MAKE) px4fmu-v2_APM”命令进行编译。
PX4_MAKE = $(v) GIT_SUBMODULES_ARE_EVIL=1 make -C $(SKETCHBOOK) -f $(PX4_ROOT)/Makefile EXTRADEFINES="$(SKETCHFLAGS) $(WARNFLAGS) "'$(EXTRAFLAGS)' APM_MODULE_DIR=$(SKETCHBOOK) SKETCHBOOK=$(SKETCHBOOK) PX4_ROOT=$(PX4_ROOT) NUTTX_SRC=$(NUTTX_SRC) MAXOPTIMIZATION="-Os"
该命令展开之后很长,主要是头文件很多。将头文件去掉,剩下的命令为:
GIT_SUBMODULES_ARE_EVIL=1 make -C /home/bitcraze/apm/ardupilot -f /home/bitcraze/apm/PX4Firmware/Makefile -DARDUPILOT_BUILD -DCONFIG_HAL_BOARD=HAL_BOARD_PX4 -DSKETCHNAME=\"ArduCopter\" -DSKETCH_MAIN=ArduPilot_main -DAPM_BUILD_DIRECTORY=APM_BUILD_ArduCopter -Wno-psabi -Wno-packed -Wno-error=double-promotion -Wno-error=unused-variable -Wno-error=unused-but-set-variable -Wno-error=reorder -DGIT_VERSION="\"b6d361a3\"" -DNUTTX_GIT_VERSION="\"eba6b56f\"" -DPX4_GIT_VERSION="\"cf208916\""APM_MODULE_DIR=/home/bitcraze/apm/ardupilot SKETCHBOOK=/home/bitcraze/apm/ardupilot PX4_ROOT=/home/bitcraze/apm/PX4Firmware NUTTX_SRC=/home/bitcraze/apm/PX4NuttX/nuttx/MAXOPTIMIZATION=-Os
可以看到,命令依然很长。这里我们编译使用的头文件是 “PX4Firmware/Makefile”,编译目标为默认 all目标。但是
#
# Built products
#
DESIRED_FIRMWARES   = $(foreach config,$(CONFIGS),$(IMAGE_DIR)$(config).px4)
STAGED_FIRMWARES  = $(foreach config,$(KNOWN_CONFIGS),$(IMAGE_DIR)$(config).px4)
FIRMWARES   = $(foreach config,$(KNOWN_CONFIGS),$(BUILD_DIR)$(config).build/firmware.px4)
all:   $(DESIRED_FIRMWARES)
“$(DESIRED_FIRMWARES)”的值为: “PX4Firmware/Images/px4fmu-v2_APM.px4”。过程不清楚,但可以确定的是最后还是匹配了 “$(FIRMWARES)”这个目标。于是下面有顺理成章地回到了 “firmware.mk”。 “firmware.mk”前面我们已经简单分析过期编译流程了。跟 IO板相比主要有两个不同,一是此时 “$(BUILTIN_COMMANDS)”值不为空,也就是会生成 builtin_commands.c文件;二是 “$(MODULE_OBJS)”值不一样,其值包含了 PX4的各种模块,如传感器, PWM。模块多了编译的东西自然也就多了。这些模块在核心板看来就是命令。
#
# Transitional support - add commands from the NuttX export archive.
#
# In general, these should move to modules over time.
#
# Each entry here is <command>.<priority>.<stacksize>.<entrypoint> but we use a helper macro
# to make the table a bit more readable.
#
define _B
$(strip $1).$(or $(strip $2),SCHED_PRIORITY_DEFAULT).$(or $(strip $3),CONFIG_PTHREAD_STACK_DEFAULT).$(strip $4)
endef
#                  command                 priority                   stack  entrypoint
BUILTIN_COMMANDS := \
$(call _B, sercon,                 ,                          2048,  sercon_main                ) \
$(call _B, serdis,                 ,                          2048,  serdis_main                )
我们可以通过研究这段 Makefile去了解 “$(BUILTIN_COMMANDS)”的值是怎么来的,只是我现在可没这功夫去研究它。因为这段 Makefile在 IO板中根本就不存在,其值也就为空了。那么下面我们来看看 “$(MODULE_OBJS)”是怎么编译的。
    “$(MODULE_OBJS)”是 “$(PRODUCT_ELF)”的依赖,所以当 “$(PRODUCT_ELF)”需要编译的时候, “$(MODULE_OBJS)”也会被编译。
# make a list of module makefiles and check that we found them all
MODULE_MKFILES  := $(foreach module,$(MODULES),$(call MODULE_SEARCH,$(module)))
MISSING_MODULES  := $(subst MISSING_,,$(filter MISSING_%,$(MODULE_MKFILES)))
ifneq ($(MISSING_MODULES),)
$(error Can't find module(s): $(MISSING_MODULES))
endif
# Make a list of the object files we expect to build from modules
# Note that this path will typically contain a double-slash at the WORK_DIR boundary; this must be
# preserved as it is used below to get the absolute path for the module.mk file correct.
#
MODULE_OBJS  := $(foreach path,$(dir $(MODULE_MKFILES)),$(WORK_DIR)$(path)module.pre.o)
# rules to build module objects
.PHONY: $(MODULE_OBJS)
$(MODULE_OBJS):  relpath = $(patsubst $(WORK_DIR)%,%,$@)
$(MODULE_OBJS):  mkfile = $(patsubst %module.pre.o,%module.mk,$(relpath))
$(MODULE_OBJS):  workdir = $(@D)
$(MODULE_OBJS):  $(GLOBAL_DEPS) $(NUTTX_CONFIG_HEADER)
$(Q) $(MKDIR) -p $(workdir)
$(Q) $(MAKE) -r -f $(PX4_MK_DIR)module.mk \
  -C $(workdir) \
  MODULE_WORK_DIR=$(workdir) \
  MODULE_OBJ=$@ \
  MODULE_MK=$(mkfile) \
  MODULE_NAME=$(lastword $(subst /, ,$(workdir))) \
  module

通过注释我们知道这段 Makefile是用来编译 module的。对 “MODULE_OBJS”进行跟踪,我们发现数据最终源自 “$(MODULES)”,那么这又是一个什么变量,它的值又是什么呢?
    这就是 “PX4Firmware/makefiles/”目录下那些 “config”开头的 mk文件。例如 IO板 “config_px4io-v2_default.mk”内容如下:
#
# Makefile for the px4iov2_default configuration
#
#
# Board support modules
#
MODULES  += drivers/stm32
MODULES  += drivers/boards/px4io-v2
MODULES  += modules/px4iofirmware
而处理到最后, “mkfile”存放的是个模块目录下的 “module.mk”文件。而最后编译使用的 mk文件为: “PX4Firmware/makefiles/module.mk”,目标为:
################################################################################
# Build rules
################################################################################
#
# What we're going to build
#
module:   $(MODULE_OBJ) $(MODULE_COMMAND_FILES)
#
# Object files we will generate from sources
#
OBJS    = $(addsuffix .o,$(SRCS))
#
# Dependency files that will be auto-generated
#
DEPS    = $(addsuffix .d,$(SRCS))
#
# SRCS -> OBJS rules
#
$(OBJS):  $(GLOBAL_DEPS)
vpath %.c $(MODULE_SRC)
$(filter %.c.o,$(OBJS)): %.c.o: %.c $(GLOBAL_DEPS)
$(call COMPILE,$<,$@)
vpath %.cpp $(MODULE_SRC)
$(filter %.cpp.o,$(OBJS)): %.cpp.o: %.cpp $(GLOBAL_DEPS)
$(call COMPILEXX,$<,$@)
vpath %.S $(MODULE_SRC)
$(filter %.S.o,$(OBJS)): %.S.o: %.S $(GLOBAL_DEPS)
$(call ASSEMBLE,$<,$@)
#
# Built product rules
#
$(MODULE_OBJ):  $(OBJS) $(GLOBAL_DEPS)
$(call PRELINK,$@,$(OBJS))

这里是将各自的源文件编译成各自的目标文件,即 "*.o"文件。而这许多个目标文件最后又通过 “PRELINK”链接成一个目标文件,也就是 “module.pre.o”。
    而通过 “$(MODULE_COMMAND_FILES)”会输出这样一些信息:
CMD:     l3gd20
CMD:     ll40ls
CMD:     mpu6000
CMD:     ms5611
CMD:     fmu
CMD:     px4io
CMD:     reboot
也就是说 module并不特指硬件,正确的理解应当是应用程序。然而在操作系统里边像 Linux应用程序可以在 shell中以命令的方式进行调用,于是这里称之为命令也就不奇怪了。

6. archives

    “$(PX4_ROOT)/Archives/px4fmu-v2.export”是 px4-v2的又一个依赖,前面我们已经知道其编译的命令为: “make -C /home/bitcraze/apm/PX4Firmware NUTTX_SRC=/home/bitcraze/apm/PX4NuttX/nuttx/ archives MAXOPTIMIZATION="-Os"”,我们找到 “archives”目标:
#
# Build the NuttX export archives.
#
# Note that there are no explicit dependencies extended from these
# archives. If NuttX is updated, the user is expected to rebuild the
# archives/build area manually. Likewise, when the 'archives' target is
# invoked, all archives are always rebuilt.
#
# XXX Should support fetching/unpacking from a separate directory to permit
#     downloads of the prebuilt archives as well...
#
NUTTX_ARCHIVES   = $(foreach board,$(BOARDS),$(ARCHIVE_DIR)$(board).export)
.PHONY:   archives
archives:  $(NUTTX_ARCHIVES)
# We cannot build these parallel; note that we also force -j1 for the
# sub-make invocations.
ifneq ($(filter archives,$(MAKECMDGOALS)),)
.NOTPARALLEL:
endif
$(ARCHIVE_DIR)%.export: board = $(notdir $(basename $@))
$(ARCHIVE_DIR)%.export: configuration = nsh
$(NUTTX_ARCHIVES): $(ARCHIVE_DIR)%.export: $(NUTTX_SRC)
@$(ECHO) %% Configuring NuttX for $(board)
$(Q) (cd $(NUTTX_SRC) && $(RMDIR) nuttx-export)
$(Q) $(MAKE) -r -j1 -C $(NUTTX_SRC) -r $(MQUIET) distclean
$(Q) (cd $(NUTTX_SRC)/configs && $(COPYDIR) $(PX4_BASE)nuttx-configs/$(board) .)
$(Q) (cd $(NUTTX_SRC)tools && ./configure.sh $(board)/$(configuration))
@$(ECHO) %% Exporting NuttX for $(board)
$(Q) $(MAKE) -r -j1 -C $(NUTTX_SRC) -r $(MQUIET) CONFIG_ARCH_BOARD=$(board) export
$(Q) $(MKDIR) -p $(dir $@)
$(Q) $(COPY) $(NUTTX_SRC)nuttx-export.zip $@
$(Q) (cd $(NUTTX_SRC)/configs && $(RMDIR) $(board))
于是最终将跳转到 “PX4NuttX/nuttx/”目的对 Nuttx进行编译。关于 Nuttx的编译就在这里点到为止,暂不做过深入的分析。
7. $(SKETCHCPP)

#
# Build the sketch.cpp file
$(SKETCHCPP): showflags $(SKETCHCPP_SRC)
@echo "building $(SKETCHCPP)"
$(RULEHDR)
$(v)$(AWK) -v mode=header '$(SKETCH_SPLITTER)'   $(SKETCHCPP_SRC) >  $@.new
$(v)echo "#line 1 \"autogenerated\""                              >> $@.new
$(v)$(AWK)                '$(SKETCH_PROTOTYPER)' $(SKETCHCPP_SRC) >> $@.new
$(v)$(AWK) -v mode=body   '$(SKETCH_SPLITTER)'   $(SKETCHCPP_SRC) >> $@.new
$(v)cmp $@ $@.new > /dev/null 2>&1 || mv $@.new $@
$(v)rm -f $@.new
这部分 Makefile其实只做了一件事,那就是 “ardupilot/Build.ArduCopter/ArduCopter.cpp”文件,而 “$(SKETCHCPP_SRC)”就是所有的这些 pde文件。也就是说 “ardupilot/ArduCopter”目录下的源文件最终将被处理成一个 ArduCopter.cpp文件进行编译。

    分析到这里,编译流程基本告一段路了,剩下的一些东西我们后面分析会借助源码进行理解。
阅读(3446) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~