Могу ли я контролировать исключение источников из target_sources в CMake?

#cmake #cmake-language #cmakelists-options

Вопрос:

Я новичок в 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 на основе флага, называемого 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
)
 

Комментарии:

1. оооочень if(DEFINED myFlag) target_sources(myTarget myDir3/src/c.c) endif() ? Нет смысла добавлять один и тот же каталог в оба PUBLIC и PRIVATE

2. @KamilCuk я удалю с публики тогда…

3. Ты определенно не хочешь if(DEFINED myFlag) здесь находиться… что, если myFlag установлено значение OFF ?

4. Нет смысла включать PUBLIC или INTERFACE если к ним ничего не добавляется

Ответ №1:

Вы не можете поместить операторы 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


lt;


lt;BOOL:${myFlag}>:myDir3/src/c.c>
)

Комментарии:

1. один вопрос, второй вариант, который вы разместили, декларативный вариант, включает или отключает использование myDir3/src/c.c if myFlag , если он присутствует?

2. Если myFlag оценит что-то истинное (например 1 , ON TRUE , и т.д.), Оно будет включено.

3. Спасибо! Как я могу использовать эту опцию, если я хотел бы включить файл в случае, если флаг «myflag» равен «0», «Ложь» или » ВЫКЛЮЧЕН‘?

4. $<NOT:$<BOOL:...>> см.: cmake.org/cmake/help/latest/manual/…

5. Видите разницу? $<$<NOT:$<BOOL:${myFlag}>>:myDir3/src/c.c> . Если вам нужна дополнительная помощь, пожалуйста, задайте новый вопрос.

Ответ №2:

В зависимости от того, почему вы пытаетесь это сделать, также может иметь смысл сохранить их в качестве исходных файлов (чтобы они отображались, например, в целевом представлении Visual Studio), но пометить их как заголовки, чтобы они не компилировались:

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

Это даже рекомендуется в документации CMake для этой цели:

Это полезно, если у вас есть некоторые исходные файлы, которые вы каким-то образом предварительно обрабатываете, а затем добавляете эти предварительно обработанные источники с помощью add_library() или add_executable(). Обычно в IDE не было бы ссылок на исходные источники, только на эти предварительно обработанные источники. Поэтому, установив это свойство для всех исходных исходных файлов в значение ВКЛЮЧЕНО, а затем либо вызвав add_library (), либо add_executable() при передаче как предварительно обработанных источников, так и исходных источников, либо используя target_sources() для добавления исходных исходных файлов, я сделаю именно то, что можно было бы ожидать.e. исходные исходные файлы будут видны в среде IDE и не будут созданы.

Комментарии:

1. В современном мире Visual Studio может напрямую открывать проекты CMake, и это фактически предпочтительный рабочий процесс. Так что причин для этого очень мало.

2. @AlexReinking: Я знаю, что Visual Studio может открывать проекты CMake напрямую, но если вы это сделаете, в представлении цели будут отображаться только файлы, добавленные в цель. Если вы не добавите заголовки, они не будут отображаться. Аналогично, если вы только условно добавляете исходный файл в целевые источники, он не будет отображаться, если не установлен флаг. И то же самое верно для других IDE, таких как Qt Creator. И я не вижу никакого способа, как IDE могли бы надежно сделать что-то по-другому. В конце концов, заголовки могут быть включены из любого места, как среда разработки должна определять, в какую цель их добавлять?