目錄
- 1. 正文
- 1.1. 編譯LibKML
- 1.1.1. 第三方庫支持
- 1.1.2. 編譯錯誤
- 1.2. 配置GDAL
- 1.3. 鏈接問題
- 1.1. 編譯LibKML
- 2. 參考
1. 正文
GDAL可以支持將KML作為矢量檔案檔案讀取,但是需要在編譯的時候添加第三方庫的支持,否則默認的編譯結果是還是會不識別這種格式,
查閱官方檔案發現有兩種驅動可以支持KML:一種驅動名稱是KML,需要Expat庫的支持,這是一個決議XML格式的庫;另一種驅動名稱是LIBKML,需要LibKML庫的支持,這是google自己的KML讀寫庫,第二種方式支持的功能更多,并且LibKML本身也需要Expat庫的支持,如果兩種驅動都存在,那么在讀取的時候第二種會覆寫第一種,也就是采用LIBKML的方式讀取KML,我這里就是順手把兩種驅動都添加進去了,
閱讀這篇文章之前需要預先知道GDAL是如何編譯的,可參看《Win64下編譯集成GEOS和Proj4的GDAL》,
1.1. 編譯LibKML
LibKML的原始碼托管在GitHub(可點擊點擊進入),下載解壓后可在其根目錄找到libkml.sln這個檔案,通過這個檔案可以在visual studio中打開,然后直接編譯就可以了,總結下在編譯程序中我遇到的問題:
1.1.1. 第三方庫支持
LibKML的原始碼檔案夾中已經自帶了其需要的第三方庫,如下圖所示:

LibKML這個靜態庫挺奇怪,只需要包含第三方對應的頭檔案即可編譯了,所以如果編譯的時候提示找不到頭檔案,可以自己把包含目錄重新設定一下,如下圖所示,這種問題一般都是包含目錄的相對路徑出錯或者缺失造成的,

1.1.2. 編譯錯誤
在編譯libkmlbase這個庫的file_win32.cc這個檔案的時候,提示這段代碼出錯:
// Internal to the win32 file class. We need a conversion from string to
// LPCWSTR.
static std::wstring Str2Wstr(const string& str) {
std::wstring wstr(str.length(), L'');
std::copy(str.begin(), str.end(), wstr.begin());
return wstr;
}
// Internal to the win32 file class. We need a conversion from std::wstring to
// string.
string Wstr2Str(const std::wstring& wstr) {
size_t s = wstr.size();
string str(static_cast<int>(s+1), 0);
WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), static_cast<int>(s), &str[0],
static_cast<int>(s), NULL, NULL);
return str;
}
出錯的地方在std::wstring wstr(str.length(), L'')這一行,錯誤提示是“error C2137: 空字符常量”,其實就是C/C++沒有定義“空字符常量”,L''這種寫法不太標準,將其改成L' '就可以了,同時這段代碼還存在另一個問題:這段代碼的意思是字串wstring和字串string互相轉換,但是很明顯這種寫法是不支持中文字符的,我這里就將這段代碼替換為:
//改動:
//str 與 wstr 的互轉
static std::wstring Str2Wstr(const string& str)
{
size_t i;
std::string curLocale = setlocale(LC_ALL, NULL);
setlocale(LC_ALL, "chs");
const char* _source = str.c_str();
size_t _dsize = str.size() + 1;
wchar_t* _dest = new wchar_t[_dsize];
wmemset(_dest, 0x0, _dsize);
mbstowcs_s(&i, _dest, _dsize, _source, _dsize);
std::wstring result = _dest;
delete[] _dest;
setlocale(LC_ALL, curLocale.c_str());
return result;
}
string Wstr2Str(const std::wstring& wstr)
{
size_t i;
std::string curLocale = setlocale(LC_ALL, NULL);
setlocale(LC_ALL, "chs");
const wchar_t* _source = wstr.c_str();
size_t _dsize = 2 * wstr.size() + 1;
char* _dest = new char[_dsize];
memset(_dest, 0x0, _dsize);
wcstombs_s(&i, _dest, _dsize, _source, _dsize);
std::string result = _dest;
delete[] _dest;
setlocale(LC_ALL, curLocale.c_str());
return result;
}
1.2. 配置GDAL
修改GDAL的編譯組態檔nmake.opt,找到LibKML部分,修改為:
# Uncomment out the following lines to enable LibKML support.
#LIBKML_DIR = C:/Dev/libkml
#LIBKML_INCLUDE = -I$(LIBKML_DIR)/src -I$(LIBKML_DIR)/third_party/boost_1_34_1
#LIBKML_LIBRARY = $(LIBKML_DIR)/msvc/Release
#LIBKML_LIBS = $(LIBKML_LIBRARY)/libkmlbase.lib \
# $(LIBKML_LIBRARY)/libkmlconvenience.lib \
# $(LIBKML_LIBRARY)/libkmldom.lib \
# $(LIBKML_LIBRARY)/libkmlengine.lib \
# $(LIBKML_LIBRARY)/libkmlregionator.lib \
# $(LIBKML_LIBRARY)/libkmlxsd.lib \
# $(LIBKML_LIBRARY)/minizip_static.lib \
# $(LIBKML_DIR)/third_party\expat.win32/libexpat.lib \
# $(LIBKML_DIR)/third_party\uriparser-0.7.5.win32/release/uriparser.lib \
# $(LIBKML_DIR)/third_party\zlib-1.2.3.win32/lib/minizip.lib \
# $(LIBKML_DIR)/third_party\zlib-1.2.3.win32/lib/zlib.lib
LIBKML_DIR = C:/Work/GDALBuild/libkml-master
LIBKML_INCLUDE = -I$(LIBKML_DIR)/src -I$(LIBKML_DIR)/third_party/boost_1_34_1
LIBKML_LIBRARY = $(LIBKML_DIR)/x64/Release
LIBKML_LIBS = $(LIBKML_LIBRARY)/libkmlbase.lib \
$(LIBKML_LIBRARY)/libkmlconvenience.lib \
$(LIBKML_LIBRARY)/libkmldom.lib \
$(LIBKML_LIBRARY)/libkmlengine.lib \
$(LIBKML_LIBRARY)/libkmlregionator.lib \
$(LIBKML_LIBRARY)/libkmlxsd.lib \
$(LIBKML_DIR)/third_party/zlib-1.2.3/contrib/minizip/x64/Release/minizip_static.lib \
$(EXPAT_DIR)/build/Release/libexpat.lib \
$(LIBKML_DIR)/third_party/uriparser-0.7.5/win32/uriparser.lib \
$(LIBKML_DIR)/third_party\zlib-1.2.3.win32/lib/minizip.lib \
$(LIBKML_DIR)/third_party\zlib-1.2.3.win32/lib/zlib.lib
這里的目錄設定可能每個人有點不太一樣,注意不要硬抄根據實際情況修改下,具體來說LIBKML_DIR定義的一個根目錄,通過這個目錄依次找到:LIBKML_INCLUDE包含的頭檔案目錄;LIBKML_LIBRARY依賴的庫檔案目錄;LIBKML_LIBS具體的每一個lib,
minizip_static.lib這個檔案可能沒有直接提供,但是是有源代碼的,可以自己編譯一下:

