ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

64位libtiff与libgeotiff编译指南:Visual Studio下的CMake配置与排错

64位libtiff与libgeotiff编译指南:Visual Studio下的CMake配置与排错 简介在Windows平台借助VS2013编译64位libtiff与libgeotiff库常会遇到环境配置和依赖链问题这份文档正是针对此需求的实操指南。内容以tiff-4.0.6和libgeotiff-1.4.0源码为例分别演示两个项目的64位编译过程包括调用vcvarsall.bat切换x64环境、使用nmake生成库文件并对编译中典型的libport.lib文件缺失、libtiff头文件未复制、libtiff_i.lib输入文件打不开等问题给出明确的处理步骤。文档还提示重新编译libgeotiff前需先删除旧生成的dll和lib文件以保证结果正确。资源为1个doc格式的说明文档大小仅31KB内容紧凑、步骤清晰。当前已有949人学习下载适合从事地理信息系统或遥感图像处理、需要自建GeoTIFF开发环境的C开发者按照文档操作可少走弯路快速产出64位库文件。1. 64位libtiff和libgeotiff编译方法为什么这个组合常让人卡在链接阶段先看一个真实场景你拿到一份带地理坐标的TIFF影像程序一读就报错查了半天发现32位进程内存不够决定把整个地理编码链路迁到64位。结果libtiff倒是顺利编出来了libgeotiff一链接就报一堆无法解析的外部符号折腾两天才发现是库的依赖顺序和CSV数据文件路径没配对。这就是64位libtiff和libgeotiff编译方法的典型痛点——不是编译本身有多难而是两个库的版本配对、依赖解析、数据文件路径这三件事没理顺玄学问题就全来了。这篇文章要解决的就是这件事在Windows上用Visual Studio从源码编出64位的libtiff和libgeotiff讲清楚每一步的CMake选项、依赖顺序和验证方法。适合正在把遥感影像处理管线从32位迁到64位、或者被GDAL的大包体积劝退想自己编精简库的人。读完你能得到一套可复现的步骤以及我踩过的那些坑的记录。先说结论64位编译本身和32位差别不大真正的翻车点多在CMAKE选项配置和数据文件路径上这两处处理好了整个编译过程半小时内能跑通。2. 编译前置准备依赖关系、工具链与版本配对2.1 先搞清楚libtiff和libgeotiff的依赖倒置关系libgeotiff不是独立的地理编码库它依赖libtiff来读写TIFF结构自己只负责处理GeoTIFF头里的GeoKey。所以编译顺序必须是先编libtiff再编libgeotiff。这个顺序反了后面链接时会出现一大堆unresolved external symbol因为libgeotiff的静态库或者DLL导入库需要引用libtiff的导出函数。另一个容易忽略的点是libgeotiff从1.5.0版本开始把PROJ库作为可选依赖引入了用于坐标系转换。如果你的项目只是读GeoTIFF头里的坐标信息做投影参数解析不涉及坐标变换运算可以在CMake里关掉PROJ支持。但如果你需要把经纬度转成投影坐标那就必须在编译libgeotiff之前先把PROJ编出来然后让libgeotiff找到PROJ的库文件。版本配对也值得多说一句。libtiff的4.0.x系列和4.1.x、4.2.x、4.3.x、4.4.x、4.5.x在API上基本兼容但libgeotiff老版本比如1.4.2对libtiff 4.3的兼容性会有小问题主要体现在一些宏定义的变更上。我一般推荐用小版本较新的组合比如libtiff 4.5.1配合libgeotiff 1.7.1这个组合在VS2019和VS2022上都能顺利编译。用到的工具清单也很简单Visual Studio 2019或2022社区版足够、CMake 3.20以上版本、Git拉源码用直接下载压缩包也行。不需要额外的依赖包因为libtiff的内部压缩格式可以通过配置选择内置版本这一点后面细说。2.2 工具链选择的两个关键点64位编译意味着你要在CMake里明确指定Visual Studio的x64生成器。常见做法是打开“x64 Native Tools Command Prompt for VS 2019”或者直接使用CMake GUI选择Visual Studio 17 2022的x64架构。如果只是装了VS但没装“使用C的桌面开发”工作负载CMake会直接报编译器找不到这一步卡住的频率相当高。第二个关键点是决定用静态库还是动态库。做二次开发的话我建议编动态库因为地理编码程序往往要搭配Python或C#调用动态库DLL加导入库LIB的组合灵活得多。但如果你的目标是做一个单文件命令行工具拿去部署静态库更省事。这个选择要在CMake配置阶段定下来因为libtiff和libgeotiff的链接方式要一致否则会出现运行时找不到DLL的问题。提示编译64位库时所有参与链接的第三方库必须是同一种调用约定x64统一使用Microsoft x64调用约定不存在32位时代的__cdecl和__stdcall混用问题但动态库和静态库混用依然会产生LNK2019错误这点要注意。我自己的习惯是把源码放在C:\geo_libs\src目录下构建目录和源码分离分别建build_tiff和build_geotiff子目录。这样即使配置错了删掉构建目录重新来就行不需要重新解压源码也算是个后悔药吧。2.3 下载哪个版本、选哪个编译器分支libtiff的官方GitHub仓库只保留一个master分支但它会在每个release打tag。你需要下载对应tag的源码而不是直接clone master。因为master分支可能包含尚未稳定的代码比如4.6.0的改动就可能影响到libgeotiff的接口编译。libgeotiff同理它的GitHub仓库叫geotiff/libgeotiff注意别和libgeotiff.org上的旧版本搞混了。旧版本在SourceForge上有零散发布但那些已经是历史遗留物新项目直接用GitHub上的最新release即可。编译器方面VS2019和VS2022生成的库文件在二进制层面兼容但如果你用VS2019编库、VS2022编调用程序链接一般没问题。反过来也一样。唯一需要注意的如果用了vcpkg或者conda的预编译库编译器版本必须严格匹配这就不属于手动编译范围了所以这篇文章里不讨论这种混合方式。3. 编译64位libtiffCMake选项与四步构建3.1 用CMake GUI完成首次配置libtiff的编译推荐用CMake GUI因为选项比较多GUI能把开关直观地列出来。首次配置时分四步走第一步打开CMake GUI设置源码目录为C:\geo_libs\src\tiff-4.5.1构建目录设为C:\geo_libs\build\tiff-64。第二步点击Configure按钮在弹出窗口中选择Visual Studio 2022的x64版本生成器。如果你是VS2019选Visual Studio 16 2019并且把右侧的Optional platform for generator设为x64。这一步千万别漏否则CMake会给32位程序编译库文件后面链接时会出现无法解析的外部符号还很难排查。第三步等待Configure完成后在CMake GUI里修改关键选项。下表是我在64位编译时使用的配置选项名建议值原因tiff-toolsOFF不需要命令行工具减少编译时间和依赖tiff-contribOFFcontrib里的扩展代码和老API不兼容tiff-testsOFF测试数据需要网络下载离线环境下会报错tiff-docsOFF纯文档不参与编译cxxOFFlibtiff本身就是C库不需要C编译器支持jpegON 内置版本支持JPEG压缩的TIFF内置免去外部依赖zipON 内置版本支持DEFLATE压缩的TIFFzlibONlibgeotiff会间接用到zlib的压缩原语lzmaOFF除非你有XZ压缩的TIFF需求否则不用开zstdOFF同上ZSTD压缩格式在交通和测绘领域用得少第四步再次点击Configure等选项生效后再点Generate。Generate完成后构建目录里会出现一个tiff.sln解决方案文件用Visual Studio打开它就能编译。3.2 命令行构建方式与参数说明如果你不喜欢Visual Studio的IDE也可以用命令行。打开“x64 Native Tools Command Prompt for VS 2022”输入以下命令cmake -S C:\geo_libs\src\tiff-4.5.1 -B C:\geo_libs\build\tiff-64 -G Visual Studio 17 2022 -A x64 -DCMAKE_CONFIGURATION_TYPESRelease -Dtiff-toolsOFF -Dtiff-contribOFF -Dtiff-testsOFF -DcxxOFF cmake --build C:\geo_libs\build\tiff-64 --config Release --parallel 8第一行里-S和-B指定源码和构建目录-G指定生成器-A x64明确目标架构为64位。CMAKE_CONFIGURATION_TYPESRelease表示只生成Release配置这样在VS里切换配置时会少一些选项减少误操作。第二行的--parallel 8是让编译器用8个线程并行构建速度能提升不少机器配置低的改4就行。编译完成后用Visual Studio打开解决方案在解决方案资源管理器里右键tiff项目选择生成。如果你更习惯命令行可以用MSBuild命令msbuild tiff.sln /p:ConfigurationRelease /p:Platformx64这一步生成的Release目录下会看到tiff.dll、tiff.lib、tiffxx.dll如果开了cxx选项才会有等文件。注意检查一下是否有tiff.lib生成这个导入库文件在后面链接libgeotiff时是必需的。3.3 libtiff编译结果的验证与安装编译完成后先别急着编libgeotiff先验证libtiff本身是64位的。打开命令行进入输出目录执行dumpbin /headers tiff.dll | findstr machine输出里会显示machine (x64)如果显示x86说明编译成32位了需要回到CMake重新确认-A x64参数是否生效。验证通过后建议把libtiff的头文件、库文件和DLL集中到一个目录方便libgeotiff编译时引用。常见做法是创建C:\geo_libs\install目录手动把include和lib文件复制过去。也可以使用CMake的install步骤cmake --install C:\geo_libs\build\tiff-64 --config Release --prefix C:\geo_libs\install这个命令会把头文件装到include目录库文件装到lib目录。用这个方式的好处是libgeotiff的CMakeLists.txt可以通过find_package(TIFF)自动找到安装好的libtiff省去手动指定路径的麻烦。血泪经验如果手动复制头文件务必连带tiffconf.h和tiffvers.h一起复制缺了它们libgeotiff编译时会疯狂报错因为libtiff的公共头文件会include这两个文件。4. 编译64位libgeotiffCSV数据文件与PROJ依赖的处理4.1 libgeotiff的CMake配置和依赖项绑定libgeotiff的编译比libtiff稍微复杂一点因为它的CMakeLists需要显式指定TIFF库的位置还有一些选项会直接影响运行时行为。以libgeotiff 1.7.1为例推荐配置如下cmake -S C:\geo_libs\src\libgeotiff-1.7.1 -B C:\geo_libs\build\geotiff-64 -G Visual Studio 17 2022 -A x64 -DCMAKE_CONFIGURATION_TYPESRelease -DCMAKE_PREFIX_PATHC:\geo_libs\install -Dtiff_INCLUDE_DIRC:\geo_libs\install\include -Dtiff_LIBRARYC:\geo_libs\install\lib\tiff.lib -DPROJ_INCLUDE_DIRC:\geo_libs\install\include -DPROJ_LIBRARYC:\geo_libs\install\lib\proj.lib -DBUILD_SHARED_LIBSON -DCMAKE_WINDOWS_EXPORT_ALL_SYMBOLSONCMAKE_PREFIX_PATH是告诉CMake去哪里找已安装的第三方库这里指向了前面install的目录。tiff_INCLUDE_DIR和tiff_LIBRARY是手动指定libtiff的位置如果find_package失败这种手动指定就很管用。BUILD_SHARED_LIBSON表示生成动态库因为我们要的是DLL和导入库。CMAKE_WINDOWS_EXPORT_ALL_SYMBOLSON这个选项很关键CMake在Windows上不会自动导出所有符号必须显式开启这个选项否则生成的lib文件可能是空的链接时照样报一堆LNK2001错误。如果你不需要PROJ坐标转换功能把PROJ_INCLUDE_DIR和PROJ_LIBRARY对应的行去掉就行。但要注意libgeotiff的代码中有条件编译的代码块通过HAVE_PROJ宏控制关掉PROJ后,其Libgeotiff库里的某些API会缺失比如GTIFProj4ToLatLong。所以除非确定不用坐标转换否则我建议还是把PROJ编出来反正PROJ的编译也是标准CMake流程。4.2 地理CSV数据文件最容易踩坑的路径设置libgeotiff运行时依赖一个名叫GeoTIFF_CSV.csv的CSV文件里面记录了所有GeoKey的ID、名称、取值范围和默认值。这个文件在源码的csv子目录下编译时并不会自动复制到安装目录需要手动处理。编译阶段要做两件事第一在CMake配置时设置GeoTIFF_CSV_CSV_DIR变量把它指向csv目录的绝对路径第二编译完成后把整个csv目录复制到安装目录里。这个顺序不能反因为CSV文件的路径在编译时会被写入库内部的默认搜索路径里。安装后的目录结构建议如下C:\geo_libs\install\ include\ geotiff.h geo_tiffp.h geokeys.h geo_keyp.h ... lib\ geotiff.lib proj.lib tiff.lib bin\ geotiff.dll proj.dll tiff.dll csv\ GeoTIFF_CSV.csv ...运行时假如DLL放在bin目录程序的工作目录在别处需要设置环境变量GEOTIFF_CSV_DIR指向csv目录或者把dll和csv目录放在同一级。很多人在程序里读GeoTIFF时得到一堆奇怪的警告比如“GeoTIFF keys not recognized”就是因为这个CSV文件没加载到GeoKey ID无法被翻译成有意义的字符串。注意GeoTIFF_CSV.csv的编码必须是ANSI或者UTF-8无BOM。如果你用记事本另存过并默认加上了BOM会导致libgeotiff解析CSV时第一行出错表现为所有GeoKey都解析失败这个bug查起来非常隐蔽。4.3 库文件的合并与链接顺序编译完成后bin目录下会有三个DLLtiff.dll、proj.dll、geotiff.dll以及对应的导入库。链接时链接器有顺序要求geotiff.lib必须在tiff.lib和proj.lib之前。这是Visual Studio的惯例依赖库放在被依赖库之前。用Visual Studio进行链接时在“项目属性 → 链接器 → 输入 → 附加依赖项”里按下列顺序填写geotiff.lib tiff.lib proj.lib不要写成tiff.lib geotiff.lib proj.lib因为libgeotiff的函数在解析时需要先看到tiff和proj的符号表。如果顺序反了会报LNK2019或者LNK2001具体为geotiff相关函数无法解析。如果你用CMake搭建自己的项目可以用target_link_libraries来保证顺序target_link_libraries(my_app PRIVATE geotiff tiff proj)如果你用CMake强烈建议用find_package(GeoTIFF)和find_package(TIFF)代替手动指定LIB路径CMake会自动处理依赖顺序。不过前提是libgeotiff安装时正确生成了GeoTIFFConfig.cmake配置文件通常1.7.0版本都会安装。5. 常见编译错误排查3个高频翻车场景与对策5.1 现象一C4996错误刷屏strcpy被标记为不安全编译64位libtiff时VS2019或VS2022会报大量C4996警告或错误断言为“This function or variable may be unsafe”聚焦在strcpy、sprintf等C运行时库函数上。如果项目设置了“将警告视为错误”/WX这些警告会直接变成编译错误。原因MSVC对旧版C标准库函数做了弃用标记建议用strcpy_s、sprintf_s替代。但libtiff源码为了跨平台兼容性使用标准ANSI C函数并没有跟着MSVC的建议走。解决方案在CMake配置时追加编译参数-DCMAKE_C_FLAGS/D_CRT_SECURE_NO_WARNINGS这个宏会让MSVC忽略这些弃用警告。或者在CMakeLists里修改项目属性target_compile_definitions(tiff PRIVATE _CRT_SECURE_NO_WARNINGS)如果不想改CMake也可以在VS项目属性里C/C → 预处理器 → 预处理器定义中添加_CRT_SECURE_NO_WARNINGS。我一般两种方法都加保险起见。5.2 现象二libgeotiff库编好了但链接时出现缺少GeoTIFF_CSV相关的错误这个问题的表现形式比较多样有的是在程序启动时报段错误或者空指针有的是在GTIFNew或GTIFNewFromFile函数返回NULL但编译和链接一切正常。用debugger看会发现,程序卡在读取csv目录文件时找不到对应的CSV条目。原因GeoTIFF_CSV.csv没有放在libgeotiff默认搜索的目录里。默认搜索路径是编译时写入的字符串常量如果你手动移动了安装目录这个路径就会失效。解决方案第一次运行时设置一个环境变量set GEOTIFF_CSV_DIRC:\geo_libs\install\csv然后重新运行你的程序看是否恢复正常。如果正常说明路径问题确认之后在程序启动处设置环境变量或者把库和csv的路径固定下来。这个环境变量的优先级高于编译时写入的路径所以也算是个运行时补救手段。排查技巧用vcpkg安装的libgeotiff通常把这些CSV数据文件放在share\data目录但手动编译的库需要自己维护这个目录结构。这就导致很多人从vcpkg切换到手动编译后突然报错实际上不是代码变了是CSV路径没跟上。5.3 现象三链接时报LNK1104无法打开tiff.dll 或 proj.dll这是Windows上特有的链接错误程序运行时需要加载动态库但系统找不到DLL文件。编译阶段不会报错在运行阶段报“由于找不到tiff.dll无法继续执行代码”。原因tiff.dll和proj.dll的安装目录不包含在系统的PATH环境变量里或者你没有把DLL复制到exe的相邻目录。解决方案直接把tiff.dll、proj.dll、geotiff.dll三个DLL复制到exe所在目录或者把bin目录加入环境变量PATH。如果只想在本地调试用Visual Studio调试时在项目属性 → 调试 → 环境变量中添加PATH...就行。还有一个进阶方案用lib.exe的/dll参数把三个导入库合并成一个静态库但这在MSVC下实现起来曲折而且要处理导出符号重复问题不如直接复制DLL省事。这个坑我踩过一次之后就不再折腾了。6. 验证编译成果与运行GeoTIFF文件的测试方法这一章直接给一个可落地的验证步骤确保你编译出的库真的能读带地理坐标的TIFF文件并且坐标解析精确到小数点后六位。先写一个最小的C测试程序用GTIFNewFromFile函数读取GeoTIFF并打印投影参数#include stdio.h #include stdlib.h #include geotiff.h #include geo_tiffp.h int main(int argc, char *argv[]) { if (argc 2) { printf(usage: test_geotiff input.tif\n); return 1; } TIFF *tif TIFFOpen(argv[1], r); if (tif NULL) { printf(cannot open tif\n); return 1; } GTIF *gtif GTIFNewFromFile(tif); if (gtif NULL) { printf(cannot read geokey from tif\n); TIFFClose(tif); return 1; } // 读取投影坐标系类型GeoTIFF Key 3072 int projection 0; int count 0; int *vals NULL; if (GTIFKeyInfo(gtif, GeoTIFFKey_ProjectedCSParm, count, NULL) 0 count 0) { vals (int *)malloc(sizeof(int) * count); GTIFKeyGet(gtif, GeoTIFFKey_ProjectedCSParm, vals, 0, count); projection vals[0]; free(vals); } printf(projection key %d\n, projection); // 读取地理坐标转换参数GeoTIFF Key 3076 double vals2[10] {0}; int count2 0; if (GTIFKeyGet(gtif, GeoTIFFKey_GeographicTypeGeoKey, vals2, 0, 1) 0) { // 打印经纬度转换参数便于人工比对 printf(GeographicType %.6f\n, vals2[0]); } (void)projection; (void)count2; GTIFFree(gtif); TIFFClose(tif); return 0; }代码里的GTIFKeyGet函数是libgeotiff读取GeoKey的核心接口第三和第四个参数指定取值的起始索引和个数。GeoTIFFKey_ProjectedCSParm对应的是投影坐标系统代码如EPSG:32650对应UTM Zone 50NGeographicTypeGeoKey对应的则是地理坐标系代码。这段程序只做校验用不会做实际坐标运算重点在验证库是否能正常解析tif头的键值结构。编译命令是cl /I C:\geo_libs\install\include test_geotiff.c /link C:\geo_libs\install\lib\geotiff.lib C:\geo_libs\install\lib\tiff.lib C:\geo_libs\install\lib\proj.lib如果链接成功且运行正常说明64位libtiff和libgeotiff的编译成果可用。如果链接报错对照第5部分的排错章节逐项排查。验证时有个技巧先用tiffinfo -v工具libtiff自带确认文件标签里的软件版本信息如果你编译的libtiff写入了版本字符串能看到类似LIBTIFF, Version 4.5.1的字样。再用listgeolibgeotiff自带的命令行工具输出CSV转换后的键值对照表这个表能直观地显示每个GeoKey的ID和名称匹配是否正确。运行listgeo之前记得把csv目录的环境变量设置好否则它输出一堆-1或者Unknown。最后测试CGCS2000坐标系和WGS84的GeoTIFF各一枚。这两个坐标系在GeoKey编码上的差异很小如果CSV文件没加载好解析出来的代码值会错得很离谱。CGCS2000在EPSG里对应的是4490地理坐标或4491-4500投影坐标WGS84对应4326。如果程序输出这两个值能正确区分说明整个编译链路从libtiff到libgeotiff再到CSV数据文件全部打通了。我现在的习惯是每次编译完都跑这组测试再顺手跑一遍GeoTIFF的坐标换算确认投影值精确到小数点后第三位。这套流程帮我拦下了好几次升级库版本后引入的回归。希望帮到你。本文还有配套的精品资源点击获取
返回列表