colmapCompile - colmap windows的编译

编译colmap

1 前期准备

1 github上下载colmap稳定版源码:

https://github.com/colmap/colmap/archive/refs/tags/3.6.zip
之后解压进入,执行: git init

2 确保编译环境

  • 1 确保你的vs不是vs2019 16.9.3以及以上,否则会有奇怪的cuda错误, 解决方案是:
  • 2 如果本篇博客所有内容都详细读完,任然无法成功编译colmap,那就装VS2015,然后用他的生成工具(cmake -G 参数指定编译器版本,命令行里输入cmake -G),项目打开还是可以用vs2019的。

然后将编译器加入环境变量:
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.16.27023\bin\HostX64\x64
输入cl能看到输出即可.

2 依赖安装

2.1 boost 直接安装(推荐下载vs2015版本,我用的是v_1_73)

https://boostorg.jfrog.io/artifactory/main/release/1.64.0/binaries/

1
2
3
4
5
6
7
8
9
10
boost使用源码编译的静态方式编译:
```sh
.\b2.exe --toolset=msvc-14.2 `
--address-model=64 `
--architecture=x86 `
--threading=multi `
-sZLIB_SOURCE="F:\BASE_ENV\forOpenMVS\zlib-1.2.11" -sZLIB_INCLUDE="F:\BASE_ENV\forOpenMVS\zlib-1.2.11" `
--with-iostreams --with-iostreams --with-log --with-program_options --with-graph --with-test --with-regex --with-filesystem `
--link=static --runtime-link=shared --build-type=complete `
stage --stagedir="F:\BASE_ENV\forOpenMVS\boost_1_66_0\msvc142_linkStatic_runShared" `

2.2 安装GMP和MFPR

  • 0 不想要自己折腾: 参考: https://github.com/emphasis87/libmpfr-msys2-mingw64,这里面应该有现成的库。

  • 1 安装Cygwin

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Setup Environment
    Install Cygwin, add the following packages to the default installation:

    gcc-core
    gcc-g++
    libgcc
    m4
    make #不知为何安装后在Cygwin根目录下搜不到make程序,见下面步骤2安装make
    cmake
    bash
    Add the following Environment Variable to the User PATH: C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.15.26726\bin\Hostx64\x64
    This is so you can use the lib command. Your lib.exe may be located elsewhere.

    安装好Cygwin以及一些依赖以后,在其根目录(方便说明记为: CygwinRoot=”D:\CygwinRooto”)下的bin/minnty.exe是其终端入口,然后每次打开该终端,进入的是:$CygwinRoot/home/$(userName), 运行”cd /“后就可以理解了;

  • 2 下载并安装make

    • 2.1 从如下网址下载make的源码,https://ftp.gnu.org/gnu/make/,然后解压
    • 2.2 打开Cygwin64 Terminal命令行,进入源码根目录,然后运行:configure && ./build.sh
    • 2.3 编译得到了make.exe后将其移动到Cygwin的bin目录下
  • 3 编译gmp
    运行两个: ./configure 和 make install

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ./configure --prefix=/home/chenxy/mylibs/newTry/gmp-6.2.0/build/static --enable-static --disable-shared
    configure: summary of build options:

    Version: GNU MP 6.2.0
    Host type: skylake-pc-cygwin
    ABI: 64
    Install prefix: /home/chenxy/mylibs/newTry/gmp-6.2.0/build/static
    Compiler: gcc
    Static libraries: yes
    Shared libraries: no

    编译结果(默认生成的是static的数据):

    1
    2
    3
    4
    5
    6
    7
    @nash-5 ~/mylibs/gmp-6.2.0
    $ ls /usr/local/include/
    gmp.h

    @nash-5 ~/mylibs/gmp-6.2.0
    $ ls /usr/local/lib/
    libgmp.a libgmp.la pkgconfig

    生成动态连接库(注意: 动态连接库和静态连接库的.h文件不同,所以注意分成2个文件夹,至少对于gmp是如此):

    1
    ./configure --prefix=/home/chenxy/mylibs/gmp-6.2.0/build/shared --enable-shared --disable-static
  • 4 编译mfpr(需要gmp的依赖,而且是动态连接库)
    进入mfpr的根目录:
    运行./configure:

    1
    2
    checking for gmp.h... no
    configure: error: gmp.h can't be found, or is unusable.

    运行./configure –help

    1
    2
    3
    4
    ···
    --with-gmp-include=DIR GMP include directory
    --with-gmp-lib=DIR GMP lib directory
    ···

    所以:

    1
    2
    3
    4
    5
    6
    ./configure --prefix=/home/chenxy/mylibs/newTry/mpfr-4.1.0/build/static \
    --enable-static --disable-shared \
    --with-gmp-include=/home/chenxy/mylibs/newTry/gmp-6.2.0/build/static/include \
    --with-gmp-lib=/home/chenxy/mylibs/newTry/gmp-6.2.0/build/staic/lib

    make install
    1
    2
    3
    4
    ./configure --prefix=/home/chenxy/mylibs/mpfr-4.1.0/build/static \
    --with-gmp-include=/home/chenxy/mylibs/gmp-6.2.0/build/static/include \
    --with-gmp-lib=/home/chenxy/mylibs/gmp-6.2.0/build/static/lib \
    --enable-static --disable-shared

2.3 其他依赖build.py会帮你下载编译

确保你能够流畅访问github,否则需要你自己下载然后修改build.py。

3 编译colmap

3.1 对编译文件和某些源文件的修改如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7333a04..d73a6ad 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -72,8 +72,10 @@ endif()

if(BOOST_STATIC)
set(Boost_USE_STATIC_LIBS ON)
+ # message("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ using static boost", ${BOOST_STATIC})
else()
add_definitions("-DBOOST_TEST_DYN_LINK")
+ # message("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ using dll boost", ${BOOST_STATIC})
endif()

################################################################################
@@ -86,6 +88,7 @@ endif()

find_package(Ceres REQUIRED)

+set(Boost_DEBUG ON)
find_package(Boost REQUIRED COMPONENTS
program_options
filesystem
diff --git a/scripts/python/build.py b/scripts/python/build.py
index 89dff59..fe1e4c4 100644
--- a/scripts/python/build.py
+++ b/scripts/python/build.py
@@ -75,10 +75,12 @@ def parse_args():
help="The path to the folder containing Boost, "
"e.g., under Windows: "
"C:/local/boost_1_64_0/lib64-msvc-12.0")
+ parser.add_argument("--boost_include_dir", default="F:/BASE_ENV/forOpenMVS/boost_1_73_0_v140")
+ parser.add_argument("--boost_lib_dir", default="F:/BASE_ENV/forOpenMVS/boost_1_73_0_v140/lib64-msvc-14.0")
parser.add_argument("--cgal_path", default="",
help="The path to the folder containing CGAL, "
"e.g., under Windows: C:/dev/CGAL-4.11.2/build")
- parser.add_argument("--cuda_path", default="",
+ parser.add_argument("--cuda_path", default="C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v10.2",
help="The path to the folder containing CUDA, "
"e.g., under Windows: C:/Program Files/NVIDIA GPU "
"Computing Toolkit/CUDA/v8.0")
@@ -108,7 +110,7 @@ def parse_args():
help="Whether to build unit tests")
parser.add_argument("--build_type", default="Release",
help="Build type, e.g., Debug, Release, RelWithDebInfo")
- parser.add_argument("--cmake_generator", default="",
+ parser.add_argument("--cmake_generator", default="Visual Studio 14",
help="CMake generator, e.g., Visual Studio 14")
parser.add_argument("--no_ssl_verification",
dest="ssl_verification", action="store_false",
@@ -429,8 +431,28 @@ def build_colmap(args):
extra_config_args.append(
"-DBOOST_ROOT={}".format(args.boost_path))
extra_config_args.append(
- "-DBOOST_LIBRARYDIR={}".format(args.boost_path))
-
+ "-DBOOST_INCLUDEDIR={}".format(args.boost_include_dir))
+ extra_config_args.append(
+ "-DBOOST_LIBRARYDIR={}".format(args.boost_lib_dir))
+ # print("BOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOST: ", extra_config_args)
+ # extra_config_args.append("-DBOOST_STATIC=ON")
+ # extra_config_args.append("-DBoost_USE_STATIC_LIBS=ON")
+ # extra_config_args.append("-DBoost_USE_MULTITHREADED=ON")
+ # extra_config_args.append("-DBoost_USE_STATIC_RUNTIME=ON")
+ # extra_config_args.append("-DBOOST_ALL_DYN_LINK=ON")
+
+ # -DGMP_INCLUDE_DIR="F:\BASE_ENV\forOpenMVS\gmp_mpfr\include" `
+ # -DGMP_LIBRARIES="F:\BASE_ENV\forOpenMVS\gmp_mpfr\lib\libgmp-10.lib" `
+ # -DMPFR_INCLUDE_DIR="F:\BASE_ENV\forOpenMVS\gmp_mpfr\include" `
+ # -DMPFR_LIBRARIES="F:\BASE_ENV\forOpenMVS\gmp_mpfr\lib\libmpfr-4.lib"
+ extra_config_args.append(
+ "-DGMP_INCLUDE_DIR={}".format("F:/BASE_ENV/forOpenMVS/gmp_mpfr/include"))
+ extra_config_args.append(
+ "-DGMP_LIBRARIES={}".format("F:/BASE_ENV/forOpenMVS/gmp_mpfr/lib/libgmp-10.lib"))
+ extra_config_args.append(
+ "-DMPFR_INCLUDE_DIR={}".format("F:/BASE_ENV/forOpenMVS/gmp_mpfr/include"))
+ extra_config_args.append(
+ "-DMPFR_LIBRARIES={}".format("F:/BASE_ENV/forOpenMVS/gmp_mpfr/lib/libmpfr-4.lib"))
if args.cuda_path != "":
extra_config_args.append(
"-DCUDA_TOOLKIT_ROOT_DIR={}".format(args.cuda_path))
@@ -479,6 +501,8 @@ def build_post_process(args):
os.path.basename(lapack_path)))

