如何在CMake 3.7及更高版本中表达PGO依赖项?

ippsafx7  于 2023-03-02  发布在  Go
关注(0)|答案(1)|浏览(147)

我有一个C++程序,我正在用Clang 3.9的配置文件引导优化特性来构建它。
1.我构建的程序启用了插桩。
1.我运行该程序,创建一个包含配置文件数据的文件:prof.raw.
1.我使用llvm-profdataprof.raw转换为新文件prof.data

  • 我创建了同一程序新版本,但做了一些更改:
  • 在将每个. cpp文件编译为. o文件时,我使用编译器标志-fprofile-use=prof.data
  • 在链接可执行文件时,我还指定了-fprofile-use

我有一个Gnu Makefile,它工作得很好。我的问题出现了,现在我试图将该Makefile移植到CMake(3.7,但我可以升级)。我需要解决方案(至少)与Unix Makefile生成器一起工作,但理想情况下,它将适用于所有生成器。
在CMake中,我定义了两个可执行目标:foo-genfoo-use

  • 执行foo-gen时,它将创建prof.raw文件。
  • 我使用add_custom_command来创建一个规则,以便从prof.raw创建prof.data
    • 我的问题**是,我不知道如何告诉CMake foo-use所依赖的每个对象文件都对文件prof.data有依赖关系。
  • 我最有希望的想法是(1)找到一种方法来枚举foo-use依赖的所有.o文件,然后(2)迭代这些.o文件中的每一个,为每个文件调用add_dependency

这种方法的问题是,在我的CMakeLists.txt文件中找不到一种惯用的方法来枚举可执行文件所依赖的目标文件列表,这可能是be an open problem with CMake

这样做的问题(AFAICT)是我的每个.cpp文件都被用来创建两个不同的.o文件:一个用于foo-gen,另一个用于foo-use。我希望链接到foo-use.o文件在编译时对prof.data具有这种依赖性;但是链接到foo-gen中的.o文件必须 * 不 * 具有对prof.data的编译时依赖性。
AFAIK,set_source_files_properties不允许我将OBJECT_DEPENDS属性设置为两个值之一,这取决于当前感兴趣的目标是foo-gen还是foo-use
有什么建议,一个干净的(ish)方式,使这项工作?

o7jaxewo

o7jaxewo1#

讨论作者的想法#1

我最有希望的想法是(1)找到一种方法来枚举foo-use依赖的所有.o文件,然后(2)迭代这些.o文件中的每一个,为每个文件调用add_dependency
根据add_dependencies的文档,这不应该起作用,该文档指出:
使顶级依赖于***其他顶级目标***以确保它们在之前构建。
也就是说,你不能用它来使一个目标依赖于 * 文件 *-只能依赖于 * 其他目标 *。

讨论作者的想法#2

我还考虑过使用set_source_files_properties来设置foo-use使用的每个.cpp文件的OBJECT_DEPENDS属性,并将prof.data添加到该属性列表中。
这样做的问题(AFAICT)是我的每个.cpp文件都被用来创建两个不同的.o文件:一个用于foo-gen,另一个用于foo-use。我希望链接到foo-use.o文件在编译时对prof.data具有这种依赖性;但是链接到foo-gen中的.o文件必须不具有对prof.data的编译时依赖性。
AFAIK,set_source_files_properties不允许我将OBJECT_DEPENDS属性设置为两个值之一,这取决于当前感兴趣的目标是foo-gen还是foo-use
在评论部分,你提到如果OBJECT_DEPENDS支持生成器表达式,你可以解决这个问题,但是它不支持。作为一个旁注,有is an issue ticket tracking this on the CMake gitlab repo。你可以去给予它一个大拇指,并描述你的用例供他们参考。
在评论部分,你也提到了一个可能的解决方案:
潜在的其他解决方案a)双项目系统,其中主用户调用的项目将设置转发到第二个pgo项目,再次编译相同的设置。
实际上,您可以通过ExternalProject将其放入CMake项目中,使其成为生成的构建系统的一部分:使顶级项目 * 包含其自身 * 作为外部项目。可以向外部项目传递缓存变量以将其配置为-gen版本,并且顶级项目可以是-use版本。
从经验上讲,如果您以前从未手动调用或使用ExternalProject执行过任何操作,那么这是一个完全不同的长时间CMake文档阅读和挑剔会话的兔子洞,因此答案可能属于一个专门针对它的新问题。
这可以解决OBJECT_DEPENDS中没有生成器表达式的问题,但是如果您希望为顶层项目使用多配置,并且多配置配置中的一些配置不适用于PGO,那么您将回到起点。

拟定解决方案

以下是我发现的一些在配置文件数据更改时使源代码重新编译的方法:
1.向运行训练可执行文件并生成和重新格式化训练数据的自定义命令添加另一个COMMAND,该命令生成一个在注解中包含时间戳的c++头文件。
1.如果重新运行了培训,请将该标题包含在要重新编译的所有源代码中。
如果您希望支持非PGO构建,请将时间戳头 Package 在一个头中,该头检查它是否存在于__has_include中,并且仅在它存在时包含它。
我非常肯定,使用这种方法,CMake不会在概要文件数据上执行TU的依赖性检查,相反,这是生成的buildsystem的头文件依赖项跟踪所做的工作。在头文件中包含时间戳注解而不仅仅是“touch”的基本原理使用它来改变文件系统中的时间戳是因为生成的buildsystem可能通过文件内容而不是通过文件系统时间戳来检测改变。

建议解决方案的所有缺点

这种方法令人痛苦的明显缺点是,你需要给所有你想检查重新编译的.cpp文件添加一个头文件包含,这会产生几个问题(从最小到最严重):
1.从美学的Angular 看你可能不喜欢它。
1.这当然会为忘记包含新.cpp文件的头文件的人为错误打开一个漏洞。我不知道如何解决这个问题。一些编译器有一个标志,你可以使用它在每个源文件中包含一个文件,比如GCC的-include标志。然后你可以使用target_compile_options(<target> PRIVATE "SHELL:-include <path>")将这个标志添加到CMake目标中
1.您可能无法更改某些需要重新编译的源代码,例如您的库所依赖的来自第三方静态库的源代码。如果您使用ExternalProject,可以通过执行patch步骤来解决,但我不知道。
对于我的个人项目,#1和#2是可以接受的,#3碰巧不是一个问题。

相关问题