C++动态phpcms加载第三方类库库?

下次自动登录
现在的位置:
& 综合 & 正文
JNI技术之Java调用C/C++编写的第三方dll-动态链接库
JNI技术之Java调用C/C++编写的第三方dll动态链接库
JNI(Java Native Interface)简称JNI,是中文为JAVA本地调用。从Java1.1开始,Java
NativeInterface(JNI)标准成为平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。
使用与本地已编译的代码交互,通常会丧失平台可移植性。但是,有些情况下这样做是可以接受的,甚至是必须的。例如,使用一些旧的库,与硬件、进行交互,或者为了提高程序的性能。JNI标准至少保证能工作在任何Java 实现下。
JNI设计目的:标准的类库可能不支持你的程序所需的特性。或许你已经有了一个用其他语言写成的库或程序,而你希望在程序中使用它。你可能需要用底层语言实现一个小型的时间敏感代码,比如汇编,然后在你的程序中调用这些功能。JNI就是设计用来解决此类问题的。
下面是从网上摘取的JNI工作示意图
图1 JNI的工作模式
个人理解:
JNI就是java调用本地方法的技术,最简单的来说,java运行一个程序需要要和不同的系统平台打交道,在windows里就是和windows平台底层打交道,mac就是要和mac打交道,jvm就是通过大量的jni技术使得java能够在不同平台上运行。而使用了这技术的一个标志就是native,如果一个类里的一个方法被native修饰,那就说明这个方法是jni来实现的,他是通过本地系统api里的方法来实现的。当然这个本地方法可能是c或者C++,当然也可能是别的语言。JNI是java跨平台的基础,jvm通过在不同系统上调用不同的本地方法使得jvm可以在不同平台间移植。
JAVA的跨平台的特性深受java程序员们的喜爱,但正是由于它为了实现跨平台的目的,使得它和本地机器的各种内部联系变得很少,大大约束了它的功能,比如与一些硬件设备通信,往往要花费很大的精力去设计流程编写代码去管理设备端口,而且有一些设备厂商提供的硬件接口已经经过一定的封装和处理,不能直接使用java程序通过端口和设备通信,这种情况下就得考虑使用java程序去调用比较擅长同系统打交道的第三方程序,从1.1版本开始的JDK提供了解决这个问题的技术标准:JNI技术.
JNI是Java NativeInterface(Java本地接口)的缩写,本地是相对于java程序来说的,指直接运行在操作系统之上,与操作系统直接交互的程序.从1.1版本的JDK开始,JNI就作为标准平台的一部分发行.在JNI出现的初期是为了Java程序与本地已编译语言,尤其是C和C++的互操作而设计的,后来经过扩展也可以与c和c++之外的语言编写的程序交互,例如Delphi程序.
使用JNI技术固然增强了java程序的性能和功能,但是它也破坏了java的跨平台的优点,影响程序的可移植性和安全性,例如由于其他语言(如C/C++)可能能够随意地分配对象/占用内存,Java的指针安全性得不到保证.但在有些情况下,使用JNI是可以接受的,甚至是必须的,例如上面提到的使用java程序调用硬件厂商提供的类库同设备通信等,目前市场上的许多读卡器设备就是这种情况.在这必须使用JNI的情况下,尽量把所有本地方法都封装在单个类中,这个类调用单个的本地库文件,并保证对于每种目标操作系统,都可以用特定于适当平台的版本替换这个文件,这样使用JNI得到的要比失去的多很多.
比如,一般设备商会提供两种类型的类库文件,windows系统的会包含.dll/.h/.lib文件,而linux系统的会包含.so/.a文件,我们不能直接使用java程序通过端口和设备通信,这种情况下就得考虑使用java程序的JNI技术去调用比较擅长同系统打交道的第三方程序。
二 应用实例
最近在用weka做一个数据挖掘相关的项目,不得不说,weka还是一个不错的开放源代码库,提供了很多最常用的分类和聚类。
在我的项目中要用到一个聚类算法,Affinity Propagation(AP),由多伦多大学的Brendan J. Frey发表于2007年。相比其他的聚类算法,AP算法的聚类结果更加准确。在AP的官方网站公布了AP算法的动态链接库,我的目标就是实现在Java工程中调用这个动态链接库。在网上查了资料,发现,如果仅仅是想调用Windows的Native API还是比较省事的,这里我主要针对第三方DLL的调用。
这里主要用的方法是JNI。在网上查资料时看到很多人说用JNI非常的复杂,不仅要看很多的文档,而且要非常熟悉C/C++编程。恐怕有很多人在看到诸如此类的评论时已经决定绕道用其他方法了。但是,假如你要实现的功能并不复杂(简单的参数传递,获取返回值等等),我还是支持使用这个方法的。
下面就举具体的例子说明一下使用步骤,具体详见博文 。
【上篇】【下篇】在这个例子中主要是调用了 math
库(libm.so)中的“cosf”函数,dlopen函数的第二个参数表示加载库文件的模式,主要有两种:RTLD_LAZY
暂缓决定,等有需要时再解出符号;RTLD_NOW 立即决定,返回前解除所有未决定的符号。另外记得引用包含API的头文件“#include
&dlfcn.h&”(^_^)。
#include &stdio.h&
#include &dlfcn.h&
int main(int argc, char *argv[]){
void * libm_handle = NULL;
float (*cosf_method)(float);
char *errorI
// dlopen 函数还会自动解析共享库中的依赖项。这样
,如果您打开了一个依赖于其他共享库的对象,它就会自动加载它们。
// 函数返回一个句柄,该句柄用于后续的 API 调用
libm_handle = dlopen("libm.so", RTLD_LAZY );
// 如果返回 NULL 句柄,表示无法找到对象文件,过程结束。否则的话,将会得到对象的一个句柄,可以进一步询问对象
if (!libm_handle){
// 如果返回 NULL 句柄,通过dlerror方法可以取得无法访问对象的原因
printf("Open Error:%s.\n",dlerror());
// 使用 dlsym 函数,尝试解析新打开的对象文件中的符号。您将会得到一个有效的指向该符号的指针,或者是得到一个 NULL 并返回一个错误
cosf_method = dlsym(libm_handle,"cosf");
errorInfo = dlerror();// 调用dlerror方法,返回错误信息的同时,内存中的错误信息被清空
if (errorInfo != NULL){
printf("Dlsym Error:%s.\n",errorInfo);
// 执行“cosf”方法
result = (*cosf_method)(0.0);
printf("result = %f.\n",result);
// 调用 ELF 对象中的目标函数后,通过调用 dlclose 来关闭对它的访问
dlclose(libm_handle);
浏览: 183787 次
来自: 上海
浪费感情!
太简单了!
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'0、前言笔者为客户提供C/C++动态链接库调用WEBSOCKET功能时,最初错误地认定客户采用静态加载的方式使用DLL库,导致使用其它编程语言的客户无法使用。考虑到为客户服务常常要跨语言和跨IDE,最好的DLL库的使用方式是动态调用,并且要减少DLL库的依赖库,避免对Windows下VS自带库的调用。本文针对动态调用提出一起DLL编写注意事项。1、静态调用与动态调用1.1 静态调用使用这种方式调用DLL库的步骤(摘自网上)为,youApp是你DLL的工程名,需要dll\lib\h头文件:①把你的youApp.DLL拷到你目标工程(需调用youApp.DLL的工程)的Debug目录下;②把你的youApp.lib拷到你目标工程(需调用youApp.DLL的工程)目录下;③把你的youApp.h(包含输出函数的定义)拷到你目标工程(需调用youApp.DLL的工程)目录下;④打开你的目标工程选中工程,选择Visual C++的Project主菜单的Settings菜单;⑤执行第4步后,VC将会弹出一个对话框,在对话框的多页显示控件中选择Link页。然后在Object/library modules输入框中输入:youApp.lib⑥选择你的目标工程Head Files加入:youApp.h文件;⑦最后在你目标工程(*.cpp,需要调用DLL中的函数)中包含你的:#include "youApp.h"此种调用方式的优点是:DLL的函数名是通过.h文件和lib文件寻找到,实际的接口名可能和函数名不一致,但是不会导致无找不到入口的情况。它的缺点就是:非C/C++语言无法加载.h头文件,跨语言时会遇到各种问题。1.2 动态调用动态调用的方法,先LoadLibrary,再GetProcAddress(即找到DLL中函数的地址),不用后FreeLibrary。具体示例代码(摘自网上)如下:
HINSTANCE hDllInst = LoadLibrary("youApp.DLL");
if(hDllInst){
typedef DWORD (WINAPI *MYFUNC)(DWORD,DWORD);
MYFUNC youFuntionNameAlias = NULL; // youFuntionNameAlias 函数别名
youFuntionNameAlias = (MYFUNC)GetProcAddress(hDllInst,"youFuntionName");
// youFuntionName 在DLL中声明的函数名
if(youFuntionNameAlias){
youFuntionNameAlias(param1,param2);
FreeLibrary(hDllInst);
动态调用优点在于:不需要依赖.h和lib文件,更加便捷。缺点在于:生成DLL库接口名需要和函数名一致,否则无法找到函数的入口点。2、DLL库接口名和函数名的关系2.1 接口名和函数名分析如果接口名和函数名不一致找不到dll中的函数,出现&无法定位程序输入点&的问题,如下图所示。对于DLL库,查看它的接口名称可以使用Depends工具,如需要可以联系我。使用depends可以看到如下示例,在这个例子中Function的名称即接口名称,它和函数名称是一致,这样可以正常调用DLL。而函数名称与接口名不一致情况笔记忘了保存,举例说明,sendMessage的Function name为_sendMessage@12,其中符号"_"和"@12"导致接口名和函数名不一致。这种情况使用在GetProcAddress函数中将函数名作为参数是无法找到函数入口点的。所以使用动态调用时,最好确保函数名和接口名的一致。2.2 如何确保函数名和接口名一致C++编译器在生成DLL时,会对导出的函数进行名字改编,并且不同的编译器使用的改编规则不一样,因此改编后的名字也是不同的(一般涉及到C++ 中的重载等)。一般而言,生成dll有两种方法,一是使用def文件,二是在函数定义前加_declspec(dllexport)。如果要导出C++文件中的函数,并且不让编译器改动函数名,用def文件导出函数并且在函数名前加extern "C"。def的定义示例如下:
LIBRARY PrinterManager
initPrinterManager
setRecvDataCallback
sendMessage
closePrinterManager
关于DLL导出名如下图(来源于网上文章),如果采用extern "C"和def则函数名和接口名一致,C++采用_declspec(dllexport)即函数名和接口名一致。其它情况函数名会被编译器改编。3、参数入栈顺序(__stdcall和__cdecl),参考网上文章接口函数最好不用使用std中的容器,如string和vector等。这是因为计算机给这个函数传递参数,传递参数的工作必须由函数调用者和函数本身来协调,即函数传递参数的方式需要一致才能正确传递参数。计算机使用栈来支持参数传递,函数调用时,调用者依次把参数压栈,然后调用函数,函数被调用以后,在堆栈中取得数据,并进行计算。函数计算结束以后,或者调用者、或者函数本身修改堆栈,使堆栈恢复原装。问题出现了,当参数个数多于一个时(数组为多个参数),按照什么顺序把参数压入堆栈,函数调用后,由谁来把堆栈恢复原装&在高级语言中,通过函数调用约定来说明这两个问题。常见的调用约定有:stdcall、cdecl、fastcall等,本文仅介绍stdcall和cdecl。3.1 __stdcall声明方法:int __stdcall function(int a,int b)__stdcall的调用约定意味着:1)参数从右向左压入堆栈,2)函数自身修改堆栈 3)函数名自动加前导的下划线,后面紧跟一个@符号,其后紧跟着参数的尺寸。在DLL的生成代码中和使用代码中都需要声明__stdcall。跨语言推荐使用该方法。3.2&__cdeclcdecl调用约定又称为C调用约定,是C语言缺省的调用约定,它的定义语法是:& & int function (int a ,int b) //不加修饰就是C调用约定& & int __cdecl function(int a,int b)//明确指出C调用约定参数采用从右到左的压栈方式,传送参数的内存栈由调用者维护。_cedcl约定的函数只能被C/C++调用,故跨语言不应该使用该方法。4、减少DLL库的依赖库,避免对Windows下VS自带库的调用如果对外提供的DLL库使用VS自带库,那么其它语言很有可能就因为没有VS自带库而无法运行。根据笔者的经验,以下两个步骤一定要使用来将减少DLL库的依赖。4.1 步骤一:发布注意使用release方式而不能是debug选择方法如下图所示:4.2 步骤二:将项目中的MD改为MT/MT是 "multithread, static version & 意思是多线程静态的版本,定义了它后,编译器把LIBCMT.lib 安置到OBJ文件中,让链接器使用LIBCMT.lib 处理外部符号。/MD是 "multithread- and DLL-specific version& ,意思是多线程DLL版本,定义了它后,编译器把MSVCRT.lib 安置到OBJ文件中,它连接到DLL的方式是静态链接,实际上工作的库是MSVCR80.DLL。故采用MD的方式会使用额外的库,如vcruntime140.dll或msvcp140.dll,而这两库在ISV处很可能是没有的。修改方法:①打开项目的&属性页&对话框;②展开&C/C++&文件夹;③选择&代码生成&属性页;④修改&运行库&属性。如下图所示:5、总结C/C++动态链接库的使用充满了复杂,很多新接触者会无缘无故地陷入各种问题当中,故写本文给看到的人以减少他们的弯路。特别感谢阿里实习同事的帮助,他们在我确决问题中给了我不少的指点。
阅读(...) 评论()fluent加载第三方(C++,Fortan等)动态链接库
这里我介绍一种比较简单的方法,首先我们从ANSYS
Fluent UDF
Manual上随便找一段正确的UDF,下面这段UDF取自ANSYS
18的ANSYS Fluent UDF Manual,位于2.3.23.3.
Example 1 - Pressure Profile
***********************************************************************
for specifying steady-state parabolic pressure profile
for a turbine vane
************************************************************************/
DEFINE_PROFILE(pressure_profile,t,i)
real x[ND_ND]; / * this will hold the position vector */
begin_f_loop(f,t)
F_CENTROID(x,f,t);
F_PROFILE(f,t,i) = 1.1e5 - y*y/(.)*0.1e5;
end_f_loop(f,t)
我们将上面的UDF源代码存为prepare.c
我们启动Fluent&
然后我们直接编译我们刚才保存的prepare.c
我们打开Visual
Studio(我是Visual Studio 2013英文版)
DLL的代码很简单,就是输出Hello
Fluent,这里有一点需要注意一下Solution
PlatForms一定要根据Fluent的位数来选择,默认是编译为Win32,而我们现在的一般使用的是64位的Fluent,所以我们需要改变为x64才行(见截图)
/ *包含输入输出流头文件*/
*一定要这样写,以c语言的形式导出,在Fluent当中才能识别*/
"C" __declspec(dllexport) void CppDynamicLinkLibrary()
cout && "Hello Fluent" && / *输出“Hello
Fluent”*/
然后准备真实需要编译且加载了加载第三方动态链接库的UDF源文件,代码如下:
*链接我们刚才动态链接库的函数*/
void CppDynamicLinkLibrary();
*******************************************
*我们在每次迭代完成以后,
*用动态链接库中的函数输出一次“Hello
********************************************/
DEFINE_ADJUST(my_adjust,d)
CppDynamicLinkLibrary(); / *调用动态链接库中的函数*/
将源代码也保存为prepare.c
然后前面动态链接库项目文件夹下
重新打开Fluent&
导入网格,设置好各种求解参数
加载刚才编译的UDF(注意:此处只需要加载(Load),而不需要编译(Build)了!见截图)&
求解运行算例
makefile文件的注释说明
###########################################################
## Copyright
ANSYS, Inc.
## All Rights Reserved&
###########################################################
# purpose:
This file is the makefile for NT UDF builds.
Change file name 'makefile_nt.udf' to 'makefile'.
Place the makefile file in the target dir.
Place the helper file 'user_nt.udf' in same directory.
Edit user_nt.udf file.
Execute an 'nmake'& (no arguments
The user should not need to change this file.
The following macros are expected to be in the user_nt.udf
SOURCES, VERSION, PARALLEL_NODE and USER_OBJECTS.
The macro FLUENT_LIB is automatically defined here based on
and PARALLEL_NODE.
Only this makefile and the helper file 'user_nt.udf' needs to
the target dir, all other files are automatically
generated,
and removed in an 'nmake clean'.
The source file is expected in ..\..\src directory.
Make sure the VC compiler is set up for command line mode,
the file Vcvars32.bat from Visual Studio to assist this.
This makefile uses the public domain program 'sed', make
sed is in your executable path.
The '^' char in the SRC literal is a quote for the '\'
otherwise interpretted as a line continuation char.
Use the 'nmake clean' command to restart builds.
###########################################################
#包含user_nt.udf文件
!INCLUDE user_nt.udf
# These need to be updated for each
LIB_RELEASE=1800
RELEASE=18.0.0
# If a local path can be found, use it
!IF (("$(FLUENT_INC_LOCAL_RESERVED)" != "")
&& ("$(FLUENT_INC)" == ""))
FLUENT_INC =
$(FLUENT_INC_LOCAL_RESERVED)
# it is assumed $(FLUENT_INC)is already
!IF !DEFINED(FLUENT_INC)
!& ERROR You need to
define the environmental variable FLUENT_INC.
!IF !DEFINED(FLUENT_ARCH)
!IF ("$(PROCESSOR_ARCHITECTURE)" ==
FLUENT_ARCH = ntalpha
!IF ("$(PROCESSOR_ARCHITECTURE)" ==
FLUENT_ARCH = ntx86
!IF ("$(PROCESSOR_ARCHITECTURE)" ==
FLUENT_ARCH = win64
!IF ("$(PROCESSOR_ARCHITEW6432)" ==
!& MESSAGE You seem to
be working on a 64-bit machine, but in a 32-bit build
environment.
!& MESSAGE If you really
want to build the UDF for the "ntx86" FLUENT_ARCH, then
!& MESSAGE set the
"FLUENT_ARCH" environment variable to "ntx86" before calling
!& ERROR&&
# set FLUENT_LIB based on VERSION macro
!IF (("$(VERSION)" == "2d") || ("$(VERSION)" ==
"3d") || \
("$(VERSION)" == "2ddp") || ("$(VERSION)" == "3ddp"))
FLUENT_LIB = fl$(LIB_RELEASE).lib
/Libpath:"$(FLUENT_INC)"\fluent$(RELEASE)\$(FLUENT_ARCH)\$(VERSION)
!IF (("$(VERSION)" == "2d_host") || ("$(VERSION)"
== "3d_host") || \
("$(VERSION)" == "2ddp_host") || ("$(VERSION)" ==
"3ddp_host"))
COMM = net
FLUENT_LIB =& mport.lib
fl$(LIB_RELEASE).lib
/Libpath:"$(FLUENT_INC)"\fluent$(RELEASE)\$(FLUENT_ARCH)\$(VERSION)&
/Libpath:"$(FLUENT_INC)"\fluent$(RELEASE)\multiport\$(FLUENT_ARCH)\$(COMM)\shared
!IF (("$(VERSION)" == "2d_node") || ("$(VERSION)"
== "3d_node") || \
("$(VERSION)" == "2ddp_node") || ("$(VERSION)" ==
"3ddp_node"))
!IF (("$(PARALLEL_NODE)" != "none") &&
("$(PARALLEL_NODE)" != "net"))
PARALLEL_NODE = mpi
COMM = mpi
FLUENT_LIB =& mport.lib
fl_$(PARALLEL_NODE)$(LIB_RELEASE).lib
/Libpath:"$(FLUENT_INC)"\fluent$(RELEASE)\$(FLUENT_ARCH)\$(VERSION)&
/Libpath:"$(FLUENT_INC)"\fluent$(RELEASE)\multiport\$(FLUENT_ARCH)\$(COMM)\shared
###########################################################
#定义变量SRC,其中^表示回车符成为字符串的一部分,其实就是表示字符串..\..\src\
SRC = ..\..\src^\
#使用vc的编译器
#CFLAGS用来指定头文件的路径
# compile flags
#& /c for compile
only,& /Za
for ansi c and __STDC__ is set
CFLAGS = /c /Za /DUDF_EXPORTING /DUDF_NT
#目标文件为libudf.dll动态链接库
TARGET = libudf.dll
UDFDATA = udf_names.c
# generate object names from source
#".cpp=.obj"的意思是做一个替换
#把变量比如$CSOURCES,$SOURCES2,$SRC_OBJECT,$UDFDATA
#所有的[.cpp]的字符串转换为[.obj]字符串
SOURCES2 = $(CSOURCES:..\..\src\=)
#这里实际上就是test.c
SRC_OBJECT = $(SOURCES2:.cpp=.obj)
#这里实际上如果是cpp文件就是test.obj,否则默认不发生变化
SRC_OBJECT =
$(SRC_OBJECT:.c=.obj)#这里如果是c文件就是test.obj
UDF_OBJECT = $(UDFDATA:.c=.obj)& #这里实际上是udf_name.obj
OBJECTS = $(UDF_OBJECT) $(SRC_OBJECT)
$(USER_OBJECTS) #
#此处为包含的头文件
INCLUDES= -I. \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\$(FLUENT_ARCH)\$(VERSION)
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\main \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\addon-wrapper \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\io \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\species \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\pbns \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\numerics \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\sphysics \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\storage \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\mphase \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\bc \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\models \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\material \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\amg \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\util \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\mesh \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\udf \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\ht \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\dx \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\turbulence \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\parallel \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\etc \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\ue \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\dpm \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\dbns \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\cortex\src \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\client\src \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\tgrid\src \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\multiport\src \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\multiport\mpi_wrapper\src
!IF ("$(GPU_SUPPORT)" == "on")
#如果开启了GPU加速,那么久将GPU的头文件也包含到INCLUDE里面,默认为off的
INCLUDES = $(INCLUDES) \
&&&&&&&&&&
-I"$(FLUENT_INC)"\fluent$(RELEASE)\multiport\gpu_wrapper\include
GPU_LIB = OpenCL.lib
LIBS = $(LIBS)
/Libpath:"$(FLUENT_INC)"\fluent$(RELEASE)\multiport\gpu_wrapper\$(FLUENT_ARCH)\stub
default:&&
$(TARGET) #假想目标,每次更新$(TARGET)即libudf.dll
$(UDF_OBJECT): $(UDFDATA) #从udf_name.c编译生成目标文件udf_name.obj
$(CC) $(CFLAGS) $(INCLUDES)& $**&&
#采用cl编译器
替换(编译但不链接
禁用语言扩展
定义预处理器)
包含头文件
编译所有的文件
$(SRC_OBJECT): $(CSOURCES) #从test.c编译生成目标文件test.obj
@echo # Generating ud_io1.h
resolve.exe -udf $(CSOURCES) -head_file ud_io1.h
$(CC) $(CFLAGS) $(INCLUDES)& $**
#采用cl编译器
替换(编译但不链接
禁用语言扩展
定义预处理器)
包含头文件
编译所有的文件
$(TARGET): makefile user_nt.udf $(UDF_OBJECT)
$(SRC_OBJECT)& #生成目标文件libudf.dll
@echo # Linking $@ because of $?
$(LIBS) /dll&&
/out:$(TARGET) \&&&
#/dll表示生成dll文件
$(OBJECTS)&
$(FLUENT_LIB) $(GPU_LIB) #需要链接文件
$(UDFDATA): makefile $(SRC_OBJECT)
#自动生成udf_name.c文件
@echo # Generating $@ because of $?
@echo & $@
@echo && $@
@echo #include "udf.h" && $@
@echo #include "prop.h" && $@
@echo #include "dpm.h" && $@
-n "s/^ *\(DEFINE_[_A-Z]*(.*)\)/extern \1;/p" $(CSOURCES) &&
@echo __declspec(dllexport) UDF_Data udf_data[] = { &&
-n "s/^ *DEFINE_\([_A-Z]*\)( *\([_a-zA-Z0-9]*\).*)/\{\"\2\", (void
(*)(void))\2, UDF_TYPE_\1\},/p" $(CSOURCES) && $@
@echo }; && $@
@echo __declspec(dllexport) int n_udf_data =
sizeof(udf_data)/sizeof(UDF_Data); && $@
@echo #include "version.h" && $@
@echo __declspec(dllexport) void UDF_Inquire_Release(int *major,
int *minor, int *revision) && $@
@echo { && $@
*major = RampantReleaseM && $@
*minor = RampantReleaseM && $@
*revision = RampantReleaseR && $@
@echo } && $@
#清理输出文件
@del& *.dll
*.obj *.ilk *.exp *.lib *.pdb *.c
tellfluentarch:
@echo FLUENT_ARCH: $(FLUENT_ARCH)
@echo PROCESSOR_ARCHITECTURE: $(PROCESSOR_ARCHITECTURE)
@echo PROCESSOR_ARCHITEW6432: $(PROCESSOR_ARCHITEW6432)
$(OBJECTS): $(HSOURCES)
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。改变一个正在被调用的 C++动态库,对需要调用它,且当前正在执行的的程序有什么影响?
01:34:27 +08:00 · 1245 次点击
我在 linux 下, C++ 源码编译成了一个动态库,然后有一个正在执行的程序需要调用这个库,这个程序要运行很长时间。这时,我忽然想起来库里有一个函数错了,我修改了这个函数,并且重新编译了一下这个动态库。改完以后,发现我的程序并没有停止运行,也没有任何反馈信息。可又有一次,同样的情形,当我修改了库,重新编译了库以后,程序却报错了,跟内存有关的报错,详细信息当时没保存下来,那么问题来了:
请问什么情况下改变了库会导致调用它的程序报错退出?什么情况不会?
在程序没有报错退出的情况下,程序是在调用我修改以后的库函数吗?
本人不是 CS 专业,也不太懂编译原理相关理论,半路出家,现在搞一点科学计算,希望有经验的大大给一点指导,谢谢
14 回复 &| &直到
16:48:08 +08:00
& & 01:44:50 +08:00
如果你主程序是直接用 linker 链接到动态库的话,程序启动的同时就会链接到动态库,这时候修改库文件不会生效。
如果是在代码里用 dlopen 函数运行时链接的话,在调用 dlopen 之前修改或者 dlclose 之后修改,主程序看到的就是新的动态库。
看样子你应该没有用 dlopen 和 dlclose ,所以报错应该是旧版的库里有 bug 导致的。
& & 01:45:44 +08:00
可以参考 CSAPP 第 7 章。
& & 01:56:50 +08:00
@ 感谢。请问我怎么才知道我是用 linker 还是 dlopen 呢?动态库是用 make 编译的,可执行程序是在 make 里用 -l 参数链接的,编译器是 g++。另,感谢推荐的书,我去看看第 7 章。
& & 02:01:16 +08:00
@ 那就是直接用 linker(ld)链接了
& & 02:06:48 +08:00
可以学习一下,都有哪些修改会改变 ABI ,哪些修改不会改变 ABI 。这方面的文章很多的。
& & 02:10:22 +08:00
@ 你没说到点子上。 lz 的程序本身就是动态链接的,报错是因为改变了动态链接库的 ABI 导致。
& & 02:22:58 +08:00
@ 动态链接也分情况啊,以楼主这种方式动态链接,主程序还在运行的时候修改是不生效的...
& & 02:44:17 +08:00 via Android
@ 确实,如果已经在运行了,覆盖 so 应该没影响……这个确实奇怪
& & 11:41:03 +08:00
想到一个问题,替换动态库时,用 unlink 再 open 和直接 open O_TRUNC 是不是效果不一样啊?
楼主你是用什么命令替换的?
& & 12:15:41 +08:00
你修改的是 磁盘镜像,无论是 编译时 link 或者 dlopen, 运行的时候都会先将 so 文件加载到内存中,只要不是重新从磁盘中读取,那么就依然使用的是 旧的 so, 而 Windows 不一样, Windows 的 dll 会被锁定,然后,替换不了。
这也是为什么 linux
rm -rf / 系统还能跑,重启起不来了。
& & 23:23:00 +08:00 via Android
楼上不懂装懂小学们去看淘宝团队技术博客,讲的很清楚可了。
一句话结论,看运气,可能崩溃。
& & 23:28:06 +08:00 via Android
什么叫以己昏昏,使人昭昭 。这贴就是。不过我猜即使我在此指出了关键点,估计也不会有人顺藤摸瓜去学习一个。
& & 23:41:37 +08:00
给小学生一点提示,崩溃和 linux 对共享库的延迟加载有关,所以知道为啥说看运气了不。
& & 16:48:08 +08:00
@ 我是幼稚园还没毕业的。。。请问大神,您提到的淘宝团队技术博客,可否给一个链接看看?我 Google 过了,不确定我找到的是不是大神说的那个
& · & 2910 人在线 & 最高记录 3541 & · &
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.0 · 46ms · UTC 08:07 · PVG 16:07 · LAX 00:07 · JFK 03:07? Do have faith in what you're doing.}

我要回帖

更多关于 yii2 加载第三方类库 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信