作者:朱金灿
来源:http://blog.csdn.net/clever101
为什么要用VS工程的方式来编译gdal库?主要还是为了调试方便,虽然理论上使用命令行方式生成库也能调试,详见:GDAL库调试(包括跨语言调试),但是我把gdal库的pdb文件、ilk文件都拷贝到输出目录依然无法调试,使用windbg进行调试,感觉繁琐了点,还有开发组的其他成员还不会用windbg这玩意,于是开始折腾将gdal源码转化为VS工程。
结果一折腾之下,发现自己仿佛掉进无穷深的坑,可能就是俗称的dll地狱吧,终于在今天折腾完。下面就详细说说这一过程:
第一步:使用makegdal_gen.bat生成一个VS2008工程makegdal90.vcproj,makegdal_gen.bat的具体用法见参考文献一,这里不作详述。可能有读者认为这样生成不是VS工程吗?实际上这并不是我想要可以调试的dll工程,而是一个Make工程,这个Make工程实际上调用的还是nmake的命令行,具体看下图:
第二步就是要把make工程转化为dll工程,转化的过程很简单,用记事本将makegdal90.vcproj打开,找到Configurations节点,具体如下:
<Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="0" > <Tool Name="VCNMakeTool" BuildCommandLine="cd $(ProjectDir) && nmake -f makefile.vc MSVC_VER=1400 DEBUG=1" ReBuildCommandLine="cd $(ProjectDir) && nmake -f makefile.vc MSVC_VER=1400 DEBUG=1 clean && nmake -f makefile.vc MSVC_VER=1400 DEBUG=1" CleanCommandLine="cd $(ProjectDir) && nmake -f makefile.vc MSVC_VER=1400 DEBUG=1 clean" Output="gdal17.dll" PreprocessorDefinitions="" IncludeSearchPath="" ForcedIncludes="" AssemblySearchPath="" ForcedUsingAssemblies="" CompileAsManaged="" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="0" > <Tool Name="VCNMakeTool" BuildCommandLine="cd $(ProjectDir) && nmake -f makefile.vc MSVC_VER=1400 && nmake -f makefile.vc MSVC_VER=1400 install" ReBuildCommandLine="cd $(ProjectDir) && nmake -f makefile.vc MSVC_VER=1400 clean && nmake -f makefile.vc MSVC_VER=1400 && nmake -f makefile.vc MSVC_VER=1400 install" CleanCommandLine="cd $(ProjectDir) && nmake -f makefile.vc MSVC_VER=1400 clean" Output="gdal17.dll" PreprocessorDefinitions="" IncludeSearchPath="" ForcedIncludes="" AssemblySearchPath="" ForcedUsingAssemblies="" CompileAsManaged="" /> </Configuration> </Configurations>
替换为如下内容:
<Configurations> <Configuration Name="Debug|Win32" OutputDirectory="........Outdirdebug" IntermediateDirectory="........Intdir$(ConfigurationName)$(ProjectName)" ConfigurationType="2" InheritedPropertySheets="$(VCInstallDir)VCProjectDefaultsUpgradeFromVC71.vsprops" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;GDAL_EXPORTS" IgnoreStandardIncludePath="false" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" DisableSpecificWarnings="4251" ForcedIncludeFiles="" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="" OutputFile="$(OutDir)/gdal-vc9.dll" LinkIncremental="2" AdditionalLibraryDirectories="" IgnoreAllDefaultLibraries="false" IgnoreDefaultLibraryNames="msvcrt.lib" ForceSymbolReferences="" GenerateDebugInformation="true" ProgramDatabaseFile="$(OutDir)/gdal.pdb" SubSystem="1" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="$(OutDir)/gdal-vc9.lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" CommandLine="" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="........outdir elease" IntermediateDirectory="........Intdir$(ConfigurationName)$(ProjectName)" ConfigurationType="2" InheritedPropertySheets="$(VCInstallDir)VCProjectDefaultsUpgradeFromVC71.vsprops" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories="" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;GDAL_EXPORTS" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="0" DisableSpecificWarnings="4251" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="" OutputFile="$(OutDir)/gdal-vc9.dll" LinkIncremental="1" AdditionalLibraryDirectories="" IgnoreDefaultLibraryNames="" ForceSymbolReferences="" GenerateDebugInformation="false" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="$(OutDir)/gdal-vc8.lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" CommandLine="" /> </Configuration> </Configurations>
这样你就将一个make工程转化为一个win32 dll工程。
第三步添加附加头文件路径、预处理器和附加库。事实上这一步最为繁琐。先说说添加头文件路径,因为gdal库涉及到众多的格式,只要你数下frmts目录以及ogrogrsf_frmts目录下有多少个子文件夹就可以知道gdal支持多少种栅格格式和矢量格式(我的感觉是gdal库就像一座桥梁,把众多的图形图像库联结在一起),也就是说要把这么多格式的路径都添加进头文件路径。手动添加肯定是不行的,我写了一个JS文件通过遍历文件路径进行添加。然后开始添加预处理器,预处理器的作用主要有两方面,一是控制gdal库支持哪些格式,比如添加了FRMT_gtiff预处理器表示支持geotiff格式,想知道哪些栅格格式对应哪些预处理器,请看GDALAllRegister函数源码,对于支持哪些矢量格式,比如添加SHAPE_ENABLED表示支持shp格式,想知道哪些矢量格式对应哪些预处理器,请看OGRRegisterAll函数源码,二是控制是否添加附加库,比如添加HAVE_LIBJPEG表示有额外的jpeg库。我添加了下面这些预处理器:
HAVE_XERCES FRMT_ceos FRMT_aigrid FRMT_elas FRMT_hfa FRMT_gtiff FRMT_sdts FRMT_raw FRMT_gxf FRMT_ceos2 FRMT_png FRMT_dted FRMT_mem FRMT_jdem FRMT_gif FRMT_envisat FRMT_aaigrid FRMT_usgsdem FRMT_l1b FRMT_vrt FRMT_xpm FRMT_bmp FRMT_jpeg SHAPELIB_DLLEXPORT ZIP_SUPPORT SHAPE_ENABLED TAB_ENABLED NTF_ENABLED SDTS_ENABLED TIGER_ENABLED S57_ENABLED DGN_ENABLED VRT_ENABLED AVCBIN_ENABLED REC_ENABLED MEM_ENABLED _CRT_SECURE_NO_DEPRECATE BUILD_AS_DLL USE_CPL HAVE_GEOS BIGTIFF_SUPPORT PROJ_STATIC COMPILATION_ALLOWED HAVE_EXPAT JAS_WIN_MSVC_BUILD USE_IN_GDAL OGR_ENABLED LIBHDF_EXPORTS HAVE_LIBJPEG HAVE_LIBZ HDF5CPP_USEDLL _HDF5USEDLL_ BUILDING_LIBCURL HAVE_CURL
既然gdal库支持那么多格式,是不是我们都应该把每种格式的源码都编译一遍呢?回答是否定的,理由很简单,有些格式很生僻,其数据很可能你一辈子都没见过,那你编译它做什么,因此你完全可以在工程文件里果断地将一些你不想支持的格式的源码移除掉。尽管如此,我们需要的第三方库还是很多的。下面是我们需要的第三方库一览表:
第三方库名及版本 | 备注 |
Expat v2.1.0_vc9 | xml格式解析库,主要为支持kml格式提供支持。 |
zlib v1.2.3 | 开源压缩库,为很多第三方库提供支持。 |
geos v3.3.5 | 开源空间分析库 |
xerces v3.1.1 | xml文件解析库 |
sqlite v3071401 | 开源数据库,可作为ogr库的空间数据库支持 |
OpenDWG | 用于支持Autocad的dwg格式,值得注意的是OpenDWG是一个cad商业联盟为解析dwg格式而联合推出的一个解析库,其库需要购买,其源码并不公开,它并不是一个库,而是一系列库的集合,具体如下 TD_Gs.lib TD_Db.lib TD_DbRoot.lib TD_Ge.lib TD_Root.lib TD_AcisBuilder.lib TD_Gi.lib TD_Alloc.lib TD_ExamplesCommon.lib TD_SpatialIndex.lib。 |
libwebp v0.2.0 | 貌似是支持一种网络图片格式webp。 |
Openjpeg v2.0.0-win32-x86lib | 用于支持jpeg200格式 |
pthreads v2_9_1 | 跨平台线程库 |
Libkml v1.3.0 | 用于支持kml格式 |
Jasper v1.900.1 | 用于支持Jasper格式 |
Curl v7.32.0 | 文件传输库,貌似为了支持GIS的WMS服务,在windows平台上需要win socket支持,具体需要ws2_32.lib、wsock32.lib、Wldap32.lib这三个库支持。 |
libiconv v1.11.1 | 跨平台文本编码转换库 |
proj v4.8 | 投影转换库 |
hdfeos 2_18 | 用于支持hdf格式 |
hdf5 v1.8.8 | 用于支持hdf5格式 |
hdf v4.2.6 | 用于支持hdf5格式 |
libj2k | 用于支持jpeg2000格式,不知和openjpeg有何区别。 |
jpeg v8d | 用于支持jpeg库 |
minizip | 支持kml格式的附加库 |
uriparser | 支持kml格式的附加库 |
参考文献: