Search code examples
windowsopencvcmakeconan

Strange behaviour by conan when generating CMake files


I'm currently writing a conanfile.py to build OpenCV, a custom build used internally by my company. We're trying to use CMake to build but we're coming across an unexpected behaviour by OpenCV: when generating a Release build without specifying the build_type in settings, OpenCV generates a release and a debug build.

This is our conanfile.py:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Conan file to build OpenCV according to other specs.
"""

from conans import ConanFile, CMake, tools
import re
import os.path


class OpenCVConan(ConanFile):
    name = "opencv"
    version = "3.4.3"
    url = "https://github.com/opencv/opencv"
    license = "https://github.com/opencv/opencv/blob/master/LICENSE"
    settings = "os", "compiler", "arch"
    options = {"shared": [True, False]}
    default_options = {"shared": True}
    topics = ("kv", "opencv", "C++")
    generators = "cmake_find_package"
    description = "Building OpenCV from sources according to our specs."
    _msvc_archs = {"x86": "x86", "x86_64": "x64"}

    def source(self):
        self.run("git clone --depth 1 --branch %s https://github.com/opencv/opencv" % (self.version))
        self.run("git clone --depth 1 --branch %s https://github.com/opencv/opencv_contrib" % (self.version))

    def _configure_cmake(self):
        cmake = CMake(self)

        cmake.definitions["CPACK_BINARY_NSIS"] = False
        cmake.definitions["CPACK_SOURCE_7Z"] = False
        cmake.definitions["CPACK_SOURCE_ZIP"] = False

        cmake.definitions["ENABLE_CXX11"] = True
        cmake.definitions["ENABLE_LTO"] = False
        cmake.definitions["ENABLE_THIN_LTO"] = False
        cmake.definitions["OPENCV_ENABLE_NONFREE"] = False
        cmake.definitions["TINYDNN_USE_AVX"] = False
        cmake.definitions["ENABLE_SOLUTION_FOLDERS"] = False

        cmake.definitions["OPENCV_EXTRA_MODULES_PATH"] = "opencv_contrib/modules"

        cmake.definitions["WITH_1394"] = False
        cmake.definitions["WITH_MATLAB"] = False
        cmake.definitions["WITH_NVCUVID"] = False
        cmake.definitions["WITH_GSTREAMER"] = False
        cmake.definitions["WITH_OPENEXR"] = False
        cmake.definitions["WITH_OPENGL"] = True
        cmake.definitions["WITH_FFMPEG"] = False

        cmake.definitions["BUILD_DOCS"] = False
        cmake.definitions["BUILD_EXAMPLES"] = False
        cmake.definitions["BUILD_JAVA"] = False
        cmake.definitions["BUILD_OPENEXR"] = False
        cmake.definitions["BUILD_PACKAGE"] = False
        cmake.definitions["BUILD_PERF_TESTS"] = False
        cmake.definitions["BUILD_TESTS"] = False
        cmake.definitions["BUILD_WITH_STATIC_CRT"] = False

        cmake.definitions["BUILD_opencv_ts"] = False
        cmake.definitions["BUILD_opencv_js"] = False
        cmake.definitions["BUILD_opencv_java_bindings_generator"] = False

        cmake.definitions["BUILD_CUDA_STUBS"] = True
        cmake.definitions["BUILD_opencv_world"] = False
        cmake.definitions["BUILD_opencv_cudaoptflow"] = True
        cmake.definitions["BUILD_opencv_stitching"] = False
        cmake.definitions["WITH_CUDA"] = True
        cmake.definitions["WITH_CUFFT"] = True
        cmake.definitions["WITH_CUBLAS"] = True
        cmake.definitions["CUDA_ARCH_BIN"] = "5.0 5.2 6.0 6.1"

        cmake.definitions["CMAKE_BUILD_TYPE"] = "Release"

        cmake.configure(source_folder="opencv")
        return cmake

    def build(self):
        cmake = self._configure_cmake()
        cmake.build()
        #self.run('cmake "%s" %s -DCMAKE_BUILD_TYPE="Release"' % (self.source_folder, cmake.command_line))
        #self.run('cmake --build . --config Release')

    def package(self):
        cmake = self._configure_cmake()
        self.run('cmake --build . --target install')
        cmake.patch_config_paths()

        library_folder = os.path.join(self.package_folder, self._msvc_archs[self.settings.arch.value], "vc15")
        self.copy(pattern="*.lib", dst="lib", src=library_folder, keep_path=False)
        self.copy(pattern="*.dll", dst="bin", src=library_folder, keep_path=False)

        # Remove debug headers from the packages
        with open(self.package_folder + "\include\opencv2\core\cvdef.h", 'r+') as f:
            """
            Let's clarify what's going on here:
            We open a file for reading, change the data we read from the buffer, then place the
            cursor at the beginning of the file and save the content. Since this will append to
            the file we need to call truncate() to remove excessive data that may have remained there.

            Yep, this is a thing.
            """
            content = f.read()
            first_change = re.sub("namespace(\s+)debug_build_guard(\s+){", "", content, 1)
            second_change = re.sub("}", "", first_change, 1)
            f.seek(0)
            f.write(second_change)
            f.truncate()

    def package_info(self):
        self.cpp_info.libs.extend(tools.collect_libs(self))

and this is the generated configuration:

[...]
-- General configuration for OpenCV 3.4.3 =====================================
--   Version control:               3.4.3
--
--   Extra modules:
--     Location (extra):            C:/Users/RHPACHECO/.conan/data/opencv/3.4.3/kiwi/testing/build/66bc1bfbe8eb268302b5afcd9e75e1a476dbdbef/opencv_contrib/modules
--     Version control (extra):     3.4.3
--
--   Platform:
--     Timestamp:                   2019-07-31T10:13:15Z
--     Host:                        Windows 10.0.17763 AMD64
--     CMake:                       3.14.1
--     CMake generator:             Visual Studio 15 2017 Win64
--     CMake build tool:            C:/Program Files (x86)/Microsoft Visual Studio/2017/Enterprise/MSBuild/15.0/Bin/MSBuild.exe
--     MSVC:                        1916
--
--   CPU/HW features:
--     Baseline:                    SSE SSE2 SSE3
--       requested:                 SSE3
--     Dispatched code generation:  SSE4_1 SSE4_2 FP16 AVX AVX2
--       requested:                 SSE4_1 SSE4_2 AVX FP16 AVX2 AVX512_SKX
--       SSE4_1 (3 files):          + SSSE3 SSE4_1
--       SSE4_2 (1 files):          + SSSE3 SSE4_1 POPCNT SSE4_2
--       FP16 (1 files):            + SSSE3 SSE4_1 POPCNT SSE4_2 FP16 AVX
--       AVX (5 files):             + SSSE3 SSE4_1 POPCNT SSE4_2 AVX
--       AVX2 (9 files):            + SSSE3 SSE4_1 POPCNT SSE4_2 FP16 FMA3 AVX AVX2
--
--   C/C++:
--     Built as dynamic libs?:      YES
--     C++11:                       YES
--     C++ Compiler:                C:/Program Files (x86)/Microsoft Visual Studio/2017/Enterprise/VC/Tools/MSVC/14.16.27023/bin/Hostx86/x64/cl.exe  (ver 19.16.27032.1)
--     C++ flags (Release):         /DWIN32 /D_WINDOWS /W4 /GR  /D _CRT_SECURE_NO_DEPRECATE /D _CRT_NONSTDC_NO_DEPRECATE /D _SCL_SECURE_NO_WARNINGS /Gy /bigobj /Oi      /EHa /wd4127 /wd4251 /wd4324 /wd4275 /wd4512 /wd4589 /MP12   /MD /O2 /Ob2 /DNDEBUG
--     C++ flags (Debug):           /DWIN32 /D_WINDOWS /W4 /GR  /D _CRT_SECURE_NO_DEPRECATE /D _CRT_NONSTDC_NO_DEPRECATE /D _SCL_SECURE_NO_WARNINGS /Gy /bigobj /Oi      /EHa /wd4127 /wd4251 /wd4324 /wd4275 /wd4512 /wd4589 /MP12   /MDd /Zi /Ob0 /Od /RTC1
--     C Compiler:                  C:/Program Files (x86)/Microsoft Visual Studio/2017/Enterprise/VC/Tools/MSVC/14.16.27023/bin/Hostx86/x64/cl.exe
--     C flags (Release):           /DWIN32 /D_WINDOWS /W3  /D _CRT_SECURE_NO_DEPRECATE /D _CRT_NONSTDC_NO_DEPRECATE /D _SCL_SECURE_NO_WARNINGS /Gy /bigobj /Oi        /MP12    /MD /O2 /Ob2 /DNDEBUG
--     C flags (Debug):             /DWIN32 /D_WINDOWS /W3  /D _CRT_SECURE_NO_DEPRECATE /D _CRT_NONSTDC_NO_DEPRECATE /D _SCL_SECURE_NO_WARNINGS /Gy /bigobj /Oi        /MP12  /MDd /Zi /Ob0 /Od /RTC1
--     Linker flags (Release):      /machine:x64  /INCREMENTAL:NO
--     Linker flags (Debug):        /machine:x64  /debug /INCREMENTAL
--     ccache:                      NO
--     Precompiled headers:         YES
--     Extra dependencies:          opengl32 glu32 cudart_static.lib nppc.lib nppial.lib nppicc.lib nppicom.lib nppidei.lib nppif.lib nppig.lib nppim.lib nppist.lib nppisu.lib nppitc.lib npps.lib cublas.lib cufft.lib -LIBPATH:C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v10.1/lib/x64
--     3rdparty dependencies:
--
--   OpenCV modules:
--     To be built:                 aruco bgsegm bioinspired calib3d ccalib core cudaarithm cudabgsegm cudacodec cudafeatures2d cudafilters cudaimgproc cudalegacy cudaobjdetect cudaoptflow cudastereo cudawarping cudev datasets dnn dnn_objdetect dpm face features2d flann fuzzy hfs highgui img_hash imgcodecs imgproc line_descriptor ml objdetect optflow phase_unwrapping photo plot python_bindings_generator reg rgbd saliency shape stereo structured_light superres surface_matching text tracking video videoio videostab xfeatures2d ximgproc xobjdetect xphoto
--     Disabled:                    java_bindings_generator js stitching world
--     Disabled by dependency:      -
--     Unavailable:                 cnn_3dobj cvv freetype hdf java matlab ovis python2 python3 sfm ts viz
--     Applications:                apps
--     Documentation:               NO
--     Non-free algorithms:         NO
--
--   Windows RT support:            NO
--
--   GUI:
--     Win32 UI:                    YES
--     OpenGL support:              YES (opengl32 glu32)
--     VTK support:                 NO
--
--   Media I/O:
--     ZLib:                        build (ver 1.2.11)
--     JPEG:                        build-libjpeg-turbo (ver 1.5.3-62)
--     WEBP:                        build (ver encoder: 0x020e)
--     PNG:                         build (ver 1.6.34)
--     TIFF:                        build (ver 42 - 4.0.9)
--     JPEG 2000:                   build (ver 1.900.1)
--     HDR:                         YES
--     SUNRASTER:                   YES
--     PXM:                         YES
--
--   Video I/O:
--     Video for Windows:           YES
--     DirectShow:                  YES
--     Media Foundation:            YES
--
--   Parallel framework:            Concurrency
--
--   Trace:                         YES (with Intel ITT)
--
--   Other third-party libraries:
--     Intel IPP:                   2017.0.3 [2017.0.3]
--            at:                   C:/Users/RHPACHECO/.conan/data/opencv/3.4.3/kiwi/testing/build/66bc1bfbe8eb268302b5afcd9e75e1a476dbdbef/3rdparty/ippicv/ippicv_win
--     Intel IPP IW:                sources (2017.0.3)
--               at:                C:/Users/RHPACHECO/.conan/data/opencv/3.4.3/kiwi/testing/build/66bc1bfbe8eb268302b5afcd9e75e1a476dbdbef/3rdparty/ippicv/ippiw_win
--     Lapack:                      NO
--     Eigen:                       NO
--     Custom HAL:                  NO
--     Protobuf:                    build (3.5.1)
--
--   NVIDIA CUDA:                   YES (ver 10.1, CUFFT CUBLAS)
--     NVIDIA GPU arch:             50 52 60 61
--     NVIDIA PTX archs:
--
--   OpenCL:                        YES (no extra features)
--     Include path:                C:/Users/RHPACHECO/.conan/data/opencv/3.4.3/kiwi/testing/build/66bc1bfbe8eb268302b5afcd9e75e1a476dbdbef/opencv/3rdparty/include/opencl/1.2
--     Link libraries:              Dynamic load
--
--   Python (for build):            C:/Program Files (x86)/Python37-32/python.exe
--
--   Install to:                    C:/Users/RHPACHECO/.conan/data/opencv/3.4.3/kiwi/testing/package/66bc1bfbe8eb268302b5afcd9e75e1a476dbdbef
-- -----------------------------------------------------------------
[...]

Notice how it generated Release and Debug builds and then it builds both.

We also have a batch file that uses CMake to generate a Visual Studio solution for OpenCV which is then built using MSBuild and that works exactly as we want it to, so I suspect the problem is with conan. We also tried to build OpenCV using the CMake helper and self.run() and the result seems to be the same.


Solution

  • Running the install target would trigger the second build as it didn't have the same build type as the build command. The solution is to, if using the CMake helper, pass build_type="Release" as a parameter of the constructor or, if running CMake from the command line helper, pass "--config Release".