When working with CMake and Visual Studio some things are a little hard to achieve. This post will show you three things I stumbled across:
1. Activating precompiled headers:
This is quiet easy to do:
function(use_precompiled_header TARGET HEADER_FILE SRC_FILE) get_filename_component(HEADER ${HEADER_FILE} NAME) if (MSVC) add_definitions(/Yu"${HEADER}") set_source_files_properties(${SRC_FILE} PROPERTIES COMPILE_FLAGS /Yc"${HEADER}" ) endif () endfunction(use_precompiled_header)
This function can be called after an executable or library is defined with use_precompiled_header(<name> "stdafx.h" "stdafx.cpp"). This works by simply setting the /Yc option for the stdafx.cpp and the option /Yu for all other files. This is exactly what you would do if you configure it on your own.
2. Sadly there is a subtle bug in recent VC versions, triggering the error fatal error C1027: Inconsistent values for /Ym between creation and use of precompiled header.
The switch /Ym is used internally by the compiler to pass the start address of the precompiled header memory[1]. Precompiled headers are essentially a memory snapshot of the parser that can be loaded into memory the next time the PCH are required. Because it is just a snapshot, there are pointers in it that require loading the PCH to the same memory location where it was when the snapshot was taken. That is the reason for the switch. The compiler tries to allocate the memory as soon as possible, because dlls that are loaded may be loaded into the memory required for the PCH. (The reason for this is ASLR - Address Space Layout Randomization - that is used to load dlls in different locations, every time they are loaded to make it harder to exploit bugs.)
It turns out, that the switch /Zm1000 is set by CMake for whatever reason. That flag is used to specify the maximum size of precompiled headers (since CMake doesn't seem to know about precompiled headers I don't know, why it uses this switch...). A value of 1000 means 1000 times 0.5 MB = 500 MB. The default value is 100 = 50 MB. A user on Microsoft Connect[1] reported that removing this flag resolved his build issues. I think the reason this works is the following: If we need 500 MB of contiguous memory starting at a specific location, the probability that the memory is used by other allocations is 10 times as high as for 50 MB of contiguous memory.
Nevertheless, the MSDN says you shouldn't set /Zm unless the compiler tells you to with error C1076 compiler limit : internal heap limit reached; use /Zm to specify a higher limit[2] Removing this switch makes the build more stable. The following CMake code removes the switch:
string(REGEX REPLACE "/Zm[0-9]+ *" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" CACHE STRING "" FORCE)
The first line removes the option from the CXX_FLAGS and the second line ensures the new flags are inserted into the CMake cache.
3. If you want to get rid of the MinSizeRel or any other configuration you can use the following snippet:
set(CMAKE_CONFIGURATION_TYPES Debug Release RelWithDebInfo) set(CMAKE_CONFIGURATION_TYPES "${CMAKE_CONFIGURATION_TYPES}" CACHE STRING "" FORCE)
This snippet resets the configuration types variable and inserts it into the cache again. You can also add more configurations using this variable and setting CMAKE_CXX_FLAGS_<TYPE> and other variables suffixed with the new type. (I had to delete the generated project files in order to get this to work correctly.)
[1] http://connect.microsoft.com/VisualStudio/feedback/details/731299/error-c1027-inconsistent-values-for-ym-between-creation-and-use-of-precompiled-header-c
[2] http://msdn.microsoft.com/en-us/library/bdscwf1c(v=vs.71).aspx