简介:面向需要在Windows环境下编译64位libtiff和libgeotiff库的开发者,该文档梳理了基于VS2013工具链的完整编译流程,针对libport.lib缺失、头文件路径、libtiff_i.lib链接报错等常见问题给出了可复现的解决办法,适合GIS或遥感图像处理方向的C++开发人员参考。资源为doc格式文档,仅1个文件,压缩包大小31KB,内容精炼,步骤划分清晰。该资料已有949人学习。文档以命令行操作为主线,细致说明了x86本机工具命令提示符下调用vcvarsall.bat进入x64编译环境的方法,并逐个给出libtiff、libgeotiff库的生成顺序、切换目录、执行nmake的命令及出错时的处置策略。掌握这些操作后,读者可以自行产出64位libtiff、geotiff.dll及相关导入库,为后续基于GeoTIFF格式的图像处理应用开发提供基础支持。
1. 有现成包却要自己编 64 位 libgeotiff:场景与取舍
做 GIS 和遥感数据处理的人,手头遇到 GeoTIFF 要读写时,第一反应是找预编译包。libtiff 官方站点也好,libgeotiff 源码包也好,Windows 下 64 位预编译产物其实并不完整,能直接拿过来用的多数还停留在 32 位时代。为了把 GeoTIFF 后端库接进自己的 C++ 工具,绕不开自己动手编译这一步。这套编译方法针对的正是 VS2013 下编译 64 位 libtiff-4.0.6 与 libgeotiff-1.4.0 的完整过程:全程用 nmake 命令行,不依赖 CMake,也不需要额外装环境。适合要封装 GeoTIFF 读写库的 GIS 开发者,也适合在各种 Windows 工程里复用同一套编译产物的朋友。
2. 编译前的环境准备:VS2013 工具链与不带空格的 D:\VC 目录
2.1 为什么用 nmake 而不是 CMake
libtiff-4.0.6 源码包里面已经带了一份可以直接供 nmake 使用的 makefile.vc,libgeotiff-1.4.0 同样在根目录保留了这套构建入口。VS2013 自带 nmake.exe,所以不需要额外安装 CMake,也不用考虑生成器选型、缓存变量这类干扰问题。早期这些代码包大量依赖 nmake 的批处理语义,诸如“让某个子目录先编译”“把某个头文件放到指定位置”这类操作,都写在 makefile.vc 里面了。你只要保证 nmake 能跑起来,剩下的编译顺序由 makefile 控制。
这里要刻意提一句:VS2013 里所谓“x86 本机工具命令提示符”,并不是只能编 32 位程序。它自带的 cl.exe 编译器可以同时生成 x86 和 x64 目标代码,区别只在环境变量里 LIB、INCLUDE、PATH 指向的是哪一套工具链。所以在该命令提示符里再执行一次D:\VC\vcvarsall.bat x64,等于把当前 cmd 进程的环境变量整体切换到 x64 交叉编译状态。下面所有步骤都默认你在这个环境里操作,不要另开一个普通 cmd 窗口。
2.2 vcvarsall.bat 的 x64 参数和默认行为
vcvarsall.bat 是 VS 官方提供的环境配置脚本,作用是把编译器、库、头文件目录写进当前进程的环境变量。不带参数执行时,它把环境指向 32 位工具链;带 x64 参数时,指向 64 位工具链。对 tiff 和 geotiff 这两个库来说,你要编 64 位版本,每次打开新命令行窗口后都要确保 x64 环境被真正加载过。
D:\VC\vcvarsall.bat x64这条命令本身没有输出,或者只有一行版本信息。判断环境是否生效,用下面的方式验证:
where cl echo %LIB%如果where cl能返回 cl.exe 的完整路径,并且%LIB%里含有 x64 相关目录,说明 64 位环境已经就绪。如果LIB变量为空或者指向 x86 目录,后面编译出来的库大概率是 32 位,等链接 64 位程序时会踩一脚大的。
2.3 D:\VC 目录的由来和路径空格问题
为什么要把 VS 的 VC 目录整个复制到 D:\VC?原因很实际:默认安装路径是D:\Program Files\Microsoft Visual Studio 12.0\VC,中间带空格。VS2013 的“x86 本机工具命令提示”启动时可以正确处理这个路径,但 nmake 在处理 makefile.vc 里的路径拼接时,遇到空格就可能不自动加引号,导致找不到 cl.exe、找不到头文件这类怪问题。与其去改 makefile,不如直接把 VC 目录复制到 D:\VC,让所有路径都不带空格。这也是很多老工程在 Windows 上手动编译源码包的通用做法。
具体操作是把 VS2013 安装目录下的 VC 文件夹完整复制一份,保留里面的 bin、include、lib、PlatformSDK 等子目录。注意不要只复制 vcvarsall.bat 一个文件,因为脚本启动时会调用同目录下的其他工具,缺少子目录照样会失败。复制完成后,编译流程里所有vcvarsall.bat调用都指向D:\VC\vcvarsall.bat。
2.4 编译前要确认的目录结构
开始之前,建议把源码包按下面的布局放好,后面每一步都依赖这个目录约定:
| 目录 | 作用 |
|---|---|
| D:\VC\ | 从 VS2013 安装目录复制的 VC 工具链 |
| D:\tiff-4.0.6\port\ | tiff 源码包中的 port 兼容层 |
| D:\tiff-4.0.6\libtiff\ | libtiff 核心源码与最终输出目录 |
| D:\libgeotiff-1.4.0\ | libgeotiff 源码目录 |
| D:\libgeotiff-1.4.0\libxtiff\ | geotiff 内部对接 libtiff 的目录 |
libgeotiff 的 makefile 里写死了相对路径..\libtiff\libtiff\libtiff_i.lib,这决定了 libtiff_i.lib 最终要放在哪,后面会专门讲到。目录布局尽量保持和上面一致,能省掉后续大量排查时间。
3. 编译 64 位 libtiff-4.0.6:先补 libport.lib,再回 libtiff 目录
3.1 配置 x64 环境并进入 libtiff 目录
打开 VS2013 的“x86 本机工具命令提示符”,第一步不是直接切目录,而是确认 cl.exe 和 nmake 可用。这一步常被忽略,但它决定了后面所有命令能否识别。按下面顺序执行:
cd /d D:\tiff-4.0.6\libtiff D:\VC\vcvarsall.bat x64 nmake /f makefile.vc注意cd /d这个写法。cmd 里只输入cd D:\tiff-4.0.6\libtiff不会切换盘符,必须带 /d 参数才能跨盘跳转。如果你当前就在 D 盘,不带 /d 也没问题,但写成 /d 更保险。
执行nmake /f makefile.vc后,第一次大概率会收到这样的报错:在D:\tiff-4.0.6\port目录下找不到libport.lib。这不是你操作错了,而是 libtiff 的 makefile 默认假设 port 目录已经编译完成。port 目录在 tiff 源码包里承担的是 Windows 平台缺失的 POSIX 兼容函数实现,比如一些字符串处理函数、文件操作替代,libtiff 主库在链接时需要用到它。所以你得手动先把这个前置库编出来。
3.2 切换到 port 目录生成 libport.lib
回到 VS2013 命令行窗口,当前目录切到D:\tiff-4.0.6\port,然后重新加载一次 x64 环境变量,再编译:
cd /d D:\tiff-4.0.6\port D:\VC\vcvarsall.bat x64 nmake /f makefile.vc对这里的参数说明:虽然 vcvarsall.bat 在上一步已经执行过,但它设置的环境变量只作用于当前 cmd 会话。同一会话内理论上不重复执行也能继续用,但多执行一次并不会有负面影响,也不会把编译器路径“叠加”坏,只是重新覆盖一遍。真正需要注意的是别关掉当前 cmd 窗口再重新开一个普通窗口,那样环境就丢了。
port 目录编译完成后,会生成libport.lib。这个库是给 libtiff 主库链接用的,不需要手动拷贝到任何地方,只要留在原目录即可。接下来回到 libtiff 目录继续主库编译。
3.3 返回 libtiff 目录完成主库编译
现在回到D:\tiff-4.0.6\libtiff,再次执行 nmake。这个时候 port 目录下的 libport.lib 已经存在,makefile 能顺利通过依赖检查:
cd /d D:\tiff-4.0.6\libtiff nmake /f makefile.vcnmake 判断是否需要重新编译某个目标,靠的是文件时间戳。所以第二次执行时,它不会把 port 目录重新编一遍,只会继续处理当前目录里跟 libtiff 库直接相关的源文件。这是 nmake 的正常增量行为,不需要担心。
编译结束后,去D:\tiff-4.0.6\libtiff目录查看,正常情况下能看到 2 个 lib 文件和 1 个 dll 文件。文件名大致是libtiff.dll、libtiff_i.lib和另一个 lib 文件,具体名称以 makefile.vc 的输出设置为准。这三个文件后续各有分工:libtiff.dll是运行时动态库,libtiff_i.lib是链接程序时用的导入库,程序启动后仍会去找同名的 dll。另一个 lib 文件通常对应静态链接版或 makefile 默认输出的附加库,具体用途可以看 makefile.vc 顶部的配置注释。
3.4 编译输出文件怎么确认真正是 64 位
第一次编出 libtiff 后,别急着往下走,先确认平台位数。最省事的办法是用 VS 自带的 dumpbin 工具:
dumpbin /headers D:\tiff-4.0.6\libtiff\libtiff.dll输出里有一段 PE 头信息,找到machine字段。如果是8664或x64,说明是 64 位版本;如果显示14C或x86,那说明 vcvarsall.bat 的 x64 参数没真正生效,编译出来的是 32 位库。这种情况下一步链接 libgeotiff 时大概率会报架构不匹配,早点验证比最后排查省时间。
4. 编译 64 位 libgeotiff-1.4.0:补齐 libxtiff 头文件,链接 libtiff_i.lib
4.1 进入 libgeotiff 目录并加载 x64 环境
libgeotiff 的编译入口同样是根目录下的 makefile.vc。打开 VS2013 x86 本机工具命令提示符,先切换到源码目录,再加载 64 位环境:
cd /d D:\libgeotiff-1.4.0 D:\VC\vcvarsall.bat x64 nmake /f makefile.vc这一步的报错会来得很直接:提示D:\libgeotiff-1.4.0\libxtiff\目录下缺少 libtiff 库里的头文件。libxtiff 是 libgeotiff 内部用来对接 libtiff 的适配层,它里面的源码文件大量#include "tiffio.h"、#include "tiff.h"这类头文件。但 libgeotiff 源码包发布时,不会把 libtiff 的头文件也放进去,需要你自己从 libtiff 源码里补过来。
4.2 复制 libtiff 头文件到 libxtiff 目录
复制头文件时不要只复制报错里提到的那一个。常见的做法是把 libtiff 主目录里的几个核心头文件一起复制,包括tiff.h、tiffio.h、tiffvers.h、tiffconf.h等。如果有其他缺失头文件的报错,按报错清单继续补齐就行,一般不会超出这几个的范围。
copy /Y D:\tiff-4.0.6\libtiff\tiff.h D:\libgeotiff-1.4.0\libxtiff\ copy /Y D:\tiff-4.0.6\libtiff\tiffio.h D:\libgeotiff-1.4.0\libxtiff\ copy /Y D:\tiff-4.0.6\libtiff\tiffvers.h D:\libgeotiff-1.4.0\libxtiff\ copy /Y D:\tiff-4.0.6\libtiff\tiffconf.h D:\libgeotiff-1.4.0\libxtiff\/Y参数的作用是覆盖已存在文件时不弹确认提示,避免复制过程中被交互打断。复制完成后,重新执行一次nmake /f makefile.vc,这次会继续往下走,但大概率会碰到第二个错误:无法打开输入文件..\libtiff\libtiff\libtiff_i.lib。
这个报错很关键,它暴露了 makefile.vc 里写死的相对路径。..\libtiff\libtiff\libtiff_i.lib相对于当前目录D:\libgeotiff-1.4.0解析,得到的就是D:\libtiff\libtiff\libtiff_i.lib。它不会去 D:\tiff-4.0.6 下面找,即使你把 libtiff_i.lib 放在源码包里它也不认。
4.3 把 libtiff_i.lib 放到相对路径要求的位置
解决方式很直接:在 D 盘根目录建立一个D:\libtiff\libtiff\目录,把编译 libtiff 时得到的 libtiff_i.lib 复制过去。
mkdir D:\libtiff\libtiff 2>nul copy /Y D:\tiff-4.0.6\libtiff\libtiff_i.lib D:\libtiff\libtiff\2>nul是为了忽略 mkdir 在目录已存在时输出的错误提示,不影响命令执行。复制完成后,再次运行nmake /f makefile.vc,这次应该能走完整个编译流程。完成后在D:\libgeotiff-1.4.0目录下会生成geotiff.dll、geotiff_i.lib、geotiff.lib三个文件。geotiff_i.lib是供链接使用的导入库,geotiff.dll是运行期动态库,geotiff.lib通常配合静态链接场景使用。
注意一个容易忽视的点:libgeotiff 链接时只需要 libtiff_i.lib 这个导入库,不需要把 libtiff.dll 复制到 libgeotiff 目录。但最终运行测试程序时,libtiff.dll 和 geotiff.dll 两个动态库都必须能被系统找到,否则程序启动会直接报“找不到 DLL”错误。
4.4 重新编译前必须清理旧文件和临时文件
如果 libgeotiff 目录下已经有过编译产物,下次再想完整重新编译,必须先删掉旧文件。nmake 依赖文件时间戳判断是否需要重新生成,如果 geotiff.dll 已经存在且时间戳比源文件新,它会直接跳过 DLL 的生成步骤,最后你看着目录里有文件,实际内容还是旧的,甚至可能不完整。
del /Q D:\libgeotiff-1.4.0\geotiff.dll del /Q D:\libgeotiff-1.4.0\geotiff_i.lib del /Q D:\libgeotiff-1.4.0\geotiff.lib del /S /Q D:\libgeotiff-1.4.0\*.obj/S表示递归删除子目录里的 .obj,/Q表示安静模式。如果你中间改过 libtiff 的路径或者复制过不同版本的头文件,清理后重新编译才是正确姿势。否则下一次 nmake 可能静默跳过关键步骤,导致你排查半天才发现跑的是旧产物。
5. 常见问题排查:手动编译最容易翻车的五个环节
5.1 新开一个 shell 窗口,nmake 又不见了
现象:编译到一半关掉了命令行窗口,重新打开一个普通 cmd,输入nmake /f makefile.vc,系统提示“nmake 不是内部或外部命令”。
原因:VS 的工具链环境变量只存在于启动它的那个 cmd 进程里。普通 cmd 没有把 VS 的 bin 目录加进 PATH,自然找不到 nmake.exe。这和当时在 VS2013 x86 本机工具命令提示符下可以跑是两回事。
解决:要么重新从开始菜单打开“VS2013 x86 本机工具命令提示符”,要么在新窗口里先执行一次D:\VC\vcvarsall.bat x64,让 PATH、INCLUDE、LIB 重新加载当前会话,再继续编译。建议一个窗口走完所有步骤,中间不要反复开关。
5.2 nmake 静默跳过导致产出旧库
现象:明明改了源码配置重新编译,库文件时间戳没变化,程序链接后行为还是旧的。
原因:首次编译中断或者手动执行过部分目录的 nmake,导致某些中间 .obj 文件已经生成而最终 DLL 没有生成。第二次 nmake 看到 .obj 比 makefile 新,认为目标已更新,直接不执行 DLL 的链接步骤。
解决:编译库类项目时,删除所有 .obj、.idb、.pch 等中间文件,再重新跑完整的nmake /f makefile.vc。想确认到底有没有重新编译,看命令行回显里是否有cl.exe被调用的记录。没有新编译输出,说明 makefile 认为不需要动作,这种时候回收站里翻一下旧文件清理是否到位。
5.3 libtiff_i.lib 放错位置,链接错误反复出现
现象:已经把 libtiff_i.lib 复制到源码包某个目录,libgeotiff 编译时仍然报“无法打开输入文件..\libtiff\libtiff\libtiff_i.lib”。
原因:libgeotiff 的 makefile 里使用相对路径定位 libtiff 的导入库,编译器只认这个写死的相对位置,不会去全盘搜索。你把 libtiff_i.lib 放到 libgeotiff 源码目录下,或者放到 D:\tiff-4.0.6\libtiff 下,它依然找不到。
解决:看清报错路径的前半段..\libtiff\libtiff\,把这个目录完整建立出来。也就是放在 D:\libtiff\libtiff\ 下,让相对路径解析后能准确命中。如果不希望 D 盘根目录多出这个目录,也可以改 makefile.vc 里的 TIFF 相关变量,但改文件不如放文件省事,生产环境少动 makefile。
5.4 64 位程序运行时报缺少 DLL
现象:程序编译链接都通过,一运行提示找不到 libtiff.dll 或 geotiff.dll。甚至有的程序在开发机上能跑,拷贝到别的机器就挂。
原因:链接时使用的 libtiff_i.lib 只是导入库,它记录的是符号和库文件名的对应关系,不会把 DLL 复制到 exe 输出目录。运行时系统会依次搜索 exe 所在目录、系统目录和 PATH 环境变量路径,这些地方都没有对应 DLL,自然报错。
解决:把 libtiff.dll、geotiff.dll 复制到 exe 同目录,同时确认目标机器装了 VS2013 对应的 VC++ 运行库,64 位程序需要的是 x64 版本的 msvcp120.dll、msvcr120.dll。如果目标机器是精简环境的国产系统或工控系统,把这两个运行库 DLL 一并放到 exe 目录是最稳妥的办法。
5.5 32位和64位库混用导致链接器报错
现象:用 x64 配置编译 libgeotiff 成功,但接到工程里链接时报 LNK1112 或类似的模块机器类型冲突,提示 x86 与 x64 不匹配。
原因:链接错误的一方不是 geotiff 库本身,而是工程里另外链接了 32 位版本的 libtiff 或其他依赖库。Windows 的导入库和动态库在链接时必须保持相同的目标机器类型,一个工程里混用不同位宽,链接器直接拒绝。
解决:把整个 VS 工程切换到 x64 平台配置,所有第三方库统一换成 64 位编译版本。千万别只替换 libtiff_i.lib,其他依赖库比如 jpeg、zlib 也得对应换掉。也可以用 dumpbin /headers 逐个检查导入库的 machine 字段,这一步虽然繁琐但最可靠。
6. 编译结果的验证:dumpbin 检查位宽,最小调用程序测试链路
6.1 用 dumpbin 验证 DLL 平台位宽
编译完成后不要只看文件名带不带 x64 字样,文件名是可以骗人的。用 dumpbin 直接读 DLL 的 PE 头最可靠:
dumpbin /headers D:\libgeotiff-1.4.0\geotiff.dll | findstr "machine"输出里如果看到14D machine (x64),说明这个 DLL 是货真价实的 64 位版本。若显示14C machine (x86),说明环境变量加载环节出了问题,之前跑的 nmake 还是 32 位工具链。/headers会把 DOS 头和 PE 头完整列出来,findstr "machine"只是筛选出机器类型那一行,避免刷屏。
6.2 写一个最小 C 程序验证 libtiff 到 libgeotiff 的调用链路
验证库能不能用,不能只停留在“文件存在”层面。写一个最小的调用程序,同时调用 libtiff 的 TIFFOpen 和 libgeotiff 的 GTIFNew,能跑通说明头文件路径、导入库链接、DLL 运行依赖三个环节都正常:
#include "tiffio.h" #include "xtiffio.h" #include <stdio.h> int main(void) { TIFF* tif = TIFFOpen("D:\\test_gt.tif", "w"); if (!tif) { puts("TIFFOpen failed"); return 1; } TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, 16); TIFFSetField(tif, TIFFTAG_IMAGELENGTH, 16); TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8); TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1); TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); GTIF* gtif = GTIFNew(tif); if (!gtif) { puts("GTIFNew failed"); TIFFClose(tif); return 1; } GTIFFree(gtif); TIFFClose(tif); puts("GTIF link ok"); return 0; }用 cl 编译时,把两个库的 include 目录和 lib 目录都带进来:
cl /nologo test_gt.c /I D:\tiff-4.0.6\libtiff /I D:\libgeotiff-1.4.0\libxtiff /link /LIBPATH:D:\tiff-4.0.6\libtiff /LIBPATH:D:\libgeotiff-1.4.0 libtiff_i.lib geotiff_i.lib编译完成后,把 libtiff.dll 和 geotiff.dll 复制到 test_gt.exe 同目录再运行。输出GTIF link ok说明整条调用链通了。这段代码里TIFFSetField只是写入基础的 TIFF 标签,没有涉及 GeoKey 写入,但足够验证库的导入导出符号是否正常解析。
6.3 在 VS2013 工程里接入这两个库的常规配置
如果要在自己的 VS2013 工程里用,配置路径大致固定。工程先切到 x64 平台,然后按下表补属性:
| 配置项 | 位置 | 填入内容 |
|---|---|---|
| 附加包含目录 | C/C++ 常规 | D:\tiff-4.0.6\libtiff;D:\libgeotiff-1.4.0\libxtiff |
| 附加库目录 | 链接器 常规 | D:\tiff-4.0.6\libtiff;D:\libgeotiff-1.4.0 |
| 附加依赖项 | 链接器 输入 | libtiff_i.lib;geotiff_i.lib |
运行部署时再补一步:把两个 DLL 复制到 exe 目录。这样配置过一轮之后,后续再碰到其他基于 tiff 的库,比如 libgeotiff 的其他模块,思路就完全一样了。
从那以后,我每次拿到源码包手动编译,都强制自己把 dumpbin 验证走一遍,确认输出确实带 x64 标记、最小调用程序能跑通,才敢把库接进正式工程。这套流程多花十分钟,但省掉的是拿着一个名字带 x64、实际 x86 的库白调一晚上的痛苦。希望帮到你。
本文还有配套的精品资源,点击获取