Bug #58231 CMake option -DCMAKE_BUILD_TYPE=Debug does not result in full debug build
Submitted: 16 Nov 2010 15:30 Modified: 18 Nov 2010 9:57
Reporter: John Embretsen Email Updates:
Status: Duplicate Impact on me:
None 
Category:MySQL Server: Compiling Severity:S3 (Non-critical)
Version:5.5.8 OS:Any
Assigned to: Assigned Account CPU Architecture:Any
Tags: cmake

[16 Nov 2010 15:30] John Embretsen
Description:
According to the MySQL CMake instructions on http://forge.mysql.com/wiki/CMake, the CMake options "-DCMAKE_BUILD_TYPE=Debug" and "-DWITH_DEBUG=1" should be equivalent.

Quote:

    *  A typical debug build is done with -DCMAKE_BUILD_TYPE=Debug (shortcut for it is -DWITH_DEBUG=1) and this would include DBUG instrumentation, plus wrapper around pthread mutexes known as SAFE_MUTEX on Unixes.
    * Full debug (set with -DWITH_DEBUG_FULL=1) would additonally add malloc instrumentation 

(end quote)

It seems this is slightly outdated, since WITH_DEBUG_FULL seems to have been removed. However, the first bullet should still be true. Comments in CMakeLists.txt also indicate this:

"# We choose to provide WITH_DEBUG as alias to standard CMAKE_BUILD_TYPE=Debug"

However, it turns out that on Unix at least, running

cmake -DCMAKE_BUILD_TYPE=Debug ..

does not result in the same type of debug build as 

cmake -DWITH_DEBUG=1 ..

(the above examples are out-of-source builds)

This could also be a "documentation" bug, but I would find that strange.

How to repeat:
$ cd srcdir
$ mkdir bld-debug
$ cd bld-debug
$ cmake -DCMAKE_BUILD_TYPE=Debug ..
$ cmake -LA | grep WITH_DEBUG

Notice that this will say:
WITH_DEBUG:BOOL=OFF

However, it _is_ some kind of debug build, as tests requiring this run OK.

If you do (after the above):

$ rm CMakeCache.txt
$ cmake -DCMAKE_BUILD_TYPE=Debug -DWITH_DEBUG=1 ..

You will see:
WITH_DEBUG:BOOL=ON

You can also run an MTR test case and look for UNIV_DEBUG message printed in the top of the error log. UNIV_DEBUG is only enabled if WITH_DEBUG=1 (explicitly).

Suggested fix:
Make the code in CMakeLists.txt account for the situation where CMAKE_BUILD_TYPE=Debug and WITH_DEBUG is undefined. In that case, set WITH_DEBUG to "ON".

The current CMakeLists.txt file accounts for:

IF(WITH_DEBUG)
  (set CMAKE_BUILD_TYPE=Debug...)

and

ELSEIF(NOT HAVE_CMAKE_BUILD_TYPE OR OLD_WITH_DEBUG)
   (do some more stuff)

So it seems like an ELSEIF(CMAKE_BUILD_TYPE MATCHES "Debug") case is missing. If there is supposed to be two different levels of debug, make this clear in the documentation, and make the CMake script consistent with the actual behavior.

The comment in CMakeLists.txt that this "turns out to be not trivial" seems to be correct.
[16 Nov 2010 15:59] Vladislav Vaintroub
WITH_DEBUG is an alias for CMAKE_BUILD_TYPE=Debug, but the reverse is not true:)

I'll paste here a mail I sent to Tor recently on the similar subject

> -----Original Message-----
> From: Tor Didriksen [mailto:tor.didriksen@oracle.com]
> Sent: Monday, November 08, 2010 4:33 PM
> To: Vladislav Vaintroub
> Cc: Olav Sandstaa
> Subject: debug builds (or not) on windows
> 
> Hi Vlad.
> 
> When building on windows, I do something like this:
> cmake .. -DBUILD_CONFIG=mysql_release -DWITH_DEBUG=1 -G"Visual Studio 10"
> devenv mysql.sln /build Debug
> 
> In pushbuild, they do something like this:
> cscript win\configure.js WITH_INNOBASE_STORAGE_ENGIN......
> cmake -G "Visual Studio 9 2008 Win64"
> 
> set TARGET=Debug
> devenv.com /build %TARGET% MySql.sln
> 
> Does this actually generate debug binaries, with DBUG macros etc. etc.?
> 
> Looking at CMakeCache.txt in pushbuild, is confusing:
> WITH_DEBUG:BOOL=OFF
> 

