Сборка и использование C# wrapper'а грамматического движка в Ubuntu с .NET Core

Sep 12, 2017 20:57

Предисловие: wchar_t в API есть зло

При разработке C API под Win и Linux всегда следует помнить, что фактический размер wchar_t не гарантируется стандартом, даже в рамках одной платформы, и разными компиляторами может реализовываться по-разному. Поэтому нет ничего удивительного, что wchar_t для gcc под Linux - это 4 байта, а для штатного компилятора в VisualStudio - 2 байта (https://en.wikipedia.org/wiki/Wide_character).

Для удобства вызова API из C++ кода я все процедуры, принимающие или возвращающие строки, объявлял с wchar_t* в сигнатурах. Если стартовать проект сейчас, то я бы подумал насчет char16_t в C++11, но грамматический движок писался раньше, так что wchar_t на тот момент выглядел естественно. В общем, код на C++, которому нужна обработка текста, выделял у себя wchar_t* блок, затем дергал процедуру в  solarix_grammar_engine.(dll|so) и все работало прозрачно. Ну или второй вариант заключался в дополнительных процедурах, принимающих или отдающих utf-8 строки, что было более удобно для Linux.

К чему это привело в .NET Core PInvoke под Linux? Чтобы вызвать процедуру в неуправляемом коде, на входе которой нужна строка, мы должны описать правило маршалинга из System.String в соответствующий C-тип. Для  преобразования в массив 16-битных символов, точнее говоря в UTF-16 с возможными суррогатными парами, есть стандартное правило, которое отлично справляется с преобразованием в wchar_t* под Windows, поскольку по обеим сторонам присутствуют 2-байтные символы в utf16. А вот для преобразования из System.String в массив 4-байтных wchar_t готового правила маршалинга я не нашел, да и вряд ли оно будет простым, учитывая нюансы перекодирования UTF16 в UTF32 и обратно.

В итоге враппер под Linux использует варианты процедур с представлением строк в кодировке utf-8, а для Windows остается штатный вариант с дефолтным маршалингом.

Использование .NET Core под Ubuntu

Перед использованием матриала установите .NET Core на свою систему. Для Ubuntu это делается предельно просто, через скачивание дистрибутива и запуск инсталяции. У меня на Ubuntu 16.04 все прошло без дополнительных вопросов. Подробности можно найти
тут https://www.microsoft.com/net/core.

Теперь сборка запчастей.

Сначала надо скомпилировать динамическую библиотеку solarix_grammar_engine.so (это plain C api) и установить ее в нужное место в системе, создав синонимы, примерно так:

cp solarix_grammar_engine.so /usr/lib64
rm -f /usr/lib64/libgren.so
rm -f /usr/lib64/libgren.so.1
rm -f /usr/lib64/libgren.so.1.0
ln -s /usr/lib64/solarix_grammar_engine.so /usr/lib64/libgren.so
ln -s /usr/lib64/solarix_grammar_engine.so /usr/lib64/libgren.so.1
ln -s /usr/lib64/solarix_grammar_engine.so /usr/lib64/libgren.so.1.0

Сборка .NET wrapper

Далее нужно подготовить проект для сборки .NET wrapper, который позволит вызывать динамическую библиотеку C API из C# через механизм PInvoke. Идем в папку /home/eek/Solarix/GrammarEngine/src/demo/ai/solarix/engines/grammar_engine_fx. Там лежит исходный текст враппера Grammar_Engine_fx.cs и готовый проект для сборки под Linux gren.ubuntu.csproj. Другой файл проекта нужен для win-версии сборки под старый .NET Framework. Чтобы он не путался под ногами и не вызывал жалобы у команды dotnet, лишние проекты из этой папки лучше удалить.

Просим NuGet подкачать и установить все необходимые компоненты .NET Core (по поводу команды dotnet и того, что она делает, читайте официальное руководство тут: https://docs.microsoft.com/ru-ru/dotnet/core/tutorials/using-with-xplat-cli):

dotnet restore

Теперь можно проверить, что враппер скомпилируется:

dotnet build

Успешное построение выглядит так:



Сборка финальной программы

Ок, теперь перейдем в папку с консольной программой на C#, которая будет использовать грамматический движок через .NET обертку:

cd ../../Grammar_Engine/SimpleGREN_FX

Там лежит файл Program.cs и проект SimpleGREN_FX.csproj.
Вы можете пересоздать проект с нуля командой:

dotnet new console

Но при этом файл Program.cs будет затерт, так что либо используйте мой проект, либо восстановитте потом Program.cs.

Просим Nuget восстановить необходимые компоненты:

dotnet restore

И добавляем ссылку на .NET Wrapper:

dotnet add SimpleGREN_FX.csproj reference ../../engines/grammar_engine_fx/gren.ubuntu.csproj

Собираем программу и запускаем:

dotnet run

Вы увидите в консоли что-то типа этого:


api, грамматический словарь, исходники, c

Previous post Next post
Up