How to print all the properties of a target in cmake?
Asked Answered
T

4

79

With the following cmake scrpt:

get_cmake_property(_variableNames VARIABLES)
foreach (_variableName ${_variableNames})
    message(STATUS "${_variableName}=${${_variableName}}")
endforeach()

We can print all the variables in the CMake project. Then my question is: is there a function that can print all the properties of a target?

Turro answered 24/8, 2015 at 13:48 Comment(4)
This doesn't "print all the variables in the CMake project." It prints the one _variable passed to it. You can trivially do something similar for properties using get_property. Is that what you're asking about?Effect
@Angew Thanks, and I have rewritten the question.Turro
@m.s. Thanks, and it is exactly what I am looking for, and I will have an investigation.Turro
@m.s. I met a problem when running the script: #32198163Turro
V
91

I have had limited success with the following work-around to the apparent lack of ability to dynamically query for the properties of a target.

I invoke the cmake command to list all properties, and then try each one on the target.

# Get all propreties that cmake supports
if(NOT CMAKE_PROPERTY_LIST)
    execute_process(COMMAND cmake --help-property-list OUTPUT_VARIABLE CMAKE_PROPERTY_LIST)
    
    # Convert command output into a CMake list
    string(REGEX REPLACE ";" "\\\\;" CMAKE_PROPERTY_LIST "${CMAKE_PROPERTY_LIST}")
    string(REGEX REPLACE "\n" ";" CMAKE_PROPERTY_LIST "${CMAKE_PROPERTY_LIST}")
    list(REMOVE_DUPLICATES CMAKE_PROPERTY_LIST)
endif()
    
function(print_properties)
    message("CMAKE_PROPERTY_LIST = ${CMAKE_PROPERTY_LIST}")
endfunction()
    
function(print_target_properties target)
    if(NOT TARGET ${target})
      message(STATUS "There is no target named '${target}'")
      return()
    endif()

    foreach(property ${CMAKE_PROPERTY_LIST})
        string(REPLACE "<CONFIG>" "${CMAKE_BUILD_TYPE}" property ${property})

        # Fix https://mcmap.net/q/263112/-how-can-i-remove-the-quot-the-location-property-may-not-be-read-from-target-quot-error-in-cmake
        if(property STREQUAL "LOCATION" OR property MATCHES "^LOCATION_" OR property MATCHES "_LOCATION$")
            continue()
        endif()

        get_property(was_set TARGET ${target} PROPERTY ${property} SET)
        if(was_set)
            get_target_property(value ${target} ${property})
            message("${target} ${property} = ${value}")
        endif()
    endforeach()
endfunction()
Verniavernice answered 15/12, 2015 at 15:7 Comment(10)
yes, this is useful. Had to add a " when CMAKE_PROPERTY_LIST was used, and CMAKE_BUILD_TYPE has to be configured manually.Demob
The LOCATION property may not be read from target "PandemicCore". Use the target name directly with add_custom_command, or use the generator expression $<TARGET_FILE>, as appropriate. #32198163Bohi
Fixed with: # Fix https://stackoverflow.com/questions/32197663/how-can-i-remove-the-the-location-property-may-not-be-read-from-target-error-i IF(prop STREQUAL "LOCATION" OR prop MATCHES "^LOCATION_" OR prop MATCHES "_LOCATION$") CONTINUE() ENDIF()Bohi
Thought this answer was a great approach, but noticed it raised a lot of errors for INTERFACE_LIBRARY targets. I tweaked it to be able to handle this, as well as a few other small improvements (ie, removed duplicates, and pulled Dawid Drozd's fix outside of the main loop); wanted to submit as an edit, but it was rejected ("edit was intended to address the author of the post and makes no sense as an edit", which doesn't make sense to me... maybe there were just too many changes??), so I have an alternative "answer" below: https://mcmap.net/q/262296/-how-to-print-all-the-properties-of-a-target-in-cmakeConfinement
LOCATION property may be read without errors now (tested in cmake 3.14).Nephritis
Does not work on INTERFACE library targets: CMake Error at ring/common/CMakeLists.txt:49 (get_property): INTERFACE_LIBRARY targets may only have whitelisted properties. The property "PARENT_DIRECTORY" is not allowed. Call Stack (most recent call first): ring/common/CMakeLists.txt:57 (print_target_properties)Lumbye
To fix this use get_target_properties() instead of get_property(). With get_target_properties() you don't need if(prop STREQUAL "LOCATION"...Lumbye
I also suggest to list(REMOVE_DUPLICATES CMAKE_PROPERTY_LIST)Lumbye
I appreciate all of the new answers, when I posted originally I just got enough info for debugging and moved on and didn't solve all the problems that you guys are mentioning, that is why my answer said "limited success with the following..." doing things besides printing the errors on special case properties should probably go into new answers as you guys are doing.Verniavernice
With execute_process, use "${CMAKE_COMMAND}" instead of "cmake". Using "cmake" requires it to be in the PATH, whereas ${CMAKE_COMMAND} is a full path reference and always works.Acarology
C
21

