Как выразить зависимости PGO в CMake 3.7?

У меня есть программа на C++, которую я создаю с помощью функции оптимизации профиля Clang 3.9. Вот что должно произойти:

  1. Я строю программу с включенными инструментами.
  2. Я запускаю эту программу, создавая файл с данными профиля: prof.raw,
  3. я использую llvm-profdata преобразовать prof.raw в новый файл, prof.data,
  4. Я создаю новую сборку этой же программы с несколькими изменениями:
    • При компиляции каждого файла.cpp в файл.o я использую флаг компилятора -fprofile-use=prof.data,
    • При связывании исполняемого файла я также указываю -fprofile-use,

У меня есть Gnu Makefile для этого, и он прекрасно работает. Моя проблема возникает сейчас, когда я пытаюсь портировать этот Makefile на CMake (3.7, но я могу обновить). Мне нужно решение для работы (по крайней мере) с генератором Makefiles Unix, но в идеале оно будет работать для всех генераторов.

В CMake я определил две исполняемые цели: foo-gen а также foo-use:

  • когда foo-gen выполняется, это создает prof.raw файл.
  • я использую add_custom_command создать правило для создания prof.data от prof.raw,

Моя проблема в том, что я не могу понять, как сказать CMake, что каждый из объектных файлов зависит от foo-use имеет зависимость от файла prof.data,

  • Самая многообещающая идея, которую я имел, состояла в том, чтобы (1) найти способ перечислить все .o файлы, на которых foo-use зависимости, а затем (2) перебрать каждый из этих .o файлы, звонящие add_dependency для каждого.

    Проблема с этим подходом состоит в том, что я не могу найти идиоматический способ, в моем файле CMakeLists.txt, перечислить список объектных файлов, от которых зависит исполняемый файл. Это может быть открытой проблемой с CMake.

  • Я также подумал об использовании set_source_files_properties установить OBJECT_DEPENDS недвижимость на каждом из моих .cpp файлы, используемые foo-use, добавив prof.data в список этого свойства.

    Проблема с этим (AFAICT) заключается в том, что каждый из моих .cpp файлы используются для создания двух разных .o файлы: один для foo-gen и один для foo-use, Я хочу .o файлы, которые связаны в foo-use иметь эту зависимость во время компиляции от prof.data; но .o файлы, которые связаны в foo-gen не должен зависеть от времени компиляции prof.data,

    И AFAIK, set_source_files_properties не позволяет мне установить OBJECT_DEPENDS свойство иметь одно из двух значений, в зависимости от того, foo-gen или же foo-use текущая цель интереса.

Какие-нибудь предложения для чистого (ish) способа сделать эту работу?

1 ответ

Обсуждение авторской идеи №1

Самая многообещающая идея, которая у меня была, состояла в том, чтобы (1) найти способ перечислить все файлы, от которых зависит, а затем (2) перебрать каждый из этих файлов, вызвавдля каждого.

Это не должно работать в соответствии с документацией дляadd_dependencies, в котором говорится:

Делает верхний уровень зависимым от других целей верхнего уровня , чтобы убедиться, что они строятся раньше.

Т.е. Вы не можете использовать его, чтобы цель зависела от файлов — только от других целей .

Обсуждение авторской идеи №2

Я также рассматривал возможность использования set_source_files_properties для установки свойства для каждого из моих файлов, используемых , добавляя в список этого свойства.

Проблема с этим (AFAICT) в том, что каждый из моихfiles используется для создания двух разных файлов: одного для и одного для . Я хочу, чтобы файлы, на которые ссылаются, имели эту зависимость времени компиляции от ; нофайлы, на которые ссылаются, не должны иметь зависимости во время компиляции от.

И, как ни крути,не позволяет мне установить для свойства одно из двух значений в зависимости от того,илиявляется текущей интересующей целью.

В разделе комментариев вы упомянули, что могли бы решить эту проблему, если бы поддерживали выражения генератора, но это не так. В качестве примечания: в репозитории CMake gitlab есть отслеживание проблемы. Вы можете поставить лайк и описать свой вариант использования для справки.

В разделе комментариев вы также упомянули возможное решение этой проблемы:

Возможное другое решение: а) система двойного проекта, в которой основной пользователь, вызываемый проектом, пересылает настройки второму проекту pgo, снова компилируя те же настройки.

На самом деле вы можете поместить это в проект CMake, чтобы он стал частью сгенерированной системы сборки: сделайте так, чтобы проект верхнего уровня включал себя как внешний проект. Внешнему проекту можно передать переменную кэша, чтобы настроить его какверсия, а верхний уровень может бытьверсия.

Говоря по опыту, это совсем другая кроличья нора, состоящая из длинных сеансов чтения и проверки документации CMake, если вы никогда раньше не вызывали и не делали ничего с этим вручную, поэтому этот ответ может относиться к новому вопросу, посвященному ему.

Это может решить проблему отсутствия выражений генератора в, но если вы хотите иметь мультиконфиг для проекта верхнего уровня и чтобы некоторые конфиги в мультиконфиге не были для PGO, то вы вернетесь к исходной точке.

Предложенное решение

Вот что я нашел, чтобы заставить исходники перекомпилировать при изменении данных профиля:

  1. К пользовательской команде, которая запускает исполняемый файл обучения, создает и переформатирует данные обучения, добавьте еще однукоторый создает заголовочный файл С++, содержащий метку времени в комментарии.
  2. Включите этот заголовок во все исходники, которые вы хотите перекомпилировать, если обучение было повторено.

Если вы хотите поддерживать сборки без PGO, оберните заголовок временной метки в заголовок, который проверяет его существование с помощьюи включает его только в том случае, если он существует.

Я почти уверен, что при таком подходе CMake не выполняет проверку зависимостей TU от данных профиля, и вместо этого это работает отслеживание зависимостей заголовков сгенерированной системы сборки. Обоснование включения комментария временной метки в заголовочный файл вместо того, чтобы просто «прикоснуться» к нему для изменения временной метки в файловой системе, заключается в том, что сгенерированная система сборки может обнаруживать изменения по содержимому файла, а не по временной метке файловой системы.

Все недостатки предлагаемого решения

До боли очевидная слабость этого подхода заключается в том, что вам нужно добавить заголовок во все файлы .cpp, которые вы хотите проверить на повторную компиляцию. Из этого может возникнуть несколько проблем (от наименее до наиболее вопиющих):

  1. Возможно, вам это не понравится с эстетической точки зрения.

  2. Это, безусловно, открывает дыру для человеческой ошибки, если вы забываете включить заголовок для новых файлов .cpp. Я не знаю, как это решить.В некоторых компиляторах есть флаг, который можно использовать для включения файла в каждый исходный файл, например, в GCC. флаг. Затем вы можете просто добавить этот флаг к цели CMake, используяtarget_compile_options(<target> PRIVATE "SHELL:-include <path>")

  3. Возможно, вы не сможете изменить некоторые исходные коды, которые необходимо перекомпилировать, например исходные коды из сторонних статических библиотек, от которых зависит ваша библиотека. Могут быть обходные пути, если вы используетеделая что-то сшаг, но я не знаю.

Для моего личного проекта приемлемы #1 и #2, а #3 не является проблемой.

К стандартному модулю PGO CMake

См. https://gitlab.kitware.com/cmake/cmake/-/issues/19273 .

Другие вопросы по тегам