【问题标题】:How can I specify an include directory to use when compiling a specific, generated, source file?在编译特定的、生成的源文件时,如何指定要使用的包含目录?
【发布时间】:2020-10-29 07:42:21
【问题描述】:

我在我的CMakeLists.txt:

add_custom_command(OUTPUT chattr.tab.cpp
  DEPENDS table_gen
  COMMAND ./table_gen > chattr.tab.cpp
)

这会将生成的源文件chattr.tab.cpp 放在对象目录中(这是我想要的)。但是,chattr.tab.cpp 内的 #include "someheader.h" 找不到源目录中的标头。

这个生成的文件只添加到一些目标。有没有办法在编译这个生成的源文件(到CMakeFiles/sometarget.dir/chattr.tab.cpp.o)时添加一些包含目录,并且只有在编译那个源文件时?与将包含目录添加到所有使用它的目标相反?后者需要添加多个 target_include_directories() 并导致包含用于该目标的每个源文件,而不仅仅是生成的源文件。

编辑:

根据 squareskittles 的回答,我生成了以下 CMakeLists.txt 文件(仅显示底部):

....
#=================================================================
# GENERATED SOURCE FILES
#

add_executable(table_gen table_gen.cxx)

add_custom_command(OUTPUT chattr.tab.cpp
  DEPENDS table_gen
  COMMAND ./table_gen > chattr.tab.cpp
)

add_custom_command(OUTPUT PgnGrammar.h
  DEPENDS generate_PgnGrammar.h.sh
  COMMAND ${CMAKE_CURRENT_LIST_DIR}/generate_PgnGrammar.h.sh
)

set(GENERATED_SOURCES chattr.tab.cpp PgnGrammar.h)

set_source_files_properties(chattr.tab.cpp PROPERTIES
  INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}"  # For local header files.
)

#=================================================================
# TEST EXECUTABLES
#

add_executable(tstchessposition tstchessposition.cxx)
target_link_libraries(tstchessposition PRIVATE AICxx::cwchessboard AICxx::cwds)

add_executable(tstbenchmark tstbenchmark.cxx)
target_link_libraries(tstbenchmark PRIVATE AICxx::cwchessboard AICxx::cwds)

add_executable(tstpgnread tstpgnread.cxx PgnDatabase.cxx MemoryBlockList.cxx ${GENERATED_SOURCES})
target_link_libraries(tstpgnread PRIVATE AICxx::cwchessboard AICxx::cwds)

add_executable(tsticonv tsticonv.cxx)
target_link_libraries(tsticonv PRIVATE PkgConfig::glibmm)

add_executable(tstpgn tstpgn.cxx PgnDatabase.cxx MemoryBlockList.cxx ${GENERATED_SOURCES})
target_link_libraries(tstpgn PRIVATE AICxx::cwchessboard AICxx::cwds)

add_executable(tstspirit tstspirit.cxx PgnGrammar.h)
target_include_directories(tstspirit PUBLIC "${top_objdir}")

但这会导致:

[ 51%] Generating chattr.tab.cpp
./table_gen > chattr.tab.cpp
[ 54%] Generating chattr.tab.cpp
./table_gen > chattr.tab.cpp

显然,因为tstpgnreadtstpgn 都与chattr.tab.cpp 链接,所以会生成两次?!这是 CMake 中的错误还是我做错了什么?

【问题讨论】:

  • 与我在下面的回复相关,您的代码似乎使用了${CMAKE_CURRENT_SRC_DIR},除非您自己定义,否则它不是由 CMake 填充的变量。你可能想要${CMAKE_CURRENT_SOURCE_DIR}。关于您的新问题,它似乎与您的原始问题无关,但您可以尝试使用this 帖子中描述的成语添加add_custom_target,以确保生成的源文件在需要时更新。
  • 这似乎对我不起作用:我需要将生成的源文件作为源添加到可执行文件中,这使得它们直接依赖于它们。因此,在“中间”添加一个目标是行不通的。出于这个原因,我无法使用您的解决方案并使用了不同的方法。我也会将其添加为“答案”。
  • 关于 CMAKE_CURRENT_SRC_DIR...谢谢。我自己没有定义它,但出于某种原因两者都有效(也许这个错字是“支持”的:p)。不过,我只是编辑了问题并将其修复为文档所说的正确。再次感谢。

标签: cmake


【解决方案1】:

我最终为生成的源文件创建了一个 OBJECT 库,然后与之“链接”:

...
#================================================================
# GENERATED SOURCE FILES
#

add_executable(table_gen table_gen.cxx)

add_custom_command(OUTPUT chattr.tab.cpp
  DEPENDS table_gen
  COMMAND ./table_gen > chattr.tab.cpp
)

add_custom_command(OUTPUT PgnGrammar.h
  DEPENDS generate_PgnGrammar.h.sh
  COMMAND ${CMAKE_CURRENT_LIST_DIR}/generate_PgnGrammar.h.sh
)

add_library(generated_ObjLib OBJECT)
target_sources(generated_ObjLib
  PRIVATE
    "chattr.tab.cpp"
    "PgnGrammar.h"
)

target_include_directories(generated_ObjLib
  PRIVATE
    "${CMAKE_CURRENT_SOURCE_DIR}" # For local header files.
)

add_library(generated::sources ALIAS generated_ObjLib)

#==================================================================
# TEST EXECUTABLES
#

add_executable(tstchessposition tstchessposition.cxx)
target_link_libraries(tstchessposition PRIVATE CWChessboard::position AICxx::cwds)

add_executable(tstbenchmark tstbenchmark.cxx)
target_link_libraries(tstbenchmark PRIVATE CWChessboard::position AICxx::cwds)

add_executable(tstpgnread tstpgnread.cxx PgnDatabase.cxx MemoryBlockList.cxx)
target_link_libraries(tstpgnread PRIVATE generated::sources CWChessboard::position AICxx::cwds)

add_executable(tsticonv tsticonv.cxx)
target_link_libraries(tsticonv PRIVATE PkgConfig::glibmm)

add_executable(tstpgn tstpgn.cxx PgnDatabase.cxx MemoryBlockList.cxx)
target_link_libraries(tstpgn PRIVATE generated::sources CWChessboard::position AICxx::cwds)

add_executable(tstspirit tstspirit.cxx PgnGrammar.h)
target_include_directories(tstspirit PUBLIC "${top_objdir}")

诀窍是add_library(generated_ObjLib OBJECT)及以下,然后与generated::sources链接。

【讨论】:

  • 感谢您的回复。请记住在找到适合您的解决方案后将答案标记为已接受。没有赞成答案或接受答案的问题将保持未解决状态。
  • 你说得对,这不好。我不接受我的原因是因为它对你很粗鲁。虽然我觉得我也不能接受你的,因为我诚实地尝试了你的解决方案,但最终对于我的具体情况来说还不够。计划是等待一段时间,然后在您完全忘记我的答案时将其标记为已接受;)。谢谢提醒,我都忘记了。
【解决方案2】:

与“override compile flags for single files”帖子一样,您可以修改单个文件的INCLUDE_DIRECTORIES 源文件属性:

set_source_files_properties(chattr.tab.cpp PROPERTIES 
    INCLUDE_DIRECTORIES ${CMAKE_SOURCE_DIR}/other/include/dir
)

【讨论】:

  • 谢谢,这行得通。但是还有一个问题。此评论太小,无法添加细节,因此请允许我编辑问题以添加:/.
猜你喜欢
  • 2014-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多