Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/cmake/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
尝试使用CMake触发最小重建并设置\u源文件\u属性_Cmake - Fatal编程技术网

尝试使用CMake触发最小重建并设置\u源文件\u属性

尝试使用CMake触发最小重建并设置\u源文件\u属性,cmake,Cmake,我将我的问题隔离到一个非常小的两个源项目: 我试图做的是在version.c中没有硬编码的版本号,而是从外部变量将版本号输入到构建过程中。请参阅s/build了解我的构建过程:如果定义了$VERSION,我希望它是程序打印的版本号。我通过在shell中执行命令VERSION=1.2s/build来实现这一点(或者,如果版本未定义,则使用git中最新的标记) 问题是我运行了cmake-DVERSION=$VERSION每次构建时,都会重新创建生成文件,这会导致完全重建。我只想重建version.o

我将我的问题隔离到一个非常小的两个源项目:

我试图做的是在version.c中没有硬编码的版本号,而是从外部变量将版本号输入到构建过程中。请参阅s/build了解我的构建过程:如果定义了$VERSION,我希望它是程序打印的版本号。我通过在shell中执行命令VERSION=1.2s/build来实现这一点(或者,如果版本未定义,则使用git中最新的标记)

问题是我运行了
cmake-DVERSION=$VERSION
每次构建时,都会重新创建生成文件,这会导致完全重建。我只想重建version.o,因为它是唯一依赖于版本号的源文件。构建main.o(在实际项目中,其他对象也是如此)是不必要的。我最初使用的是add_定义,它会将-D compile开关添加到每个源代码中,我认为set_source_files_properties是解决这个问题的方法,但是由于两个对象文件都是由build/CMakeFiles/version.dir/build.make中生成的相同Makefile生成的,这会被cmake过程所触及。似乎在安全方面犯了错误,只是重建了一切


也许我完全找错了方向,只是没有找到正确的CMake命令,我不知道。也许还有其他的,被证实的方法来实现我的目标?在这一点上,我花了这么多时间在这上面,我不羞于寻求帮助。

我找到了解决这一问题的方法。这里的根本问题是CMake为每个库或可执行目标创建一个Makefile,因为我的代码只有一个目标,所以每次都会触及该Makefile。因此,答案是为version.c创建一个库目标

add_library(version OBJECT version.c)
add_executable(hello main.c $<TARGET_OBJECTS:version>)

这不是什么大问题,但有点烦人。

这似乎是CMake
Unix Makefile
生成器中的一个bug。我使用
Ninja
生成器尝试了您的(原始)代码示例,如果您只更改版本号,
Ninja
可以避免重建
main.c

在您的情况下,您不需要每次都重新配置。编写生成/构建环境后,问题可以简化为一个简单的“文件是否已更改”问题,由
make
本身检查

因此,我可能只会在构建脚本中生成
version.c
(并将此文件添加到
.gitignore
,或者直接将其生成到
build
目录中):

s/build

#/垃圾箱/垃圾箱
如果[-z“$VERSION”];然后
版本=$(git描述--标记--匹配“v*”)
如果[-z“$VERSION”];然后
版本=1.0.0
fi
fi
echo“constchar*version(void){return\“${version}\”;}”>version.c~
如果cmake-E比较文件version.c~version.c
然后
cmake-E删除版本.c~
其他的
cmake-E重命名version.c~ version.c
fi
如果![-d构建];然后
cmake-E生成目录
cmake-H.-Bbuild
fi
cmake——构建
CMakeLists.txt

cmake_最低要求(2.8版)
项目(C版)
添加_可执行文件(version.c main.c)
version.c

constchar*版本(void){返回“1.0.0”;}
main.c

#包括“stdio.h”
常量字符*版本(无效);
真空总管(真空){
put(version());
}

如果解析实际字符串而不是环境变量,是否也会发生这种情况?有时你所要做的就是向某人解释你的问题,突然你的大脑想出了一个解决方案。我在回答我自己的问题。代码应该在问题本身,而不是链接。由于你有这么小的文件,我认为没有理由不把它们包括在问题中。至于这个问题,有很多关于SO的问题,它们倾向于在构建阶段重新生成版本文件,而不是将其传递到
cmake
。这个方法适用于你吗?我不知道这个规则,但我知道它是如何防止链接腐烂的,可能是一个好方法。我觉得包含30-40行代码会让阅读变得更加困难,拥有一个任何人都可以克隆的github项目更方便。我觉得添加库(…对象…)是CMake 2.8.8的一项功能,而Ubuntu Precise(我们的CI builder)只有2.8.7。叹气。升级到一个更新的CMake可能非常值得努力;在更新的CMAKE中有很多很好的功能和错误修复。遗憾的是,我只限于Ubuntu Precise中的功能,因为Travis CI就是这样使用的。要求他们升级比它的价值更麻烦,只要我绝对不需要这些功能或错误修复。我敢肯定,他们最终会升级他们的docker图像。我可以等。我听说过忍者的好消息,但从来没有仔细研究过。Makefiles只是最通用的构建块,所以我没有强烈的欲望进行更改。ninja生成器可能会以不同的方式构造其输出,并且不会遇到与Makefile生成器相同的问题(我甚至不会称之为bug,只是一个实现细节)。但是谢谢你的检查!有趣。我不认为我们可以完全摆脱version.c文件,因为我们的VisualStudio构建(它不关心版本号是否正确,也不使用bash脚本来运行git),但这里肯定有我应该能够使用的东西。例如,我不知道cmake-E。谢谢@埃诺,不客气。您还可以做的一件事是将
version.c
创建转换为可以使用
CMake-P
调用的CMake脚本。这样做的好处是,这些脚本是独立于平台的,而且CMake无论如何都可以在主机系统上使用。在我的环境中,我使用这样的脚本作为预链接步骤,因为我们添加了用户信息和
add_library(version version.c)
add_executable(hello main.c)
target_link_libraries(hello version)