我刚刚将一个有点大的项目从Visual解决方案迁移到了CMake,我注意到了一个奇怪的行为。我有如下结构:
project/CMakeLists.txt
project/code/CMakeLists.txt
project/code/library-1/CMakeLists.txt
project/code/library-1/*.hpp
project/code/library-1/*.cpp
project/code/library-2/CMakeLists.txt
project/code/library-2/*.hpp
project/code/library-2/*.cpp
...
project/code/library-n/CMakeLists.txt
project/code/library-n/*.hpp
project/code/library-n/*.cpp
project/demo/CMakeLists.txt
project/demo/demo-1/CMakeLists.txt
project/demo/demo-1/*.hpp
project/demo/demo-1/*.cpp
project/demo/demo-2/CMakeLists.txt
project/demo/demo-2/*.hpp
project/demo/demo-2/*.cpp
...
project/demo/demo-n/CMakeLists.txt
project/demo/demo-n/*.hpp
project/demo/demo-n/*.cppCMakeLists.txt文件配置编译标志、宏定义等,并使用CMake的add_subdirectory()包括由库和演示项目定义的目标。code子文件夹包含一个平面子文件夹列表,每个子文件夹都包含静态库的源代码(以及在CMakeLists.txt文件中定义的目标)。demo子文件夹包含一个扁平的子文件夹列表.每个文件都包含可执行文件和相关CMakeLists.txt文件的源代码。code子文件夹中的一个或多个不同的库。这个设置真的很不错。如果我想改变构建选项,我只需要修改根CMakeLists.txt,所有的东西都会用新的设置重新编译。如果我在树中的任何地方修改任何源代码,适当的库(如果有的话)将被重新编译,并且所有依赖的演示程序也会被重新构建。
但是,如果我在树中的任何地方修改任何CMakeLists.txt文件,那么整个库和程序树就会在不考虑依赖关系的情况下重新编译。为了理解我的意思,这里是CMake构建脚本的几个部分。
project/demo/CMakeLists.txt
# Resolve libraries built in `code` sub-folder.
link_directories(${LIBRARY_OUTPUT_PATH})
set(demo-projects
demo-1
demo-2
...
demo-n
)
foreach(demo-project ${demo-projects})
add_subdirectory(${demo-project})
endforeach()project/demo/demo-n/CMakeLists.txt
# Find all source code in the same folder.
file(GLOB ${demo-project}_headers
${CMAKE_CURRENT_SOURCE_DIR}/*.hpp
)
file(GLOB ${demo-project}_sources
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
)
# Select libraries to link with.
set(${demo-project}_libraries
library-1
library-2
library-5
)
# Build the demo program.
add_executable(${demo-project}
${${demo-project}_headers}
${${demo-project}_sources}
)
if(${demo-project}_libraries)
target_link_libraries(${demo-project} ${${demo-project}_libraries})
endif()
# Manually register some dependencies on other targets.
if(${demo-project}_dependencies)
add_dependencies(${demo-project} ${${demo-project}_dependencies})
endif()如果我碰巧修改了project/demo/demo-n/CMakeLists.txt以添加一个额外的库,如下所示:
set(${demo-project}_libraries
library-1
library-2
library-5
library-6
)然后,重新编译项目中所有库和演示程序的全部源代码。为何会这样呢?是否有更好的方法来构造我的脚本以避免这种情况?
发布于 2011-12-21 18:42:56
碰巧我的问题是由一个完全无关的问题引起的。我应用了比尔·霍夫曼的建议,项目中任何"CMakeLists.txt“文件的修改最终都会修改所有生成的Makefile中的CXX_FLAGS (C++编译器标志)变量。
我将其追溯到根目录"CMakeLists.txt“文件,该文件有如下内容:
if(MSVC)
# ...
set(CMAKE_CXX_FLAGS_DEBUG
"${CMAKE_CXX_FLAGS_DEBUG} /WX /wd4355" // depends on cached value.
CACHE STRING "Debug compiler flags" FORCE)
# ...
endif()我把它改成了下面的。
if(MSVC)
# ...
set(CMAKE_CXX_FLAGS_DEBUG
"/DWIN32 /D_WINDOWS /WX /wd4355" // no longer depends on cached value.
CACHE STRING "Debug compiler flags" FORCE)
# ...
endif()CMake在更新构建脚本时不再重复/WX /wd4355标志,而且我的项目不再在每次修改时从头开始重新编译!
发布于 2011-12-21 17:05:29
你要做的第一件事就是找出什么改变。如果您安装了git,您可以使用git来帮助您做到这一点。
发布于 2011-12-21 16:51:13
确实,如果任何CMakeLists.txt文件更改(或任何对其的输入,例如configure_file调用的“源文件”),那么CMake将在构建树的顶层重新运行,并重新生成已更改的解决方案文件和项目文件。
但是,它只应该重新生成与上次运行时不同的文件.因此,基于你在问题中所展示的,我并没有一个很好的解释为什么一切都在重建。
另一方面,当触发“构建解决方案”时,CMake确实要由Visual来决定重新构建什么。除了将源和头放在正确的项目中、正确设置包含目录以及信任VS在头和源文件更改时正确分析包含和重新构建之外,我们不表示VS的任何依赖关系。
您不显示任何include_directories调用。您是否在顶级CMakeLists.txt文件中设置了这些值,以便使所有子目录都具有相同的包含值?如果是这样的话,也许这就是引发一切重建的原因。
我们当然会尽最大努力使CMake生产出最少重建时间的构建系统。
你的项目公开了吗?我能看到它的完整源代码并尝试在我自己的机器上重现这个问题吗?
https://stackoverflow.com/questions/8479929
复制相似问题