resgen и libpng

Разработка на C# под linux
 
resgen имеет привычку падать при компилировании файлов .resx в .resources
можно было бы создать другой проект (например nresgen), в который скопировать код из resgen, код из system.windows.forms для работы с форматом ResX для XML а так же добавить зависимость для библиотеки обработки .png-файлов, написанной на pure C# (вместо libpng работающей через interop)

Получится, что некоторые файлы (в частности /usr/bin/resgen) устанавливаются несколькими пакетами (пакетом mono и пакетом nresgen)
можно было бы написать модуль eselect для выбора одного из двух этих resgen

мне не ясно, как убрать предупреждение о том, что файл устанавливается двумя пакетами (ты сначала проверь, что то предупреждение действительно есть) обычно выдаваемое при установке второго пакета (collision)

Проапгрейженные либы

Я думал, что если обновить libpng и libgdiplus до последних версий (5.1.2 и 4.2 на 2016-02-19)
то возможно начнёт работать. Нет, не начинает

А можно ли заменить загрузку через unmanaged libpng на загрузку через pure C# библиотеку?
нельзя :) - https://github.com/leonbloy/pngcs/issues/12
ну то есть можно, но для этого надо прочитать RFC 2083
а потом реализовать код для заполнения пикселов в объекте класса Bitmap

Как заменить resgen в portage?

Как monodevelop запускает resgen ?
ну, он запускает msbuild или xbuild, а уже они запускают resgen

The tools in the Toolset that MSBuild defines come from the following sources:
  The .NET Framework folder.
   Additional managed tools.
The managed tools include ResGen.exe and TlbImp.exe.

утилиты сборки (xbuild и msbuild) читают узел ToolsVersion из файла-проекта ToolsVersion attribute on the Project element in the project file. затем ищут соответствующий toolset, где ищут - переопределяется из своего (утилиты) конфига, (а определяется в реестре (в windows). Где определяется в mono - неясно) You can modify the value of $(MSBuildToolsPath) by defining a custom Toolset.

MSBuild Toolset = https://msdn.microsoft.com/en-us/library/bb383796.aspx

When a ToolsVersion value is defined in a project file,
MSBuild uses that value to determine the values of the Toolset properties that are available to the project.

This behavior can be overridden by using the /ToolsVersion flag. When you build a solution on the command line and specify a ToolsVersion for msbuild.exe, all projects and their project-to-project dependencies are built according to that ToolsVersion, even if each project in the solution specifies its own ToolsVersion.

MSBuildToolsPath

One Toolset property is $(MSBuildToolsPath), which specifies the path of the .NET Framework tools. Only that Toolset property (or $(MSBuildBinPath)), is required.

MSBuild finds the Microsoft.CSharp.targets file by using the MSBuildToolsPath reserved property.

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

# pwd
/usr/lib64/mono
# grep -R "resgen" *
Binary file 4.5/resgen.exe.mdb matches
Binary file 4.5/resgen.exe matches
Binary file gac/Microsoft.Build.Tasks.Core/14.0.0.0__b03f5f7f11d50a3a/Microsoft.Build.Tasks.Core.dll.mdb matches
Binary file gac/Microsoft.Build.Tasks.v4.0/4.0.0.0__b03f5f7f11d50a3a/Microsoft.Build.Tasks.v4.0.dll.mdb matches
Binary file gac/Microsoft.Build.Tasks.v12.0/12.0.0.0__b03f5f7f11d50a3a/Microsoft.Build.Tasks.v12.0.dll.mdb matches

# find . -iname "xbuild.exe.config"
./xbuild/12.0/bin/xbuild.exe.config
./xbuild/14.0/bin/xbuild.exe.config
./4.5/xbuild.exe.config

You may define toolsets but not sub-toolsets in the configuration file.

configuration file for MSBuild.exe could include the following Toolset definition
if you wished to override the default behavior of ToolsVersion 12.0.

<msbuildToolsets default="12.0">
  <toolset toolsVersion="12.0">
    <property name="MSBuildToolsPath"
      value="C:\SpecialPath" />
  </toolset>
</msbuildToolsets>

ToolsetConfigurationSection is a custom configuration section
that can be used by any MSBuild host for custom configuration.
<msbuildToolsets> must also be defined in the configuration file, as follows.

<configSections>
  <section name="msbuildToolsets"
    Type="Microsoft.Build.BuildEngine.ToolsetConfigurationSection,
    Microsoft.Build.Engine, Version=12.0.0.0, Culture=neutral,
    PublicKeyToken=b03f5f7f11d50a3a"
  </section>
