3 高效的程序开发
总的来说,在uClinux上的开发和标准Linux还是很类似的。通常可以按照下面的步骤去设计和调试:
1. 建立基于以太网的开发环境;
2. 如果所设计的程序和硬件的关联不大,那么一定要在标准Linux上先编译和调试通过。灵活地使用gcc和gdb将大大节省时间;
3. 将x86上的GCC编译好的应用程序用交叉编译工具来编译;如果编译时发现错误,那么很可能存在以下问题:
n 交叉编译器或库文件的路径不正确;最彻底的解决办法是重新装一次编译器;
n 遇到库不支持的函数;此时需要自己把函数的实现做成另外一个库供应用程序使用。如果是uClinux本身不支持的调用,那么就需要改写代码了。
n C++的一些写法不太标准,需要修改;
4. 通过网络(nfsmount)运行交叉编译成功的应用程序;
5. 如果程序工作初步正常,那么就可以进一步在板子上测试了;否则,需做修改重新编译,尤其要检查与uClinux的内存特性有关的代码。
如果程序较小,设计时就可以比较灵活。如果是一个比较庞大的工程,那么,建立一个好的编译环境非常重要。下面,给出一个较为复杂的工程中所建立的一系列编译文件例子,用好它们可以提高效率。
例如,在编译x86平台上的程序时,可以这样输入:
>make config
出现提示:
Target Platform Selection
Choose a Vendor/Product combination.
Vendor/Product [Intel/i386| Motorola/M5307C3]
如果我们输入i386,那么就可以编译出PC上运行的程序;而输入M5307C3,就可以编译出uClinux上运行的程序。这对于经常需要在标准Linux和uClinux之间进行交叉编译和查找错误的程序来说非常方便。
首先,建立图 2所示的整个工程目录结构。
图 2 整个工程的目录结构
在config中,存放一些编译有关的配置文件;src目录下,按照各个程序模块分别创建一个目录。
在Project目录下,是整个工程的Makefile文件,如下:
###########################################################
#
# Makefile – Whole Project makefile.
#
# Copyright (c) 2001-2002, Tsinghua MAC
#
###########################################################
#
# Get the core stuff worked out
#
ROOT_DIR = $(shell pwd)
SRC_DIR = $(ROOT_DIR)/src
CONFIG_DIR = $(ROOT_DIR)/config
SCRIPTS_DIR = $(ROOT_DIR)/scripts
CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
else if [ -x /bin/bash ]; then echo /bin/bash; \
else echo sh; fi ; fi)
TOPDIR := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)
HPATH = $(TOPDIR)/include
FINDHPATH = $(HPATH)/asm $(HPATH)/linux $(HPATH)/scsi $(HPATH)/net
export ROOT_DIR SRC_DIR CONFIG_DIR SCRIPTS_DIR HPATH FINDHPATH
###########################################################
# normal make targets
#
#
.PHONY: all
all:
$(MAKE) -C $(SRC_DIR) all
###########################################################
#
# Config stuff, we recall ourselves to load the new config.arch before
# running the kernel and other config scripts
#
.PHONY: config
config: $(CONFIG_DIR)/config.in
cd $(CONFIG_DIR); $(CONFIG_SHELL) $(SCRIPTS_DIR)/Configure $(CONFIG_DIR)/config.in
@rm -f $(SRC_DIR)/arch.config
@if egrep "^CONFIG_DEFAULTS_INTEL_I386" $(CONFIG_DIR)/.config > /dev/null; then \
ln -s "$(CONFIG_DIR)/arch.i386" $(SRC_DIR)/arch.config; \
fi
@if egrep "^CONFIG_DEFAULTS_MOTOROLA_M5272C3" $(CONFIG_DIR)/.config > /dev/null; then \
ln -s "$(CONFIG_DIR)/arch.m68k" $(SRC_DIR)/arch.config; \
fi
@echo "#This dir.config file is automaticly generated by make config!" > $(SRC_DIR)/dir.config
@echo "ROOT_DIR="$(ROOT_DIR) >> $(SRC_DIR)/dir.config
@echo "CONFIG_DIR="$(CONFIG_DIR) >> $(SRC_DIR)/dir.config
@echo "SRC_DIR="$(SRC_DIR) >> $(SRC_DIR)/dir.config
@echo "SCRIPTS_DIR="$(SCRIPTS_DIR) >> $(SRC_DIR)/dir.config
@echo "HPATH="$(HPATH) >> $(SRC_DIR)/dir.config
@echo "FINDPATH="$(FINDPATH) >> $(SRC_DIR)/dir.config
###########################################################
#
# normal make dependancy
#
#
.PHONY: dep
dep:
$(MAKE) -C $(SRC_DIR) dep
# This one removes all executables from the tree and forces their relinking
clean:
$(MAKE) -C $(SRC_DIR) clean
test:
$(MAKE) -C $(SRC_DIR) test
run:
$(MAKE) -C $(SRC_DIR) run
config_error:
@echo "*************************************************"
@echo "You have not run make config."
@echo "The build sequence for this source tree is:"
@echo "1. 'make config' or 'make xconfig'"
@echo "2. 'make dep'"
@echo "3. 'make'"
@echo "*************************************************"
@exit 1
###########################################################
src目录下的Makefile文件,如下:
VERSION = 2
PATCHLEVEL = 0
SUBLEVEL = 39
UCRELEASE = uc2
.EXPORT_ALL_VARIABLES:
CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
else if [ -x /bin/bash ]; then echo /bin/bash; \
else echo sh; fi ; fi)
TOPDIR := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)
TARGET = ESGateway
all: $(TARGET)
# Include the make variables (CC, etc...)
#
SUBDIRS = public serial packet cal xml fifo main interface
$(TARGET):
@set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i all_targets; done
linuxsubdirs: dummy
set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done
clean:
@set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i clean; done
dep:
@set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i fastdep; done
.PHONY: test
test:
@set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i test; done
run:
# @set -e; for i in $(SUBDIRS); do $(MAKE) -i -C $$i run; read junk; done
make -C main run
src目录下的Rules.make文件给出了编译的一些规则,如下:
#
# This file contains rules which are shared between multiple Makefiles.
#
#
# False targets.
#
.PHONY: dummy
#
# Special variables which should not be exported
#
unexport EXTRA_ASFLAGS
unexport EXTRA_CFLAGS
ifneq "$(ARCH)" "h8300"
unexport EXTRA_LDFLAGS
endif
unexport EXTRA_ARFLAGS
unexport SUBDIRS
unexport SUB_DIRS
unexport ALL_SUB_DIRS
unexport MOD_SUB_DIRS
unexport O_TARGET
unexport O_OBJS
unexport L_OBJS
unexport M_OBJS
unexport MI_OBJS
unexport ALL_MOBJS
# objects that export symbol tables
unexport OX_OBJS
unexport LX_OBJS
unexport MX_OBJS
unexport MIX_OBJS
unexport SYMTAB_OBJS
unexport MOD_LIST_NAME
include ../dir.config
include $(SRC_DIR)/arch.config
#
# Get things started.
#
first_rule: sub_dirs
$(MAKE) all_targets
#
# Common rules
#
INC_DIR = -I$(SRC_DIR)/cal -I$(SRC_DIR)/xml -I$(SRC_DIR)/serial -I$(SRC_DIR)/packet -I$(SRC_DIR)/fifo -I$(SRC_DIR)/ping -I$(SRC_DIR)/interface -I$(SRC_DIR)/public
%.o: %.c
@echo "Compiling..."
@echo "$ " $@
@$(LD) $(EXTRA_LDFLAGS) -r -o $@ $(O_OBJS)
else
$(O_TARGET): .depend
endif
#
#
#
all: $(O_OBJS)
echo all
all_targets: $(O_OBJS) $(O_TARGET)
#
#
# Rule to compile a set of .o files into one .a file
#
ifdef L_TARGET
$(L_TARGET): $(LX_OBJS) $(L_OBJS)
rm -f $@
$(AR) $(EXTRA_ARFLAGS) rcs $@ $(LX_OBJS) $(L_OBJS)
endif
#
# This make dependencies quickly
#
fastdep: dummy
@echo "make fastdep"
if [ -n "$(wildcard *.[chS])" ]; then \
$(SCRIPTS_DIR)/mkdep *.[chS] > .depend; fi
if [ -n "$(wildcard *.cpp)" ]; then \
$(SCRIPTS_DIR)/mkdep *.cpp >> .depend; fi
#
# A rule to make subdirectories
#
sub_dirs: dummy
ifdef SUB_DIRS
set -e; for i in $(SUB_DIRS); do $(MAKE) -C $$i; done
endif
#
# A rule to do nothing
#
dummy:
config:
cd $(ROOT_DIR); make config
c clean:
rm -f *.o
rm -f *.gdb
rm -f .depend
rm -f test
rm -f core
rm -f *.elf
rm -f *.elf2flt
#
# This is useful for testing
#
script:
$(SCRIPT)
run: test
@echo ... running ...
@echo `pwd`/test
@./test
#
# This sets version suffixes on exported symbols
# Uses SYMTAB_OBJS
# Separate the object into "normal" objects and "exporting" objects
# Exporting objects are: all objects that define symbol tables
#
$(MX_OBJS):
$(CC) $(CFLAGS) -DEXPORT_SYMTAB -c $(@:.o=.c)
$(LX_OBJS) $(OX_OBJS):
$(CC) $(CFLAGS) -DMODVERSIONS -DEXPORT_SYMTAB -c $(@:.o=.c)
$(M_OBJS):
ifdef MAKING_MODULES
$(O_OBJS) $(L_OBJS):
endif
在config 目录下,编写两个和架构有关的文件,对于x86平台,是arch.i386,如下:
.EXPORT_ALL_VARIABLES:
###################################################################
#
# Vendor specific settings
#
CONSOLE_BAUD_RATE = 19200
###################################################################
#
# The makefiles need to know how to do things in different contexts
# To save some pain we put it all here
#
# First settings we always want for all build
#
# ARCH = kernel, TARGET_ARCH = uClibc
MACHINE = i386
ARCH = i386
CROSS_COMPILE =
CROSS = $(CROSS_COMPILE)
# We've used -m5307 here because the bulk of the 5272 instruction timings
# happen to be closer to the 5307 than the 5200 series. Luckily, the
# actual instructions on the two processors are essentially identical.
# This should be fixed at some stage.
CPUFLAGS =
CC = $(CROSS_COMPILE)gcc
AS = $(CROSS_COMPILE)as
CXX = $(CROSS_COMPILE)g++
AR = $(CROSS_COMPILE)ar
LD = $(CROSS_COMPILE)ld
OBJCOPY = $(CROSS_COMPILE)objcopy
RANLIB = $(CROSS_COMPILE)ranlib
STRIPTOOL = $(CROSS_COMPILE)strip
STRIP = $(STRIPTOOL)
UCLINUX_BUILD_SET = 0 # have we set a special config below
###################################################################
#
# General purpose lib building rules, uClibc.config uses these when
# possible
#
###################################################################
# Settings for building user apps
#
CFLAGS = -Wall -Wstrict-prototypes -O2 -g
#CFLAGS = -Wstrict-prototypes -g
LDFLAGS = -m elf_i386
###################################################################
# fall through, do other config options perhaps
#
ifeq ($(UCLINUX_BUILD_SET),1)
endif
###################################################################
在config 目录下,对于嵌入式平台,是arch.m68k,如下:
.EXPORT_ALL_VARIABLES:
###################################################################
#
# Vendor specific settings
#
CONSOLE_BAUD_RATE = 19200
###################################################################
#
# The makefiles need to know how to do things in different contexts
# To save some pain we put it all here
#
# First settings we always want for all build
#
# ARCH = kernel, TARGET_ARCH = uClibc
MACHINE = m68k
ARCH = m68knommu
CROSS_COMPILE = m68k-elf-
CROSS = $(CROSS_COMPILE)
# We've used -m5307 here because the bulk of the 5272 instruction timings
# happen to be closer to the 5307 than the 5200 series. Luckily, the
# actual instructions on the two processors are essentially identical.
# This should be fixed at some stage.
CPUFLAGS = -m5200
CC = $(CROSS_COMPILE)gcc
AS = $(CROSS_COMPILE)as
CXX = $(CROSS_COMPILE)g++
AR = $(CROSS_COMPILE)ar
LD = $(CROSS_COMPILE)ld
OBJCOPY = $(CROSS_COMPILE)objcopy
RANLIB = $(CROSS_COMPILE)ranlib
ELF2FLT = elf2flt
STRIPTOOL = $(CROSS_COMPILE)strip
STRIP = $(STRIPTOOL)
UCLINUX_BUILD_SET = 0 # have we set a special config below
###################################################################
#
# Settings for building user apps
#
#CFLAGS = -m5200 -msep-data -g
CFLAGS = -m5200 -msep-data
LDFLAGS = -Wl,-elf2flt
SYSLIBS = -lc -lstdc++ -lgcc
###################################################################
#
# fall through, do other config options perhaps
#
ifeq ($(UCLINUX_BUILD_SET),1)
endif
###################################################################
在config 目录下的config.in文件如下:
mainmenu_name 'uClinux Configuration'
mainmenu_option next_comment
comment 'Target Platform Selection'
comment 'Choose a Vendor/Product combination.'
choice 'Vendor/Product [Intel/i386 | Motorola/M5307C3] ' "1 CONFIG_DEFAULTS_INTEL_I386 \
2 CONFIG_DEFAULTS_MOTOROLA_M5307C3 \
" Intel/i386
endmenu