Re: MSBuild, встроить препроцессор
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 01.11.21 14:45
Оценка: 20 (1) +1
Здравствуйте, Коваленко Дмитрий, Вы писали:

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


КД>Это не есть хорошо.


КД>Но как победить — пока не догоняю...


Победил. И даже немного улучшил.

Нужно было посмотреть на количество элементов в GeneratedItem__M4 — Condition="@(GeneratedItem__M4->Count())>0"

  <ItemGroup>
    <GeneratedItem__M4 Include="@(EmbeddedResource->WithMetadataValue('LCPI_TemplateRule','M4'))" />
  </ItemGroup>

  <Target Name="ProcessGeneratedItemList__M4" BeforeTargets="CoreResGen" Outputs="%(GeneratedItem__M4.Identity)" Condition="@(GeneratedItem__M4->Count())>0">
    <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>

    <MakeDir
      Directories="$([System.IO.Path]::GetDirectoryName(%(GeneratedItem__M4.Identity)))"/>

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


Спасибо всем за помощь!

---
UPD1. Мне тут лайков за косячный код отсыпали .

Поправил ProcessGeneratedItemList__M4 — у него нужно еще Outputs="%(GeneratedItem__M4.Identity)" прописать, чтобы он правильно выполнял задачи над элементами. И MakeDir тоже не помешает.

В более правильном варианте, пришлось заменить Exec (и, до кучи, WriteLinesToFile) на свой Task для вызова m4.exe. Внезапно обнаружилось что Exec триммит результирующие строки, чем напрочь убивает форматирование.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Отредактировано 02.11.2021 4:31 DDDX . Предыдущая версия .
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 все равно возвращает один элемент с пустыми полями.

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

Но как победить — пока не догоняю...
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re: MSBuild, встроить препроцессор
От: Kolesiki  
Дата: 01.11.21 15:05
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Ну или сам, описав проблему, допру как поправить


Ну так мы так и не услышали саму проблему! Что именно такого неправильного в "однотипных файлах", что ты полез их препроцессить??
Re[2]: MSBuild, встроить препроцессор
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 02.11.21 04:43
Оценка:
Здравствуйте, Kolesiki, Вы писали:

КД>>Ну или сам, описав проблему, допру как поправить


K>Ну так мы так и не услышали саму проблему! Что именно такого неправильного в "однотипных файлах", что ты полез их препроцессить??


Их количество — 38 (19x2) штук.

Заменил на 2 шаблона (english, russian).

  reg.resx для n4_5_0-n4_6_2-Debug
  <data name="Provider_Description" xml:space="preserve">
    <value>LCPI ADO.NET provider for OLE DB data source.

Use this provider for connect to Firebird and InterBase databases through LCPI.IBProvider [OLE DB].

Data provider platform: FW4.5.0. DDEX provider platform: FW4.6.2. Debug assemblies.</value>
  </data>
  <data name="Provider_DisplayName" xml:space="preserve">
    <value>LCPI .NET Framework Data Provider for OLE DB [FW4.5.0][Debug]</value>
  </data>
  <data name="Provider_ShortDisplayName" xml:space="preserve">
    <value>OLE DB [LCPI][FW4.5.0][Debug]</value>
  </data>

  reg.resx для s2_0-n4_8_0-Debug
  <data name="Provider_Description" xml:space="preserve">
    <value>LCPI ADO.NET provider for OLE DB data source.

Use this provider for connect to Firebird and InterBase databases through LCPI.IBProvider [OLE DB].

Data provider platform: .Net Standard 2.0. DDEX provider platform: FW4.8.0. Debug assemblies.</value>
  </data>
  <data name="Provider_DisplayName" xml:space="preserve">
    <value>LCPI .NET Framework Data Provider for OLE DB [STD2.0][Debug]</value>
  </data>
  <data name="Provider_ShortDisplayName" xml:space="preserve">
    <value>OLE DB [LCPI][STD2.0][Debug]</value>
  </data>

  reg.resx для s2_0-n4_8_0-Release
  <data name="Provider_Description" xml:space="preserve">
    <value>LCPI ADO.NET provider for OLE DB data source.

Use this provider for connect to Firebird and InterBase databases through LCPI.IBProvider [OLE DB].

Data provider platform: .Net Standard 2.0. DDEX provider platform: FW4.8.0.</value>
  </data>
  <data name="Provider_DisplayName" xml:space="preserve">
    <value>LCPI .NET Framework Data Provider for OLE DB [STD2.0]</value>
  </data>
  <data name="Provider_ShortDisplayName" xml:space="preserve">
    <value>OLE DB [LCPI][STD2.0]</value>
  </data>

  шаблон reg.resx.m4
changequote([[, ]])
...
  <data name="Provider_Description" xml:space="preserve">
    <value>LCPI ADO.NET provider for OLE DB data source.

Use this provider for connect to Firebird and InterBase databases through LCPI.IBProvider [OLE DB].

Data provider platform: M4_PROVIDER_PLATFORM. DDEX provider platform: M4_DDEX_PLATFORM.ifelse(M4_BUILD_CONFIGURATION,[[Debug]],[[ Debug assemblies.]],)</value>
  </data>
  <data name="Provider_DisplayName" xml:space="preserve">
    <value>LCPI .NET Framework Data Provider for OLE DB [M4_PROVIDER_PLATFORM__SHORT]ifelse(M4_BUILD_CONFIGURATION,[[Debug]],[Debug],)</value>
  </data>
  <data name="Provider_ShortDisplayName" xml:space="preserve">
    <value>OLE DB [LCPI][M4_PROVIDER_PLATFORM__SHORT]ifelse(M4_BUILD_CONFIGURATION,[[Debug]],[Debug],)</value>
  </data>
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Отредактировано 02.11.2021 4:44 DDDX . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.