MSBuild, встроить препроцессор
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 01.11.21 14:02
Оценка:
В проекте (C#, собирается под разные платформы) образовалась критическая масса однотипных resx-файлов.

Отличия в сведениях о целевой платформе.

Решил все эти файлы гененировать в процессе компиляции, используя шаблон и препроцессор m4.

В перспективе нужно будет прикручивать другие правила, например простое копирование.

Задачу осилил, но кажется как-то криво.

Может кто подскажет лучший вариант. Ну или сам, описав проблему, допру как поправить

--- текущее решение
В проектный файл добавил описания дополнительных свойств для ресурсов

  <ItemDefinitionGroup>
   <EmbeddedResource>
     <LCPI_TemplateSource></LCPI_TemplateSource>
     <LCPI_TemplateRule></LCPI_TemplateRule>
   </EmbeddedResource>
  </ItemDefinitionGroup>


в LCPI_TemplateSource будет указываться файл с шаблоном
в LCPI_TemplateRule будет указывать правило обработки шаблона

Откорректировал описание ресурсов, файлы которых будут генерироваться в процессе компиляции:

    <EmbeddedResource Include="$(LCPI_BUILD_CFG__FOLDER__GEN)reg.resx" Link="resources\reg.resx">
      <LCPI_TemplateSource>template\reg.resx.m4</LCPI_TemplateSource>
      <LCPI_TemplateRule>M4</LCPI_TemplateRule>
    </EmbeddedResource>
    <EmbeddedResource Include="$(LCPI_BUILD_CFG__FOLDER__GEN)reg.ru.resx" Link="resources\reg.ru.resx">
      <LCPI_TemplateSource>template\reg.ru.resx.m4</LCPI_TemplateSource>
      <LCPI_TemplateRule>M4</LCPI_TemplateRule>
    </EmbeddedResource>


Физически они будут находиться в каталоге $(LCPI_BUILD_CFG__FOLDER__GEN). Этот путь генерируется с учетом целевой платформы и конфигурации проекта.

В дереве проекта они будут якобы находится в каталоге resources.

Указаны шаблоны и правило генерации 'M4'.

---
Далее определяем Target, формирующий список файлов, которые надо пропустить через M4

  <Target Name="BuildGeneratedItemList__M4" BeforeTargets="ProcessGeneratedItemList__M4" Returns="@(GeneratedItem__M4)">
    <ItemGroup>
      <GeneratedItem__M4 Include="%(EmbeddedResource.Identity)" Condition="'%(EmbeddedResource.LCPI_TemplateSource)' != '' and '%(EmbeddedResource.LCPI_TemplateRule)' == 'M4'">
       <LCPI_TemplateSource>%(EmbeddedResource.LCPI_TemplateSource)</LCPI_TemplateSource>
      </GeneratedItem__M4>
    </ItemGroup>
  </Target>


И наконец Target, который будет запускать прогонять шаблоны через m4.exe и сохранять результат в финальном файле

  <Target Name="ProcessGeneratedItemList__M4" BeforeTargets="CoreResGen">
    <Message Importance="High" Text="HELLO FROM ProcessGeneratedItemList__M4! File: %(GeneratedItem__M4.Identity). Source: %(GeneratedItem__M4.LCPI_TemplateSource)."/>

    <Exec
      Command="m4.exe -D &quot;M4_PROVIDER_PLATFORM=$(LCPI_UI_ProviderPlatform)&quot; -D &quot;M4_DDEX_PLATFORM=$(LCPI_UI_DDEXPlatform)&quot; -D &quot;M4_BUILD_CONFIGURATION=$(Configuration)&quot; &quot;%(GeneratedItem__M4.LCPI_TemplateSource)&quot;"
      WorkingDirectory="$(ProjectDir)"
      ConsoleToMsBuild="true"
      StdOutEncoding="UTF-8">
        <Output TaskParameter="ConsoleOutput" PropertyName="M4_OUTPUT" />
    </Exec>

    <WriteLinesToFile
      File="%(GeneratedItem__M4.Identity)"
      Lines="$(M4_OUTPUT)"
      Overwrite="true"
      WriteOnlyWhenDifferent="true" />
  </Target>


Работает, но есть заковырка.

Если в проекте нет элементов EmbeddedResource с заполненными {LCPI_TemplateSource, LCPI_TemplateRule}, то BuildGeneratedItemList__M4 все равно возвращает один элемент с пустыми полями.

Это не есть хорошо.

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