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(字符串) ...
随机推荐
- 你的跑步姿势正确吗? 教你正确跑步姿势 & 常识
转载!!!!!搞IT必须运动一下 前言: 最近两年跑步的人越来越多,跑步在大部分人的观念中都是毫无技术含量,只要迈开腿就行了,其实这也是造成大多数跑步人士伤病的根源.对跑步的认知不足,跑步是一项看起来 ...
- elasticsearch 亿级数据检索案例与原理
版权说明: 本文章版权归本人及博客园共同所有,转载请标明原文出处( https://www.cnblogs.com/mikevictor07/p/10006553.html ),以下内容为个人理解,仅 ...
- 文件上传demo
前端代码: <form action="upload.php" enctype="multipart/form-data" method="po ...
- 原型设计工具 Axure
ahjesus Axure RP 7.0注册码 ahjesus Axure RP 7.0注册码 用户名:axureuser 序列号:8wFfIX7a8hHq6yAy6T8zCz5R0NBKeVxo9I ...
- Python的静态方法和类成员方法
http://www.cnblogs.com/2gua/archive/2012/09/03/2668125.html Python的静态方法和类成员方法都可以被类或实例访问,两者概念不容易理清,但还 ...
- onInterceptTouchEvent 与 onTouchEvent 分析与MotionEvent在ViewGroup与View中的分发
onInterceptTouchEvent 与 onTouchEvent 分析与MotionEvent在ViewGroup与View中的分发 Notice:本文将紧接着 Android ...
- 淘宝API得到单个商品的信息,用了淘宝的SDK...
淘宝api获取到的数据.返回结果可以选择json格式和xml格式的啊.每个api下面都有sdk调用示例哦. 详细:http://wenwen.soso.com/z/q335640192.htm 淘宝开 ...
- 在Powerdesigner中创建概念数据模型
点击菜单“File”---->“New Model” 点击[OK]按钮后,将进入如下的画面 系统将出现一个工具栏如下,用于在设计面板中设计模型
- 用最简单的例子理解适配器模式(Adapter Pattern)
中国足球的水平虽然不高,但实际上,在每个城市会有一批足球爱好者,他们踢球.看球.懂球.有这样的2个足球爱好者,一个是左脚选手,另一个是右脚选手. public class PlayWithLeft { ...
- Python之“可变”的tuple
前面我们看到了tuple一旦创建就不能修改.现在,我们来看一个"可变"的tuple: >>> t = ('a', 'b', ['A', 'B']) 注意到 t 有 ...