简介:CMake 3.14.2 的 Windows 64 位官方发行包,面向需要在 Windows 平台上管理 C/C++ 项目构建的开发者,尤其适合配合 OpenCV 等复杂依赖库进行工程配置与编译调试,新手与有经验的开发者均可使用。压缩包共 5681 个文件,约 29.58MB,以 txt、html、rst 文档和 cmake 模块脚本为主,另含少量 exe 可执行程序、c/cpp 示例源码及 png、css 等辅助资源,覆盖安装程序、用户手册、示例项目、cmake-gui 与命令行工具、运行时库和 ctest、cpack 等配套脚本。已有 172 人学习下载。包内文档体系完整,从 cmake-commands、cmake-properties 到各类策略与变量说明一应俱全,便于读者系统查阅命令用法、理解构建规则,并借助示例快速上手 CMakeLists.txt 的编写,为 OpenCV 项目的跨平台构建打下基础。
1. 从一份 cmake-3.14.2-win64-x64 包说起:为什么老项目编译 OpenCV 总卡在第一步
手上拿到一个cmake-3.14.2-win64-x64的压缩包,很多人第一反应是“版本这么老,还有必要留吗”。我最近在帮一个做视觉检测的团队复现一套老工程,源码里写死了cmake_minimum_required(VERSION 3.5),依赖的 OpenCV 是 3.x 系列,用新版本 CMake 一配置就报策略警告甚至直接中断,换成这个 3.14.2 的 Windows 64 位包,配置阶段一次通过。这就是它存在的意义:不是让你追新,而是让一批锁死工具链的老项目能重新跑起来。这篇笔记围绕 cmake3 与 opencv 的实际组合场景,讲清这个包能干什么、怎么配、参数怎么设、哪些地方容易翻车,适合正在维护老 C++ 视觉工程、又不想大动构建系统的从业者。
2. 拆开这个包:cmake-3.14.2-win64-x64 里到底有什么
2.1 目录结构与可执行文件的分工
解压之后,根目录下通常能看到bin、share、doc这几个文件夹,核心全在bin里。cmake.exe是命令行主程序,负责读取CMakeLists.txt、生成构建文件;cmake-gui.exe是带界面的配置工具,适合第一次接触某个工程时逐项看缓存变量;ctest.exe跑测试,cpack.exe打包,cmake-server之类在 3.14 这个年代还不是重点。真正每天要用的是前两个。
这里有个容易被忽略的点:这个包是预编译的 Windows 64 位版本,不依赖你机器上装没装 Visual Studio 的编译器,但它生成构建文件时需要能找到编译器。也就是说,CMake 本身只是“构建系统的构建系统”,它不编译代码,只负责把CMakeLists.txt翻译成 Visual Studio 的.sln、Ninja 的build.ninja或者 MinGW 的 Makefile。理解这一层,后面很多报错就不会慌。
判断包是否完整,最直接的办法是在bin目录下开一个终端跑版本查询:
# 进入解压后的 bin 目录再执行,避免和系统里其他 cmake 混淆 ./cmake.exe --version输出里应该能看到cmake version 3.14.2,并且带有Windows和x86_64字样。如果提示找不到命令,多半是没进对目录,或者路径里有中文和空格导致解析异常。我一般会把整个包放到一个纯英文、无空格的路径下,比如D:\tools\cmake-3.14.2,这是后面所有操作的前提。
2.2 为什么老 OpenCV 工程偏爱 3.14 这个版本区间
OpenCV 的构建体系对 CMake 版本相当敏感。3.x 系列的 OpenCV 在CMakeLists.txt里用了不少后来被废弃的写法,比如旧式的cmake_policy设置、对FindCUDA模块的依赖,以及对CMAKE_MINIMUM_REQUIRED的宽松处理。CMake 从 3.12 之后逐步收紧策略,到 3.20 以后对很多老写法直接报错。3.14.2 正好处在一个“够新能支持现代编译器、够老不强制新策略”的窗口里。
具体到 opencv 场景,常见做法是用这个版本的 CMake 去配置 OpenCV 源码,生成 Visual Studio 工程,再编译出opencv_world库。老工程里如果直接find_package(OpenCV REQUIRED),配套的OpenCVConfig.cmake也是那个年代生成的,版本错配时会出现“找到了库但链接失败”或者“配置阶段就报 target 不存在”。把 CMake 固定到 3.14.2,等于把变量收敛到一个已知能工作的组合上,这在维护遗留项目时比升级源码划算得多。
需要说清楚边界:这个包只解决“配置与生成”环节,不解决编译器版本、运行库、OpenCV 自身源码兼容性。如果你的工程还依赖特定版本的 MSVC 工具集,那 CMake 版本对了也可能在编译阶段翻车,这部分放到后面的避坑章节讲。
3. 用 cmake3 配置 OpenCV 工程:从命令行到 GUI 的完整走法
3.1 命令行配置:一条命令里每个参数的含义
最省事的复现方式是用命令行生成 Visual Studio 工程。假设 OpenCV 源码在D:\src\opencv,想生成到D:\build\opencv-vs,并且指定 64 位、Release 配置,命令大致是这样:
# 在 cmake 的 bin 目录下执行,或用绝对路径调用 cmake.exe cmake.exe -S D:/src/opencv -B D:/build/opencv-vs ^ -G "Visual Studio 15 2017 Win64" ^ -DCMAKE_BUILD_TYPE=Release ^ -DBUILD_opencv_world=ON ^ -DBUILD_TESTS=OFF ^ -DBUILD_PERF_TESTS=OFF ^ -DWITH_CUDA=OFF逐项说明:-S指定源码目录,-B指定构建目录,这两个参数在 3.13 之后才支持,3.14.2 正好可用,比老式的“先 cd 再 cmake ..”更清晰。-G是生成器,Visual Studio 15 2017 Win64对应 VS2017 的 64 位工具集,如果你装的是别的版本,要用cmake --help里列出的准确名称,写错会直接报“could not create named generator”。-DCMAKE_BUILD_TYPE=Release在多配置生成器下其实不生效,VS 工程靠--config在构建时指定,这里写上是为了兼容单配置生成器,属于习惯性冗余。BUILD_opencv_world=ON把多个模块合成一个库,减少链接时的库列表长度,老工程里很常见。关掉测试和 CUDA 是为了缩短配置和编译时间,视觉检测团队如果不用 GPU 加速,这一步能省不少事。
配置成功后,构建目录里会出现.sln文件。接着构建:
# 用 cmake 驱动构建,避免手动打开 VS cmake.exe --build D:/build/opencv-vs --config Release --target opencv_world -j 8--config Release对多配置生成器是必须的,不写会默认 Debug,编出来的库和 Release 主程序混链会出运行库冲突。--target只编目标库,不编全部示例。-j 8控制并行度,按 CPU 核心数给,给太高在机械硬盘上反而因为 IO 争抢变慢。
3.2 GUI 配置:第一次接触陌生工程时怎么读缓存变量
命令行适合已知参数的情况,第一次碰一个来源不明的工程,我一般先用cmake-gui.exe走一遍。填入源码路径和构建路径,点Configure,选对生成器,然后会看到一长串红色高亮的缓存变量。红色表示“本次新出现或值有变化”,不是错误。
重点看几类变量:CMAKE_INSTALL_PREFIX决定make install装到哪;OpenCV_DIR在消费方工程里指向已编译 OpenCV 的配置目录;CMAKE_CXX_STANDARD决定 C++ 标准,老工程常卡在 11 和 14 之间;BUILD_SHARED_LIBS决定动态库还是静态库。改完再点一次Configure,红色消失、出现Generate按钮,才算配置稳定。这个“配置两遍”的流程是 CMake 的常态,第一遍收集环境信息,第二遍应用你的修改,别在第一遍就急着生成。
GUI 里还有一个Add Entry可以手动加缓存变量,但我不建议在没搞清工程逻辑前乱加,容易制造出“本地能编、别人不能编”的隐性依赖。所有非默认参数都应该记在构建脚本或文档里,这是团队协作的基本纪律。
3.3 消费方工程怎么指向这份 OpenCV
编译出 OpenCV 之后,真正要用它的是业务工程。业务工程的CMakeLists.txt里通常这样写:
cmake_minimum_required(VERSION 3.5) project(detection_demo CXX) # 指向 OpenCV 的配置目录,路径按实际安装位置改 set(OpenCV_DIR "D:/build/opencv-vs/install") find_package(OpenCV REQUIRED) add_executable(detection_demo main.cpp) target_link_libraries(detection_demo PRIVATE ${OpenCV_LIBS}) target_include_directories(detection_demo PRIVATE ${OpenCV_INCLUDE_DIRS})find_package会去OpenCV_DIR下找OpenCVConfig.cmake,这个文件是 OpenCV 编译安装时生成的,里面记录了库路径、版本、编译选项。如果报“Could not find a package configuration file provided by OpenCV”,九成是OpenCV_DIR指错了层级——它应该指向包含OpenCVConfig.cmake的那一层,而不是bin或lib。target_link_libraries用PRIVATE是现代写法,老工程里常见裸写库名,效果类似但作用域不清晰。这套写法在 3.14.2 下能稳定工作,也是我推荐给老项目做最小改造的模板。
4. 避坑与排查:cmake3 配 opencv 最常见的五处翻车
4.1 生成器名称写错,配置阶段直接中断
现象是执行cmake -G后立刻报Could not create named generator,连CMakeLists.txt都没读到。原因通常是生成器名称和本机装的 Visual Studio 版本对不上,比如装了 VS2019 却写Visual Studio 15 2017 Win64,或者漏了Win64后缀导致默认生成 32 位工程。解决办法是先跑cmake.exe --help,在Generators列表里找到本机实际可用的准确字符串,复制粘贴,不要凭记忆写。另一个隐蔽点是 VS 的 C++ 工作负载没装,生成器存在但底层工具集缺失,这时报错会晚一步出现在编译阶段,配置阶段反而“成功”,容易误判。
4.2 路径含中文或空格,缓存变量被截断
现象是配置能过,但生成的工程里某些路径变成乱码或只剩前半段,编译时找不到头文件。原因是 CMake 在 Windows 下对含空格路径的处理依赖引号,而部分老模块和第三方Find*.cmake脚本没有正确加引号。我的做法是把源码、构建目录、安装目录全部放在纯英文无空格路径下,比如D:/work/...,从源头规避。已经踩了的,清理构建目录重新配置,不要试图在缓存里手改路径,残留的旧值会继续干扰。
4.3 Debug 与 Release 混链,运行时报 CRT 冲突
现象是程序能编过,一运行就崩,或者链接期报LNK2038运行库不匹配。原因是多配置生成器下,OpenCV 编的是 Release,业务工程默认编了 Debug,两边的MSVCRT一个带调试一个不带。解决办法是构建 OpenCV 时把 Debug 和 Release 都编出来,业务工程用--config明确指定,并在target_link_libraries里用debug和optimized关键字区分库路径。老工程里常见只编了一种配置就到处用,这是血泪经验里排前三的坑。
4.4 OpenCV_DIR 指向层级错误,find_package 静默失败
现象是find_package(OpenCV REQUIRED)报找不到配置文件,但你明明看到磁盘上有OpenCVConfig.cmake。原因是OpenCV_DIR指到了它的父目录或子目录。正确做法是让OpenCV_DIR精确等于OpenCVConfig.cmake所在目录,通常是安装根目录或lib/cmake/opencv4这类位置。排查时直接在终端dir /s OpenCVConfig.cmake定位,再把该目录赋给变量。另一个变数是系统里存在多份 OpenCV,find_package按搜索顺序命中了你不想用的那份,这时在CMakeLists.txt里显式set(OpenCV_DIR ...)覆盖,比改环境变量可靠。
4.5 策略警告被当成错误,配置中途停止
现象是配置输出里出现Policy CMP00xx is not set之类的警告,随后流程中断。3.14.2 对部分老写法会给出策略警告,默认多数是警告而非错误,但如果工程里写了-Werror=dev或者把警告提升为错误,就会中断。解决办法是不要盲目全局关警告,而是在CMakeLists.txt顶部用cmake_policy(SET CMP00xx OLD)针对具体策略做兼容,并记录原因。全局-Wno-dev会把真正的问题一起吞掉,属于后悔药式的偷懒,后期排查更痛苦。
5. 进阶技巧:把这份老版本 CMake 用出可复现的工程纪律
真正让一个老工具链稳定的,不是记住某个版本号,而是把版本、生成器、配置类型、依赖路径全部显式化。我现在的习惯是在工程根目录放一个build.bat,把调用 cmake 的完整命令固化下来,任何人拿到源码都跑同一个脚本,而不是各自在 GUI 里点。脚本里第一行先打印cmake --version,确认用的是包内这份 3.14.2 而不是系统 PATH 里的新版,这一步能挡掉大量“我这儿能编你那儿不能编”的扯皮。
@echo off REM 固定使用包内 cmake,避免 PATH 干扰 set CMAKE_BIN=D:\tools\cmake-3.14.2\bin\cmake.exe "%CMAKE_BIN%" --version "%CMAKE_BIN%" -S . -B build -G "Visual Studio 15 2017 Win64" ^ -DOpenCV_DIR=D:/build/opencv-vs/install ^ -DCMAKE_INSTALL_PREFIX=D:/build/install if errorlevel 1 exit /b 1 "%CMAKE_BIN%" --build build --config Release -j 8这段脚本的关键不在语法,而在“绝对路径 + 版本自检 + 失败即停”。if errorlevel 1 exit /b 1保证配置失败时不会继续构建,避免在半成品缓存上浪费时间。OpenCV_DIR用正斜杠,CMake 在 Windows 下能正确识别,反斜杠反而容易在转义上出问题。
验证配置是否真的生效,我一般看三个地方:构建目录下CMakeCache.txt里CMAKE_GENERATOR和OpenCV_DIR的值是否和预期一致;生成的.sln里目标工程的运行库设置是否统一;编出来的可执行文件用依赖查看工具确认链接的是预期那份 OpenCV 动态库。这三步走完,基本能排除“看起来编过了、实际链错库”的玄学问题。
还有一个值得养成的习惯:把这份 CMake 包和 OpenCV 的编译产物一起归档,标注清楚版本组合,比如“cmake 3.14.2 + opencv 3.4.x + VS2017 x64”。老项目的可复现性靠的就是这种版本快照,而不是某台机器上的环境残留。从那以后我每次接手遗留工程,都强制先跑一遍版本自检和依赖路径核对,再动任何源码。希望帮到你。
本文还有配套的精品资源,点击获取