之前一直在搞GDAL的C++开发,因此对linux下的GDAL编译算是有一点心得,但是从未搞过Windows下的GDAL编译,更没有弄过.NET平台下的GDAL库。
今天一天时间总算是编译出了.NET(x86)可用的GDAL with netCDF库,把遇到的几个问题记下来。
1、Windows下GDAL C/C++库的编译
(1)由于要支持netCDF格式,因此首先下载UNIDATA提供的netcdf的二进制发行包,下载地址:netCDF4.3RC4-NC4-DAP-32.exe
安装解压后,只需要其中的bin、deps、include、lib四个文件夹及其内容,假设放在本地D:\GDAL\compiled\netcdf430 目录下。
(2)下载SWIG-2.0.6(或者1.3.39,最新的2.0.9均可),解压后放置在D:\GDAL\swigwin-2.0.6 目录下。
(3)下载GDAL-1.9.2源码,点击此处下载地址,下载并解压后放置在本地目录,例如 D:\GDAL\gdal-1.9.2 下。
(4)修改nmake.opt文件:
GDAL_HOME = "C:\warmerda\bld" 修改为: GDAL_HOME = "D:\GDAL\current_bld" # Uncomment the following to enable NetCDF format. #NETCDF_PLUGIN = NO #NETCDF_SETTING=yes #NETCDF_LIB=C:\Software\netcdf\lib\netcdf.lib #NETCDF_INC_DIR=C:\Software\netcdf\include 修改为: # Uncomment the following to enable NetCDF format. NETCDF_PLUGIN = yes NETCDF_SETTING=yes NETCDF_LIB=D:\GDAL\compiled\netcdf430\lib\netcdf.lib NETCDF_INC_DIR=D:\GDAL\compiled\netcdf430\include # Set the location of your SWIG installation !IFNDEF SWIG SWIG = swig.exe !ENDIF 修改为: # Set the location of your SWIG installation !IFNDEF SWIG SWIG = D:\GDAL\swigwin-2.0.6\swig.exe !ENDIF
(5)启动VS2010命令行工具,转到 D:\GDAL\gdal-1.9.2 目录下, 依次运行下面的命令:
nmake -f makefile.vc nmake -f makefile.vc install 或者 nmake -f makefile.vc devinstall
(6)将netcdf的dll以及依赖的所有dll全部copy到gdal19.dll目录下,运行gdalinfo.exe --formats命令查看支持的文件格式,能够找到下述一行即说明成功。
netCDF (rw+): Network Common Data Format
2、编译C#可用的GDAL库
第一步完成后得到的gdal19.dll是C/C++可用的本地代码DLL,还不能被C#所调用,使用SWIG可以实现对GDAL接口的快速封装和多语言导出。
第一步编译以及安装完成后,转到D:\GDAL\gdal-1.9,2\swig\csharp目录下,依次运行下述命令:
nmake -f makefile.vc interface nmake -f makefile.vc nmake -f makefile.vc install
在设置的GDAL_HOME目录下出现内含8个dll的csharp文件夹,将其copy到gdal19.dll相同目录下,C#引用gdal_csharp.dll即可。
在执行上述命令时,可能遇到的问题有以下几个:
(1)接口重定义
osr\OsrPINVOKE.cs(192,10): error CS0111: 类型“OSGeo.OSR.OsrPINVOKE”已定义了一个名为“OsrPINVOKE”的具有相同参数类型的成员 osr\OsrPINVOKE.cs(188,10): (与前一个错误相关的符号位置) NMAKE : fatal error U1077: “C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.EXE”: 返回代码“0x1”
解决办法比较简单,只需要进入到..\gdal-1.9.2\swig\csharp\gdal|ogr|osr三个文件夹下,找到GdalPINVOKE.cs、OgrPINVOKE.cs、OsrPINVOKE.cs三个文件大约都是第188~192行,将下述重复的声明注释掉其中一个。
static GdalPINVOKE() { } //static GdalPINVOKE() { //}
(2)SWIG生成的接口成员名称错误,如:
gdal\Band.cs(17,79): error CS0117: “OSGeo.GDAL.GdalPINVOKE”并不包含“BandUpcast”的定义 gdal\Dataset.cs(17,82): error CS0117: “OSGeo.GDAL.GdalPINVOKE”并不包含“DatasetUpcast”的定义 gdal\Driver.cs(17,81): error CS0117: “OSGeo.GDAL.GdalPINVOKE”并不包含“DriverUpcast”的定义 NMAKE : fatal error U1077: “C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.EXE”: 返回代码“0x1”
上述3个错误比较难定位,只能根据名称去相关类的文件里面搜索,经过反复查找发现SWIG-2.0.6/9均犯了同样的一个错误:在GdalPINVOKE.cs声明为下述三个名称的接口:
[DllImport("gdal_wrap", EntryPoint="CSharp_Driver_SWIGUpcast")] public static extern IntPtr Driver_SWIGUpcast(IntPtr jarg1); [DllImport("gdal_wrap", EntryPoint="CSharp_Dataset_SWIGUpcast")] public static extern IntPtr Dataset_SWIGUpcast(IntPtr jarg1); [DllImport("gdal_wrap", EntryPoint="CSharp_Band_SWIGUpcast")] public static extern IntPtr Band_SWIGUpcast(IntPtr jarg1);
在Driver、Dataset、Band类中调用时竟然搞错了名字,写成了DriverUpcast、DatasetUpcast、BandUpcast,分别修改为下列名称即可。
public Driver(IntPtr cPtr, bool cMemoryOwn, object parent) : base(GdalPINVOKE.Driver_SWIGUpcast(cPtr), cMemoryOwn, parent) { swigCPtr = new HandleRef(this, cPtr); public Dataset(IntPtr cPtr, bool cMemoryOwn, object parent) : base(GdalPINVOKE.Dataset_SWIGUpcast(cPtr), cMemoryOwn, parent) { swigCPtr = new HandleRef(this, cPtr); public Band(IntPtr cPtr, bool cMemoryOwn, object parent) : base(GdalPINVOKE.Band_SWIGUpcast(cPtr), cMemoryOwn, parent) { swigCPtr = new HandleRef(this, cPtr);
(3)安全透明代码无法调用本机C++代码的问题
System.MethodAccessException”类型的未经处理的异常出现在 gdal_csharp.dll 中。
其他信息: 安全透明方法“OSGeo.GDAL.Gdal.AllRegister()”尝试通过方法“OSGeo.GDAL.GdalPINVOKE.AllRegister()”调用本机代码失败。方法必须是安全关键的或安全可靠关键的,才能调用本机代码。
往往在执行到第一句:Gdal.AllRegister();时就会报出上述错误。
上述错误应该是由.NET平台的安全机制所导致,swig在自动封装GDAL的.NET库时,默认采用下述安全描述(在D:\GDAL\gdal-1.9.2\swig\csharp\AssemblyInfo.cs中):
// The AllowPartiallyTrustedCallersAttribute requires the assembly to be signed with a strong name key. // This attribute is necessary since the control is called by either an intranet or Internet // Web page that should be running under restricted permissions. [assembly: AllowPartiallyTrustedCallers] // Use the .NET Framework 2.0 transparency rules (level 1 transparency) as default #if (CLR4) [assembly: SecurityRules(SecurityRuleSet.Level1)] #endif
要解决该问题,只需要将调用该库的代码变为所要求的安全关键代码或者安全可靠关键代码即可,但是我搞了半天也不清楚该怎么修改,此路没走通。
另外一种解决办法是修改swig生成的C#封装类代码,强制声明为可被安全透明代码调用即可,以D:\GDAL\gdal-1.9.2\swig\csharp\gdal\Gdal.cs类和D:\GDAL\gdal-1.9.2\swig\csharp\gdal\Dataset.cs类为例,在其类声明的开头添加下述两行代码:
namespace OSGeo.GDAL { using System; using System.Runtime.InteropServices; using System.Security;//新加 [SecuritySafeCritical]//新加 public class Gdal { //...}}
namespace OSGeo.GDAL { using System; using System.Runtime.InteropServices; using System.Security;//新加 [SecuritySafeCritical]//新加 public class Dataset : MajorObject { //...}}
同理,如果想在C#中调用哪个类,就为哪个类添加上述两行代码即可。
3、C#读取nc文件实验结果
Open netCDF file SUCCESS! Data X Size:512; Y Size:512 SUBDATASET_1_NAME=NETCDF:"D:\test\nc\copy.nc":floatv SUBDATASET_1_DESC=[0x5x5x4] floatv (32-bit floating-point) SUBDATASET_2_NAME=NETCDF:"D:\test\nc\copy.nc":doublev SUBDATASET_2_DESC=[0x5x5x4] doublev (64-bit floating-point) SUBDATASET_3_NAME=NETCDF:"D:\test\nc\copy.nc":chv SUBDATASET_3_DESC=[0x80] chv (8-bit character)
做人当然要厚道,编译后的GDAL库的下载地址:http://download.csdn.net/detail/yeahgis/5241135
于2013-04-10 00:53