我可以在 CMake 中控制 target_sources 中的来源排除吗?

Can I control sources exclusion from target_sources in CMake?

我是 CMake 的新手,我想知道是否有可能根据变量从 target_sources() 中排除某些来源。

假设我在下面有这个

target_sources(myTarget
    PUBLIC
    PRIVATE
        myDir1/src/a.c
        myDir2/src/b.c
        myDir3/src/c.c      
    INTERFACE
)

target_include_directories(myTarget
    PUBLIC
    PRIVATE       
        myDir1/inc
        myDir2/inc
        myDir3/inc  
    INTERFACE
)

我想从 myDir3 exclude/include sources/directories 基于一个名为 myFlag 的标志。我怎样才能做到这一点?

target_sources(myTarget
    PUBLIC
    PRIVATE
        myDir1/src/a.c
        myDir2/src/b.c
        if(DEFINED myFlag)
           myDir3/src/c.c
        endif()
    INTERFACE
)

target_include_directories(myTarget
    PUBLIC
    PRIVATE        
        myDir1/inc
        myDir2/inc
        if(DEFINED myFlag)
           myDir3/inc  
        endif()
    INTERFACE
)

不能将 if 语句放入命令的参数列表中。 target_* 命令不会覆盖,而是追加,因此最简单的解决方案如下:

target_sources(
  myTarget
  PRIVATE
    myDir1/src/a.c
    myDir2/src/b.c 
)
if (myFlag) 
  target_sources(myTarget PRIVATE myDir3/src/c.c)
endif ()

target_include_directories(
  myTarget
  PRIVATE
    myDir1/inc
    myDir2/inc
)
if (myFlag) 
  target_include_directories(myTarget PRIVATE myDir3/inc)
endif ()

另一个更具声明性的选项是使用生成器表达式,如下所示:

target_sources(
  myTarget
  PRIVATE
    myDir1/src/a.c
    myDir2/src/b.c
    $<$<BOOL:${myFlag}>:myDir3/src/c.c>
)

根据您尝试这样做的原因,将它们保留为源文件也可能有意义(因此它们会显示在 Visual Studio 的目标视图中),但将它们标记为 headers 所以它们没有被编译:

if (NOT myFlag)
  set_source_files_properties(
      srcfile1.cpp
      srcfile2.cpp
    PROPERTIES
      HEADER_FILE_ONLY ON
  )
endif()

CMake 的 documentation 甚至为此推荐了此方法:

This is useful if you have some source files which you somehow pre-process, and then add these pre-processed sources via add_library() or add_executable(). Normally, in IDE, there would be no reference of the original sources, only of these pre-processed sources. So by setting this property for all the original source files to ON, and then either calling add_library() or add_executable() while passing both the pre-processed sources and the original sources, or by using target_sources() to add original source files will do exactly what would one expect, i.e. the original source files would be visible in IDE, and will not be built.