在用SourceInsight分析VLC-Android源码过程中,有几个宏定义在源代码中一直没有找到出处,比如HAVE_DYNAMIC_PLUGINS和__PLUGIN__,以及MODULE_NAME和MODULE_STRING,在网上找了VLC源码的分析资料都是老版本的,老版本中MODULE_NAME在每一个MODULES模块下面都有定义,MODULE_STRING也有如下宏定义:
#define STRINGIFY(z) UGLY_KLUDGE(z) #define UGLY_KLUDGE(z) #z #define MODULE_STRING STRINGIFY(MODULE_NAME)但是在新版本的VLC源码中,MODULE_NAME除了在vlc/src/libvlc-modules.c文件中有#define MODULE_NAME main 的定义外,其他再无出处,MODULE_STRING更是没有找到任何定义,后来发现实际上GCC在编译时可以向源文件中传递宏定义,形式如gcc -Dmacro 或者 gcc -Dmacro=defn,于是去看查看makefile文件,果然在modules/common.am文件中有如下发现
# Module name from object or executable file name. MODULE_NAME = $$(p="$@"; p="$${p\#\#*/}"; p="$${p\#lib}"; echo "$${p%_plugin*}") AM_CPPFLAGS = \ -DMODULE_NAME=$(MODULE_NAME) \ -DMODULE_NAME_IS_$(MODULE_NAME) \ -DMODULE_STRING=\"$(MODULE_NAME)\" if HAVE_DYNAMIC_PLUGINS AM_CPPFLAGS += -D__PLUGIN__ endif实际上问题已经逐渐明朗,就是在编译过程中gcc向源文件传递了宏定义,为了查看编译选项,分别对VLC-Android和VLC的vlc/modules/demux/live555.cpp的的编译选项进行了输出,这里做的办法是对vlc/modules/demux/makefile.in文件进行了修改,找到编译目标
liblive555_plugin_la-live555.lo: live555.cpp
@am__fastdepCXX_TRUE@ echo $(AM_V_CXX) $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblive555_plugin_la_CPPFLAGS) $(CPPFLAGS) $(liblive555_plugin_la_CXXFLAGS) $(CXXFLAGS) -E -o testlive555.txt live555.cpp并在编译前用script -a test.txt命令进行终端输出记录,得到如下结果
VLC-Android输出如下:
echo @echo " CXX " liblive555_plugin_la-live555.lo; /androidApp/android-ndk-r8b/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin//arm-linux-androideabi-g++ --sysroot=/androidApp/android-ndk-r8b/platforms/android-9/arch-arm -DHAVE_CONFIG_H -I. -I../../../modules/demux -I../.. -DMODULE_NAME=$(p="liblive555_plugin_la-live555.lo"; p="${p##*/}"; p="${p#lib}"; echo "${p%_plugin*}") -DMODULE_NAME_IS_$(p="liblive555_plugin_la-live555.lo"; p="${p##*/}"; p="${p#lib}"; echo "${p%_plugin*}") -DMODULE_STRING=\"$(p="liblive555_plugin_la-live555.lo"; p="${p##*/}"; p="${p#lib}"; echo "${p%_plugin*}")\" -I../../../include -I../../include -I/androidApp/android-ndk-r8b/sources/cxx-stl/gnu-libstdc++/4.6/include -I/androidApp/android-ndk-r8b/sources/cxx-stl/gnu-libstdc++/4.6/libs/armeabi-v7a/include -I/vlc-android/android/vlc/contrib/arm-linux-androideabi/include -I/vlc-android/android/vlc/contrib/arm-linux-androideabi/include/liveMedia -I/vlc-android/android/vlc/contrib/arm-linux-androideabi/include/groupsock -I/vlc-android/android/vlc/contrib/arm-linux-androideabi/include/BasicUsageEnvironment -I/vlc-android/android/vlc/contrib/arm-linux-androideabi/include/UsageEnvironment -g -O2 -fstrict-aliasing -funsafe-math-optimizations -mlong-calls -I/vlc-android/android/vlc/contrib/arm-linux-androideabi/include -Wall -Wextra -Wsign-compare -Wundef -Wpointer-arith -Wvolatile-register-var -fvisibility=hidden -ffast-math -funroll-loops @echo CXX liblive555_plugin_la-live555.lo
echo @echo " CXX " liblive555_plugin_la-live555.lo; g++ -DHAVE_CONFIG_H -I. -I../.. -DMODULE_NAME=$(p="liblive555_plugin_la-live555.lo"; p="${p##*/}"; p="${p#lib}"; echo "${p%_plugin*}") -DMODULE_NAME_IS_$(p="liblive555_plugin_la-live555.lo"; p="${p##*/}"; p="${p#lib}"; echo "${p%_plugin*}") -DMODULE_STRING=\"$(p="liblive555_plugin_la-live555.lo"; p="${p##*/}"; p="${p#lib}"; echo "${p%_plugin*}")\" -D__PLUGIN__ -I../../include -I../../include -I/home/vlc/contrib/i486-linux-gnu/include -I/home/vlc/contrib/i486-linux-gnu/include/liveMedia -I/home/vlc/contrib/i486-linux-gnu/include/groupsock -I/home/vlc/contrib/i486-linux-gnu/include/BasicUsageEnvironment -I/home/vlc/contrib/i486-linux-gnu/include/UsageEnvironment -g -O2 -I/home/vlc/contrib/i486-linux-gnu/include -Wall -Wextra -Wsign-compare -Wundef -Wpointer-arith -Wvolatile-register-var -fvisibility=hidden -ffast-math -funroll-loops -fomit-frame-pointer @echo CXX liblive555_plugin_la-live555.lo
VLC-Android中的该文件内容为:
extern "C" int vlc_entry__live555 (vlc_set_cb, void *); extern "C" int vlc_entry__live555 (vlc_set_cb vlc_set, void *opaque) { module_t *module; module_config_t *config = __null; if (vlc_set (opaque, __null, VLC_MODULE_CREATE, &module)) goto error; if (vlc_set (opaque, module, VLC_MODULE_NAME, ("live555"))) goto error; ...而VLC中的该文件内容为:
extern "C" __attribute__((visibility("default"))) int vlc_entry__2_1_0a (vlc_set_cb, void *); extern "C" __attribute__((visibility("default"))) int vlc_entry__2_1_0a (vlc_set_cb vlc_set, void *opaque) { module_t *module; module_config_t *config = __null; if (vlc_set (opaque, __null, VLC_MODULE_CREATE, &module)) goto error; if (vlc_set (opaque, module, VLC_MODULE_NAME, ("live555"))) goto error; ...
# define MODULE_SYMBOL 2_1_0a # define MODULE_SUFFIX "__2_1_0a" #define CONCATENATE( y, z ) CRUDE_HACK( y, z ) #define CRUDE_HACK( y, z ) y##__##z #ifdef __PLUGIN__ # define __VLC_SYMBOL( symbol ) CONCATENATE( symbol, MODULE_SYMBOL ) #else # define __VLC_SYMBOL( symbol ) CONCATENATE( symbol, MODULE_NAME ) #endif
即定义了__PLUGIN__,那么就用MODULE_SYMBOL,否则就用MODULE_NAME,那么__PLUGIN__又在哪里定义了呢?为什么VLC-Android和VLC又不同呢,我们回到上面的源头,发现
if HAVE_DYNAMIC_PLUGINS AM_CPPFLAGS += -D__PLUGIN__ endif
而实际上HAVE_DYNAMIC_PLUGINS是在运行configure过程中对其进行配置的。
我们在vlc/configure.ac中发现有如下代码:
dnl Check for dynamic plugins LIBDL="" have_dynamic_objects="no" VLC_SAVE_FLAGS AC_SEARCH_LIBS(dlopen, [dl svld], [ AS_IF([test "$ac_cv_search_dlopen" != "none required"], [ LIBDL="$ac_cv_search_dlopen" ]) have_dynamic_objects="yes" ]) VLC_RESTORE_FLAGS # Windows AS_IF([test "${SYS}" = "mingw32"], [ LIBDL="" have_dynamic_objects="yes" #assume we can use shared objects ]) AS_IF([test "${enable_shared}" = "no"], [ have_dynamic_objects=no ]) AM_CONDITIONAL(HAVE_DYNAMIC_PLUGINS, [test "${have_dynamic_objects}" != "no"])
sh $VLC_SOURCEDIR/configure --host=$TARGET_TUPLE --build=x86_64-unknown-linux $EXTRA_PARAMS \ --enable-live555 --enable-realrtsp \ --enable-avformat \ --enable-swscale \ --enable-avcodec \ --enable-opus \ --enable-opensles \ --enable-android-surface \ --enable-mkv \ --enable-taglib \ --enable-dvbpsi \ --disable-vlc --disable-shared \
--enable-shared[=PKGS] build shared libraries [default=yes] --enable-static[=PKGS] build static libraries [default=no] --with-pic try to use only PIC/non-PIC objects [default=use both] --enable-fast-install[=PKGS] optimize for fast installation [default=yes]