0

We implement a logger which automatically prints out the project name of a log entry among other infos.

We recently change our build system from using native Microsoft visual c++ to cmake generated.

With native Microsoft c++ build files, we were just defining a macro "PROJECT_NAME" in a global ".props" as such:
<PreprocessorDefinitions>%(PreprocessorDefinitions);PROJECT_NAME=R"($(ProjectName))"</PreprocessorDefinitions>

However, now that we use CMake, I struggle to find a good way to access the project name at compile time. I can use configure_file or target_compile_definitions to access a CMake variable at compile time but I do not know any variable holding a string with the target name. Is there such a variable or can it be defined?
Also, can it be defined only in one place? I don't want to copy paste in every CMakeList.txt a line of the such:
target_compile_definitions(MYTARGET PRIVATE PROJECT_NAME="$mytarget_name")

pepece
  • 360
  • 5
  • 17
  • 1
    CMake doesn't create an automaticall macro which contains a project's name. If you want to define a macro available for all targets in your project, then use [add_compile_definitions](https://cmake.org/cmake/help/latest/command/add_compile_definitions.html) command. – Tsyvarev Dec 07 '22 at 13:58

2 Answers2

1

If you've got multiple options to apply to all targets, you could link a INTERFACE library which allows you to inherit multiple properties of this cmake target via a single target_link_libraries use.

For using the name of the linking target, generator expressions that do not require specifying the target can be used:

add_library(OptionsForAll INTERFACE)

# note: using the target name not the cmake project name here
target_compile_definitions(OptionsForAll INTERFACE PROJECT_NAME=\"$<TARGET_PROPERTY:NAME>\")

target_link_libraries(MYTARGET PRIVATE OptionsForAll)

Another option mentioned in @Tsyvarevs comment would be to use add_compile_definitions to apply the definition for all targets defined in the current directory and subdirectory, but this makes it harder to remove it from some targets...

fabian
  • 80,457
  • 12
  • 86
  • 114
0

fabian's answer is IMO the good approach.
However, i wanted to offer an alternative based on BUILDSYSTEM_TARGETS inspired from this answer.
Thus, there is no need to modify all target's call to target_link_libraries.

function(get_all_targets var)
    set(targets)
    get_all_targets_recursive(targets ${CMAKE_CURRENT_SOURCE_DIR})
    set(${var} ${targets} PARENT_SCOPE)
endfunction()

macro(get_all_targets_recursive targets dir)
    get_property(subdirectories DIRECTORY ${dir} PROPERTY SUBDIRECTORIES)
    foreach(subdir ${subdirectories})
        get_all_targets_recursive(${targets} ${subdir})
    endforeach()

    get_property(current_targets DIRECTORY ${dir} PROPERTY BUILDSYSTEM_TARGETS)
    list(APPEND ${targets} ${current_targets})
endmacro()

function(define_targetname all_targets)
    foreach(target ${all_targets})
        get_target_property(type ${target} TYPE)
        if (NOT ${type} STREQUAL "INTERFACE_LIBRARY" AND NOT ${target} STREQUAL "PCHTarget") # INTERFACE library cannot target_compile_definitions && precompiled headers will redefine the MACRO
            target_compile_definitions(${target} PRIVATE PROJECT_NAME="${target}")
        endif()
    endforeach()
endfunction()

get_all_targets(all_targets)
define_targetname("${all_targets}")

pepece
  • 360
  • 5
  • 17