Inside GDALAllRegister之二: 自动加载驱动

来源:互联网 发布:斯大林大战火星人2知乎 编辑:程序博客网 时间:2024/06/03 16:42

代码    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代码在这里没有加载任何驱动。就是我想要的结果。:)