[CMake] Forcing /MDd using externalproject_add

Brian Davis bitminer at gmail.com
Wed Jan 22 11:27:56 EST 2014


Continuing on here from results of bug submittal at
http://public.kitware.com/Bug/view.php?id=14705 I will try to post whatever
necessary bits from that here in hopes of making this cohesive discussion.

The bug report example has two CMakeLists.txt files:

external_project/CMakeLists.txt

referred to here as TOP and

external_project/some_external_project/CMakeLists.txt

referred to here as SUB, sets some CMAKE_C*_FLAGS (not using CACHE FORCE).
TOP ExternalProject_Adds SUB and tries to set CMAKE_C*_FLAGS* and friends
vars by using -DVAR_NAME:VAR_TYPE="VAR_VALUE"  with VAR_TYPE as INTERNAL in
hopes of FORCING subproject vars, which IMHO should not be this difficult.

>From Bug Report Brad responds with:

"FORCE tells set() to overwrite an existing non-INTERNAL cache entry and
ignore whatever the user may have manually configured. An INTERNAL cache
entry means it belongs to the project and should not be edited by the user
manually."

Yes force will overwrite and existing non-INTERNAL cache entry.  I am
passing the values as INTERNAL so why is a non forced value overriding it
in the subproject? There are various CMAKE_* variables some are specified
as INTERNAL such as *maybe*

*CMAKE_<LANG>_COMPILER_ABI*: An internal variable subject to change.
*CMAKE_<LANG>_PLATFORM_ID*: An internal variable subject to change.
*CMAKE_INTERNAL_PLATFORM_ABI*: An internal variable subject to change.

as I am not *sure* if internal == INTERNAL

but not

CMAKE_C*_FLAGS* and friends.

At least that's my probably incorrect understanding.

>From Bug Report Brad also responds with:

"The code in your ExternalProject_Add call correctly sets the cache entry
values for the build tree of the inner project. However, as I explained in
0014705:0034966
<http://public.kitware.com/Bug/view.php?id=14705#c34966>the code in
your inner-project's CMakeLists.txt hides those values by
setting normal variables of the same name. Therefore the cache values are
not visible and are ignored regardless of their type or value. This is
explained in the documentation linked in
0014705:0034968<http://public.kitware.com/Bug/view.php?id=14705#c34968>
."

Document Brad referred to is:

http://cmake.org/gitweb?p=cmake.git;a=blob;f=Help/manual/cmake-language.7.rst;hb=1b395813#l393

This document does not state any persistence a variable should have when
terms INTERNAL or FORCE are used.  From my reading documentation "INTERNAL
implies FORCE".  So while the document has a wonderful discussion on
variables it says nothing as to how variables persist or can be
overridden.  If it is explained there I certainly do not see where.  I
almost wonder if the wrong link was posted in his reply.


Yes the inner project does specify the values.  However should passing in
the variable type as INTERNAL imply FORCE and override the internal setting
of the subproject as INTERNAL implies FORCE?  Clearly it does not, but
should it?  I really wish I could get a direct answer to this simple
question.  It's as though the documentation implies a certain
functionality, but CMake does not operate this way.

The referenced document makes no reference to FORCE or INTERNAL.  If this
is the holy grail of CMake internal operation then shouldn't it?  The
document references a persistent cache, but I do not glean from this how it
promptly ignores types as he states such as INTERNAL.  I don't see or
understand how it is explained here and I am probably thick headed on this
and just not seeing it.  It appears to expalin some of the internal
workings of the language, but not how external interfaces affect it such as
-D at the command prompt or when using ExternalProject_Add.  This document
is "aware" of -D option (Paragraph beginning "To support legacy CMake
code"), but does not reference how it is interpreted and how variables are
ignored or stored in the CACHE.

I also enjoy reading the grammar definition for CMake in order to determine
how CMake should work.  I had never see this doc before this post.   It
also looks as though it refrences CMake 3.0  so maybe 3.0 will have a
better gramar parser?  Not sure how this document helps me in 2.8 if this
is gramar spec for 3.0, but likely backwards compatible?

This doc may need section such as

"ExternalProject_Add and Command Line Scope
CMake promptly ignores all attempts you the take to set or  force variables
in project if variables are set in project even if said variables are not
CACHE FORCE in sub project.  Thinking about using
-DVAR_NAME:INTERNAL="VAR_VALUE" thinking that INTERNAL implies FORCE...
don't bother CMake will ignore that too.  What's FORCE mean?... certainly
not what you think.  Ha Ha programmer jokes on you :-)!"

