在CMake的配置阶段(而不是生成阶段)如何获取目标输出文件的名称?

huangapple go评论50阅读模式
英文:

How can I get a target's output-file's name during CMake's configuration phase (not the generation phase)?

问题

我知道我们可以在构建时使用$<TARGET_FILE_NAME:Foo>来获取add_custom_commandadd_custom_target的文件名,但我似乎找不到如何在配置时间获取文件名的答案。例如,

add_library(Foo SHARED foo.cpp foo.h)

我得到的最好答案是get_target_property(FOO_NAME Foo NAME),但${FOO_NAME}Foo,我想要的是类似于libFoo.solibFoo.dylib,具体取决于平台。我们如何在CMake配置时间获取目标文件名呢?

英文:

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: https://stackoverflow.com/q/75415268/11107541.

答案1

得分: 1

你不能-至少不能覆盖所有可能的情况。构建输出文件名的方式足够复杂,以至于你只能处理“简单”情况,即使这些情况也足够复杂。我是说,看看你必须处理的所有事情,以及它们如何互相覆盖:

我认为你可以做类似这样的事情:

# cmake_minimum_required(VERSION 3.x)
project(hello)
function(get_target_filename target outvar)
    set(outname "${target}")

    get_target_property(prop_outname "${target}" OUTPUT_NAME)
    if(NOT ("${prop_outname}" STREQUAL "prop_outname-NOTFOUND"))
        set(outname "${prop_outname}")
    endif()

    get_target_property(prop_cfg_outname "${target}" "${OUTPUT_NAME}_${CMAKE_BUILD_TYPE}")
    if(NOT ("${prop_cfg_outname}" STREQUAL "prop_cfg_outname-NOTFOUND"))
        set(outname "${prop_cfg_outname}")
    endif()

    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)
    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}")
    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()

    get_target_property(prop_type "${target}" TYPE)
    get_target_property(prop_is_framework "${target}" FRAMEWORK)
    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(prefix "${CMAKE_STATIC_LIBRARY_PREFIX}")
        set(suffix "${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(prefix "${CMAKE_SHARED_MODULE_LIBRARY_PREFIX}")
        set(suffix "${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(prefix "${CMAKE_SHARED_LIBRARY_PREFIX}")
        set(suffix "${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(prefix "${CMAKE_EXECUTABLE_PREFIX}")
        set(suffix "${CMAKE_EXECUTABLE_SUFFIX}")
    else()
        message(FATAL_ERROR "target \"${target}\" is not of type STATIC_LIBRARY, MODULE_LIBRARY, SHARED_LIBRARY, or EXECUTABLE.")
    endif()

    get_target_property(prop_prefix "${target}" PREFIX)
    if(NOT ("${prop_prefix}" STREQUAL "prop_prefix-NOTFOUND"))
        set(prefix "${prop_prefix}")
    endif()
    get_target_property(prop_suffix "${target}" PREFIX)
    if(NOT ("${prop_suffix}" STREQUAL "prop_suffix-NOTFOUND"))
        set(suffix "${prop_suffix}")
    endif()

    set("${out

<details>
<summary>英文:</summary>

You can&#39;t- at least- not covering all the possible scenarios. The way a output file name is constructed is complicated enough that you can only handle &quot;simple&quot; cases, and even doing that is complicated enough. I mean- look at all the things you have to handle, and the ways that they can override each other:

- [`variable/CMAKE_BUILD_TYPE`](https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html)
- [`prop_tgt/TYPE`](https://cmake.org/cmake/help/latest/prop_tgt/TYPE.html)
- [`prop_tgt/FRAMEWORK`](https://cmake.org/cmake/help/latest/prop_tgt/FRAMEWORK.html)
- [`variable/CMAKE_STATIC_LIBRARY_PREFIX`](https://cmake.org/cmake/help/latest/variable/CMAKE_STATIC_LIBRARY_PREFIX.html) and [`variable/CMAKE_STATIC_LIBRARY_SUFFIX`](https://cmake.org/cmake/help/latest/variable/CMAKE_STATIC_LIBRARY_SUFFIX.html) and the language-specific overrides
- [`variable/CMAKE_SHARED_LIBRARY_PREFIX`](https://cmake.org/cmake/help/latest/variable/CMAKE_SHARED_LIBRARY_PREFIX.html) and [`variable/CMAKE_SHARED_LIBRARY_SUFFIX`](https://cmake.org/cmake/help/latest/variable/CMAKE_SHARED_LIBRARY_SUFFIX.html) and the language-specific overrides
- [`variable/CMAKE_SHARED_MODULE_PREFIX`](https://cmake.org/cmake/help/latest/variable/CMAKE_SHARED_MODULE_PREFIX.html) and [`variable/CMAKE_SHARED_MODULE_SUFFIX`](https://cmake.org/cmake/help/latest/variable/CMAKE_SHARED_MODULE_SUFFIX.html) and the language-specific overrides
- [`variable/CMAKE_EXECUTABLE_SUFFIX`](https://cmake.org/cmake/help/latest/variable/CMAKE_EXECUTABLE_SUFFIX.html) and the language-specific overrides
- [`prop_tgt/OUTPUT_NAME`](https://cmake.org/cmake/help/latest/prop_tgt/OUTPUT_NAME.html) and [`prop_tgt/OUTPUT_NAME_&lt;CONFIG&gt;`](https://cmake.org/cmake/help/latest/prop_tgt/OUTPUT_NAME_CONFIG.html)
- [`prop_tgt/ARCHIVE_OUTPUT_NAME`](https://cmake.org/cmake/help/latest/prop_tgt/ARCHIVE_OUTPUT_NAME.html) and [`prop_tgt/ARCHIVE_OUTPUT_NAME_&lt;CONFIG&gt;`](https://cmake.org/cmake/help/latest/prop_tgt/ARCHIVE_OUTPUT_NAME_CONFIG.html)
- [`prop_tgt/LIBRARY_OUTPUT_NAME`](https://cmake.org/cmake/help/latest/prop_tgt/LIBRARY_OUTPUT_NAME.html) and [`prop_tgt/LIBRARY_OUTPUT_NAME_&lt;CONFIG&gt;`](https://cmake.org/cmake/help/latest/prop_tgt/LIBRARY_OUTPUT_NAME_CONFIG.html)
- [`prop_tgt/RUNTIME_OUTPUT_NAME`](https://cmake.org/cmake/help/latest/prop_tgt/RUNTIME_OUTPUT_NAME.html) and [`prop_tgt/RUNTIME_OUTPUT_NAME_&lt;CONFIG&gt;`](https://cmake.org/cmake/help/latest/prop_tgt/RUNTIME_OUTPUT_NAME_CONFIG.html)

I believe you could do something like this:

```cmake
# cmake_minimum_required(VERSION 3.x)
project(hello)
function(get_target_filename target outvar)
    set(outname &quot;${target}&quot;)

    get_target_property(prop_outname &quot;${target}&quot; OUTPUT_NAME)
    if(NOT (&quot;${prop_outname}&quot; STREQUAL &quot;prop_outname-NOTFOUND&quot;))
        set(outname &quot;${prop_outname}&quot;)
    endif()

    get_target_property(prop_cfg_outname &quot;${target}&quot; &quot;${OUTPUT_NAME}_${CMAKE_BUILD_TYPE}&quot;)
    if(NOT (&quot;${prop_cfg_outname}&quot; STREQUAL &quot;prop_cfg_outname-NOTFOUND&quot;))
        set(outname &quot;${prop_cfg_outname}&quot;)
    endif()

    get_target_property(prop_archive_outname &quot;${target}&quot; ARCHIVE_OUTPUT_NAME)
    get_target_property(prop_library_outname &quot;${target}&quot; LIBRARY_OUTPUT_NAME)
    get_target_property(prop_runtime_outname &quot;${target}&quot; RUNTIME_OUTPUT_NAME)
    get_target_property(prop_archive_cfg_outname &quot;${target}&quot; &quot;${ARCHIVE_OUTPUT_NAME}_${CMAKE_BUILD_TYPE}&quot;)
    get_target_property(prop_library_cfg_outname &quot;${target}&quot; &quot;${LIBRARY_OUTPUT_NAME}_${CMAKE_BUILD_TYPE}&quot;)
    get_target_property(prop_runtime_cfg_outname &quot;${target}&quot; &quot;${RUNTIME_OUTPUT_NAME}_${CMAKE_BUILD_TYPE}&quot;)
    if(NOT (&quot;${prop_archive_cfg_outname}&quot; STREQUAL &quot;prop_archive_cfg_outname-NOTFOUND&quot;))
        set(prop_archive_outname &quot;${prop_archive_cfg_outname}&quot;)
    endif()
    if(NOT (&quot;${prop_library_cfg_outname}&quot; STREQUAL &quot;prop_library_cfg_outname-NOTFOUND&quot;))
        set(prop_library_outname &quot;${prop_library_cfg_outname}&quot;)
    endif()
    if(NOT (&quot;${prop_runtime_cfg_outname}&quot; STREQUAL &quot;prop_runtime_cfg_outname-NOTFOUND&quot;))
        set(prop_runtime_outname &quot;${prop_runtime_cfg_outname}&quot;)
    endif()


    get_target_property(prop_type &quot;${target}&quot; TYPE)
    get_target_property(prop_is_framework &quot;${target}&quot; FRAMEWORK)
    if(&quot;${prop_is_framework}&quot;)
        set(filename &quot;${outname}&quot;)
    elseif(prop_type STREQUAL &quot;STATIC_LIBRARY&quot;)
        if(NOT (&quot;${prop_archive_outname}&quot; STREQUAL &quot;prop_archive_outname-NOTFOUND&quot;))
            set(outname &quot;${prop_archive_outname}&quot;)
        endif()
        set(prefix &quot;${CMAKE_STATIC_LIBRARY_PREFIX}&quot;)
        set(suffix &quot;${CMAKE_STATIC_LIBRARY_SUFFIX}&quot;)
    elseif(prop_type STREQUAL &quot;MODULE_LIBRARY&quot;)
        if(NOT (&quot;${prop_library_outname}&quot; STREQUAL &quot;prop_library_outname-NOTFOUND&quot;))
            set(outname &quot;${prop_library_outname}&quot;)
        endif()
        set(prefix &quot;${CMAKE_SHARED_MODULE_LIBRARY_PREFIX}&quot;)
        set(suffix &quot;${CMAKE_SHARED_MODULE_LIBRARY_SUFFIX}&quot;)
    elseif(prop_type STREQUAL &quot;SHARED_LIBRARY&quot;)
        if(WIN32)
            if(NOT (&quot;${prop_runtime_outname}&quot; STREQUAL &quot;prop_runtime_outname-NOTFOUND&quot;))
                set(outname &quot;${prop_runtime_outname}&quot;)
            endif()
        else()
            if(NOT (&quot;${prop_library_outname}&quot; STREQUAL &quot;prop_library_outname-NOTFOUND&quot;))
                set(outname &quot;${prop_library_outname}&quot;)
            endif()
        endif()
        set(prefix &quot;${CMAKE_SHARED_LIBRARY_PREFIX}&quot;)
        set(suffix &quot;${CMAKE_SHARED_LIBRARY_SUFFIX}&quot;)
    elseif(prop_type STREQUAL &quot;EXECUTABLE&quot;)
        if(NOT (&quot;${prop_runtime_outname}&quot; STREQUAL &quot;prop_runtime_outname-NOTFOUND&quot;))
            set(outname &quot;${prop_runtime_outname}&quot;)
        endif()
        set(prefix &quot;${CMAKE_EXECUTABLE_PREFIX}&quot;)
        set(suffix &quot;${CMAKE_EXECUTABLE_SUFFIX}&quot;)
    else()
        message(FATAL_ERROR &quot;target \&quot;${target}\&quot; is not of type STATIC_LIBRARY, MODULE_LIBRARY, SHARED_LIBRARY, or EXECUTABLE.&quot;)
    endif()

    get_target_property(prop_prefix &quot;${target}&quot; PREFIX)
    if(NOT (&quot;${prop_prefix}&quot; STREQUAL &quot;prop_prefix-NOTFOUND&quot;))
        set(prefix &quot;${prop_prefix}&quot;)
    endif()
    get_target_property(prop_suffix &quot;${target}&quot; PREFIX)
    if(NOT (&quot;${prop_suffix}&quot; STREQUAL &quot;prop_suffix-NOTFOUND&quot;))
        set(suffix &quot;${prop_suffix}&quot;)
    endif()

    set(&quot;${outvar}&quot; &quot;${prefix}${outname}${suffix}&quot; 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 &quot;static_lib_filename: ${static_lib_filename}&quot;)
message(STATUS &quot;shared_lib_filename: ${shared_lib_filename}&quot;)
message(STATUS &quot;executable_filename: ${executable_filename}&quot;)

The above is a basic implementation. I got too lazy to handle language-specific overrides, and 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_&lt;LANG&gt;

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 $&lt;GENEX_EVAL:...&gt; generator expression, but of course- that doesn't apply to this question, which is about configure time.

答案2

得分: 0

A little bit clumsy but the file name can be constructed in the following way:
```cmake
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_&lt;LANG&gt; 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.


<details>
<summary>英文:</summary>
A little bit clumsy but the file name can be constructed in the following way:
```cmake
set(FOO_NAME &quot;${CMAKE_SHARED_LIBRARY_PREFIX}Foo${CMAKE_SHARED_LIBRARY_SUFFIX}&quot;)

See also cmake doc.

Note that the two variables will be overridden by the respective CMAKE_SHARED_LIBRARY_??FIX_&lt;LANG&gt; 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.

huangapple
  • 本文由 发表于 2023年2月10日 15:03:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/75407883.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定