UPDATED w/Minimal Example - Having trouble setting flags for custom build type

Minimum example:
I’ve whittled the problem down to the following minimal example:

CMakeLists.txt

cmake_minimum_required(VERSION 3.18)                                             
                                                                                    
project(gprof-test VERSION 0.1 LANGUAGES C)                                         
                                                                                 
set(CMAKE_C_STANDARD 99)                                                         
set(CMAKE_C_STANDARD_REQUIRED ON)                                                
                                                                                 
set(CMAKE_C_FLAGS_PROFILE "-pg -g -O2" CACHE STRING "")                          
set(CMAKE_EXE_LINKER_FLAGS_PROFILE "-pg" CACHE STRING "")                        
                                                                                 
#add_compile_options(-Wall -Wextra -Werror)                                      
                                                                                 
add_executable(test main.c)

And the corresponding source from the gprof article:

main.c

#include <stdio.h>                                                                  
                                                                                    
void func2(void)                                                                 
{                                                                                
        for (int count = 0; count < 0xfffff; ++count)                            
                ;                                                                
}                                                                                
                                                                                 
void func1(void)                                                                 
{                                                                                
        for (int count = 0; count < 0xff; ++count)                               
                func2();                                                         
}                                                                                
                                                                                 
int main(void)                                                                   
{                                                                                
        printf("\n*** Hello Profiling ***\n\n");                                 
        func1();                                                                 
        func2();                                                                 
        return 0;                                                                
} 

If I make any other type of build the cache will have the correct flags for the profile build type:

$ mkdir build-release && cd build-release
$ cmake -DCMAKE_BUILD_TYPE=Release ..
$ grep "CMAKE_C_FLAGS_PROFILE" CMakeCache.txt
CMAKE_C_FLAGS_PROFILE:STRING=-pg -g -O2

But when I state the profile build type the flags are not set:

$ mkdir build-profile && cd build-profile
$ cmake -DCMAKE_BUILD_TYPE=Profile ..
$ grep "CMAKE_C_FLAGS_PROFILE" CMakeCache.txt
CMAKE_C_FLAGS_PROFILE:STRING=
//ADVANCED property for variable: CMAKE_C_FLAGS_PROFILE
CMAKE_C_FLAGS_PROFILE-ADVANCED:INTERNAL=1

Now there is the extra “advanced” flags that I don’t know anything about but when I run the program a gmon.out is not generated and launching a gdb session leads to no debugging symbols being found in the executable.

Hopefully this is more helpful than the original post.

Original Post:
I’m working out of the Professional CMake book and experimenting with profiling my C code. When I pretty much copy and paste the examples from the book in section 14.3 I find that my flags are not being set and the profiling is not enabled.

I’m wondering if some other part of my CMakeLists.txt file is interfering with this. Here is the full CMakeLists.txt and some of the resulting CMakeCache.txt:

cmake_minimum_required(VERSION 3.18)

project(aoc-2018 VERSION 0.1 LANGUAGES C)

set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)

# Profile build settings
set(CMAKE_C_FLAGS_PROFILE               "-pg -g -O2" CACHE STRING "")
set(CMAKE_CXX_FLAGS_PROFILE             "-pg -g -O2" CACHE STRING "")
set(CMAKE_EXE_LINKER_FLAGS_PROFILE      "-pg -g -O2" CACHE STRING "")
set(CMAKE_SHARED_LINKER_FLAGS_PROFILE   "-pg -g -O2" CACHE STRING "")
set(CMAKE_STATIC_LINKER_FLAGS_PROFILE   "" CACHE STRING "")
set(CMAKE_MODULE_LINKER_FLAGS_PROFILE   "-pg -g -O2" CACHE STRING "")

# General compilation flags
add_compile_options(-Wall -Wextra -Werror)

# From Professional CMake section 14.3
get_property(isMultiConfig GLOBAL
        PROPERTY GENERATOR_IS_MULTI_CONFIG
)
if (isMultiConfig)
        if (NOT "Profile" IN_LIST CMAKE_CONFIGURATION_TYPES)
                list(APPEND CMAKE_CONFIGURATION_TYPES Profile)
        endif()
else()
        set(allowedBuildTypes Debug Release Profile)
        set_property(CACHE CMAKE_BUILD_TYPE PROPERTY
                STRINGS "${allowedBuildTypes}"
        )
        if (NOT CMAKE_BUILD_TYPE)
                set(CMAKE_BUILD_TYPE Release CACHE STRING "" FORCE)
        elseif(NOT CMAKE_BUILD_TYPE IN_LIST allowedBuildTypes)
                message(FATAL_ERROR
                        "Unknown build type: ${CMAKE_BUILD_TYPE}"
                )
        endif()

        # Profile build settings
        #if (CMAKE_BUILD_TYPE STREQUAL Profile)
        #        add_compile_options(-pg -g -O2)
        #        add_link_options(-pg)
        #endif()
endif()

# Libraries
find_package(cgs REQUIRED)
find_package(fruity REQUIRED)

if(APPLE)
        include_directories(${CMAKE_INSTALL_PREFIX}/include)
        link_directories(${CMAKE_INSTALL_PREFIX}/lib)
endif()

set(solutions
	"1801.c"
	"1802.c"
	"1803.c"
	"1804.c"
	"1805.c"
	"1806.c"
)

foreach(file IN LISTS solutions)
	get_filename_component(exe_name "${file}" NAME_WE)
	add_executable("${exe_name}" "${file}")
	target_link_libraries("${exe_name}" cgs fruity)
endforeach()

And the Cache after:

$ cmake -DCMAKE_BUILD_TYPE=Profile ..
$ grep PROFILE CMakeCache.txt
CMAKE_CXX_FLAGS_PROFILE:STRING=-pg -g -O2
//Flags used by the C compiler during PROFILE builds.
CMAKE_C_FLAGS_PROFILE:STRING=
//Flags used by the linker during PROFILE builds.
CMAKE_EXE_LINKER_FLAGS_PROFILE:STRING=
// PROFILE builds.
CMAKE_MODULE_LINKER_FLAGS_PROFILE:STRING=
// during PROFILE builds.
CMAKE_SHARED_LINKER_FLAGS_PROFILE:STRING=
// during PROFILE builds.
CMAKE_STATIC_LINKER_FLAGS_PROFILE:STRING=
//ADVANCED property for variable: CMAKE_C_FLAGS_PROFILE
CMAKE_C_FLAGS_PROFILE-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_PROFILE
CMAKE_EXE_LINKER_FLAGS_PROFILE-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_PROFILE
CMAKE_MODULE_LINKER_FLAGS_PROFILE-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_PROFILE
CMAKE_SHARED_LINKER_FLAGS_PROFILE-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_PROFILE
CMAKE_STATIC_LINKER_FLAGS_PROFILE-ADVANCED:INTERNAL=1

So it’s setting the CXX flag but none of the others.

Edit: At the bottom of my multiConfig if-statement I have some commented out lines. If I comment out the above set's and uncomment these the build works but that is not the recommended practice.

After some experimentation I found that adding ‘FORCE’ to the ‘set’ commands fixed the problem. The text Professional CMake does not have this directive in the calls though.

Looking at the documentation for the set command shows that if the cache variable is already defined then a ‘set’ command will not over write it without FORCE. I rm -rf'd my build directory and re-ran the steps. All I did was declare my build type to be ‘Profile’, I did not define any variables.

So the remaining question is, does CMake auto generate and define these variables before my 'set’s get called?

You can use trace mode to track when the variables are set. My guess is because you didn’t define them before enabling the language they get defined by CMake. If you set them before the project() command or in a tool chain file then it probably would have worked.