Inside GDALAllRegister之二: 自动加载驱动
代码 GetGDALDriverManager()->AutoLoadDrivers(); 包含了两部分:
首先获得GDALDriverManager的singleton对象的指针,这点之前已经说明过,采用DCLP是个错误用法,不过可以通过下面的方法规避:
永远只在main函数内部单线程调用一次GDALAllRegister, 在其他线程尚未创建之前,singleton对象已经被创建出来
然后运行void GDALDriverManager::AutoLoadDrivers() 函数。这是本次分析的主要内容。注释写的不错,很容易就理解了该函数的逻辑。
/**
* \brief Auto-load GDAL drivers from shared libraries.
*
* This function will automatically load drivers from shared libraries. It
* searches the "driver path" for .so (or .dll) files that start with the
* prefix "gdal_X.so". It then tries to load them and then tries to call a
* function within them called GDALRegister_X() where the 'X' is the same as
* the remainder of the shared library basename ('X' is case sensitive), or
* failing that to call GDALRegisterMe().
*
* There are a few rules for the driver path. If the GDAL_DRIVER_PATH
* environment variable it set, it is taken to be a list of directories to
* search separated by colons on UNIX, or semi-colons on Windows. Otherwise
* the /usr/local/lib/gdalplugins directory, and (if known) the
* lib/gdalplugins subdirectory of the gdal home directory are searched on
* UNIX and $(BINDIR)\gdalplugins on Windows.
*/
该函数在driver path中查找文件名为gdal_X.dll或者gdal_X.so的动态库文件。如果找到,就加载该动态库,并调用其中的GDALResiter_X()函数,每隔动态库都应该实现这个函数。X代表库的名称。
driver path可以通过设置环境变量GDAL_DRIVER_PATH来获得,path之间通过,或者;分隔。 如果没有设定环境变量,就使用默认查找路径:/usr/local/lib/gdalplugins,
并且:
1. 如果Unix下有gdal home 目录的话,还会找该目录下的lib/gdalplugins子目录,
2. 如果windows下会用$(BINDDIR)\gdalplugins 作为查找路径。这里$(BINDIR)值得是当前进程所在目录。
下面是全部代码:
void GDALDriverManager::AutoLoadDrivers()
{
char **papszSearchPath = NULL;
const char *pszGDAL_DRIVER_PATH =
CPLGetConfigOption( "GDAL_DRIVER_PATH", NULL );
/* -------------------------------------------------------------------- */
/* Where should we look for stuff? */
/* -------------------------------------------------------------------- */
if( pszGDAL_DRIVER_PATH != NULL )
{
#ifdef WIN32
papszSearchPath =
CSLTokenizeStringComplex( pszGDAL_DRIVER_PATH, ";", TRUE, FALSE );
#else
papszSearchPath =
CSLTokenizeStringComplex( pszGDAL_DRIVER_PATH, ":", TRUE, FALSE );
#endif
}
else
{
#ifdef GDAL_PREFIX
papszSearchPath = CSLAddString( papszSearchPath,
#ifdef MACOSX_FRAMEWORK
GDAL_PREFIX "/PlugIns");
#else
GDAL_PREFIX "/lib/gdalplugins" );
#endif
#else
char szExecPath[1024];
if( CPLGetExecPath( szExecPath, sizeof(szExecPath) ) )
{
char szPluginDir[sizeof(szExecPath)+50];
strcpy( szPluginDir, CPLGetDirname( szExecPath ) );
strcat( szPluginDir, "\\gdalplugins" );
papszSearchPath = CSLAddString( papszSearchPath, szPluginDir );
}
else
{
papszSearchPath = CSLAddString( papszSearchPath,
"/usr/local/lib/gdalplugins" );
}
#endif
#ifdef MACOSX_FRAMEWORK
#define num2str(x) str(x)
#define str(x) #x
papszSearchPath = CSLAddString( papszSearchPath,
"/Library/Application Support/GDAL/"
num2str(GDAL_VERSION_MAJOR) "."
num2str(GDAL_VERSION_MINOR) "/PlugIns" );
#endif
if( strlen(GetHome()) > 0 )
{
papszSearchPath = CSLAddString( papszSearchPath,
CPLFormFilename( GetHome(),
#ifdef MACOSX_FRAMEWORK
"/Library/Application Support/GDAL/"
num2str(GDAL_VERSION_MAJOR) "."
num2str(GDAL_VERSION_MINOR) "/PlugIns", NULL ) );
#else
"lib/gdalplugins", NULL ) );
#endif
}
}
/* -------------------------------------------------------------------- */
/* Scan each directory looking for files starting with gdal_ */
/* -------------------------------------------------------------------- */
for( int iDir = 0; iDir < CSLCount(papszSearchPath); iDir++ )
{
char **papszFiles = CPLReadDir( papszSearchPath[iDir] );
for( int iFile = 0; iFile < CSLCount(papszFiles); iFile++ )
{
char *pszFuncName;
const char *pszFilename;
const char *pszExtension = CPLGetExtension( papszFiles[iFile] );
void *pRegister;
#if ( defined( _WIN32 ) && ( defined(DEBUG) || defined(_DEBUG) ) )
if( !EQUALN(papszFiles[iFile],"debug_gdal_",11) )
continue;
#else
if( !EQUALN(papszFiles[iFile],"gdal_",5) )
continue;
#endif
if( !EQUAL(pszExtension,"dll")
&& !EQUAL(pszExtension,"so")
&& !EQUAL(pszExtension,"dylib") )
continue;
pszFuncName = (char *) CPLCalloc(strlen(papszFiles[iFile])+20,1);
#if ( defined( _WIN32 ) && ( defined(DEBUG) || defined(_DEBUG) ) )
CPLString sName = CPLGetBasename(papszFiles[iFile]) + 11;
#else
CPLString sName = CPLGetBasename(papszFiles[iFile]) + 5;
#endif
sprintf( pszFuncName, "GDALRegister_%s", sName.c_str() );
pszFilename =
CPLFormFilename( papszSearchPath[iDir],
papszFiles[iFile], NULL );
pRegister = CPLGetSymbol( pszFilename, pszFuncName );
if( pRegister == NULL )
{
sName.toupper();
sprintf( pszFuncName, "GDALRegister_%s", sName.c_str() );
pRegister = CPLGetSymbol( pszFilename, pszFuncName );
if( pRegister == NULL )
{
strcpy( pszFuncName, "GDALRegisterMe" );
pRegister = CPLGetSymbol( pszFilename, pszFuncName );
}
}
if( pRegister != NULL )
{
CPLDebug( "GDAL", "Auto register %s using %s.",
pszFilename, pszFuncName );
((void (*)()) pRegister)();
}
CPLFree( pszFuncName );
}
CSLDestroy( papszFiles );
}
CSLDestroy( papszSearchPath );
}
那个查找目录树的算法算不上糟糕,不过用惯了boost和newlisp的我,看到不禁皱眉头。太不优雅了。一帮C程序员在写C++代码,循环之后还要用CSLFree和CSLDestory 释放内存,有string不用。就算不用string,也可以自己写个简单的class啊。
很明显,GDAL的源代码并没有随着C++语言的发展而进步,让我不仅想起了ACE。
调试一遍后,发现我的GDAL代码在这里没有加载任何驱动。就是我想要的结果。:)
Inside GDALAllRegister之二: 自动加载驱动的更多相关文章
- 简单实现JDBC自动加载驱动,简化数据连接和关闭数据库连接
package util; import java.io.File;import java.io.FileInputStream;import java.io.IOException;import j ...
- CAD 二次开发 -- 自动加载开发的DLL
CAD二次开发可以采用写扩展DLL的方式实现.该DLL的函数可以被CAD调用. 但是调用前,必须用命令netload 将该dll加载到CAD. 其实可以修改注册表,当CAD软件启动后,自动加载扩展DL ...
- linux下自动加载设备驱动程序模块
假设你的设备驱动程序为:yourdrivername.ko 1 cp yourdrivername.ko /lib/modules/"version"/kernel/driver ...
- JDBC详解系列(二)之加载驱动
---[来自我的CSDN博客](http://blog.csdn.net/weixin_37139197/article/details/78838091)--- 在JDBC详解系列(一)之流程中 ...
- FMX StringGrid向上滑动自动加载记录(二)
写完FMX StringGrid向上滑动自动加载记录(一)自己也觉得不理想,实现的别扭与复杂,现在找到更好的实现方法,原来,StringGrid从基类TCustomPresentedScrollBox ...
- C118 免按开机自动加载固件
最近无事,研究了按按钮开机的功能:功能的起初是参考了别人的系统是怎么做免开机加载固件的. 一.原理: 1.c118 原生loader部分代码是没有源代码的,它上电只需要按开机键然后系统就会起来. 2. ...
- 构建自己的PHP框架之自动加载类中详解spl_autoload_register()函数
在了解这个函数之前先来看另一个函数:__autoload. 一.__autoload 这是一个自动加载函数,在PHP5中,当我们实例化一个未定义的类时,就会触发此函数.看下面例子: printit.c ...
- autocad2008+C#2008开发中设置自动加载dll
一.复制编译后的dlll路径,比如我的是D:\zjy\cad开发\学习\宗地图\bin\Debug\zd.dll 二.随便找个地方新建一个记事本,在记事本中写入以下内容: (command " ...
- ajax的使用:(ajaxReturn[ajax的返回方法]),(eval返回字符串);分页;第三方类(page.class.php)如何载入;自动加载函数库(functions);session如何防止跳过登录访问(构造函数说明)
一.ajax例子:ajaxReturn("ok","eval")->thinkphp中ajax的返回值的方法,返回参数为ok,返回类型为eval(字符串) ...
随机推荐
- 使用gSOAP工具生成onvif框架代码
<工具产生背景> 由于SOAP是一种基于xml的文件,手动编写SOAP文件太机械耗时,在这种背景下产生了gSAOP 这个工具,用于生成各种类型的代码,目前支持C/C++, ...
- Centos 安装 Wireshark
Wireshark是一款数据包识别软件,应用很广泛. yum install wireshark yum install wireshark-gnome
- [BZOJ4571][SCOI2016]美味(贪心+主席树)
经典问题,按位贪心,每次需要知道的是”在这一位之前的位都以确定的情况下,能否找到这一位是0/1的数”,这就是在询问[L,R]内某个值域区间是否有数,主席树即可. #include<cstdio& ...
- hdu 3613 扩展kmp+回文串
题目大意:给个字符串S,要把S分成两段T1,T2,每个字母都有一个对应的价值,如果T1,T2是回文串(从左往右或者从右往左读,都一样),那么他们就会有一个价值,这个价值是这个串的所有字母价值之和,如果 ...
- Towelroot v3.0版发布 将支持更多设备 Towelroot v3.0下载
Towelroot虽然已经发布一段时间了,虽然所Towelroot可以一键ROOT很多设备,虽然它只有100多K.不过还是有一小部分的机型没办法ROOT成功的,也不知道什么原因.不过不用担心,Geoh ...
- linux系统编程:线程原语
线程原语 线程概念 线程(thread),有时被称为轻量级进程(Lightweight Process,LWP).是程序运行流的最小单元.一个标准的线程由线程ID.当前指令指针(PC),寄存器集合和堆 ...
- Bootstrap 3之美01-下载并引入页面
本篇主要包括: ■ 下载Bootstrap 3■ Bootstrap 3引入页面 下载Bootstrap 3 →打开网站:http://getbootstrap.com/→点击屏幕中央位置的Down ...
- MVC文件上传07-使用客户端jQuery-File-Upload插件和服务端Backload组件裁剪上传图片
本篇通过在配置文件中设置,对上传图片修剪后保存到指定文件夹. 相关兄弟篇: MVC文件上传01-使用jquery异步上传并客户端验证类型和大小 MVC文件上传02-使用HttpPostedFileB ...
- SAE java应用读写文件(TmpFS和Storage)
近期不少java用户都在提sae读写本地文件的问题,在这里结合TmpFS和Storage服务说说java应用应该如何读写文件TmpFS是一个供应用临时读写的路径,但请求过后将被销毁.出于安全考虑,sa ...
- Deployment failure on Tomcat 7.x. Could not copy all resources to
今天在网上部署项目的时候出现在了问题 tomcat一直部署不上 网上查了一下 原因记下来供大家查看 [plain] <span style="font-size:18px;" ...