if args.qt_path:
+ print("copying !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", os.path.join(args.qt_path, "bin/Qt5Core.dll"))
+ print("copying !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", os.path.join(args.install_path, "lib/Qt5Core.dll"))
copy_file_if_not_exists(
os.path.join(args.qt_path, "bin/Qt5Core.dll"),
os.path.join(args.install_path, "lib/Qt5Core.dll"))
diff --git a/src/retrieval/utils.h b/src/retrieval/utils.h
index b99bf64..d773220 100644
--- a/src/retrieval/utils.h
+++ b/src/retrieval/utils.h
@@ -52,7 +52,8 @@ struct ImageScore {
template <int N, int kSigma = 16>
class HammingDistWeightFunctor {
public:
- static const size_t kMaxHammingDistance = static_cast<size_t>(1.5f * kSigma);
+ // static const size_t kMaxHammingDistance = static_cast<size_t>(1.5f * kSigma);
+ static const size_t kMaxHammingDistance = 24;

HammingDistWeightFunctor() {
// Fills the look-up table.

(END)

3.2 编辑CmakeList.txt

set(Boost_DEBUG ON),打开boost的调试信息,boost的链接最容易出问题。(以下的内容仅供了解,无需修改)

主要注意: -DBoost_USE_STATIC_RUNTIME=ON 这个设置是指boost的库在使用cpp的runtime时候将会使用静态库,如果这个选项打开了,则需要往CmakeList.txt(colmap的根目录)中添加:

1
2
3
# set the used type of runtime lib to be static
set(CMAKE_CXX_FLAGS_RELEASE "/MT")
set(CMAKE_CXX_FLAGS_DEBUG "/MTd")

上面意味着运行时库调用时选择静态运行时库(vs中,在项目->cpp->代码生成中有MT/MD的配置), 而且对应的编译出来的boost库,编译时需要带上: –link=static –runtime-link=static –build-type=complete 参数;

3.3 编译执行:

注意我们使用静态的boost避免boost 的链接错误;

1
2
3
4
5
6
7
8
9
10
11
12
python scripts/python/build.py \
--build_path "F:/prjs/colmap-3.6/build" \
--colmap_path "F:/prjs/colmap-3.6" \
--boost_path "F:/BASE_ENV/forOpenMVS/boost_1_73_0_v140" \
--boost_include_dir "F:/BASE_ENV/forOpenMVS/boost_1_73_0_v140" \
--boost_lib_dir "F:/BASE_ENV/forOpenMVS/boost_1_73_0_v140\lib64-msvc-14.0" \
--qt_path "F:/BASE_ENV/forOpenMVS/qt_msvc2015_64/msvc2015_64" \
--cgal_path "F:/BASE_ENV/forOpenMVS/CGAL-5.1/build" \
--cmake_generator "Visual Studio 14" \
--with_cuda \
--cuda_path "C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v10.2" \

上述命令会失败,但是没关系,用code打开F:/prjs/colmap-3.6/build/colmap/__build__:
全局替换的方式删除: BOOST_ALL_DYN_LINK=1,
然后在F:/prjs/colmap-3.6/build/colmap/__build__里找到COLMAP.sln,然后手动用vs打开然后编译;
推荐使用VS2015的工具对colmap进行编译.

4 给出我编译后的库目录结构(最重要的是__install__/lib下面的内容):

其中: install/lib下面的platform中必须要有qwindows.dll,参考问题4。
然后: install/lib里面的cgal*.dll也是不必须的,因为本博客使用的cgal是5.x,5.x的cgal都是header only 的库,所以该dll可以没有,但是其他的dll像是libgmp-10.dll确是必要的,否则将无法运行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
sagar@DESKTOP-QM75KNS MINGW64 /f/prjs/colmap-3.6/build
$ ls
__download__ ceres-solver colmap freeimage glew suite-sparse
__install__ CGAL-vc140-mt-4.14.3.dll eigen gflags glog
sagar@DESKTOP-QM75KNS MINGW64 /f/prjs/colmap-3.6/build
$ ls __download__/
ceres-solver-1.14.0.zip freeimage-3.18.0.zip glew-2.1.0.zip suite-sparse.zip
eigen-3.3.7.zip gflags-2.2.2.zip glog-0.3.5.zip
sagar@DESKTOP-QM75KNS MINGW64 /f/prjs/colmap-3.6/build
$ ls
__download__ ceres-solver colmap freeimage glew suite-sparse
__install__ CGAL-vc140-mt-4.14.3.dll eigen gflags glog

sagar@DESKTOP-QM75KNS MINGW64 /f/prjs/colmap-3.6/build
$ cd __install__/lib

sagar@DESKTOP-QM75KNS MINGW64 /f/prjs/colmap-3.6/build/__install__/lib
$ tree
.
├── FreeImage.dll
├── FreeImage.lib
├── Qt5Core.dll
├── Qt5Gui.dll
├── Qt5Widgets.dll
├── ceres.lib
├── cmake
│   ├── gflags
│   │   ├── gflags-config-version.cmake
│   │   ├── gflags-config.cmake
│   │   ├── gflags-nonamespace-targets-release.cmake
│   │   ├── gflags-nonamespace-targets.cmake
│   │   ├── gflags-targets-release.cmake
│   │   └── gflags-targets.cmake
│   ├── glew
│   │   ├── CopyImportedTargetProperties.cmake
│   │   ├── glew-config.cmake
│   │   ├── glew-targets-release.cmake
│   │   └── glew-targets.cmake
│   ├── glog
│   │   ├── glog-config-version.cmake
│   │   ├── glog-config.cmake
│   │   ├── glog-targets-release.cmake
│   │   └── glog-targets.cmake
│   └── suitesparse-4.5.0
│   ├── SuiteSparse-targets-release.cmake
│   ├── SuiteSparse-targets.cmake
│   ├── suitesparse-config-version.cmake
│   └── suitesparse-config.cmake
├── colmap
│   ├── colmap.lib
│   ├── colmap_cuda.lib
│   ├── flann.lib
│   ├── graclus.lib
│   ├── lsd.lib
│   ├── pba.lib
│   ├── poisson_recon.lib
│   ├── sift_gpu.lib
│   ├── sqlite3.lib
│   └── vlfeat.lib
├── cudart64_102.dll
├── gflags_nothreads_static.lib
├── gflags_static.lib
├── glew32.dll
├── glew32.lib
├── glog.lib
├── libamd.lib
├── libblas.dll
├── libbtf.lib
├── libcamd.lib
├── libccolamd.lib
├── libcholmod.lib
├── libcolamd.lib
├── libcxsparse.lib
├── libgcc_s_sjlj-1.dll
├── libgfortran-3.dll
├── libglew32.lib
├── libgmp-10.dll
├── libklu.lib
├── liblapack.dll
├── libldl.lib
├── libquadmath-0.dll
├── libspqr.lib
├── libumfpack.lib
├── metis.lib
├── pkgconfig
│   └── glew.pc
├── platforms
│   └── qwindows.dll
└── suitesparseconfig.lib

8 directories, 62 files

5 可能遇到的问题:

  • Q 1 一切都能正常编译通过,但是出现“程序无法正常启动, 0xc000007b”
  • 解决方案: 仔细核对我提供的目录,看看是否是dll少了,一般libgmp-10.dll少了就会报这个错误,可以参照问题4
  • Q 2 boost总是报link2005的重定义错误:
  • 解决方案: 打开colmap.sln,你会发现: 项目->属性c++预处理(宏定义) 中多了BOOST_ALL_DYN_LINK=1,用如下方法全局删除即可:用code打开F:/prjs/colmap-3.6/build/colmap/__build__:
    全局替换的方式删除: BOOST_ALL_DYN_LINK=1,然后vs会让你重载项目配置,再次编译应该可以直接通过。造成的原因可能是boost总是默认enable了autolink,这导致你必须把你的boost库的版本和你的vs版本对上,而且可能默认是全部动态链接(即使你配置了静态链接以后),可能的解决方案是,在项目根目录下面的CMAKELIST.txt中添加:
  • Q 3 libcpmt.lib(ppltasks.obj) : error LNK2001: 无法解析的外部符号 __CxxFrameHandler4报错:
  • 解决方案: 是因为你的库用的是vs2019编译的,然后colmap又用vs2015编译,就会报这个错误。
  • Q 4 Qt platform plugin ‘windows’ not found
  • 解决方案: 是因为你虽然安装了qt,但是没有复制相关的dll到./build/colmap/install/lib下(colmap的运行直接双击__install__/COLMAP.BAT即可),复制方案:(也就是build.py中的编译后处理部分做的事情)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    def build_post_process(args):
    if PLATFORM_IS_WINDOWS:
    lapack_paths = glob.glob(
    os.path.join(args.install_path, "lib64/lapack_blas_windows/*.dll"))
    if lapack_paths:
    for lapack_path in lapack_paths:
    copy_file_if_not_exists(
    lapack_path,
    os.path.join(
    args.install_path, "lib",
    os.path.basename(lapack_path)))

    if args.qt_path:
    copy_file_if_not_exists(
    os.path.join(args.qt_path, "bin/Qt5Core.dll"),
    os.path.join(args.install_path, "lib/Qt5Core.dll"))
    copy_file_if_not_exists(
    os.path.join(args.qt_path, "bin/Qt5Gui.dll"),
    os.path.join(args.install_path, "lib/Qt5Gui.dll"))
    copy_file_if_not_exists(
    os.path.join(args.qt_path, "bin/Qt5Widgets.dll"),
    os.path.join(args.install_path, "lib/Qt5Widgets.dll"))
    mkdir_if_not_exists(
    os.path.join(args.install_path, "lib/platforms"))
    copy_file_if_not_exists(
    os.path.join(args.qt_path, "plugins/platforms/qwindows.dll"),
    os.path.join(args.install_path, "lib/platforms/qwindows.dll"))

    if args.with_cuda and args.cuda_path:
    cudart_lib_path = glob.glob(os.path.join(args.cuda_path,
    "bin/cudart64_*.dll"))[0]
    copy_file_if_not_exists(
    cudart_lib_path,
    os.path.join(args.install_path, "lib",
    os.path.basename(cudart_lib_path)))

    if args.cgal_path:
    gmp_lib_path = os.path.join(
    args.cgal_path, "auxiliary/gmp/lib/libgmp-10.dll")
    if os.path.exists(gmp_lib_path):
    copy_file_if_not_exists(
    gmp_lib_path,
    os.path.join(args.install_path, "lib/libgmp-10.dll"))
    cgal_lib_path = glob.glob(os.path.join(
    args.cgal_path, "bin/CGAL-vc*-mt-*.dll"))
    copy_file_if_not_exists(
    cgal_lib_path[0],
    os.path.join(args.install_path, "lib",
    os.path.basename(cgal_lib_path[0])))
  • Q 5 莫名其妙报了cuda的编译的错误:error : identifier “__floorf” is undefined in device code
  • 解决方案: vs2019 16.9.3以及以上有这个问题,你需要卸载然后回退到16.8.5
  • Q 6 C2132 编译器错误:表达式的计算结果不是常数
  • 解决方案: 可能是你的编译器对cpp的新特性支持的不够好?,修改 src/retrieval/utils.h 的 55行为:
    1
    2
    // static const size_t kMaxHammingDistance = static_cast<size_t>(1.5f * kSigma);
    static const size_t kMaxHammingDistance = static_cast<size_t>(24);