Hi Tor,
Yes, it works. And it can be slightly confusing. This works a bit different dependent on generator. "* Makefiles" are single-config generators,  Visual Studio and Xcode are multi-config.

After a single cmake run you'll have a "project" with multiple (4) configuration: Debug,Release, RelWithDebInfo, and MinSizeRel. -DBUILD_TYPE has no meaning for here, and -DWITH_DEBUG(as shortcut or -DBUILD_TYPE=Debug)  also does not have much sense .You can instead control type at build time rather than "cmake" time, e.g

devenv /build Debug MySql.sln
devenv /build RelwithDebInfo MySql.sln

all from the same "project" file, or control it in VS or Xcode GUI switching the build type in the corresponding select  box.

xcodebuild (command line tool to build Xcode projects) also has those types on the command line but I do not remember then off the top of my head. Now,  after  you build can build Debug and RelWithDebInfo types, and even package them separately with e.g

devenv /build %BUILD_TYPE% MySql.sln /project package

and run mtr against it, selecting build type you want to MTR-test. The trick for MTR, with both Visual Studio on Windows and Xcode on OSX  is to set environment variable MTR_VS_CONFIG to the correct configuration, like
set MTR_VS_CONFIG=Debug (Windows)
export MTR_VS_CONFIG=Debug (OSX)

(if MTR_VS_CONFIG is not set,  there is a search logic for all known types that prefers Release types to Debug)

You  can control compiler  flags specific to configuration with CMAKE_C_FLAGS_{CONFIG} , and I'm using it in some places (this is how for example -DDBUG_OFF is added to all project types bug Debug), and this *should* be consistently done for all options that are "debug-only".   Those debug-only options is something to  keep in mind, when introducing  new ones. Specifically, one need to remember  that -DWITH_DEBUG or BUILD_TYPE  might be undefined,  and that CMAKE_C_FLAGS_DEBUG and CMAKE_CXX_FLAGS_DEBUG are  the correct place to add stuff that is "debug-only" , and perhaps also corresponding linker flags. But, if you do something that is  not *so* important or say for Linux  only,  such that  Visual Studio or Xcode are not involved , you might add IF(WITH_DEBUG) or  IF(CMAKE_BUILD_TYPE MATCHES "Debug"). Consider this "harmful" however:)   Re. install  .. INSTALL(FILES|TARGETS)  command for packaging and "make install" supports CONFIGURATIONS parameter that works with VS and Xcode and normal  "Makefiles" generators, so you can control which files to install in which configuration if necessary.

To which Tor replies:

I guess this is the problem then:
# Enable InnoDB's UNIV_DEBUG if MySQL's WITH_DEBUG is defined
IF(WITH_DEBUG)
   ADD_DEFINITIONS("-DUNIV_DEBUG")
ENDIF()

We have a couple of tests which we expected to fail on windows (asserts 
in innodb), they did not fail.

And I reply to it:

Yep, this should be SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}  -DUNIV_DEBUG") in the CMakeLists.txt

Summary:
=======
Using IF(WITH_DEBUG) or IF(CMAKE_BUILD_TYPE MATCHES "Debug") to set compile options in CMakeLists.txt is harmful does not work. 

IF(CMAKE_BUILD_TYPE MATCHES "Debug") might work but not on Windows with Visual Studio and not on OSX  with Xcode. It works only with "*Makefile" generators.

One can/should/must always use CMAKE_{C,CXX}_FLAGS_DEBUG to set debug-only options. Violations to this rule, should be fixed.
[16 Nov 2010 16:22] Vladislav Vaintroub
Added http://forge.mysql.com/wiki/CMake#Debug-only_options with good and bad examples of debug-only option
[17 Nov 2010 15:11] John Embretsen
Wlad, I think I understand most of what you are saying about the alias and multi-config (Visual Studio, XCode) vs. single-config (make).