This isn't really intended to be a competing answer, just an expansion on the answer by AlwaysTraining (and edited by Dawid Drozd)!

If the target is an INTERFACE_LIBRARY, this will print out a whole bunch of errors about whitelisted properties. Unfortunately, there doesn't seem to be a good way to dynamically query what the whitelisted properties are - by checking the source for cmTargetPropertyComputer::WhiteListedInterfaceProperty I was able to come up with a regexp, but it could change from version to version (I was looking at the source for cmake-3.11). Anyway, here's my revised version, with support for INTERFACE_LIBRARYtargets - I also removes duplicate, and made the filtering of LOCATION properties happen once, outside of the loop.

(I've made a suggested edit to the original question, but this is here in case it isn't accepted...)

Thanks AlwaysTraining and Dawid Drozd!

# Get all propreties that cmake supports
execute_process(COMMAND cmake --help-property-list OUTPUT_VARIABLE CMAKE_PROPERTY_LIST)

# Convert command output into a CMake list
STRING(REGEX REPLACE ";" "\\\\;" CMAKE_PROPERTY_LIST "${CMAKE_PROPERTY_LIST}")
STRING(REGEX REPLACE "\n" ";" CMAKE_PROPERTY_LIST "${CMAKE_PROPERTY_LIST}")
# Fix https://mcmap.net/q/263112/-how-can-i-remove-the-quot-the-location-property-may-not-be-read-from-target-quot-error-in-cmake
list(FILTER CMAKE_PROPERTY_LIST EXCLUDE REGEX "^LOCATION$|^LOCATION_|_LOCATION$")
# For some reason, "TYPE" shows up twice - others might too?
list(REMOVE_DUPLICATES CMAKE_PROPERTY_LIST)

# build whitelist by filtering down from CMAKE_PROPERTY_LIST in case cmake is
# a different version, and one of our hardcoded whitelisted properties
# doesn't exist!
unset(CMAKE_WHITELISTED_PROPERTY_LIST)
foreach(prop ${CMAKE_PROPERTY_LIST})
    if(prop MATCHES "^(INTERFACE|[_a-z]|IMPORTED_LIBNAME_|MAP_IMPORTED_CONFIG_)|^(COMPATIBLE_INTERFACE_(BOOL|NUMBER_MAX|NUMBER_MIN|STRING)|EXPORT_NAME|IMPORTED(_GLOBAL|_CONFIGURATIONS|_LIBNAME)?|NAME|TYPE|NO_SYSTEM_FROM_IMPORTED)$")
        list(APPEND CMAKE_WHITELISTED_PROPERTY_LIST ${prop})
    endif()
endforeach(prop)

function(print_properties)
    message ("CMAKE_PROPERTY_LIST = ${CMAKE_PROPERTY_LIST}")
endfunction(print_properties)

function(print_whitelisted_properties)
    message ("CMAKE_WHITELISTED_PROPERTY_LIST = ${CMAKE_WHITELISTED_PROPERTY_LIST}")
endfunction(print_whitelisted_properties)

