如何在CMake 3.7中表达PGO依赖关系?

ffscu2ro  于 2022-11-11  发布在  Go
关注(0)|答案(1)|浏览(197)

我有一个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-genfoo-use是当前感兴趣的目标。
有什么建议,一个干净的(ish)方式,使这项工作?

6yoyoihd

6yoyoihd1#

讨论作者的想法#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-genfoo-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的头依赖项跟踪所做的工作。使用它来改变文件系统中的时间戳的一个问题是,生成的buildsystem可能通过文件内容而不是通过文件系统时间戳来检测改变。

建议解决方案的所有缺点

这种方法的一个令人痛苦的明显缺点是,您需要向所有要检查是否重新编译的.cpp文件添加一个头文件include。这可能会产生几个问题(从最不严重到最严重):
1.从美学的Angular 来看,你可能不喜欢它。
1.这无疑为人为错误打开了一个漏洞,即忘记包含新的.cpp文件的头文件。我不知道如何解决这个问题。
1.您可能无法更改某些需要重新编译的源代码,例如您的库所依赖的第三方静态库中的源代码。如果您使用ExternalProject,可以通过patch步骤进行一些操作来解决问题,但我不知道。
不幸的是,我不知道如何解决这些问题。对于我的个人项目,#1和#2是可以接受的,而#3恰好不是一个问题。

相关问题