Or something to that effect :-)

These variables in the sub project are set, but are not forced so should
not be setting of these variables be overridden by parent project when
-DCMAKE_C_FLAGS_DEBUG:INTERNAL="/MDd /Z7 /Od" is specified to
ExternalProject_Add.

Or maybe a better question is what should I expect from specifying INTERNAL
as clearly it is not what I expect from reading the documentation... really
any documentation so far.

Also above document referenced following doument which was also no help.
http://www.cmake.org/cmake/help/git-master/manual/cmake-variables.7.html



>From documentation http://www.cmake.org/cmake/help/v2.8.12/cmake.html:

<snip>
INTERNAL = No GUI entry (used for persistent variables).

If <type> is INTERNAL, the cache variable is marked as internal, and will
not be shown to the user in tools like cmake-gui. This is intended for
values that should be persisted in the cache, but which users should not
normally change. INTERNAL implies FORCE.
<end snip>

Now either:

1) Above statement is a lie
2) It is correct and INTERNAL does not work in all use cases of CMake
including ExternalProject_Add and and the command prompt using -D option.
3) It is correct and CMake has a bug or is not correctly implemented for
all use cases.


>From Command prompt calling into the subproject(SUB above):

c:\projects\CMakeTesting\external_project_test\some_external_project\build>
del *.* && cmake -DCMAKE_C_FLAGS_DEBUG="=====SOME_OTHER_VARIABLE =====" ..\
CMAKE_CXX_FLAGS_INIT=/DWIN32 /D_WINDOWS /W3 /Zm1000 /EHsc /GR
Following line for CXX DEBUG should contain /MDd
CMAKE_CXX_FLAGS_DEBUG=/D_DEBUG /MTd /Zi /Ob0 /Od /Gm
CMAKE_CXX_FLAGS_DEBUG_INIT=/D_DEBUG /MTd /Zi /Ob0 /Od
CMAKE_C_FLAGS_DEBUG=CHILD_PROJECT_DEBUG
CMAKE_C_FLAGS_DEBUG_INIT=/D_DEBUG /MTd /Zi  /Ob0 /Od
CMAKE_C_FLAGS_RELEASE=CHILD_PROJECT_RELEASE
SOME_VAR=ChildProjectSomeValue
ANOTHER_VAR=
-- Configuring done
-- Generating done
-- Build files have been written to:
C:/projects/CMakeTesting/external_project_test/some_external_project/build


So CMAKE_C_FLAGS_DEBUG is not changed to "=====SOME_OTHER_VARIABLE====="
and remains CHILD_PROJECT_DEBUG.  I have slightly modified my version of
the example I posted to bug report and changed flags to a simple string
argument.  So CMake appears to promptly ignore -DVAR_NAME=VAL_VALUE if set
in sub project which I guess is normal.

Lets add -LA to opts see what happens, but still not specify INTERNAL:

