CMake and strange behavior when invoking custom fu

2019-09-02 19:59发布

I have big project. In root directory I've created file CMake\optionalsource.cmake (in directory CMake are other helper files), which contains this function definitions:

cmake_minimum_required(VERSION 3.5)
# cmake_parse_arguments needs cmake 3.5

##
# This function always adds sources to target, but when "WHEN" condition is not meet
# source is excluded from build process.
# This doesn't break build, but source is always visible for the project, what is 
# very handy when working with muti-platform project with sources needed
# only for specific platform
#
# Usage:
#      target_optional_sources(WHEN <condition> 
#                              TARGET <target>
#                              <INTERFACE|PUBLIC|PRIVATE> [items2...]
#                              [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
##
function(target_optional_sources)
    set(options OPTIONAL "")
    set(oneValueArgs WHEN TARGET)
    set(multiValueArgs PUBLIC PRIVATE INTERFACE)

    cmake_parse_arguments(target_optional_sources 
                          "${options}" "${oneValueArgs}" "${multiValueArgs}"
                          ${ARGN})

    # for debugging purposes 
    message("TARGET ${target_optional_sources_TARGET}")
    message("PUBLIC ${target_optional_sources_PUBLIC}")
    message("PRIVATE ${target_optional_sources_PRIVATE}")
    message("INTERFACE ${target_optional_sources_INTERFACE}")
    message("WHEN ${target_optional_sources_WHEN} ${${target_optional_sources_WHEN}}")

    target_sources(${target_optional_sources_TARGET}
                   PUBLIC ${target_optional_sources_PUBLIC}
                   PRIVATE ${target_optional_sources_PRIVATE}
                   INTERFACE ${target_optional_sources_INTERFACE})

    if (NOT ${target_optional_sources_WHEN})

        set_source_files_properties(${target_optional_sources_PUBLIC}
                                    PROPERTIES HEADER_FILE_ONLY TRUE)
        set_source_files_properties(${target_optional_sources_PRIVATE}
                                    PROPERTIES HEADER_FILE_ONLY TRUE)
        set_source_files_properties(${target_optional_sources_INTERFACE}
                                    PROPERTIES HEADER_FILE_ONLY TRUE)

    endif(NOT ${target_optional_sources_WHEN})

endfunction(target_optional_sources)

This is included into a root CMakeLists.txt. Now this function quite simple. It was motivated by this nice SO answer and this feature request for CMake.

Now I've encounter some strange problem. My project contains many targets (libs/dlls/execs), I used this function in one place like this:

add_library(CommonLibrary STATIC
    <list of mutliplatform sources>
)  

message("=== function CommonLibrary ===")
target_optional_sources(WHEN APPLE 
                        TARGET  CommonLibrary
                        PUBLIC
                                macos/CFUtils.cpp
                                macos/CFUtils.h
                                MacMachineData.mm
                                MacMachineData.h
                                macos/MacAutoreleasePool.mm
                                macos/MacAutoreleasePool.h
                        )

And in logs I can see this:

1>=== function CommonLibrary ===
1>TARGET CommonLibrary
1>PUBLIC macos/CFUtils.cpp;macos/CFUtils.h;MacMachineData.mm;MacMachineData.h;macos/MacAutoreleasePool.mm;macos/MacAutoreleasePool.h
1>PRIVATE
1>INTERFACE
1>WHEN APPLE

But lower I can see this error messages:

1>CMake Error at SomeOtherLib1/CMakeLists.txt:34 (add_executable):
1>  Cannot find source file:
1>
1>    macos/CFUtils.cpp
1>
1>  Tried extensions .c .C .c++ .cc .cpp .cxx .cu .m .M .mm .h .hh .h++ .hm
1>  .hpp .hxx .in .txx
1>
1>
1>CMake Error at SomeOtherLib2/CMakeLists.txt:11 (add_executable):
1>  Cannot find source file:
1>
1>    macos/CFUtils.cpp
1>
1>  Tried extensions .c .C .c++ .cc .cpp .cxx .cu .m .M .mm .h .hh .h++ .hm
1>  .hpp .hxx .in .txx
1>
1>
1>CMake Error at UnitTests/CMakeLists.txt:11 (add_executable):
1>  Cannot find source file:
1>
1>    macos/CFUtils.cpp
1>
1>  Tried extensions .c .C .c++ .cc .cpp .cxx .cu .m .M .mm .h .hh .h++ .hm
1>  .hpp .hxx .in .txx
1>

macos/CFUtils.cpp was added only by invoking my custom function, so how it is possible that other CMakeLists.txt files has been impacted by successful function invocation? When I reorder files in function invocation error messages are following this change.

What is more strange under Visual Studio this errors are coursing error report, but project files are regenerated successfully and everything works. I can't live this as it is since it will cause build issue on Jenkins machine.


Edit:

This is how CommonLibrary is linked to other targets, for example:

add_executable(TestApp
    <Test app sources>
)

target_link_libraries(TestApp
    PRIVATE
        fmt::fmt-header-only
        CommonLibrary
        SomeOtherLibrary
)

标签: c++ cmake
0条回答
登录 后发表回答