Getting the compiler to find a Cmake-created file

2019-05-23 21:26发布

I'm using the configure_file command in Cmake in a feature availability check as described on this page. That page suggests using the command like this:

configure_file(config.h.in config.h)

which will translate ${CMAKE_CURRENT_SOURCE_DIR}/config.h.in to ${CMAKE_CURRENT_BINARY_DIR}/config.h. But when I compile my program, the compiler only looks in ${CMAKE_CURRENT_SOURCE_DIR} for headers (e.g. config.h), not in ${CMAKE_CURRENT_BINARY_DIR}. So naturally, the compiler doesn't find config.h where it was generated, and the build fails.

What's the standard way to resolve this issue? Should I change CMakeLists.txt so that config.h gets created in the source directory? Or should I change it to add the build directory to the include path? (And really, why do I have to manually deal with this at all? [semi-rhetorical question])

This question concerns a similar issue but both options are suggested as possible solutions; I want to know if there's a standard practice, or if this indicates that I'm missing something about how Cmake is meant to be used.

2条回答
甜甜的少女心
2楼-- · 2019-05-23 21:53

Keeping your source tree 'pristine' is right, and not doing so is 'wrong' if you want to do multiple different builds for example, or if you want to be able to clean up a build by rm'ing the build dir (not sufficient if you're generating stuff to the source dir).

Generate it in the build dir and add the include path.

Set the variables

set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON)

to make the corresponding build dir of each source dir automatically added, and to make that a transitive behavior for other targets to consume (so that foo doesn't have to add the build dir of bar explicitly for example).

http://www.cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html#build-specification-and-usage-requirements

查看更多
疯言疯语
3楼-- · 2019-05-23 22:06

I don't think there's a standard way to handle this, but from my own limited view of other projects there doesn't really seem to be an overwhelming majority one way or the other. If I was to guess, I'd think that it's more common to place the generated file in the build tree rather than the source tree.

My own preference would be to put it in a subdirectory like ${CMAKE_CURRENT_BINARY_DIR}/GeneratedFiles/config.h for clarity. This avoids all the subdirectories of ${CMAKE_CURRENT_BINARY_DIR} appearing in autocomplete lists of IDEs like Visual Studio. It also keeps your build root a bit cleaner, particularly if you end up with several generated files. You'd have to create the directory first:

set(GeneratedFilesDir "${CMAKE_CURRENT_BINARY_DIR}/GeneratedFiles")
file(MAKE_DIRECTORY ${GeneratedFilesDir})

set(ConfigFile "${GeneratedFilesDir}/config.h")
configure_file(config.h.in ${ConfigFile})


You can then perhaps do a bit more "damage limitation" by using target_include_directories rather than include_directories. For example, if config.h is only used internally by library MyLib, you can do:

add_library(MyLib ${ConfigFile} ... other sources ...)
target_include_directories(MyLib
    PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src ${GeneratedFilesDir}
    PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)

Unlike using include_directories, this avoids all targets having ${GeneratedFilesDir} as an include path.


Things become more debatable when the generated file needs to be exposed as a public header, or added to an install command. Ultimately, I don't think there's a "wrong" option here. It boils down to whether you feel it's better to keep your source tree pristine at the expense of a more complicated CMake setup or not.

查看更多
登录 后发表回答