target_include_directories 2.8.12 之前?

target_include_directories prior to 2.8.12?

我们的 CMakeList.txt 有一个 target_include_directories 蠕变。它破坏了我们的下层客户端,例如 Ubuntu LTS、CentOS 和 Solaris。

我知道我可以用以下内容来保护它(感谢 ZW),但我需要一些用于 Cmake 2.8.11 及更早版本(???)的东西。

cmake_minimum_required(VERSION 2.8.5 FATAL_ERROR)
...

if (NOT CMAKE_VERSION VERSION_LESS 2.8.12)
  target_include_directories(...)
else()
  ???
endif()

我们的目录结构相当简单。一个目录中有头文件,同一个目录中有源文件。这是设计使然,因此用户在调试器下不会遇到麻烦。

根据我们的配置是否可以使用以下内容(如果 @steveire answer applies to us 我不清楚):

if (NOT CMAKE_VERSION VERSION_LESS 2.8.12)
  target_include_directories(...)
else()
  include_directories("${ROOT_SOURCE_DIR}")
endif()

如果不是,对于 2.8.11 及更早版本,应该使用什么来代替 target_include_directories

问题

target_include_directories() command has extended functionality compared to include_directories()。所以我同意@Tsyvarev 的观点,这主要取决于你如何使用 target_include_directories().

解决方案

如果您使用 target_include_directories(my_target PRIVATE ...),则等效为 set_property(TARGET my_target APPEND PROPERTY INCLUDE_DIRECTORIES ...)。但是 include_directories() 相比之下确实为当前 CMakeLists.txt 中的所有目标设置了这些目录,并且所有目标都是 add_subdirectory() 兄弟姐妹。

如果您使用 target_include_directories(my_target INTERFACE/PUBLIC ...),CMake 2.8.11 之前的版本中没有此类功能。您可以模拟自传播包含目录的行为,但这要复杂得多。

推荐

如果您仍想支持旧版本的 CMake,请不要使用新命令。因为这不仅仅是 target_include_directories()(参见 CMake Version Compatibility Matrix/Commands)。

参考资料

向后兼容target_include_directories()

以下代码显示了旧版 CMake 必须执行的模拟操作 target_include_directories():

function(target_include_directories _target)
    set_property(GLOBAL APPEND PROPERTY GLOBAL_TARGETS "${_target}")
    set(_mode "PRIVATE")
    foreach(_arg ${ARGN})
        if (_arg MATCHES "SYSTEM|BEFORE")
            message(FATAL_ERROR "target_include_directories: SYSTEM or BEFORE not supported")
        endif()
        if (_arg MATCHES "INTERFACE|PUBLIC|PRIVATE")
            set(_mode "${_arg}")
        else()
            get_filename_component(_inc_dir "${_arg}" ABSOLUTE)
            if (_mode MATCHES "PUBLIC|PRIVATE")
                set_property(TARGET ${_target} APPEND PROPERTY INCLUDE_DIRECTORIES "${_inc_dir}")
            endif()            
            if (_mode MATCHES "INTERFACE|PUBLIC")
                set_property(TARGET ${_target} APPEND PROPERTY MY_INTERFACE_INCLUDE_DIRECTORIES "${_inc_dir}")
            endif()            
        endif()
    endforeach()
endfunction(target_include_directories)

function(target_link_libraries _target)
    set_property(GLOBAL APPEND PROPERTY GLOBAL_TARGETS "${_target}")
    set(_mode "PUBLIC")
    foreach(_arg ${ARGN})
        if (_arg MATCHES "INTERFACE|PUBLIC|PRIVATE|LINK_PRIVATE|LINK_PUBLIC|LINK_INTERFACE_LIBRARIES")
            set(_mode "${_arg}")
        else()
            if (NOT _arg MATCHES "debug|optimized|general")
                set_property(TARGET ${_target} APPEND PROPERTY MY_LINK_LIBARIES "${_arg}")
            endif()
        endif()
    endforeach()
    _target_link_libraries(${_target} ${ARGN})
endfunction(target_link_libraries)

function(my_update_depending_inc_dirs _targets _target _dep_target)
    get_property(_libs TARGET ${_dep_target} PROPERTY MY_LINK_LIBARIES)
    if (NOT _libs)
        return()
    endif()
    foreach(_lib ${_libs})
        list(FIND _targets "${_lib}" _idx)
        if (NOT _idx EQUAL -1)
            get_property(_inc_dirs TARGET ${_lib} PROPERTY MY_INTERFACE_INCLUDE_DIRECTORIES)
            set_property(TARGET ${_target} APPEND PROPERTY INCLUDE_DIRECTORIES "${_inc_dirs}")
            # to prevent cyclic dependencies getting us into an endless loop
            # remove the target we already processed from the list
            list(REMOVE_AT _targets ${_idx})
            my_update_depending_inc_dirs("${_targets}" "${_target}" "${_lib}")
        endif()
    endforeach()
endfunction(my_update_depending_inc_dirs)

function(my_update_inc_dirs)
    get_property(_targets GLOBAL PROPERTY GLOBAL_TARGETS)
    list(REMOVE_DUPLICATES _targets)
    foreach(_target ${_targets})
        my_update_depending_inc_dirs("${_targets}" "${_target}" "${_target}")
    endforeach()
endfunction(my_update_inc_dirs)

使用以下代码测试(注意:最后需要 my_update_inc_dirs() 调用):

CMakeLists.txt

cmake_minimum_required(VERSION 2.6)

project(TargetIncludeDirectories)

...

add_library(PLib plib/source/plib.cpp)
target_include_directories(PLib PRIVATE plib/source PUBLIC plib/include)

add_library(Lib lib/source/lib.cpp)
target_include_directories(Lib PRIVATE lib/source PUBLIC lib/include)
target_link_libraries(Lib PRIVATE PLib)

add_executable(App main.cpp)
target_include_directories(App PRIVATE . PUBLIC include)
target_link_libraries(App PRIVATE Lib)

my_update_inc_dirs()