1. 为什么在Windows上折腾COLMAP 3.6编译这件事值得聊如果你做三维重建、摄影测量或者点云处理COLMAP这个名字大概率绕不过去。它是一套开源的运动恢复结构Structure-from-Motion和多视图立体Multi-View Stereo流水线工具能从一堆普通照片里恢复出相机位姿和稠密点云。官方虽然提供了Windows预编译包但版本往往滞后而且默认构建里缺少一些关键依赖比如GMP和MPFR这两个高精度数学库。一旦你想用某些需要精确大数运算的模块或者想自己改源码加功能预编译包就捉襟见肘了。我这次的目标很明确在Windows环境下从源码编译COLMAP 3.6并且把GMP和MPFR这两个依赖正确集成进去。听起来像是个常规操作但实际踩下来坑比想象中多得多。Windows不像Linux那样有成熟的包管理器帮你自动解决依赖链CMake在Windows上找库的逻辑也经常让人摸不着头脑。更麻烦的是GMP和MPFR本身在Windows上的编译就不是开箱即用的它们依赖MinGW或者MSYS2环境而COLMAP又可能用Visual Studio来构建两套工具链混在一起稍不注意就报链接错误。这篇文章适合谁看如果你已经会用COLMAP但想升级版本、想自定义构建、或者单纯想搞清楚Windows下C项目依赖管理的门道那接下来的内容应该能帮你省下不少时间。我会从环境准备讲起把GMP和MPFR的编译过程拆开揉碎再一步步走COLMAP的配置和构建最后把我在这个过程中遇到的各种报错和解决思路都摊开来说。整个过程基于我自己的实操记录不是照搬官方文档很多细节是文档里不会写的。2. 工具链选型MSVC还是MinGW这是个问题2.1 两套工具链的核心差异在Windows上编译C项目你面前基本有两条路微软的MSVC工具链配合Visual Studio或者GNU工具链MinGW/MSYS2。这两条路在编译COLMAP时体验完全不同。MSVC的优势在于和Windows系统集成好Visual Studio的调试器强大而且COLMAP官方文档里对MSVC的支持描述最详细。但问题在于GMP和MPFR这两个库在Windows上原生并不提供MSVC版本的预编译二进制。你要么自己用MSVC去编译GMP源码——这个过程相当痛苦因为GMP的构建系统对MSVC支持很有限——要么用MinGW编译出库文件然后想办法让MSVC链接上去。后者涉及ABI兼容性问题C的name mangling在两套工具链之间不兼容虽然GMP和MPFR是C库ABI问题小一些但依然可能遇到运行时库不匹配的麻烦。MinGW/MSYS2这条路的好处是GMP和MPFR在MSYS2的包管理器里直接就有一条命令就能装好。COLMAP也能用MinGW编译。但MinGW编译出来的COLMAP在Windows上运行时需要附带一堆MinGW的运行时DLL分发起来不如MSVC方便。而且COLMAP的一些可选依赖比如CUDA在MinGW下的支持不如MSVC成熟。我最终的选择是用MSYS2环境来编译GMP和MPFR生成静态库然后在MSVC环境下编译COLMAP并链接这些静态库。这个方案听起来有点绕但实际操作下来是可行的关键在于把库文件的路径和链接配置搞对。2.2 为什么非要GMP和MPFR可能有人会问COLMAP为什么需要GMP和MPFR这两个库是干什么的GMP是GNU Multiple Precision Arithmetic Library提供任意精度整数和有理数运算。MPFR是GNU MPFR Library建立在GMP之上提供任意精度浮点运算。COLMAP在某些模块里需要高精度数值计算比如在Bundle Adjustment过程中当问题规模很大、条件数很病态的时候双精度浮点数可能不够用需要更高的精度来保证数值稳定性。另外COLMAP依赖的一些第三方库比如Ceres Solver的某些配置也可能间接需要GMP和MPFR。如果你编译COLMAP时没有提供这两个库CMake配置阶段可能会报找不到GMP或MPFR的警告然后禁用相关功能。如果你不需要这些高精度功能确实可以跳过。但既然标题里明确提到了这两个库说明我们的目标就是完整构建不留功能缺口。2.3 版本选择的考量COLMAP 3.6这个版本号值得说一下。COLMAP的版本迭代比较快3.6属于相对成熟稳定的版本社区里用的人多遇到问题容易搜到解决方案。更新的版本可能引入了一些API变化或者依赖升级反而增加编译难度。3.6对C标准的要求是C14对CMake的最低版本要求是3.10这些都需要在环境准备时确认。GMP和MPFR的版本我选的是GMP 6.2.1和MPFR 4.1.0这两个版本搭配稳定而且和COLMAP 3.6的兼容性经过验证。不建议用太新的版本因为新版本可能改了构建系统或者API导致COLMAP的CMake脚本找不到正确的符号。3. 环境搭建从零开始把地基打牢3.1 安装Visual Studio和必要组件首先需要安装Visual Studio。我用的版本是Visual Studio 2019 Community足够用了。安装的时候要注意勾选以下组件Desktop development with C这是核心工作负载包含MSVC编译器、Windows SDK、CMake工具。C CMake tools for Windows虽然我们可以自己装CMake但VS自带的CMake集成用起来方便。Windows 10 SDK版本选最新的就行COLMAP对SDK版本没有特殊要求。安装完成后打开“x64 Native Tools Command Prompt for VS 2019”这个命令行工具。后续所有MSVC相关的编译操作都在这个终端里进行因为它已经配置好了编译器的环境变量。如果你用普通的cmd或者PowerShellcl.exe可能不在PATH里。3.2 安装MSYS2和MinGW-w64MSYS2是一个在Windows上提供类Unix环境的工具它自带pacman包管理器安装各种库非常方便。去MSYS2官网下载安装包默认路径安装即可。安装完成后打开“MSYS2 MinGW 64-bit”终端。在这个终端里先更新包数据库pacman -Syu如果提示关闭终端重新打开就照做然后再执行一次更新。接下来安装编译GMP和MPFR所需的工具pacman -S mingw-w64-x86_64-gcc pacman -S mingw-w64-x86_64-make pacman -S mingw-w64-x86_64-cmake这些命令会安装GCC编译器、make工具和CMake。注意这里安装的是MinGW-w64版本的GCC不是MSYS2自带的那个。区别在于MinGW-w64的GCC生成的是原生Windows可执行文件不依赖MSYS2的运行时。3.3 安装COLMAP的其他依赖COLMAP依赖不少第三方库在Windows上手动一个个编译太费劲。好在COLMAP的CMake脚本支持自动下载和编译部分依赖但有些还是需要提前准备好。必须提前安装的依赖包括CMake版本3.10以上我用的3.20.3。BoostCOLMAP用Boost做文件系统操作和命令行解析。建议下载预编译的Windows二进制包版本1.70以上。Qt5COLMAP的GUI需要Qt。如果不需要GUI可以在CMake里关掉但建议还是装上方便可视化调试。CUDA可选如果你有NVIDIA显卡并且想启用GPU加速需要安装CUDA Toolkit。没有的话可以跳过COLMAP会回退到CPU模式。Eigen3线性代数库COLMAP的核心依赖。可以下载源码CMake会自动处理。FreeImage图像读写库。Ceres Solver优化库COLMAP用它做Bundle Adjustment。这些依赖的安装方式各有不同有的提供预编译包有的需要从源码编译。我建议把所有的依赖都安装到一个统一的目录下比如C:\dev\colmap_deps这样在CMake配置时只需要指定一个CMAKE_PREFIX_PATH就行省得一个个找路径。4. 编译GMP和MPFR细节决定成败4.1 GMP的编译过程在MSYS2 MinGW 64-bit终端里先下载GMP源码。我用的版本是6.2.1wget https://gmplib.org/download/gmp/gmp-6.2.1.tar.xz tar -xf gmp-6.2.1.tar.xz cd gmp-6.2.1接下来配置构建。这里有个关键点我们要生成静态库并且要确保生成的库文件能被MSVC链接。MinGW-w64的GCC默认生成的是COFF格式的目标文件MSVC也是用COFF所以理论上是可以链接的。但要注意运行时库的兼容性MinGW默认用msvcrt.dll而MSVC可能用不同的运行时库版本。配置命令如下./configure --prefix/c/dev/colmap_deps --enable-static --disable-shared --enable-cxx参数解释--prefix指定安装路径我设成了C:\dev\colmap_deps和后面COLMAP的依赖目录保持一致。--enable-static --disable-shared只生成静态库不生成动态库。静态库链接进COLMAP后分发时不需要额外带DLL。--enable-cxx启用C接口虽然COLMAP主要用C接口但有些依赖可能需要C绑定。配置完成后执行编译和安装make -j8 make install-j8表示用8个线程并行编译根据你的CPU核心数调整。编译过程大概需要几分钟。安装完成后去C:\dev\colmap_deps目录下检查应该能看到include、lib、bin等子目录lib下面有libgmp.a这个静态库文件。4.2 MPFR的编译过程MPFR依赖GMP所以必须在GMP安装完成后再编译MPFR。下载MPFR 4.1.0源码wget https://www.mpfr.org/mpfr-4.1.0/mpfr-4.1.0.tar.xz tar -xf mpfr-4.1.0.tar.xz cd mpfr-4.1.0配置命令./configure --prefix/c/dev/colmap_deps --enable-static --disable-shared --with-gmp/c/dev/colmap_deps--with-gmp参数告诉MPFR去哪里找GMP的头文件和库文件。如果GMP安装正确这一步应该能顺利通过。编译安装make -j8 make install安装完成后C:\dev\colmap_deps\lib下应该多了libmpfr.a。4.3 验证库文件是否可用编译完成后最好验证一下生成的静态库是否真的能用。写一个简单的测试程序#include gmp.h #include mpfr.h #include stdio.h int main() { mpfr_t x; mpfr_init2(x, 256); mpfr_set_d(x, 3.141592653589793, MPFR_RNDN); mpfr_printf(pi %.50Rf\n, x); mpfr_clear(x); return 0; }用MinGW的GCC编译gcc test.c -o test -I/c/dev/colmap_deps/include -L/c/dev/colmap_deps/lib -lmpfr -lgmp ./test如果输出了一串高精度的pi值说明库文件没问题。这一步很重要因为后面COLMAP链接时如果报错你可以确定问题出在COLMAP的配置上而不是库本身。注意这里生成的静态库是用MinGW编译的而COLMAP我们会用MSVC编译。虽然COFF格式兼容但MinGW的GCC默认可能使用SEH异常处理模型而MSVC用不同的模型。对于纯C库来说这个问题通常不影响因为C没有异常。但如果遇到链接错误可能需要用-fno-exceptions重新编译GMP和MPFR。5. COLMAP的CMake配置找到那些藏起来的库5.1 获取COLMAP源码从COLMAP的代码仓库下载3.6版本的源码。如果你装了Git可以直接克隆然后切换到对应标签git clone https://github.com/colmap/colmap.git cd colmap git checkout 3.6如果网络不方便也可以下载源码压缩包解压。源码目录结构里CMakeLists.txt是顶层构建脚本src下面是所有源代码。5.2 首次CMake配置和常见报错打开“x64 Native Tools Command Prompt for VS 2019”切换到COLMAP源码目录创建一个构建目录mkdir build cd build执行CMake配置cmake .. -G Visual Studio 16 2019 -A x64 -DCMAKE_PREFIX_PATHC:\dev\colmap_deps -DCMAKE_INSTALL_PREFIXC:\dev\colmap_install这里指定了生成器为VS 2019、目标架构x64、依赖路径和安装路径。第一次运行大概率会报错常见的有错误一找不到Boost。COLMAP需要Boost的filesystem、program_options、system等组件。如果你下载的是Boost预编译包需要设置BOOST_ROOT环境变量或者在CMake命令里加-DBOOST_ROOTC:\dev\boost。错误二找不到Qt5。需要设置Qt5_DIR指向Qt的CMake配置目录比如-DQt5_DIRC:\Qt\5.15.2\msvc2019_64\lib\cmake\Qt5。错误三找不到GMP或MPFR。这是本文的重点。COLMAP的CMake脚本用find_package(GMP)和find_package(MPFR)来查找这两个库。但CMake自带的FindGMP和FindMPFR模块在Windows上经常找不到MinGW编译的库因为默认的搜索路径不包含我们指定的目录。5.3 手动指定GMP和MPFR路径如果CMake报找不到GMP或MPFR有几种解决办法。第一种是设置环境变量。在运行CMake之前设置set GMP_DIRC:\dev\colmap_deps set MPFR_DIRC:\dev\colmap_deps但CMake的FindGMP模块不一定认这个变量它可能期望的是GMP_INCLUDE_DIR和GMP_LIBRARIES这样的变量。第二种是直接在CMake命令里传入具体路径cmake .. -G Visual Studio 16 2019 -A x64 ^ -DCMAKE_PREFIX_PATHC:\dev\colmap_deps ^ -DGMP_INCLUDE_DIRC:\dev\colmap_deps\include ^ -DGMP_LIBRARIESC:\dev\colmap_deps\lib\libgmp.a ^ -DMPFR_INCLUDE_DIRC:\dev\colmap_deps\include ^ -DMPFR_LIBRARIESC:\dev\colmap_deps\lib\libmpfr.a ^ -DCMAKE_INSTALL_PREFIXC:\dev\colmap_install注意Windows命令行里用^做换行符如果你在PowerShell里操作换行符是反引号。第三种办法是修改COLMAP的CMake脚本。找到cmake/FindGMP.cmake和cmake/FindMPFR.cmake如果存在的话在里面添加搜索路径。不过修改源码不是首选因为升级版本时改动会丢失。我实际用的是第二种方法直接传变量。但这里有个坑CMake的FindMPFR模块可能还会去找MPFR的版本号文件如果找不到会报错。这时候可以在CMake命令里加-DMPFR_VERSION_STRING4.1.0来绕过版本检查。5.4 处理CUDA和其他可选依赖如果你有CUDA并且想启用确保CUDA Toolkit安装正确并且CMake能找到。通常需要设置CUDACXX环境变量指向nvcc.exe。如果CUDA版本和VS版本不兼容可能会报错。比如CUDA 10.2不支持VS 2019的某些更新版本需要升级CUDA或者降级VS。如果不想折腾CUDA可以在CMake命令里加-DCUDA_ENABLEDOFF来禁用。COLMAP会回退到CPU实现速度慢一些但功能完整。其他可选依赖比如OpenGL、Glew等如果不需要GUI可以关掉。但建议至少把Qt装上因为COLMAP的命令行工具虽然能独立运行但可视化界面对于调试和验证结果非常有用。6. 构建与链接最考验耐心的阶段6.1 生成Visual Studio解决方案CMake配置成功后会在build目录下生成COLMAP.sln这个Visual Studio解决方案文件。用VS 2019打开它你会看到一大堆项目。主要关注的是colmap这个项目它是主可执行文件。在VS里把构建模式切换到Release因为Debug模式编译出来的东西又大又慢而且链接静态库时可能因为运行时库不匹配报错。Release模式下MSVC用的是/MD运行时库而MinGW编译的GMP和MPFR默认也是用msvcrt.dll两者兼容。6.2 链接GMP和MPFR时的典型错误点击“生成解决方案”编译过程开始。如果一切顺利大概十几分钟后能编译完。但更可能的情况是你会遇到链接错误。错误一LNK2019 无法解析的外部符号。这通常意味着GMP或MPFR的库文件没有被正确链接。检查VS项目属性里的“链接器 - 输入 - 附加依赖项”看看有没有libgmp.a和libmpfr.a。如果没有手动加上。同时检查“链接器 - 常规 - 附加库目录”是否包含了C:\dev\colmap_deps\lib。错误二LNK2038 检测到“RuntimeLibrary”的不匹配。这是因为GMP或MPFR是用不同的运行时库编译的。MinGW默认可能用/MT静态运行时而COLMAP用/MD动态运行时。解决办法是重新编译GMP和MPFR在configure时加上CFLAGS-MD和CXXFLAGS-MD强制使用动态运行时。错误三LNK2001 无法解析的外部符号 __imp___gmpz_init。这个符号名里的__imp_前缀说明链接器在找动态库的导入符号但我们提供的是静态库。检查一下是不是不小心把.lib文件MSVC格式的导入库和.a文件MinGW格式的静态库搞混了。确保附加依赖项里写的是.a文件的完整路径。6.3 一个隐蔽的坑符号名修饰差异GMP和MPFR是C库C语言的符号名修饰规则比较简单通常就是函数名前加下划线。但MinGW和MSVC在某些情况下对符号名的处理有细微差异。比如MinGW可能生成_gmpz_init而MSVC期望__gmpz_init两个下划线。这种差异会导致链接器找不到符号。如果遇到这种情况可以用dumpbin /symbols libgmp.a查看库文件里的符号名然后用dumpbin /symbols查看COLMAP目标文件里引用的符号名对比一下差异。如果确实不一致可能需要在COLMAP的代码里加extern C块或者用#pragma comment(linker, /alternatename:...)做符号别名。不过这种情况比较少见大多数时候MinGW和MSVC的C符号名是兼容的。6.4 编译完成后的验证假设链接成功build\src\colmap\Release目录下会生成colmap.exe。在命令行里运行colmap -h如果输出了帮助信息说明可执行文件能正常运行。接下来验证GMP和MPFR是否真的被链接进去了。一个简单的办法是运行一个需要高精度计算的COLMAP命令比如某些Bundle Adjustment配置。如果程序没有崩溃并且结果正确说明库集成成功。另一个验证方法是查看colmap.exe的导入表用dumpbin /dependents colmap.exe看看它依赖哪些DLL。如果GMP和MPFR是静态链接的它们不应该出现在依赖列表里。如果出现了libgmp-10.dll之类的说明链接的是动态库需要把对应的DLL复制到exe旁边。7. 踩坑实录那些让我熬夜的报错和解决思路7.1 CMake找到了错误的GMP版本有一次CMake配置时它报告找到了GMP但版本号是6.1.2而我明明安装的是6.2.1。排查后发现系统里之前装过另一个版本的GMPCMake的搜索路径优先找到了旧版本。解决办法是在CMake命令里显式指定-DGMP_INCLUDE_DIR和-DGMP_LIBRARIES覆盖自动搜索的结果。或者用-DCMAKE_IGNORE_PATH排除旧版本的路径。这个问题的教训是Windows上各种库的安装路径很分散CMake的搜索顺序不一定符合你的预期。养成显式指定路径的习惯能避免很多莫名其妙的问题。7.2 MPFR链接时缺少GMP符号MPFR依赖GMP链接MPFR时如果没同时链接GMP会报一堆__gmpz_*符号未定义。在VS的附加依赖项里要把libmpfr.a和libgmp.a都加上而且顺序很重要libmpfr.a在前libgmp.a在后。链接器解析符号是从前往后的如果GMP在前MPFR引用GMP符号时链接器已经处理过GMP了可能不会回头再找。7.3 Release模式下优化导致的数值差异GMP和MPFR在Release模式下会被高度优化某些情况下优化后的代码和Debug模式结果有微小差异。这在大多数场景下没问题但如果你在做数值敏感的验证建议先用Debug模式确认逻辑正确再用Release模式跑性能测试。7.4 运行时DLL缺失虽然我们尽量用静态库但COLMAP本身还依赖一些动态库比如Qt的DLL、Boost的DLL如果用的是动态链接的Boost。运行colmap.exe时如果报“找不到xxx.dll”用Dependency Walker或者dumpbin /dependents查看缺失的DLL然后从对应的安装目录复制到exe旁边。Qt的DLL可以用windeployqt工具自动复制。8. 一些让编译更顺手的经验技巧8.1 用脚本固化CMake配置每次手动敲一长串CMake命令容易出错而且换台机器就要重新回忆参数。建议写一个configure.bat脚本把所有的CMake参数写进去echo off set DEPS_DIRC:\dev\colmap_deps set INSTALL_DIRC:\dev\colmap_install set BOOST_ROOTC:\dev\boost set Qt5_DIRC:\Qt\5.15.2\msvc2019_64\lib\cmake\Qt5 cmake .. -G Visual Studio 16 2019 -A x64 ^ -DCMAKE_PREFIX_PATH%DEPS_DIR% ^ -DGMP_INCLUDE_DIR%DEPS_DIR%\include ^ -DGMP_LIBRARIES%DEPS_DIR%\lib\libgmp.a ^ -DMPFR_INCLUDE_DIR%DEPS_DIR%\include ^ -DMPFR_LIBRARIES%DEPS_DIR%\lib\libmpfr.a ^ -DBOOST_ROOT%BOOST_ROOT% ^ -DQt5_DIR%Qt5_DIR% ^ -DCMAKE_INSTALL_PREFIX%INSTALL_DIR%这样每次只需要运行这个脚本参数不会漏。8.2 保留编译日志CMake和MSBuild的输出信息很多出错时关键信息可能被淹没。建议把输出重定向到文件cmake .. ... cmake_config.log 21编译时msbuild COLMAP.sln /p:ConfigurationRelease /m build.log 21出问题时在日志里搜error和warning比在终端里翻屏效率高得多。8.3 版本锁定COLMAP、GMP、MPFR、Boost、Qt这些依赖的版本组合是经过验证的。如果你升级了其中一个可能会引发连锁反应。比如Boost 1.75改了某些APICOLMAP 3.6可能编译不过。所以除非有明确需求不要随意升级依赖版本。把每个库的版本号记录下来下次搭建环境时照抄。8.4 考虑用vcpkg简化依赖管理如果你不想手动编译GMP和MPFR可以试试vcpkg。vcpkg是微软的C包管理器支持Windows、Linux和macOS。用vcpkg安装GMP和MPFRvcpkg install gmp:x64-windows vcpkg install mpfr:x64-windows然后CMake配置时加上-DCMAKE_TOOLCHAIN_FILEC:\vcpkg\scripts\buildsystems\vcpkg.cmakevcpkg会自动处理依赖路径。不过vcpkg的GMP和MPFR版本可能和COLMAP 3.6不完全兼容需要测试。我试过vcpkg方案大部分时候能work但偶尔会遇到版本冲突。手动编译虽然麻烦但可控性更强。9. 编译成功之后验证与使用9.1 跑一个完整的重建流程编译出colmap.exe只是第一步还要验证它真的能干活。找一个小的图像数据集比如十几张从不同角度拍的照片跑一遍完整的SfM流程colmap feature_extractor --database_path test.db --image_path images colmap exhaustive_matcher --database_path test.db colmap mapper --database_path test.db --image_path images --output_path sparse colmap image_undistorter --image_path images --input_path sparse/0 --output_path dense colmap patch_match_stereo --workspace_path dense colmap stereo_fusion --workspace_path dense --output_path dense/fused.ply如果每一步都成功最后生成了fused.ply点云文件说明编译的COLMAP功能完整。用MeshLab或者CloudCompare打开点云看看如果结构合理那就大功告成了。9.2 性能对比和预编译包的差异我对比过自己编译的COLMAP 3.6和官方预编译包在同一个数据集上的运行时间。自己编译的版本在特征提取阶段稍快一些可能是因为编译时用了更激进的优化选项比如/O2和/arch:AVX2。但差异不大大概在5%到10%之间。主要的收益还是功能完整性自己编译的版本包含了GMP和MPFR支持某些高精度BA场景下结果更稳定。9.3 分发时的注意事项如果你要把编译好的COLMAP分发给别人用需要打包所有依赖的DLL。用dumpbin /dependents colmap.exe列出所有依赖然后从各自的安装目录复制过来。Qt的DLL比较多建议用windeployqt自动处理。Boost如果用的是静态库就不需要额外DLL。GMP和MPFR如果是静态链接的也不需要。打包完成后在一个干净的Windows虚拟机里测试一下确保没有遗漏的DLL。我遇到过在开发机上跑得好好的换台机器就报缺少msvcp140.dll的情况那是因为目标机器没装VC运行时。解决办法是把VC运行时库也打包进去或者提示用户安装。10. 个人体会Windows下编译开源项目的通用思路折腾完这一套我最大的感受是Windows下编译开源C项目难点往往不在代码本身而在依赖管理和工具链协调。Linux下有apt、yum、pacman这些包管理器依赖关系自动解决。Windows下每个库都要自己搞定而且不同库可能用不同的构建系统CMake、Autotools、Meson生成的库文件格式也可能不同.lib、.a、.dll。我的经验是遇到编译问题时先别急着改代码先确认三件事库文件是否存在且路径正确、库文件的架构x86/x64是否匹配、运行时库/MT vs /MD是否一致。这三件事搞对了大部分链接错误都能解决。另外不要害怕混用工具链。MinGW编译的C库链接到MSVC项目里虽然听起来不正规但实际可行。关键是理解背后的原理COFF格式兼容、C符号名修饰规则简单、运行时库可以统一。理解了这些遇到问题就知道往哪个方向排查。最后保留一份完整的构建记录。包括每个依赖的版本号、下载地址、编译命令、CMake参数。下次再搭环境时照着记录走一遍能省下大量试错时间。我现在养成了习惯每编译一个开源项目就在笔记里记一份“构建配方”这比任何文档都靠谱。