c:\projects\CMakeTesting\external_project_test\some_external_project\build>
del *.* && cmake -LA -DCMAKE_C_FLAGS_DEBUG="=====SOME_OTHER_VARIABLE ====="
..\
CMAKE_CXX_FLAGS_INIT=/DWIN32 /D_WINDOWS /W3 /Zm1000 /EHsc /GR
Following line for CXX DEBUG should contain /MDd
CMAKE_CXX_FLAGS_DEBUG=/D_DEBUG /MTd /Zi /Ob0 /Od /Gm
CMAKE_CXX_FLAGS_DEBUG_INIT=/D_DEBUG /MTd /Zi /Ob0 /Od
CMAKE_C_FLAGS_DEBUG=CHILD_PROJECT_DEBUG
CMAKE_C_FLAGS_DEBUG_INIT=/D_DEBUG /MTd /Zi  /Ob0 /Od
CMAKE_C_FLAGS_RELEASE=CHILD_PROJECT_RELEASE
SOME_VAR=ChildProjectSomeValue
ANOTHER_VAR=
-- Configuring done
-- Generating done
-- Build files have been written to:
C:/projects/CMakeTesting/external_project_test/some_external_project/build
-- Cache values
CMAKE_BACKWARDS_COMPATIBILITY:STRING=2.4
CMAKE_CONFIGURATION_TYPES:STRING=Debug;Release;MinSizeRel;RelWithDebInfo
CMAKE_CXX_FLAGS:STRING= /DWIN32 /D_WINDOWS /W3 /GR /EHsc
CMAKE_CXX_FLAGS_DEBUG:STRING=/D_DEBUG /MDd /Zi /Ob0 /Od /RTC1
CMAKE_CXX_FLAGS_MINSIZEREL:STRING=/MD /O1 /Ob1 /D NDEBUG
CMAKE_CXX_FLAGS_RELEASE:STRING=/MD /O2 /Ob2 /D NDEBUG
CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=/MD /Zi /O2 /Ob1 /D NDEBUG
CMAKE_CXX_STANDARD_LIBRARIES:STRING=kernel32.lib user32.lib gdi32.lib
winspool.lib shell32.lib ole32.lib oleaut32.lib uu
id.lib comdlg32.lib advapi32.lib
CMAKE_C_FLAGS:STRING= /DWIN32 /D_WINDOWS /W3
CMAKE_C_FLAGS_DEBUG:STRING======SOME_OTHER_VARIABLE =====
CMAKE_C_FLAGS_MINSIZEREL:STRING=/MD /O1 /Ob1 /D NDEBUG
CMAKE_C_FLAGS_RELEASE:STRING=/MD /O2 /Ob2 /D NDEBUG
CMAKE_C_FLAGS_RELWITHDEBINFO:STRING=/MD /Zi /O2 /Ob1 /D NDEBUG
CMAKE_C_STANDARD_LIBRARIES:STRING=kernel32.lib user32.lib gdi32.lib
winspool.lib shell32.lib ole32.lib oleaut32.lib uuid
.lib comdlg32.lib advapi32.lib
CMAKE_EXE_LINKER_FLAGS:STRING= /machine:X86
CMAKE_EXE_LINKER_FLAGS_DEBUG:STRING=/debug /INCREMENTAL
CMAKE_EXE_LINKER_FLAGS_MINSIZEREL:STRING=/INCREMENTAL:NO
CMAKE_EXE_LINKER_FLAGS_RELEASE:STRING=/INCREMENTAL:NO
CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO:STRING=/debug /INCREMENTAL
CMAKE_INSTALL_PREFIX:PATH=C:/Program Files (x86)/Project
CMAKE_LINKER:FILEPATH=C:/Program Files (x86)/Microsoft Visual Studio
11.0/VC/bin/link.exe
CMAKE_MAKE_PROGRAM:FILEPATH=C:/PROGRA~2/MICROS~4.0/Common7/IDE/devenv.com
CMAKE_MODULE_LINKER_FLAGS:STRING= /machine:X86
CMAKE_MODULE_LINKER_FLAGS_DEBUG:STRING=/debug /INCREMENTAL
CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL:STRING=/INCREMENTAL:NO
CMAKE_MODULE_LINKER_FLAGS_RELEASE:STRING=/INCREMENTAL:NO
CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO:STRING=/debug /INCREMENTAL
CMAKE_RC_COMPILER:FILEPATH=rc
CMAKE_RC_FLAGS:STRING=
CMAKE_SHARED_LINKER_FLAGS:STRING= /machine:X86
CMAKE_SHARED_LINKER_FLAGS_DEBUG:STRING=/debug /INCREMENTAL
CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL:STRING=/INCREMENTAL:NO
CMAKE_SHARED_LINKER_FLAGS_RELEASE:STRING=/INCREMENTAL:NO
CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO:STRING=/debug /INCREMENTAL
CMAKE_SKIP_INSTALL_RPATH:BOOL=NO
CMAKE_SKIP_RPATH:BOOL=NO
CMAKE_STATIC_LINKER_FLAGS:STRING=
CMAKE_STATIC_LINKER_FLAGS_DEBUG:STRING=
CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL:STRING=
CMAKE_STATIC_LINKER_FLAGS_RELEASE:STRING=
CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO:STRING=
CMAKE_USE_RELATIVE_PATHS:BOOL=OFF
CMAKE_VERBOSE_MAKEFILE:BOOL=FALSE
EXECUTABLE_OUTPUT_PATH:PATH=
LIBRARY_OUTPUT_PATH:PATH=

