0

I know we can use $<TARGET_FILE_NAME:Foo> to get the filename for add_custom_command and add_custom_target during build time, but I can't seem to find the answer on out how to get the filename during config time. For example,

add_library(Foo SHARED foo.cpp foo.h)

The best I get is get_target_property(FOO_NAME Foo NAME), but ${FOO_NAME} is Foo, what I want is something like libFoo.so or libFoo.dylib depends on the platform. How can we get the target file name during cmake config time?

For context on why I thought I initially thought I needed to be able to do this, see this other question: In CMake how can I copy a target file to a custom location when target based generator expression for OUTPUT is not supported?.

starball
  • 20,030
  • 7
  • 43
  • 238
user3667089
  • 2,996
  • 5
  • 30
  • 56

2 Answers2

1

Through a combination of the following:

I believe you could do something like this:

# cmake_minimum_required(VERSION 3.x)
project(hello)
function(get_target_filename target outvar)
    get_target_property(prop_type "${target}" TYPE)
    get_target_property(prop_is_framework "${target}" FRAMEWORK)
    get_target_property(prop_outname "${target}" OUTPUT_NAME)
    get_target_property(prop_archive_outname "${target}" ARCHIVE_OUTPUT_NAME)
    get_target_property(prop_library_outname "${target}" LIBRARY_OUTPUT_NAME)
    get_target_property(prop_runtime_outname "${target}" RUNTIME_OUTPUT_NAME)
    # message("prop_archive_outname: ${prop_archive_outname}")    
    # message("prop_library_outname: ${prop_library_outname}")
    # message("prop_runtime_outname: ${prop_runtime_outname}")
    if(DEFINED CMAKE_BUILD_TYPE)
        get_target_property(prop_cfg_outname "${target}" "${OUTPUT_NAME}_${CMAKE_BUILD_TYPE}")
        get_target_property(prop_archive_cfg_outname "${target}" "${ARCHIVE_OUTPUT_NAME}_${CMAKE_BUILD_TYPE}")
        get_target_property(prop_library_cfg_outname "${target}" "${LIBRARY_OUTPUT_NAME}_${CMAKE_BUILD_TYPE}")
        get_target_property(prop_runtime_cfg_outname "${target}" "${RUNTIME_OUTPUT_NAME}_${CMAKE_BUILD_TYPE}")
        # message("prop_archive_cfg_outname: ${prop_archive_cfg_outname}")
        # message("prop_library_cfg_outname: ${prop_library_cfg_outname}")
        # message("prop_runtime_cfg_outname: ${prop_runtime_cfg_outname}")
        if(NOT ("${prop_cfg_outname}" STREQUAL "prop_cfg_outname-NOTFOUND"))
            set(prop_outname "${prop_cfg_outname}")
        endif()
        if(NOT ("${prop_archive_cfg_outname}" STREQUAL "prop_archive_cfg_outname-NOTFOUND"))
            set(prop_archive_outname "${prop_archive_cfg_outname}")
        endif()
        if(NOT ("${prop_library_cfg_outname}" STREQUAL "prop_library_cfg_outname-NOTFOUND"))
            set(prop_library_outname "${prop_library_cfg_outname}")
        endif()
        if(NOT ("${prop_runtime_cfg_outname}" STREQUAL "prop_runtime_cfg_outname-NOTFOUND"))
            set(prop_runtime_outname "${prop_runtime_cfg_outname}")
        endif()
    endif()
    set(outname "${target}")
    if(NOT ("${prop_outname}" STREQUAL "prop_outname-NOTFOUND"))
        set(outname "${prop_outname}")
    endif()
    if("${prop_is_framework}")
        set(filename "${outname}")
    elseif(prop_type STREQUAL "STATIC_LIBRARY")
        if(NOT ("${prop_archive_outname}" STREQUAL "prop_archive_outname-NOTFOUND"))
            set(outname "${prop_archive_outname}")
        endif()
        set(filename "${CMAKE_STATIC_LIBRARY_PREFIX}${outname}${CMAKE_STATIC_LIBRARY_SUFFIX}")
    elseif(prop_type STREQUAL "MODULE_LIBRARY")
        if(NOT ("${prop_library_outname}" STREQUAL "prop_library_outname-NOTFOUND"))
            set(outname "${prop_library_outname}")
        endif()
        set(filename "${CMAKE_SHARED_MODULE_LIBRARY_PREFIX}${outname}${CMAKE_SHARED_MODULE_LIBRARY_SUFFIX}")
    elseif(prop_type STREQUAL "SHARED_LIBRARY")
        if(WIN32)
            if(NOT ("${prop_runtime_outname}" STREQUAL "prop_runtime_outname-NOTFOUND"))
                set(outname "${prop_runtime_outname}")
            endif()
        else()
            if(NOT ("${prop_library_outname}" STREQUAL "prop_library_outname-NOTFOUND"))
                set(outname "${prop_library_outname}")
            endif()
        endif()
        set(filename "${CMAKE_SHARED_LIBRARY_PREFIX}${outname}${CMAKE_SHARED_LIBRARY_SUFFIX}")
    elseif(prop_type STREQUAL "EXECUTABLE")
        if(NOT ("${prop_runtime_outname}" STREQUAL "prop_runtime_outname-NOTFOUND"))
            set(outname "${prop_runtime_outname}")
        endif()
        set(filename "${CMAKE_EXECUTABLE_PREFIX}${outname}${CMAKE_EXECUTABLE_SUFFIX}")
    else()
        message(FATAL_ERROR "target \"${target}\" is not of type STATIC_LIBRARY, MODULE_LIBRARY, SHARED_LIBRARY, or EXECUTABLE.")
    endif()
    set("${outvar}" "${filename}" PARENT_SCOPE)