</configSections>

вот та строчка, которая получает точное месторасположение утилиты resgen.exe:

https://github.com/mono/mono/blob/0985d4aa4be4a9286db4e36cf75e3b18a31e5ff9/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/GenerateResource.cs#L382
  return ToolLocationHelper.GetPathToDotNetFrameworkFile (ToolExe, TargetDotNetFrameworkVersion.VersionLatest);

Sub-toolsets were introduced in the .NET Framework 4.5.

Sub-toolsets allow MSBuild to automatically switch which set of tools to use
based on the context in which the build is being run.
For example, MSBuild uses a newer set of tools when it's run in Visual Studio 2012
than when it's run in Visual Studio 2010,
without your having to explicitly change the project file.

During a build, MSBuild automatically determines and sets
a default value for the VisualStudioVersion property if it's not already defined.

Alternately, you can determine the Toolset programmatically by calling the methods of the
ToolLocationHelper class. The class includes these methods:
...
GetPathToDotNetFramework returns the path of the .NET Framework folder.
GetPathToDotNetFrameworkSdk returns the path of the managed tools folder.
GetPathToBuildTools returns the path of the build tools.

Sub-toolsets become active in the presence of the VisualStudioVersion build property.
This property may take one of these values:
ᰐ.0” specifies the .NET Framework 4 sub-toolset
ᰑ.0” specifies the .NET Framework 4.5 sub-toolset
ᰒ.0” specifies the .NET Framework 4.5.1 sub-toolset
Sub-toolsets 10.0 and 11.0 should be used with ToolsVersion 4.0.
In later versions, the sub-toolset version and the ToolsVersion should match.

MSBuild provides overloads for the ToolLocationHelper methods that add a VisualStudioVersion enumerated value as a parameter

https://github.com/mono/mono/blob/fa1cb5bbf426bfb7673f5f01ef0c2fc71fc25c8f/msvc/scripts/order.xml#L4473-L4482

https://github.com/mono/mono/tree/master/mcs/class/Microsoft.Build.Tasks
https://github.com/mono/mono/blob/master/mcs/class/Mono.XBuild.Tasks

Итого, для того, чтобы запустить другой resgen, он всё ещё должен называтся resgen.exe,
надо его положить в некую директорию
а директрию указать в конфиге xbuild
(а как же тогда /usr/bin/resgen ? получается на него сделан симлинк или как?)

# file /usr/lib64/mono/4.5/resgen.exe
/usr/lib64/mono/4.5/resgen.exe: PE32 executable (console) Intel 80386 Mono/.Net assembly, for MS Windows

допустим, что можно сделать отдельную директорию, наделать там симлинков
эту директорию положить в переменную MSBuildToolsPath
и во время сборки указывать эту версию утилит ключом командной строки

Пакет тогда просто установит эту директорию (хотя есть соблазн сделать это через overlayfs а не при помощи симлинков, но нет eclass-а для работы с overlayfs)

Вариант с ToolPath

Resgen является наследником от ToolTask, а у абстрактного класса ToolTask есть свойство ToolTask.ToolPath, которое вроде бы может быть присвоено из скрипта (почитать как это делается)
1. Create a custom ToolTask derived from Microsoft.Build.Utilities.ToolTask.
2. Create a UsingTask entry for it in your project. <UsingTask TaskName="MyTask" AssemblyFile="$(MSBuildThisFileDirectory).\MyTask.dll" />
3. Call the task in a target, providing the ToolPath. <Target><MyTask ToolPath="some/other/path/to/tool.exe"/></Target>
4. Execute the build script.

https://bugzilla.xamarin.com/show_bug.cgi?id=22981

Итого

1. Заменить через конфиг утилиты xbuild не получится, потому что реализация тасков не читает этот конфиг, а определяет месторасположение файлов по константам прошитым в коде ("не получится", а не "не получилось" было использовано потому что это догадка, а не результат эксперимента)
2. Указать ToolPath в месте вызова таска не получится, потому что таск ResGen вызывается напрямую из кода и ToolPath ему в месте вызова не устанавливается
https://github.com/mono/mono/blob/0985d4aa4be4a9286db4e36cf75e3b18a31e5ff9/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/GenerateResource.cs#L230-L245
можно пропатчить метод, так, что он начнёт проверять переменную окружения FULL_RESGEN_PATH и если она определена (и там есть такой файл), то значение этой переменной класть в свойство ToolPath а можно и просто путь прошить (/usr/bin/resgen), по этому пути считывать файл, выковыривать путь до правильного resgen из этого файла (RegExp-ом)