编译系统分析java
1.configurelinux
pjsip是基于autoconf与automak的编译系统,首先用./configure 传入参数,而后传入build.mak.in,最后生成build.mak,好比,咱们用./configure --enable_shared,传入一个enable_shared参数,在aconfigure.ac中,有以下一段:android
AC_SUBST(ac_shared_libraries)git AC_ARG_ENABLE(shared,架构 AC_HELP_STRING([--enable-shared],app [Build shared libraries]),eclipse [if test "$enable_shared" = "yes"; thenide [ac_shared_libraries=1]svn CFLAGS="$CFLAGS -fPIC"ui AC_MSG_RESULT([Building shared libraries... yes]) fi], AC_MSG_RESULT([Building shared libraries... no]) ) |
其中若是检测到了enable_shared=yes,那么就会将ac_shared_libraries=1,这个变量咱们从build.mak.in中能够看到。
ifeq (@ac_shared_libraries@,1) export PJ_SHARED_LIBRARIES := 1 endif |
它实际上是控制build.mak中是否输出PJ_SHARED_LIBRARIES这个变量,若是没有定义,那么最终build.mak中生成的是
ifeq (,1) export PJ_SHARED_LIBRARIES := 1 endif |
2.目标编译及rules.mak
若是咱们没有定义上面的enable_shared参数,那么最终咱们为每一个模块生成的,是一个静态库.a文件。顶层Makefile进入,会进入每一个模块目录下执行make
all clean dep depend print: for dir in $(DIRS); do \ if $(MAKE) $(MAKE_FLAGS) -C $$dir $@; then \ true; \ else \ exit 1; \ fi; \ done |
所以,咱们分析一个模块的编译过程就够了,以pjlib为例。
其实对于每一个模块好比pjlib,在pjlib/build目录下都有一个Makefile文件,对于每一个模块的编译流程其实都是千篇一概的,好比收集objs目标文件,创建依赖,而后编译.o,最终打包成一个静态库,从这个流程中咱们知道除了收集objs目标和一些特定的编译参数以外,其余的过程都同样,所以,这一块代码,被pjsip独立出来,放在了build/rules.mak中。咱们分析一下pjlib的makefile.
1.包含rules.mak,导出最终目标给rules.mak
RULES_MAK := $(PJDIR)/build/rules.mak
export PJLIB_LIB := libpj-$(TARGET_NAME)$(LIBEXT) |
2.收集OBJS,定义编译选项,并所有导出,不导出rules.mak看不到哦
export PJLIB_SRCDIR = ../src/pj export PJLIB_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \ activesock.o array.o config.o ctype.o errno.o except.o fifobuf.o \ guid.o hash.o ip_helper_generic.o list.o lock.o log.o os_time_common.o \ os_info.o pool.o pool_buf.o pool_caching.o pool_dbg.o rand.o \ rbtree.o sock_common.o sock_qos_common.o sock_qos_bsd.o \ ssl_sock_common.o ssl_sock_ossl.o ssl_sock_dump.o \ string.o timer.o types.o export PJLIB_CFLAGS += $(_CFLAGS) export PJLIB_CXXFLAGS += $(_CXXFLAGS) export PJLIB_LDFLAGS += $(_LDFLAGS) |
3.将实际编译任务交给rules.mak
$(PJLIB_LIB) $(PJLIB_SONAME): $(MAKE) -f $(RULES_MAK) APP=PJLIB app=pjlib $(subst /,$(HOST_PSEP),$(LIBDIR)/$@) |
能够看到,咱们传入了两个参数APP以及app,这就是rules.mak能够复用于编译全部模块的缘由,另外在最后咱们指定了实际的编译目标,就是$(LIBDIR)/$@
这个目标其实就是PJLIB_LIB,libpj-$(TARGET_NAME)$(LIBEXT),这个TARGET_NAME也是能够在configure指定的,能够是win32,cygw之类的,若是没有指定就是auto自动识别,在build.mak中能够看到是arm-unknown-linux-androideabi,因此对于pjlib,咱们最终生成的静态库目标是../lib/libpj-arm-unknown-linux-androideabi.a
4.rules.mak编译过程
ifneq ($(LIB),) $(subst /,$(HOST_PSEP),$(LIBDIR)/$(LIB)): $(OBJDIRS) $(OBJS) $($(APP)_EXTRA_DEP) if test ! -d $(LIBDIR); then $(subst @@,$(subst /,$(HOST_PSEP),$(LIBDIR)),$(HOST_MKDIR)); fi $(AR) $(AR_FLAGS) $@ $(OBJS) $(RANLIB) $@ endif |
很方便就能够在里面找到,咱们实际传入的目标,里面的依赖$(objs)就是咱们导出的,所以它会自动定位到下面的编译目标。
$(OBJDIR)/%$(OBJEXT): $(SRCDIR)/%.c $(CC) $($(APP)_CFLAGS) \ $(CC_OUT)$(subst /,$(HOST_PSEP),$@) \ $(subst /,$(HOST_PSEP),$<) |
编译完后最终调用AR,生成静态库。
pjsip代码很容易下,在官网用git下载就行,2.x版本已经支持video,从配置和编译上,比之前复杂多了,这里咱们下下来的最新版本是2.4
1.编译前配置
配置config_site.h文件,这是个啥呢,它是对本地库的自定义配置,全部的自定义配置都必须放在这个文件中,由于这个文件并不在svn仓库中,因此随便修改不用担忧在同步svn时会被冲掉。
这个config_site.h文件中能够复写如下文件中的宏:
· PJLIB Configuration (the pjlib/config.h file)
· PJLIB-UTIL Configuration (the pjlib-util/config.h file)
· PJNATH Configuration (the pjnath/config.h file)
· PJMEDIA Configuration (the pjmedia/config.h file)
· PJSIP Configuration (the pjsip/sip_config.h file)
同时,这个pjlib/include/pj/目录下已经有一个config_site_sample.h.咱们先建立,而后包含这个文件就行。
在config_site.h中添加android架构以及media支持。
#define PJ_CONFIG_ANDROID 1 #include <pj/config_site_sample.h>
#define PJMEDIA_HAS_VIDEO 1 |
2.添加NDK路径支持
编译时须要用到环境变量中的NDK_PATH以及两个变量TARGET_GET和APP_PLATFORM,这里咱们直接写入到配置文件configue-android中。
NDK_PATH=$(dirname $(which ndk-build)) TARGET_ABI=armeabi-v7a APP_PLATFORM=android-19 |
而后将NDK_PATH导出
export ANDROID_NDK_ROOT=${NDK_PATH} |
固然,前提是这里咱们必需要先将ndk path配置到环境变量PATH中,在/etc/profile中配置
3.编译
$ cd /path/to/your/pjsip/dir |
编译完成以后,若是咱们定义上面的enable-shared的话,会为每一个模块生成一个.a的静态库。那编译成静态库有什么意义呢,为何不默认编成动态库?由于对于Android这种系统来讲,默认编成动态库,那么Android也没法使用,由于这样的动态库是纯C库,java层是没法调用的,所以,pjsip使用了swig,自动化的为全部导出接口生成了android使用的JNI层文件,并与前面的全部静态库一块儿,编译成了android平台的动态库。
4.swig部分编译
咱们看一下pjsip-apps/src/swig/Makefile
若是识别为android平台,它会去java子目录执行make -C,继续看java/Makefile.
首先定义全局目标
all: $(LIBPJSUA2_SO) java
其中LIBPJSUA2_SO就是libpjsua2.so,首先就是要生成.so文件,这个文件的目标从哪来呢?
$(LIBPJSUA2_SO): $(OUT_DIR)/pjsua2_wrap.o $(PJ_CXX) -shared -o $(LIBPJSUA2_SO) $(OUT_DIR)/pjsua2_wrap.o \ $(MY_CFLAGS) $(MY_LDFLAGS) |
咱们能够看到它依赖于pjsua2_wrap.o(swig生成的中间接口目标),还有MY_LDFLAGS.
MY_LDFLAGS := $(PJ_LDXXFLAGS) $(PJ_LDXXLIBS) $(MY_JNI_LDFLAGS) $(LDFLAGS) |
里面包含了一个PJ_LDXXLIBS,这个定义在build.mak中,引用的变量以下
export APP_LDLIBS := $(PJSUA_LIB_LDLIB) \ $(PJSIP_UA_LDLIB) \ $(PJSIP_SIMPLE_LDLIB) \ $(PJSIP_LDLIB) \ $(PJMEDIA_CODEC_LDLIB) \ $(PJMEDIA_LDLIB) \ $(PJMEDIA_VIDEODEV_LDLIB) \ $(PJMEDIA_AUDIODEV_LDLIB) \ $(PJMEDIA_LDLIB) \ $(PJNATH_LDLIB) \ $(PJLIB_UTIL_LDLIB) \ $(APP_THIRD_PARTY_LIBS)\ $(APP_THIRD_PARTY_EXT)\ $(PJLIB_LDLIB) \ |
从中咱们能够看到,几乎全部编出来的静态库,都被它打包到一块儿了。
到这里,整个编译流程几乎已经肯定,咱们在swig目录下直接make, so文件出来了,咱们能够将android工程copy出来到eclipse或者android studio下面编译了。
5.android app注册
原始demo注册很蛋疼,选项根本不知道填什么
ID : |
sip:010101@58.58.32.154 |
Registrar: |
sip:58.58.32.154 |
Proxy: |
sip:58.58.32.154 |
Username |
010101 |
Password: |
**** |