输出编译器预处理器的中间文件
2015-10-04 11:55
344 查看
问题描述
这几天在尝试阅读一些OpenJDK的源代码,但是发现Source Insight工具无法跳转到某些些函数,类型的定义上去。例如:JNI_ENTRY(void, jni_SetStaticObjectField(JNIEnv *env, jclass clazz, jfieldID fieldID, jobject value)) JNIWrapper("SetStaticObjectField"); JNIid* id = jfieldIDWorkaround::from_static_jfieldID(fieldID); if (JvmtiExport::should_post_field_modification()) { jvalue field_value; field_value.l = value; JvmtiExport::jni_SetField_probe(thread, NULL, NULL, id->holder(), fieldID, true, 'L', (jvalue *)&field_value); } id->holder()->java_mirror()->obj_field_put(id->offset(), JNIHandles::resolve(value)); JNI_END我们知道,这种宏定义的代码导致了阅读上的困难。简单查看一下,是下面的宏带来的问题:
#define JNI_ENTRY(result_type, header) \ JNI_ENTRY_NO_PRESERVE(result_type, header) \ WeakPreserveExceptionMark __wem(thread); #define JNI_ENTRY_NO_PRESERVE(result_type, header) \ extern "C" { \ result_type JNICALL header { \ JavaThread* thread=JavaThread::thread_from_jni_environment(env); \ assert( !VerifyJNIEnvThread || (thread == Thread::current()), "JNIEnv is only valid in same thread"); \ ThreadInVMfromNative __tiv(thread); \ debug_only(VMNativeEntryWrapper __vew;) \ VM_ENTRY_BASE(result_type, header, thread) #define JNI_END } }我需要输出宏展开后的中间代码,才能流畅的阅读这种代码。
解决方法
我们都知道,现代编译器都支持输出预处理器的中间结果,而预处理过程不涉及程序的编译和链接,因而与平台无关。本文以Visual Studio 2012为例来说明如何将OpenJDK的jni.cpp文件预处理生成中间结果文件的。步骤1:
在\jdk8u\hotspot\src\share\vm\prims\jni.cpp相同的目录下创建一个Makefile文件,内容如下:CFLAGS_JDKEXE = -DCC_INTERP -D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE -D_LP64=1 -D_LITTLE_ENDIAN -DLINUX -IG:\OpenJDK8\jdk8u\build\linux-x86_64-normal-server-release\jdk\include -IG:\OpenJDK8\jdk8u\build\linux-x86_64-normal-server-release\jdk\include\linux -IG:\OpenJDK8\jdk8u\jdk\src\share\javavm\export -IG:\OpenJDK8\jdk8u\jdk\src\solaris\javavm\export -IG:\OpenJDK8\jdk8u\jdk\src\share\native\common -IG:\OpenJDK8\jdk8u\jdk\src\solaris\native\common -IG:\OpenJDK8\jdk8u\hotspot\src\share\vm\runtime -IG:\OpenJDK8\jdk8u\hotspot\src\share\vm\precompiled -IG:\OpenJDK8\jdk8u\hotspot\src\share\vm -IG:\OpenJDK8\jdk8u\build\linux-x86_64-normal-server-release\hotspot\linux_amd64_compiler2\generated\ preprocessor: cl -C -EP $(CFLAGS_JDKEXE) jni.cpp -P使用Makefile的好处是:在命令行输入简单nmake命令,就可以自动的执行这个Makefile定义的预处理动作。
步骤2:
如图所示,进入Visual Studio2012命令行,注意是“Developer CommandPrompt for VS2012”启动的命令行,而不是"cmd"启动的命令行;并且在Windows使用的命令是nmake而不是Linux上的make。期间可能有编译错误(例如,需要用“-I”来添加包含路径),需要自行解决编译错误。
生成的中间文件是jni.i文件,用文本编辑工具打开这个".i"文件就可以发现下面的函数了:
extern "C" { void jni_SetStaticObjectField(JNIEnv *env, jclass clazz, jfieldID fieldID, jobject value) { .... } }这样,Source Insight就能够正确jni_SetStaticObjectField函数了。另外,“.i”文件通常展开了很多"#include"指令包含的文件,很容易把这些展开的内容恢复成原来的"#include"语句,进而可以考虑用这个".i"文件来替换原来的".cpp"文件,方便代码阅读。
一点补充
关于预编译器的命令选项,请用“cl /?”帮助来查看。值得注意的是: "-EP"和"-P"都是必需的:"-EP"用于删除“#line 1...”输出; "-P"用于自动输出到“.i”文件。Linux上应该也有相似的编译选项,参考GCC的选项即可完成相似的工作。
相关文章推荐
- 20135306黄韧 信息安全系统设计基础第三周学习总结
- hdu1754 I hate it线段树模板 区间最值查询
- LintCode "Binary Representation"
- hdu1754 I hate it线段树模板 区间最值查询
- 证券基础--股票发行方式
- Odoo9发行说明
- 软件工程之面向过程的软件设计方法(二)
- J2EE学习路线
- 深入详解保护模式下的内存分页机制
- 证书
- andriod 实现新浪、QQ场地、朋友微信圈、微信朋友分享功能
- DirectX11 雾
- Hbase笔记二:简明系统架构
- 获取函数或程序相关的源码
- Matrix学习
- 经典算法题——第十三题 赫夫曼树
- MyEclipse 2014 破解图文详细教程
- Hbase笔记一:了解Hbase
- Java中有关Null的9件事
- 96. Unique Binary Search Trees (Tree; DFS)