libexpat.lib檔案也有點不同,宏(EXPAT_DIR)來自于Expat部分:
# Uncomment for Expat support (required for KML, GPX and GeoRSS read support).
#EXPAT_DIR = "C:\Program Files\Expat 2.0.1"
#EXPAT_INCLUDE = -I$(EXPAT_DIR)/source/lib
#EXPAT_LIB = $(EXPAT_DIR)/bin/libexpat.lib
EXPAT_DIR = "C:\Work\GDALBuild\libexpat-master"
EXPAT_INCLUDE = -I$(EXPAT_DIR)/expat/lib
EXPAT_LIB = $(EXPAT_DIR)/build/Release/libexpat.lib
這個Expat部分理論上是可以用third_party中已經編譯好的頭檔案和lib的,但是我這里并沒有詳細求證,因為我是先配置好Expat再配置LibKML的,Expat是自己編譯的,
1.3. 鏈接問題
在編譯鏈接GDAL的程序中,出現了形如“無法決議的外部符號“這種型別的錯誤,如下所示:

這是由于LibKML默認工程中包含的檔案不全,GDAL在編譯鏈接的時候找不到實作造成的,只需要搜索無法決議的函式所在的檔案,將其加入到LibKML的工程中,重新編譯LibKML和GDAL就可以了,我這里缺失的檔案有:
- libkmldom工程:xal.h、xal.cc、gx_timeprimitive.h、gx_timeprimitive.cc、gx_tour.h、gx_tour.cc
- libkmlbase工程: zip_file.h、zip_file.cc、uri_parser.cc、xml_namespaces.h、xml_namespaces.cc
- libkmlengine工程:id_mapper.h、id_mapper.cc、find_xml_namespaces.h、find_xml_namespaces.cc
2. 參考
[1] gdal集成kml庫的做法
[2] 解決gdal集成libkml的鏈接錯誤
[2] std::wstring
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/3970.html
標籤:GIS
