您的位置:首页 > 其它

利用IDEA进行JNI开发:生成Windows平台下的dll文件

2017-09-15 17:50 417 查看
由于站在巨人的肩膀上,学习过程中没遇到什么问题,所以此篇文章仅作为个人补充的内容。

阅读此篇文章前,请先站在巨人的肩膀上IntelliJ IDEA平台下JNI编程(一)—HelloWorld篇

总结下流程:

1.编写包含本地方法的类

2.使用javah获得头文件(这里不太了解的,可以看下小生我的IDEA开发,Jni中javah使用方式的探索

3.使用头文件编写.c源文件

4.使用GCC或其他编译工具(甚至你用VC,eclipse都行啊)将.c源文件编译连接为dll文件。

以下是GCC的使用参数

内容摘自GCC与MinGW的简单安装与使用

简单的GCC用法

总的来说,gcc应该是一个编译器。但整套的gcc环境并不是由gcc构成的,它是由多个包所组成的,这些包的互相作用产生了gcc的开发环境。其中,有一些包是你开发应用程序所必备的基本包,离开这些包你将无法正常使用gcc。

gcc开发环境包括如下几大包:

binary 基本包 提供基本的汇编器,连接器等

gcc 基本包 各种语言的编译器,包括C,C++,Ada,Java等

Win32api,mingwi-runtime/glibc 基本包 系统函数库

make/automake 需要包 管理项目编译的程序

gdb 附加包 调试程序

一. 常用编译命令选项

假设源程序文件名为test.c。

1. 无选项编译链接

用法:#gcc test.c

作用:将test.c预处理、汇编、编译并链接形成可执行文件。这里未指定输出文件,默认输出为a.out。编译成功后可以看到生成了一个a.out的文件。在命令行输入./a.out 执行程序。./表示在当前目录,a.out为可执行程序文件名。

2. 选项 -o

用法:#gcc test.c -o test

作用:将test.c预处理、汇编、编译并链接形成可执行文件test。-o选项用来指定输出文件的文件名。输入./test执行程序。

3. 选项 -E <大写,注意>

用法:#gcc -E test.c -o test.i

作用:将test.c预处理输出test.i文件。

4. 选项 -S <大写,注意>

用法:#gcc -S test.i

作用:将预处理输出文件test.i汇编成test.s文件。

5. 选项 -c

用法:#gcc -c test.s

作用:将汇编输出文件test.s编译输出test.o文件。

6. 无选项链接

用法:#gcc test.o -o test

作用:将编译输出文件test.o链接成最终可执行文件test。输入./test执行程序。

7. 选项-O

用法:#gcc -O1 test.c -o test

作用:使用编译优化级别1编译程序。级别为1~3,级别越大优化效果越好,但编译时间越长。输入./test执行程序。

二. 多源文件的编译方法

如果有多个源文件,基本上有两种编译方法:

[假设有两个源文件为test.c和testfun.c]

1. 多个文件一起编译

用法:#gcc testfun.c test.c -o test

作用:将testfun.c和test.c分别编译后链接成test可执行文件。

2. 分别编译各个源文件,之后对编译后输出的目标文件链接。

用法:

#gcc -c testfun.c //将testfun.c编译成testfun.o

#gcc -c test.c //将test.c编译成test.o

#gcc testfun.o test.o -o test //将testfun.o和test.o链接成test

以上两种方法相比较,第一中方法编译时需要所有文件重新编译,而第二种方法可以只重新编译修改的文件,未修改的文件不用重新编译。

三. gcc的常用编译参数

同VC,TC等编译器不同,gcc其实是可以很方便的在提示符下编译程序的。gcc在提示符下编译程序,并没有如同VC那样的冗长而晦涩的编译参数。相反,却有着比VC更灵活且简短的参数。

不得不承认,不懂gcc编译参数的人,确实会损失一些gcc的强大功能。所以,我下面简单介绍一下gcc的一些基本编译参数。这里,我以C编译器为例。

注意:gcc的编译参数是区分大小写的。

编译二进制代码

gcc -c yours.c -o yours.o

使用这段指令,gcc将会把yours.c编译成yours.o的二进制代码。其中,yours.o就类似于VC,TC中的.obj文档。

编译最简单的小程序

gcc -o yours yours.c

通过这条指令,gcc将会把yours.c源代码编译成名为yours的可执行程序。当然,您也可以将yours.c改成我们刚才介绍的yours.o文件。这样,gcc将使用编译刚才编译好的二进制文档来链接程序。这里,格式的特点是,-o 后面是一串文件列表,第一个参数是所编译程序的文件名,从第二个开始,就是您编译和连接该可执行程序所需要的二进制文档或者源代码。

编译时将自己的头文件目录设为默认头文件目录

gcc -I”Your_Include_Files_Document_Path” -c yours.c -o yours.o

这条指令中的-I参数将会把Your_Include_Files_Document_Path添加到你默认的头文件目录中。这样您将可以使用 #include <your_include.h>来导入头文件。

编译时使用自己的静态库存放目录

gcc -L”Your_Lib_Files_Document_Path” -o yours yours.o

这条指令将会让gcc在连接时除了在默认Lib存放目录中搜索指定的静态库以外,还会在Your_Lib_Files_Document_Path中搜索。

编译时使用静态连接库

gcc -lyour_lib -o yours yours.o

这条指令将会让gcc在连接时把 libyour_lib.a中您所用到的函数连接到可执行程序中。此处注意,gcc所使用的静态连接库是lib*.a格式的。在连接时,只且仅需要提供*的内容就可以了。

编译时使用优化

gcc -O2 -c yours.c -o yours.o

使用优化方式编译程序,其中除了-O2以外,还有-O3 -O1等等。他们代表不同的优化等级。最常用的,是-O2优化。当然,还有针对特殊CPU的优化,这里就不介绍了。

编译时显示所有错误和警告信息

gcc -Wall -c yours.c -o yours.o

gcc在默认情况下,将对一些如变量申请未使用这样的问题或者申请了没有给予初始值的问题忽略。但是,如果使用了-Wall参数,编辑器将列出所有的警告信息。这样,您就可以知道您的代码中有多少可能会在其他操作系统下出错的地方了。(用这个指令看看你的代码有多少地方写的不怎么合适。)

编译连接时,加入调试代码

gcc -g -o yours yours.c

正如同VC有debug编译模式一样,gcc也有debug模式。添加了-g 参数编译的可执行程序比普通程序略为大一些,其中添加了一些调试代码。这些代码将被gdb所支持。

连接时缩小代码体积

gcc -s -o yours yours.o

因为有人说Visual-MinGW生成的代码小,于是研究了一下它的编译参数,发现release模式的编译参数就加了这一项。貌似编译后的代码的确缩小了很多。

反汇编

gcc -S yours.c

用这个指令能把C语言变成汇编语言,不过不是常见的Intel语法,而是AT&T语法。两者的语法有很大的区别。

获得帮助

gcc --help

这条指令从意思上就能看出,获得gcc的帮助信息。如果您有什么特殊需要,也许这个指令能帮上点小忙。

总结:

gcc的编译参数是可以组合起来的,如:

gcc yours.c -o yours -Wall -s -O2

以下是MinGW的使用参数

内容摘自CodeBlocks综合设置
“由于近期有项目要用到JNI,但用CodeBlocks生成的dll一直不能被Java调用,而Vs、Vc却可以,后来经过一番折腾,终于弄好了。原来JNI想要VC风格的函数声明,但是CodeBlocks默认的GCC编译器生成的是GCC风格的,所以需要用编译选项修改生成风格、指定链接参数,才能使生成的dll可以被Java成功调用。否则会报错误”
网上有两种参数模式,都测试在codeblocks,都能够生成供Java调用的dll

1:-Wl,--kill-at

2:-Wl,--add-stdcall-alias

stdcall与_cdecl是两种不同的函数调用约定,区别在函数参数入栈的顺序,由调用函数还是被调用函数将参数弹出栈,以及产生函数修饰名的方法。

jni使用的dll库函数默认使用stdcall调用约定,stdcall的调用约定意味着:

1.参数从右向左压入堆栈。

2.函数自身修改堆栈。

3.函数名自动加前导的下划线,后面紧跟一个@符号,其后紧跟着参数的尺寸。gcc编译的时候可能不使用stdcall,百度说gcc默认是_cdecl约定,加上这个链接参数就可以了。

(所以说,MinGW似乎并没有默认其中一个,测试的时候未指定报错:error: ld returned 1 exit status)

-shared:使其生成动态库

-static:使其生成静态库

动态库和静态库区别:

静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。

动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。

当静态库和动态库同名时, gcc命令将优先使用动态库。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: