Skip to content

build: added DEBUG build guard (cv::debug_build_guard::_InputArray error LNK2019)#9161

Merged
opencv-pushbot merged 1 commit intoopencv:masterfrom
alalek:separate_debug_symbols
Jul 19, 2017
Merged

build: added DEBUG build guard (cv::debug_build_guard::_InputArray error LNK2019)#9161
opencv-pushbot merged 1 commit intoopencv:masterfrom
alalek:separate_debug_symbols

Conversation

@alalek
Copy link
Copy Markdown
Member

@alalek alalek commented Jul 13, 2017

To prevent linkage of binary incompatible DEBUG/RELEASE binaries/runtimes.

resolves #5227
resolves #6070
resolves #5564

It is hard to debug this kind of issues. Application just crash / hangs without any useful information from debugger.

  • This patch doesn't change release builds
  • Minimal set of entities are wrapped: "InputArray" types subset, but it is enough to catch problem configuration.
  • It prevents to link OpenCV RELEASE binaries with Applications in DEBUG mode (MSVS or GCC with _GLIBCXX_DEBUG macro).
  • This check doesn't require using of CMake scripts.
  • Error message example from linker:

error LNK2019: unresolved external symbol "void __cdecl cv::cvtColor(class cv::debug_build_guard::_InputArray const &,class cv::debug_build_guard::_OutputArray const &,int,int)"

error LNK2019: unresolved external symbol "void __cdecl cv::imshow(class cv::String const &,class cv::debug_build_guard::_InputArray const &)"

There is a special marker in these messages: debug_build_guard / cv::debug_build_guard::_InputArray .
If you see this then you should get debug version of OpenCV binaries or switch your application build mode to "release".
BTW, you can improve experience of "release builds" debugging by using of these safe hacks:

  • enable debug information: /Z7 compiler option works fine for MSVS
  • disable optimization flags (/O2 -> /O0 for MSVS)

To prevent linkage of binary incompatible DEBUG/RELEASE binaries/runtimes
@alalek
Copy link
Copy Markdown
Member Author

alalek commented Jul 19, 2017

👍

@cdcseacave
Copy link
Copy Markdown
Contributor

I am using MSVS to compile a project in Release-With-Debug-Information (that is enabling the /Zi flag). I compiled OpenCV exactly the same way and I am linking to it statically. I get the error LNK2019 specified above. What am I doing wrong?

@alalek
Copy link
Copy Markdown
Member Author

alalek commented Jul 20, 2017

@cdcseacave Please check for DEBUG / _DEBUG macros in your "Release-With-Debug-Information" build configuration.

@cdcseacave
Copy link
Copy Markdown
Contributor

They are disabled, only NDEBUG is define

@alalek
Copy link
Copy Markdown
Member Author

alalek commented Jul 20, 2017

This is very strange, because inner #if condition passes via DEBUG/_DEBUG macro only. Could you check what activates #if condition in your build?

@cdcseacave
Copy link
Copy Markdown
Contributor

I found the issue, DEBUG is defined in one external logging library. It is a macro printing something to std::cout (which to be honest looks quite legit to me). Wouldn't be safer to change your check from #if (defined(_MSC_VER) && (defined(DEBUG) || defined(_DEBUG))) to #if (defined(_MSC_VER) && (DEBUG == 1 || _DEBUG == 1))? If not, what is the way around this (assuming I can not modify an external library)?

@cdcseacave
Copy link
Copy Markdown
Contributor

I found a work around for this (maybe it will be helpful to others as well). Wrap the OpenCV includes with:

#pragma push_macro("DEBUG")
#undef DEBUG
#include <opencv2/something.hpp>
#pragma pop_macro("DEBUG")

@bblanchon
Copy link
Copy Markdown
Contributor

Hi @alalek.

I'm using CMake 3.9 and Visual Studio 2017.

As far as I can tell, DEBUG is not defined for "Debug" configuration.
I had to add the definition of DEBUG myself to make the link pass.

It seems to be a limitation of CMake, since Visual Studio does add the DEBUG definition when I create a project via the IDE.

On the other hand, NDEBUG is defined for "Release" configuration.
Would you agree to use NDEBUG instead of DEBUG to trigger the debug build guard?

I can make a Pull Request if that's OK.

Regards,
Benoit

@alalek
Copy link
Copy Markdown
Member Author

alalek commented Sep 18, 2017

@bblanchon
_DEBUG (with underscore) is missing in mentioned configuration from command-line, but it is still defined automatically by compiler (via /MDd flag).
Related CMake change: https://gitlab.kitware.com/cmake/cmake/issues/16430 (discussion)

Please check for "/MDd" compiler option in your debug build.
Also add here received error message and failed command line.


Using NDEBUG should be avoided here, it is used for turn off assertions.