Ok so there's a lot of goop there, but the important bits are the line

CMAKE_C_FLAGS_DEBUG=CHILD_PROJECT_DEBUG

before the line

-- Configuring done

and the line

CMAKE_C_FLAGS_DEBUG:STRING======SOME_OTHER_VARIABLE =====

Which means CMake sees it and promplty ignores it in subproject.  Why this
is standard operating procedure I am not sure, but I am familiar with it
operating this way.

Hey I know maybe we can pass it in as INTERNAL as that implies FORCE.
Which I understand to mean FORCE in the CACHE.


c:\projects\CMakeTesting\external_project_test\some_external_project\build>cmake
-LA -DCMAKE_C_FLAGS_DEBUG:INTERNAL="===
==SOME_OTHER_VARIABLE =====" ..\
CMAKE_CXX_FLAGS_INIT=/DWIN32 /D_WINDOWS /W3 /Zm1000 /EHsc /GR
Following line for CXX DEBUG should contain /MDd
CMAKE_CXX_FLAGS_DEBUG=/D_DEBUG /MTd /Zi /Ob0 /Od /Gm
CMAKE_CXX_FLAGS_DEBUG_INIT=/D_DEBUG /MTd /Zi /Ob0 /Od
CMAKE_C_FLAGS_DEBUG=CHILD_PROJECT_DEBUG
CMAKE_C_FLAGS_DEBUG_INIT=/D_DEBUG /MTd /Zi  /Ob0 /Od
CMAKE_C_FLAGS_RELEASE=CHILD_PROJECT_RELEASE
SOME_VAR=ChildProjectSomeValue
ANOTHER_VAR=
-- Configuring done
-- Generating done
-- Build files have been written to:
C:/projects/CMakeTesting/external_project_test/some_external_project/build
-- Cache values
CMAKE_BACKWARDS_COMPATIBILITY:STRING=2.4
CMAKE_CONFIGURATION_TYPES:STRING=Debug;Release;MinSizeRel;RelWithDebInfo
CMAKE_CXX_FLAGS:STRING= /DWIN32 /D_WINDOWS /W3 /GR /EHsc
CMAKE_CXX_FLAGS_DEBUG:STRING=/D_DEBUG /MDd /Zi /Ob0 /Od /RTC1
CMAKE_CXX_FLAGS_MINSIZEREL:STRING=/MD /O1 /Ob1 /D NDEBUG
CMAKE_CXX_FLAGS_RELEASE:STRING=/MD /O2 /Ob2 /D NDEBUG
CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=/MD /Zi /O2 /Ob1 /D NDEBUG
CMAKE_CXX_STANDARD_LIBRARIES:STRING=kernel32.lib user32.lib gdi32.lib
winspool.lib shell32.lib ole32.lib oleaut32.lib uu
id.lib comdlg32.lib advapi32.lib
CMAKE_C_FLAGS:STRING= /DWIN32 /D_WINDOWS /W3
CMAKE_C_FLAGS_MINSIZEREL:STRING=/MD /O1 /Ob1 /D NDEBUG
CMAKE_C_FLAGS_RELEASE:STRING=/MD /O2 /Ob2 /D NDEBUG
CMAKE_C_FLAGS_RELWITHDEBINFO:STRING=/MD /Zi /O2 /Ob1 /D NDEBUG
CMAKE_C_STANDARD_LIBRARIES:STRING=kernel32.lib user32.lib gdi32.lib
winspool.lib shell32.lib ole32.lib oleaut32.lib uuid
.lib comdlg32.lib advapi32.lib
CMAKE_EXE_LINKER_FLAGS:STRING= /machine:X86
CMAKE_EXE_LINKER_FLAGS_DEBUG:STRING=/debug /INCREMENTAL
CMAKE_EXE_LINKER_FLAGS_MINSIZEREL:STRING=/INCREMENTAL:NO
CMAKE_EXE_LINKER_FLAGS_RELEASE:STRING=/INCREMENTAL:NO
CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO:STRING=/debug /INCREMENTAL
CMAKE_INSTALL_PREFIX:PATH=C:/Program Files (x86)/Project
CMAKE_LINKER:FILEPATH=C:/Program Files (x86)/Microsoft Visual Studio
11.0/VC/bin/link.exe
CMAKE_MAKE_PROGRAM:FILEPATH=C:/PROGRA~2/MICROS~4.0/Common7/IDE/devenv.com
CMAKE_MODULE_LINKER_FLAGS:STRING= /machine:X86
CMAKE_MODULE_LINKER_FLAGS_DEBUG:STRING=/debug /INCREMENTAL
CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL:STRING=/INCREMENTAL:NO
CMAKE_MODULE_LINKER_FLAGS_RELEASE:STRING=/INCREMENTAL:NO
CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO:STRING=/debug /INCREMENTAL
CMAKE_RC_COMPILER:FILEPATH=rc
CMAKE_RC_FLAGS:STRING=
CMAKE_SHARED_LINKER_FLAGS:STRING= /machine:X86
CMAKE_SHARED_LINKER_FLAGS_DEBUG:STRING=/debug /INCREMENTAL
CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL:STRING=/INCREMENTAL:NO
CMAKE_SHARED_LINKER_FLAGS_RELEASE:STRING=/INCREMENTAL:NO
CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO:STRING=/debug /INCREMENTAL
CMAKE_SKIP_INSTALL_RPATH:BOOL=NO
CMAKE_SKIP_RPATH:BOOL=NO
CMAKE_STATIC_LINKER_FLAGS:STRING=
CMAKE_STATIC_LINKER_FLAGS_DEBUG:STRING=
CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL:STRING=
CMAKE_STATIC_LINKER_FLAGS_RELEASE:STRING=
CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO:STRING=
CMAKE_USE_RELATIVE_PATHS:BOOL=OFF
CMAKE_VERBOSE_MAKEFILE:BOOL=FALSE
EXECUTABLE_OUTPUT_PATH:PATH=
LIBRARY_OUTPUT_PATH:PATH=

So the line following line is still unchanged

CMAKE_C_FLAGS_RELEASE=CHILD_PROJECT_RELEASE

before the line

-- Configuring done

and the line

CMAKE_C_FLAGS_DEBUG:STRING======SOME_OTHER_VARIABLE =====

has disappeared whch it should.  So it ran away and hid and still did
nothing.  Clearly did not FORCE.  INTERNAL implies RUN AWAY HIDE DO NOTHING
when used from external interfaces such as command prompt and
ExternalProject_Add at least from my experience.

I am sure I have all this wrong.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.cmake.org/pipermail/cmake/attachments/20140122/d8715e5a/attachment-0001.html>


More information about the CMake mailing list