我有一个C++程序,我正在使用Clang 3.9的概要优化特性来构建它。
1.我构建了启用了插装的程序。
1.我运行了这个程序,创建了一个包含配置文件数据文件:prof.raw
.
1.我使用llvm-profdata
将prof.raw
转换为一个新文件prof.data
。
- 我创建了一个相同程序新版本,但做了一些更改:
- 在将每个.cpp文件编译为.o文件时,我使用编译器标志
-fprofile-use=prof.data
。 - 在链接可执行文件时,我还指定了
-fprofile-use
。
我有一个Gnu Makefile,它工作得很好。现在我的问题出现了,我试图将该Makefile移植到CMake(3.7,但我可以升级)。我需要解决方案与(至少)Unix Makefile生成器一起工作,但理想情况下,它将适用于所有生成器。
在CMake中,我定义了两个可执行目标:foo-gen
和foo-use
:
- 当执行
foo-gen
时,它会建立prof.raw
档案。 - 我使用
add_custom_command
来创建一个规则,以便从prof.raw
创建prof.data
。
我的问题是,我不知道如何告诉CMakefoo-use
所依赖的每个对象文件都依赖于文件prof.data
。 - 我最有希望的想法是:(1)找到一种方法来枚举
foo-use
依赖的所有.o
文件,然后(2)迭代这些.o
文件中的每一个,为每个文件调用add_dependency
。
这种方法的问题是,在我的CMakeLists.txt文件中,我找不到一种惯用的方法来枚举可执行文件所依赖的目标文件列表,这可能是be an open problem with CMake。
- 我还考虑使用
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
是当前感兴趣的目标。
有什么建议,一个干净的(ish)方式,使这项工作?
1条答案
按热度按时间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-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的头依赖项跟踪所做的工作。使用它来改变文件系统中的时间戳的一个问题是,生成的buildsystem可能通过文件内容而不是通过文件系统时间戳来检测改变。
建议解决方案的所有缺点
这种方法的一个令人痛苦的明显缺点是,您需要向所有要检查是否重新编译的.cpp文件添加一个头文件include。这可能会产生几个问题(从最不严重到最严重):
1.从美学的Angular 来看,你可能不喜欢它。
1.这无疑为人为错误打开了一个漏洞,即忘记包含新的.cpp文件的头文件。我不知道如何解决这个问题。
1.您可能无法更改某些需要重新编译的源代码,例如您的库所依赖的第三方静态库中的源代码。如果您使用
ExternalProject
,可以通过patch
步骤进行一些操作来解决问题,但我不知道。不幸的是,我不知道如何解决这些问题。对于我的个人项目,#1和#2是可以接受的,而#3恰好不是一个问题。