MSVS headers widely uses _DEBUG macro. "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xutility":

 #ifdef _DEBUG
				_Myptr = (_Elem *)_malloc_dbg(_Count, _CRT_BLOCK,
					__FILE__, __LINE__);

 #else /* _DEBUG */
				_Myptr = (_Elem *)_CSTD malloc(_Count);
 #endif /* _DEBUG */

@bblanchon
Copy link
Copy Markdown
Contributor

You're right @alalek!
I just realized that I had a /MT in my CMakeLists.txt.
Thank you very much for the quick response.

I managed to build properly with "Debug" and "Release" configuration.
However, there is still something bothering me: "RelWithDebInfo" and "MinSizeRel" are not linking.

"RelWithDebInfo" and "MinSizeRel" use the non-debug version of the runtime (/MD).
But, CMake picks the "debug" libraries of OpenCV (opencv_highgui330d.lib).

The solution is to map the project configurations to the imported library configurations:

set_target_properties(opencv_highgui PROPERTIES
  MAP_IMPORTED_CONFIG_MINSIZEREL Release
  MAP_IMPORTED_CONFIG_RELWITHDEBINFO Release
)

Do you mind if I make a PR?

@alalek
Copy link
Copy Markdown
Member Author

alalek commented Sep 18, 2017

OpenCV supports Debug/Release only. We don't want to support other exotic build configurations (we will not test them or prepare binaries).

Proposed solution with configuration mapping should help here. It should be added for all OpenCV targets somewhere here:

if(MSVC AND TARGET ${__cvcomponent})
  set_target_properties(${__cvcomponent} PROPERTIES
      ...
  )
endif()

@danielgindi
Copy link
Copy Markdown

What the heck is this?
This breaks DEBUG builds.
Every build in debug mode will have some of the symbols wrapped in that nonsense namespace, and therefore you can't build in debug.

@sylvain-bougnoux
Copy link
Copy Markdown

sylvain-bougnoux commented Nov 6, 2018

I confirm it breaks linking debug build of OpenCV4.0b (at least on MSVC 2015 x64).
The problem is that the default cmake generates a solution with runtime /MD instead of /MDd. Therefore the flag _DEBUG is not added automatically by the compiler, and the code is compiled without namespace debug_build_guard.
It is possible but very dangerous to link debug code with non debug libraries because some class might not have the same definition, eg stl::*. Therefore it generally crashes at runtime depending on what you are calling. Therefore the fix (maybe partial) is to use /MTd in debug compilation of OpenCV.

(cmake=3.12.3)

@alalek
Copy link
Copy Markdown
Member Author

alalek commented Nov 6, 2018

@sylvain-bougnoux Can't reproduce with CMake 3.11.0:

CMAKE_CXX_FLAGS_DEBUG_INIT= /MDd /Zi /Ob0 /Od /RTC1
CMAKE_CXX_FLAGS_RELEASE_INIT= /MD /O2 /Ob2 /DNDEBUG

/MTd is not an option (we need single code which controls memory allocations from heap).

Winpack test build for 4.0.0-beta.

@sylvain-bougnoux
Copy link
Copy Markdown

My mistake, the cmake cache was probably scrambled. For some strange reasons, it worked in Release. Now cleaning the cache, both debug & release compile fine.
Thanks.

@danielgindi
Copy link
Copy Markdown

I think that it's never the responsibility of a library to make sure it's not linked in a mixed bad way. If the developer can't figure that out, it's his problem. You should not break libraries because of this...

@alalek
Copy link
Copy Markdown
Member Author

alalek commented Nov 7, 2018

@danielgindi You should select proper DEBUG OpenCV binary for your DEBUG builds.

If the developer can't figure that out, it's his problem.

Right.
This patch just avoids user reports with "Application just crash / hangs without any useful information from debugger"

@fei4xu
Copy link
Copy Markdown

fei4xu commented Oct 4, 2021

it's very common that a Debug config of Application is linked to release version of OpenCV. On Sourceforge, only release version of OpenCV is available for download, to get a debug build, it's required to build OpenCV from source, which is another pain. If you really want to promote the usage of Debug version of OpenCV, just release a debug version, much simpler.

The error is reported very late at link phase, not build phase, as a very common error of LNK2019. It's very difficult even for a developer to check why the link is failed for only some cv functions but not all.

I'm afraid it wasted more development time than it saved, at least for me.

@dan-masek
Copy link
Copy Markdown
Contributor

On Sourceforge, only release version of OpenCV is available for download, to get a debug build, it's required to build OpenCV from source, which is another pain. If you really want to promote the usage of Debug version of OpenCV, just release a debug version, much simpler.

Don't know about Sourceforge, but on Github they do. I have official Windows packages sitting on my disk going back at least a decade and they all include a debug binary as well AFAICT.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

8 participants