diff --git a/cmake/GaudiToolbox.cmake b/cmake/GaudiToolbox.cmake
index 8cfa5a9fa018c807a4dee8f5e21be904216d7300..72380e425c29ccfa323e319b919fe67443b66cea 100644
--- a/cmake/GaudiToolbox.cmake
+++ b/cmake/GaudiToolbox.cmake
@@ -37,6 +37,19 @@ When linking against an imported target (``Project::Target``), if there is a loc
 target with the same name, use that instead of the imported one.
 This is useful in to LHCb satellite projects.
 
+.. variable:: GAUDI_PGO
+
+Used to tune Profile Guided Optimization builds. When set to ``GENERATE`` the
+binaries are instrumented to generate profile reports on execution, while if set
+to ``USE`` the compiler is instructed to optimize the code according to the
+collected profile reports. Note that PGO works best when paired to IPO/LTO,
+so, if possible, the latter will be enabled by default when using PGO.
+
+.. variable:: GAUDI_PGO_PATH
+
+Directory where to store profile reports when ``GAUDI_PGO=GENERATE`` or read them from
+when using ``GAUDI_PGO=USE``.
+
 
 Other Cached variables (added to the project)
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -129,24 +142,39 @@ set(scan_dict_deps_command ${GAUDI_TOOLBOX_DIR}/scan_dict_deps.py
 
 ##################################### PGO  #####################################
 
-if("${PGO}" MATCHES "GENERATE")
-	message("PGO generate")
-	if(DEFINED PGO_PATH)
-		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-generate=${PGO_PATH}")
-	else()
-		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-generate")
-	endif()
+if(DEFINED GAUDI_PGO)
+    # use case insensitive values for GAUDI_PGO
+    string(TOUPPER "${GAUDI_PGO}" GAUDI_PGO)
 endif()
-if("${PGO}" MATCHES "USE")
-	message("PGO use")
-	if(DEFINED PGO_PATH)
-		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-use=${PGO_PATH} -fprofile-correction")
-	else()
-		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-use -fprofile-correction")
-	endif()
-	include(CheckIPOSupported)
-	check_ipo_supported()
-	set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
+if(GAUDI_PGO STREQUAL "GENERATE")
+    if("${GAUDI_PGO_PATH}" STREQUAL "")
+        message(STATUS "PGO: building to generate execution profiles")
+        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-generate")
+    else()
+        message(STATUS "PGO: building to generate execution profiles in ${GAUDI_PGO_PATH}")
+        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-generate=${GAUDI_PGO_PATH}")
+    endif()
+elseif(GAUDI_PGO STREQUAL "USE")
+    if("${GAUDI_PGO_PATH}" STREQUAL "")
+        message(STATUS "PGO: use profiles to optimize the build")
+        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-use -fprofile-correction")
+    else()
+        message(STATUS "PGO: use profiles from ${GAUDI_PGO_PATH} to optimize the build")
+        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-use=${GAUDI_PGO_PATH} -fprofile-correction")
+    endif()
+    if(NOT DEFINED CMAKE_INTERPROCEDURAL_OPTIMIZATION)
+        include(CheckIPOSupported)
+        check_ipo_supported(RESULT CMAKE_INTERPROCEDURAL_OPTIMIZATION LANGUAGES CXX OUTPUT _ipo_output)
+    else()
+        # this message is printed if the IPO flag was already set (so we do not check)
+        # and a few lines below we find it set to false 
+        set(_ipo_output "explicitly disabled")
+    endif()
+    if(NOT CMAKE_INTERPROCEDURAL_OPTIMIZATION)
+        message(WARNING "PGO works better when combined with IPO, but IPO is not used (${_ipo_output})")
+    endif()
+elseif(GAUDI_PGO)
+    message(FATAL_ERROR "invalid value for GAUDI_PGO, allowed values are 'GENERATE', 'USE' or a false value (GAUDI_PGO == '${GAUDI_PGO}')")
 endif()
 
 ################################## Functions  ##################################