上一篇已经介绍到直接采用make就可以编译OpenNI2,这篇文章主要介绍下OpenNI2的makefile文件以及Linux下KDE集成开发环境的使用;
.
├── Makefile
├── Samples
│ ├── SimpleRead
│ │ └── Makefile
│ └── SimpleViewer
│ … └── Makefile
├── Source
│ ├── Core
│ │ └── Makefile
│ └── Drivers
│ … ├── DummyDevice
│ … │ └── Makefile
│ … ├── Kinect
│ … ├── OniFile
│ … │ └── Makefile
│ … ├── PS1080
│ … │ └── Makefile
│ … └── PSLink
│ … … └── Makefile
└── ThirdParty
… └── PSCommon
… ├── BuildSystem
… … ├── CommonCppMakefile
… … ├── CommonCSMakefile
… … ├── CommonDefs.mak
… … ├── CommonJavaMakefile
… … ├── CommonTargets.mak
… … ├── Platform.Arm
… … ├── Platform.x64
… … └── Platform.x86
顶层Makefile用于编译整个工程暂时先不去分析,我们先看下Sample目录下的Makefile
# SimpleViewer Makefile
include ../../ThirdParty/PSCommon/BuildSystem/CommonDefs.mak
BIN_DIR = ../../Bin
INC_DIRS = \
../../Include \
../../ThirdParty/GL/ \
../Common
SRC_FILES = *.cpp
ifeq ("$(OSTYPE)","Darwin")
CFLAGS += -DMACOS
LDFLAGS += -framework OpenGL -framework GLUT
else
CFLAGS += -DUNIX -DGLX_GLXEXT_LEGACY
USED_LIBS += glut GL
endif
USED_LIBS += OpenNI2
EXE_NAME = SimpleViewer
CFLAGS += -Wall
include ../../ThirdParty/PSCommon/BuildSystem/CommonCppMakefile
上面的各个变量都显而易见
- INC_DIRS 为头件目录
- SRC_FILES为源文件
- USED_LIBS为编译时需要链接的库
- EXE_NAME为生成可执行文件的名称
该文件主要定义EXE_NAME来表示该文件用于生成可执行文件,下面我们来看看CommonDefs.mak与CommonCppMakefile
# CommonDefs.mak
ifndef _COMMON_DEFS_MAKE_
_COMMON_DEFS_MAKE_=1
# some defaults
ifndef CFG
CFG = Release
endif
# find out the platform on which we're running
MACHINE = $(shell uname -m)
ifneq (,$(findstring x86_64,$(MACHINE)))
HOST_PLATFORM = x64
else ifneq (,$(findstring x86,$(MACHINE)))
HOST_PLATFORM = x86
else ifneq (,$(findstring i686,$(MACHINE)))
HOST_PLATFORM = x86
else ifneq (,$(findstring i386,$(MACHINE)))
HOST_PLATFORM = x86
else ifneq (,$(findstring arm,$(MACHINE)))
HOST_PLATFORM = Arm
else
DUMMY:=$(error Can't determine host platform)
endif
# now check if this is a cross-compilation or not
ifeq "$(PLATFORM)" ""
PLATFORM = $(HOST_PLATFORM)
else
ifneq "$(PLATFORM)" "$(HOST_PLATFORM)"
# cross compiling. Take CXX and STAGING_DIR from environment
PLATFORM_UPPER = $(shell echo $(PLATFORM) | tr 'a-z' 'A-Z')
DUMMY:=$(eval CXX = $($(PLATFORM_UPPER)_CXX))
DUMMY:=$(eval TARGET_SYS_ROOT = $($(PLATFORM_UPPER)_STAGING))
ifeq "$(and $(CXX), $(TARGET_SYS_ROOT))" ""
DUMMY:=$(error Cross-Compilation error. Can't find $(PLATFORM_UPPER)_CXX and $(PLATFORM_UPPER)_STAGING)
endif
endif
endif
# expand file list
SRC_FILES_LIST = $(wildcard $(SRC_FILES))
# define the intermediate directory
INT_DIR = $(BIN_DIR)/Intermediate/$(PLATFORM)-$(CFG)/$(OUTPUT_NAME)
# define output directory
OUT_DIR = $(BIN_DIR)/$(PLATFORM)-$(CFG)
# full path to output file
OUTPUT_FILE = $(OUT_DIR)/$(OUTPUT_NAME)
# take this file's dir
COMMON_MAK_DIR = $(dir $(lastword $(MAKEFILE_LIST)))
# get the OS type
OSTYPE := $(shell uname -s)
# platform specific args
include $(COMMON_MAK_DIR)Platform.$(PLATFORM)
endif # _COMMON_DEFS_MAKE_
# CommonCppMakefile
#############################################################################
# Primesense template makefile.
# This file should not be made, but only included from other makefiles.
# By default, this makefile compiles in release. To compile a debug version:
# make CFG=Debug
#
# Project makefile should define the following BEFORE including this file:
# SRC_FILES - a list of all source files
# Output name under one of the following:
# EXE_NAME (executable),
# LIB_NAME (dynamic library) or
# SLIB_NAME (static library) or
# BIN_DIR - Bin directory (output dir)
# INC_DIRS - a list of additional include directories
# LIB_DIRS - a list of additional library directories
# USED_LIBS - a list of libraries to link with
# DEFINES - [Optional] additional preprocessor defines
# CFLAGS - [Optional] additional flags for the compiler
# LDFLAGS - [Optional] additional flags for the linker
# SSE_GENERATION - [Optional] The SSE generation to use (default is 3)
# TARGET_SYS_ROOT - [Optional] The path to the root of the target
# ALLOW_WARNINGS - [Optional] Allow warnings during compilation
#############################################################################
# take this file's dir
COMMON_CPP_MAKE_FILE_DIR = $(dir $(lastword $(MAKEFILE_LIST)))
include $(COMMON_CPP_MAKE_FILE_DIR)CommonDefs.mak
# define a function to figure .o file for each source file (placed under intermediate directory)
SRC_TO_OBJ = $(addprefix ./$(INT_DIR)/,$(addsuffix .o,$(notdir $(basename $1))))
# create a list of all object files
OBJ_FILES = $(call SRC_TO_OBJ,$(SRC_FILES_LIST))
# define a function to translate any source file to its dependency file (note that the way we create
# dep files, as a side affect of compilation, always puts the files in the INT_DIR with suffix .d)
SRC_TO_DEP = $(addprefix ./$(INT_DIR)/,$(addsuffix .d,$(notdir $(basename $1))))
# create a list of all dependency files
DEP_FILES = $(call SRC_TO_DEP,$(SRC_FILES_LIST))
# older version of gcc doesn't support the '=' symbol in include dirs, so we replace it ourselves with sysroot
INC_DIRS_FROM_SYSROOT = $(patsubst =/%,$(TARGET_SYS_ROOT)/%,$(INC_DIRS))
# append the -I switch to each include directory
INC_DIRS_OPTION = $(foreach dir,$(INC_DIRS_FROM_SYSROOT),-I$(dir))
# append the -L switch to each library directory
LIB_DIRS_OPTION = $(foreach dir,$(LIB_DIRS),-L$(dir)) -L$(OUT_DIR)
# append the -l switch to each library used
USED_LIBS_OPTION = $(foreach lib,$(USED_LIBS),-l$(lib))
# append the -D switch to each define
DEFINES_OPTION = $(foreach def,$(DEFINES),-D$(def))
# tell compiler to use the target system root
ifdef TARGET_SYS_ROOT
CFLAGS += --sysroot=$(TARGET_SYS_ROOT)
LDFLAGS += --sysroot=$(TARGET_SYS_ROOT)
endif
# set Debug / Release flags
ifeq "$(CFG)" "Debug"
CFLAGS += -O0 -g
endif
ifeq "$(CFG)" "Release"
CFLAGS += -O2 -DNDEBUG
endif
CFLAGS += $(INC_DIRS_OPTION) $(DEFINES_OPTION)
CFLAGS += -fPIC -fvisibility=hidden
ifneq "$(ALLOW_WARNINGS)" "1"
CFLAGS += -Werror
endif
LDFLAGS += $(LIB_DIRS_OPTION) $(USED_LIBS_OPTION)
# some lib / exe specifics
ifneq "$(LIB_NAME)" ""
OUTPUT_NAME = lib$(LIB_NAME).so
ifneq ("$(OSTYPE)","Darwin")
LDFLAGS += -Wl,--no-undefined
OUTPUT_NAME = lib$(LIB_NAME).so
OUTPUT_COMMAND = $(CXX) -o $(OUTPUT_FILE) $(OBJ_FILES) $(LDFLAGS) -shared
else
LDFLAGS += -undefined error
OUTPUT_NAME = lib$(LIB_NAME).dylib
OUTPUT_COMMAND = $(CXX) -o $(OUTPUT_FILE) $(OBJ_FILES) $(LDFLAGS) -dynamiclib -headerpad_max_install_names -install_name $(OUTPUT_NAME)
endif
endif
ifneq "$(EXE_NAME)" ""
OUTPUT_NAME = $(EXE_NAME)
# We want the executables to look for the .so's locally first:
LDFLAGS += -Wl,-rpath ./
OUTPUT_COMMAND = $(CXX) -o $(OUTPUT_FILE) $(OBJ_FILES) $(LDFLAGS)
endif
ifneq "$(SLIB_NAME)" ""
OUTPUT_NAME = lib$(SLIB_NAME).a
ifneq ("$(OSTYPE)","Darwin")
OUTPUT_COMMAND = $(AR) -cq $(OUTPUT_FILE) $(OBJ_FILES)
else
OUTPUT_COMMAND = libtool -static -o $(OUTPUT_FILE) $(OBJ_FILES)
endif
endif
define CREATE_SRC_TARGETS
# create a target for the object file (the CXX command creates both an .o file
# and a .d file)
ifneq ("$(OSTYPE)","Darwin")
$(call SRC_TO_OBJ,$1) : $1 | $(INT_DIR)
$(CXX) -MD -MP -MT "$(call SRC_TO_DEP,$1) $$@" -c $(CFLAGS) -o $$@ $$<
else
$(call SRC_TO_OBJ,$1) : $1 | $(INT_DIR)
$(CXX) -x c++ -c $(CFLAGS) -o $$@ $$<
endif
endef
#############################################################################
# Targets
#############################################################################
.PHONY: clean-objs clean-defs
include $(COMMON_CPP_MAKE_FILE_DIR)CommonTargets.mak
# create targets for each source file
$(foreach src,$(SRC_FILES_LIST),$(eval $(call CREATE_SRC_TARGETS,$(src))))
# include all dependency files (we don't need them the first time, so we can use -include)
-include $(DEP_FILES)
$(OUTPUT_FILE): $(OBJ_FILES)
$(OUTPUT_COMMAND)
clean-objs:
rm -rf $(OBJ_FILES)
clean-defs:
rm -rf $(DEP_FILES)
clean: clean-objs clean-defs
CommonDefs.mak主要定义了平台、编译器以及目录
CommonCppMakefile描述了主要的make过程
当我们使用OpenNI的build system编写makefile时仅需对output name和头文件路径链接库进行描述
例如下面的Makefile用于编译libOpenNI2.so,这个文件中output name 为LIB_NAME = OpenNI2
include ../../ThirdParty/PSCommon/BuildSystem/CommonDefs.mak
BIN_DIR = ../../Bin
INC_DIRS = \
../../Include \
../../ThirdParty/PSCommon/XnLib/Include \
../Drivers/OniFile/Formats \
../../ThirdParty/LibJPEG
SRC_FILES = \
*.cpp \
../Drivers/OniFile/Formats/XnCodec.cpp \
../Drivers/OniFile/Formats/XnStreamCompression.cpp \
../../ThirdParty/LibJPEG/*.c \
ifeq ("$(OSTYPE)","Darwin")
INC_DIRS += /opt/local/include
LIB_DIRS += /opt/local/lib
LDFLAGS += -framework CoreFoundation -framework IOKit
endif
LIB_NAME = OpenNI2
LIB_DIRS = ../../ThirdParty/PSCommon/XnLib/Bin/$(PLATFORM)-$(CFG)
USED_LIBS = XnLib dl pthread
ifneq ("$(OSTYPE)","Darwin")
USED_LIBS += rt
endif
DEFINES += OPENNI2_EXPORT
CFLAGS += -Wall
include ../../ThirdParty/PSCommon/BuildSystem/CommonCppMakefile
下面在看下top Makefile
#############################################################################
# OpenNI makefile.
#
# default configuration is Release. for a debug version use:
# make CFG=Debug
#
# default compiler is g++. for another one use:
# make CXX=
#
# By default, CLR projects will only be build if mono is installed.
# To force CLR projects use:
# make FORCE_BUILD_CLR=1
#
#############################################################################
include ThirdParty/PSCommon/BuildSystem/CommonDefs.mak
MAJOR_VERSION = $(shell grep "define ONI_VERSION_MAJOR" Include/OniVersion.h | cut -f 2)
MINOR_VERSION = $(shell grep "define ONI_VERSION_MINOR" Include/OniVersion.h | cut -f 2)
MAINT_VERSION = $(shell grep "define ONI_VERSION_MAINT" Include/OniVersion.h | cut -f 2)
ifeq ("$(OSTYPE)","Darwin")
OS_NAME = MacOSX
else
OS_NAME = Linux
endif
PRODUCT_STRING = OpenNI-$(OS_NAME)-$(PLATFORM)-$(shell cd Packaging && python -c "import UpdateVersion; print UpdateVersion.getVersionName()" && cd ..)
FINAL_DIR = Packaging/Final
OPENNI = Source/Core
XNLIB = ThirdParty/PSCommon/XnLib/Source
DEPTH_UTILS = Source/DepthUtils
# list all drivers
ALL_DRIVERS = \
Source/Drivers/DummyDevice \
Source/Drivers/PS1080 \
Source/Drivers/PSLink \
Source/Drivers/OniFile
# list all wrappers
ALL_WRAPPERS = \
Wrappers/java/OpenNI.jni \
Wrappers/java/OpenNI.java
# list all tools
ALL_TOOLS = \
Source/Drivers/PS1080/PS1080Console \
Source/Drivers/PSLink/PSLinkConsole
# list all core projects
ALL_CORE_PROJS = \
$(XNLIB) \
$(OPENNI) \
$(DEPTH_UTILS) \
$(ALL_DRIVERS) \
$(ALL_WRAPPERS) \
$(ALL_TOOLS)
# list all samples
CORE_SAMPLES = \
Samples/SimpleRead \
Samples/EventBasedRead \
Samples/MultipleStreamRead \
Samples/MWClosestPoint \
Samples/MWClosestPointApp
# list all java samples
JAVA_SAMPLES = \
Samples/SimpleViewer.java
ifeq "$(GLUT_SUPPORTED)" "1"
ALL_TOOLS += \
Source/Tools/NiViewer
CORE_SAMPLES += \
Samples/SimpleViewer \
Samples/MultiDepthViewer \
Samples/ClosestPointViewer
else
ifeq "$(GLES_SUPPORTED)" "1"
CORE_SAMPLES +=
endif
endif
ALL_SAMPLES = \
$(CORE_SAMPLES) \
$(JAVA_SAMPLES)
# list all projects that are build
ALL_BUILD_PROJS = \
$(ALL_CORE_PROJS) \
$(ALL_SAMPLES)
ALL_PROJS = \
$(ALL_BUILD_PROJS)
ALL_PROJS_CLEAN = $(foreach proj,$(ALL_PROJS),$(proj)-clean)
# define a function which creates a target for each proj
define CREATE_PROJ_TARGET
$1:
$$(MAKE) -C $1
$1-clean:
$$(MAKE) -C $1 clean
endef
################ TARGETS ##################
.PHONY: all $(ALL_PROJS) $(ALL_PROJS_CLEAN) install uninstall clean release
# make all makefiles
all: $(ALL_PROJS)
core: $(ALL_CORE_PROJS)
samples: $(ALL_SAMPLES)
# create projects targets
$(foreach proj,$(ALL_PROJS),$(eval $(call CREATE_PROJ_TARGET,$(proj))))
# additional dependencies
$(OPENNI): $(XNLIB)
Wrappers/java/OpenNI.jni: $(OPENNI) $(XNLIB)
Source/Drivers/DummyDevice: $(OPENNI) $(XNLIB)
Source/Drivers/RawDevice: $(OPENNI) $(XNLIB)
Source/Drivers/PS1080: $(OPENNI) $(XNLIB) $(DEPTH_UTILS)
Source/Drivers/PS1080/PS1080Console: $(OPENNI) $(XNLIB)
Source/Drivers/PSLink: $(OPENNI) $(XNLIB)
Source/Drivers/PSLink/PSLinkConsole: $(OPENNI) $(XNLIB)
Source/Drivers/OniFile: $(OPENNI) $(XNLIB)
Source/Tools/NiViewer: $(OPENNI) $(XNLIB)
Samples/SimpleRead: $(OPENNI)
Samples/EventBasedRead: $(OPENNI)
Samples/MultipleStreamRead: $(OPENNI)
Samples/MWClosestPoint: $(OPENNI)
Samples/MWClosestPointApp: $(OPENNI) Samples/MWClosestPoint
Samples/SimpleViewer: $(OPENNI)
Samples/MultiDepthViewer: $(OPENNI)
Samples/ClosestPointViewer: $(OPENNI) Samples/MWClosestPoint
Samples/SimpleViewer.java: Wrappers/java/OpenNI.java
$(FINAL_DIR):
mkdir -p $(FINAL_DIR)
doc:
Source/Documentation/Runme.py
rm -f Source/Documentation/html/*.md5
release: | all doc $(FINAL_DIR)
Packaging/Harvest.py Packaging/$(PRODUCT_STRING) $(PLATFORM)
cd Packaging; tar -cjf Final/$(PRODUCT_STRING).tar.bz2 $(PRODUCT_STRING)
# clean is cleaning all projects
clean: $(ALL_PROJS_CLEAN)
顶层的Makefile主要定义了OpenNI生成的所有的so库和samples ,然后通过make 的-C option依次进入各个子目录进行make操作
# make all makefiles
all: $(ALL_PROJS)
# create projects targets
$(foreach proj,$(ALL_PROJS),$(eval $(call CREATE_PROJ_TARGET,$(proj))))
# define a function which creates a target for each proj
define CREATE_PROJ_TARGET
$1:
$$(MAKE) -C $1
$1-clean:
$$(MAKE) -C $1 clean
endef
到此我们简单的分析了OpenNI2的build system,makefile写的十分清晰简洁,阅读理解都很轻松不得不佩服开发的大神,当然类似的build system也是有的,使用最多的应该视android 的build system,有兴趣的可以去看看;
在Linux下使用console进行代码编写编译是最高效的方式,不过难免有些人还是喜欢有图形界面的IDE工具,这里在介绍下Linux下一款IDE工具kdevelop,ubuntu下的安装命令
sudo apt-get install kdevelop
KDE的界面如下,后面介绍下如何使用KDE编译OpenNI2
在Build System中选择“Custom Makefile Project Manager”点击“Finish”完成工程导入
到目前为止还没有涉及代码,下面马上就要浅析下OpenNI2的代码架构了