之前一直在搞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