endfunction()
add_library(static_lib STATIC test.cpp)
add_library(shared_lib SHARED test.cpp)
add_executable(executable test.cpp)
get_target_filename(static_lib static_lib_filename)
get_target_filename(shared_lib shared_lib_filename)
get_target_filename(executable executable_filename)
message(STATUS "static_lib_filename: ${static_lib_filename}")
message(STATUS "shared_lib_filename: ${shared_lib_filename}")
message(STATUS "executable_filename: ${executable_filename}")

The above is a basic implementation. It doesn't handle some (perhaps important) nuances like:

  • The fact that most of those target properties can themselves have generator expressions in them (see their docs), which, if it happens to you, I think you're out of luck.
  • The fact that CMAKE_BUILD_TYPE is only relevant for single-config generators- not multi-config generators.
  • https://cmake.org/cmake/help/latest/variable/CMAKE_EXECUTABLE_SUFFIX_LANG.html
  • Other language-specific overrides like CMAKE_SHARED_LIBRARY_PREFIX_<LANG>

You'd need to check if those exist and handle them if they do... except in honesty I'm not quite sure how, given that it doesn't seem like targets have a LANGUAGE property. Source files do, but that's not what we need here. One might need to go to the CMake Discourse to ask about this.

Note: If you want the full path to the target output file... oh boy...

More fun notes: If you want to evaluate generator expressions recursively at generation time (for generator expressions that themselves evaluate to generator expressions), you can use the $<GENEX_EVAL:...> generator expression, but of course- that doesn't apply to this question, which is about configure time.

starball
  • 20,030
  • 7
  • 43
  • 238
0

A little bit clumsy but the file name can be constructed in the following way:

set(FOO_NAME "${CMAKE_SHARED_LIBRARY_PREFIX}Foo${CMAKE_SHARED_LIBRARY_SUFFIX}")

See also cmake doc.

Note that the two variables will be overridden by the respective CMAKE_SHARED_LIBRARY_??FIX_<LANG> variables. So if that's a possibility, you need make sure you catch the right variable.

Let me add the final remark that the rationale behind CMake is you don't need to know. CMake operates on targets, not files. So whatever you're trying to achieve might be possible without getting the filename.

Friedrich
  • 2,011
  • 2
  • 17
  • 19
  • Thanks for the answer, but this doesn't work if we don't know whether the library is static or dynamic beforehand. – user3667089 Feb 10 '23 at 16:59
  • @user3667089 that's true. I assumed you would know as much and my lightweight, one line solution would suffice. Luckily, user spelled out a whole function in their answer. – Friedrich Feb 11 '23 at 10:27