Before I encountered this issue, I was under the impression that -DWITH_DEBUG in CMake was just a translation of --with-debug from autotools, and that the proper CMake way of doing it was to specify CMAKE_BUILD_TYPE=Debug instead.

Note that I care mostly about what users may and should set on the command line in order to get the types of builds they want, not what developers should do inside the CMake configuration files (or whatever the files are called).

So...

-DCMAKE_BUILD_TYPE=whatever is not used with multi-config generators (xcode, VS). This is because the build type is specified at compile time there. Good to know.

With single-config generators (Unix), build type is specified at cmake time, so setting it there is in theory useful.

What I don't understand is, what is the purpose of -DCMAKE_BUILD_TYPE, if it does not result in proper debug builds if you set it to "Debug"?

Why even have this option in the mix (apart from attracting autotools users)?
By "option" I mean:
 "WITH_DEBUG=1" = "CMAKE_BUILD_TYPE=Debug" + extra_stuff
From a user's perspective, we have two different Debug types on Unix, and one on Windows. That is confusing.

The wiki gives (me at least) the impression that if you set -DCMAKE_BUILD_TYPE=Debug on Unix you get a debug build. 
Now it turns out that one needs to set -DWITH_DEBUG=1 as well, or instead.

I guess we all agree that the fact that e.g. UNIV_DEBUG is not enabled if
CMAKE_BUILD_TYPE="Debug" and WITH_DEBUG is not defined is a bug.
Had it been done the way you describe with "SET(CMAKE_C_FLAGS_DEBUG..." etc. it
would not be an issue. Is this the correct understanding?

IMHO the wiki/documentation should make this more clear (although your latest edits helped too), or we should fix all related bugs and try to make it harder to create this kind of differentiation in the CMake config scripts.

Anyway, I have started to inlcude -DWITH_DEBUG=1 for all Unix debug builds I
intend to do. I will care less about CMAKE_BUILD_TYPE. Thanks for the lesson :)
[17 Nov 2010 15:36] Vladislav Vaintroub
What I don't understand is, what is the purpose of -DCMAKE_BUILD_TYPE, if it does not result in proper debug builds if you set it to "Debug"?

It should result in proper build, or we have bugs.

>Why even have this option in the mix (apart from attracting autotools users)?
There is no reason apart of attracting autotools users (short command line maybe). And one should use neither rely on CMAKE_BUILD_TYPE nor on WITH_DEBUG when setting flags , only CMAKE_C_FLAGS_DEBUG or CMAKE_CXX_FLAGS_DEBUG is what matters.

>By "option" I mean:
> "WITH_DEBUG=1" = "CMAKE_BUILD_TYPE=Debug" + extra_stuff
>From a user's perspective, we have two different Debug types on Unix, and one 
> on Windows. That is confusing.

IF people used CMAKE_C_FLAGS_DEBUG,  or have looked at how -DDBUG_OFF etc is set, it would not be confusing. It would be single debug build, as it should be.

>I guess we all agree that the fact that e.g. UNIV_DEBUG is not enabled if
>CMAKE_BUILD_TYPE="Debug" and WITH_DEBUG is not defined is a bug.
>Had it been done the way you describe with "SET(CMAKE_C_FLAGS_DEBUG..." etc. it
>would not be an issue. Is this the correct understanding?

It is a bug, this is something I tried to make clear with Wiki examples :)

>Anyway, I have started to inlcude -DWITH_DEBUG=1 for all Unix debug builds I
>intend to do. I will care less about CMAKE_BUILD_TYPE. Thanks for the lesson :)

Hmm, well, maybe we should define it as a bug to be fixed :)
[18 Nov 2010 9:57] John Embretsen
I filed Bug#58279 for handling the UNIV_DEBUG + WITH_DEBUG issue.

I set this bug as a duplicate of that one, since this bug's synopsis is still true, and has Bug#58279 as direct cause, so closing as Not a bug would kindof seem strange.

(Maybe I'm still unclear on why making WITH_DEBUG an alias for CMAKE_BUILD_TYPE=Debug (in addition to the other way round) is not done, but I'll let that go for now. I guess continued education and information is what is really needed to avoid similar issues in the future.)