function(print_target_properties tgt)
    if(NOT TARGET ${tgt})
      message("There is no target named '${tgt}'")
      return()
    endif()

    get_target_property(target_type ${tgt} TYPE)
    if(target_type STREQUAL "INTERFACE_LIBRARY")
        set(PROP_LIST ${CMAKE_WHITELISTED_PROPERTY_LIST})
    else()
        set(PROP_LIST ${CMAKE_PROPERTY_LIST})
    endif()

    foreach (prop ${PROP_LIST})
        string(REPLACE "<CONFIG>" "${CMAKE_BUILD_TYPE}" prop ${prop})
        # message ("Checking ${prop}")
        get_property(propval TARGET ${tgt} PROPERTY ${prop} SET)
        if (propval)
            get_target_property(propval ${tgt} ${prop})
            message ("${tgt} ${prop} = ${propval}")
        endif()
    endforeach(prop)
endfunction(print_target_properties)
Confinement answered 23/8, 2018 at 13:52 Comment(4)
This expects OpenGL::GLU to be a valid target. Was this intended?Titanothere
Both of these scripts failed to print LOCATION, the main property of a library target. And it was the one I was looking for :(Intertype
I'm not sure what you mean by "expects OpenGL::GLU" to be a valid target. I don't see a reference to OpenGL (or GLU) anywhere. Did you mean that if you call print_target_properties(OpenGL::GLU) that OpenGL::GLU needs to be a target?Confinement
These scripts are for older versions of cmake (< 3.14), where it would error if you tried to read the LOCATION property. Apparently this works in new versions. You can simply remove the line filtering the location: list(FILTER CMAKE_PROPERTY_LIST EXCLUDE REGEX "^LOCATION$|^LOCATION_|_LOCATION$")Confinement
L
15

Improved @AlwaysTraining's and @PaulMolodowitch's answers.
Solves problem with INTERFACE_LIBRARY described in kyb's comment

Functionally my implementation does at most the same as @PaulMolodowitch's implementation. But it is more laconic.

## https://mcmap.net/q/262296/-how-to-print-all-the-properties-of-a-target-in-cmake/56738858#56738858
## https://mcmap.net/q/262296/-how-to-print-all-the-properties-of-a-target-in-cmake

## Get all properties that cmake supports
execute_process(COMMAND cmake --help-property-list OUTPUT_VARIABLE CMAKE_PROPERTY_LIST)
## Convert command output into a CMake list
STRING(REGEX REPLACE ";" "\\\\;" CMAKE_PROPERTY_LIST "${CMAKE_PROPERTY_LIST}")
STRING(REGEX REPLACE "\n" ";" CMAKE_PROPERTY_LIST "${CMAKE_PROPERTY_LIST}")

list(REMOVE_DUPLICATES CMAKE_PROPERTY_LIST)

function(print_target_properties tgt)
    if(NOT TARGET ${tgt})
      message("There is no target named '${tgt}'")
      return()
    endif()

    foreach (prop ${CMAKE_PROPERTY_LIST})
        string(REPLACE "<CONFIG>" "${CMAKE_BUILD_TYPE}" prop ${prop})
        get_target_property(propval ${tgt} ${prop})
        if (propval)
            message ("${tgt} ${prop} = ${propval}")
        endif()
    endforeach(prop)
endfunction(print_target_properties)
Lumbye answered 24/6, 2019 at 14:36 Comment(3)
As soon as I use pkg_check_modules() somewhere I get a billion errors like this one: ``` CMake Error at cwm4/cmake/print_target_properties.cmake:19 (get_target_property): INTERFACE_LIBRARY targets may only have whitelisted properties. The property "INSTALL_RPATH" is not allowed. ```Resume
This generally works, but for MSVC builds, usually, ${CMAKE_BUILD_TYPE} is not set to a single "DEBUG" or "RELEASE" value (since the solutions are usually generated for multiple build configurations at the same time). I just manually used "DEBUG" instead of "${CMAKE_BUILD_TYPE}".Situate
@Lumbye Is there a reason to call get_target_property() a second time in the if()?Starlight
S
2

This version uses ideas from David Drozd's and Paul Molodowitch's answers but includes processing for <CONFIG> and <LANG> text returned by cmake --help-property-list:

# Sets the AVAILABLE_CONFIGURATION_TYPES variable to the default available configurations
# (For some reason, CMAKE_CONFIGURATION_TYPES tends to be empty)
function(get_available_configuration_types)
    # Get all variables that cmake cache defines by default
    execute_process(COMMAND cmake -LAH -N OUTPUT_VARIABLE CMAKE_CACHE_VARIABLE_LIST)

    # Convert command output into a CMake list
    string(REGEX REPLACE ";" "[:semicolon:]" CMAKE_CACHE_VARIABLE_LIST "${CMAKE_CACHE_VARIABLE_LIST}")
    string(REGEX REPLACE "\n" ";" CMAKE_CACHE_VARIABLE_LIST "${CMAKE_CACHE_VARIABLE_LIST}")

    # filter down to the variables
    list(FILTER CMAKE_CACHE_VARIABLE_LIST EXCLUDE REGEX "^$|^//.*$|^\-\-$")

    # Get the configuration types
    set(AVAILABLE_CONFIGURATION_TYPES ${CMAKE_CACHE_VARIABLE_LIST})
    list(FILTER AVAILABLE_CONFIGURATION_TYPES INCLUDE REGEX "^CMAKE_CONFIGURATION_TYPES")
    list(GET AVAILABLE_CONFIGURATION_TYPES 0 AVAILABLE_CONFIGURATION_TYPES)
    string(REGEX REPLACE ".*=" "" AVAILABLE_CONFIGURATION_TYPES "${AVAILABLE_CONFIGURATION_TYPES}")
    string(REPLACE "[:semicolon:]" ";" AVAILABLE_CONFIGURATION_TYPES "${AVAILABLE_CONFIGURATION_TYPES}")
    string(TOUPPER "${AVAILABLE_CONFIGURATION_TYPES}" AVAILABLE_CONFIGURATION_TYPES)

    # Add the current build type if it isn't already there
    string(TOUPPER ${CMAKE_BUILD_TYPE} BUILD_TYPE)
    list(FILTER AVAILABLE_CONFIGURATION_TYPES EXCLUDE REGEX ${BUILD_TYPE})
    list(APPEND AVAILABLE_CONFIGURATION_TYPES ${BUILD_TYPE})
    list(SORT AVAILABLE_CONFIGURATION_TYPES)

    # make AVAILABLE_CONFIGURATION_TYPES available to parent
    set(AVAILABLE_CONFIGURATION_TYPES ${AVAILABLE_CONFIGURATION_TYPES} PARENT_SCOPE)
endfunction()

# Sets the CMAKE_PROPERTY_LIST and CMAKE_WHITELISTED_PROPERTY_LIST variables to
# the list of properties
function(get_cmake_property_list)
    # See https://mcmap.net/q/263113/-what-are-the-possible-values-for-the-language-variable-in-cmake
    set(LANGS ASM-ATT ASM ASM_MASM ASM_NASM C CSHARP CUDA CXX FORTRAN HIP ISPC JAVA OBJC OBJCXX RC SWIFT)
    get_available_configuration_types()

    # Get all propreties that cmake supports
    execute_process(COMMAND cmake --help-property-list OUTPUT_VARIABLE CMAKE_PROPERTY_LIST)

    # Convert command output into a CMake list
    string(REGEX REPLACE ";" "\\\\;" CMAKE_PROPERTY_LIST "${CMAKE_PROPERTY_LIST}")
    string(REGEX REPLACE "\n" ";" CMAKE_PROPERTY_LIST "${CMAKE_PROPERTY_LIST}")

    # Populate "<CONFIG>" with AVAILBLE_CONFIG_TYPES
    set(CONFIG_LINES ${CMAKE_PROPERTY_LIST})
    list(FILTER CONFIG_LINES INCLUDE REGEX "<CONFIG>")
    list(FILTER CMAKE_PROPERTY_LIST EXCLUDE REGEX "<CONFIG>")
    foreach(CONFIG_LINE IN LISTS CONFIG_LINES)
        foreach(CONFIG_VALUE IN LISTS AVAILABLE_CONFIGURATION_TYPES)
            string(REPLACE "<CONFIG>" "${CONFIG_VALUE}" FIXED "${CONFIG_LINE}")
            list(APPEND CMAKE_PROPERTY_LIST ${FIXED})
        endforeach()
    endforeach()

    # Populate "<LANG>" with LANGS
    set(LANG_LINES ${CMAKE_PROPERTY_LIST})
    list(FILTER LANG_LINES INCLUDE REGEX "<LANG>")
    list(FILTER CMAKE_PROPERTY_LIST EXCLUDE REGEX "<LANG>")
    foreach(LANG_LINE IN LISTS LANG_LINES)
        foreach(LANG IN LISTS LANGS)
            string(REPLACE "<LANG>" "${LANG}" FIXED "${LANG_LINE}")
            list(APPEND CMAKE_PROPERTY_LIST ${FIXED})
        endforeach()
    endforeach()

    # no repeats
    list(REMOVE_DUPLICATES CMAKE_PROPERTY_LIST)

    # Fix https://mcmap.net/q/263112/-how-can-i-remove-the-quot-the-location-property-may-not-be-read-from-target-quot-error-in-cmake
    list(FILTER CMAKE_PROPERTY_LIST EXCLUDE REGEX "^LOCATION$|^LOCATION_|_LOCATION$")

    list(SORT CMAKE_PROPERTY_LIST)

    # Whitelisted property list for use with interface libraries to reduce warnings
    set(CMAKE_WHITELISTED_PROPERTY_LIST ${CMAKE_PROPERTY_LIST})

    # regex from https://mcmap.net/q/262296/-how-to-print-all-the-properties-of-a-target-in-cmake
    list(FILTER CMAKE_WHITELISTED_PROPERTY_LIST INCLUDE REGEX "^(INTERFACE|[_a-z]|IMPORTED_LIBNAME_|MAP_IMPORTED_CONFIG_)|^(COMPATIBLE_INTERFACE_(BOOL|NUMBER_MAX|NUMBER_MIN|STRING)|EXPORT_NAME|IMPORTED(_GLOBAL|_CONFIGURATIONS|_LIBNAME)?|NAME|TYPE|NO_SYSTEM_FROM_IMPORTED)$")

    # make the lists available
    set(CMAKE_PROPERTY_LIST ${CMAKE_PROPERTY_LIST} PARENT_SCOPE)
    set(CMAKE_WHITELISTED_PROPERTY_LIST ${CMAKE_WHITELISTED_PROPERTY_LIST} PARENT_SCOPE)
endfunction()

get_cmake_property_list()

function(print_target_properties tgt)
    if(NOT TARGET ${tgt})
      message("There is no target named '${tgt}'")
      return()
    endif()

    get_target_property(target_type ${tgt} TYPE)
    if(target_type STREQUAL "INTERFACE_LIBRARY")
        set(PROPERTIES ${CMAKE_WHITELISTED_PROPERTY_LIST})
    else()
        set(PROPERTIES ${CMAKE_PROPERTY_LIST})
    endif()

    foreach (prop ${PROPERTIES})
        #message ("Checking ${prop}")
        get_property(propval TARGET ${tgt} PROPERTY ${prop} SET)
        if (propval)
            get_target_property(propval ${tgt} ${prop})
            message ("${tgt} ${prop} = ${propval}")
        endif()
    endforeach(prop)
endfunction(print_target_properties)
Sueannsuede answered 22/8, 2021 at 11:49 Comment(2)
Since there can be no CMAKE_CONFIGURATION_TYPES at all, cmake would error on list(GET AVAILABLE_CONFIGURATION_TYPES 0 AVAILABLE_CONFIGURATION_TYPES)Ruler
Does this answer cover everything in David and Paul's answers, including more their more recent edits?Lead

© 2022 - 2024 — McMap. All rights reserved.