Sebekerga / native_api_1c

Crate for simple implementation of Component for Native API 1C:Enterprise written in rust
https://crates.io/crates/native_api_1c
62 stars 13 forks source link

Вопросы по реализации - vtable и target #2

Closed bapho-bush closed 1 year ago

bapho-bush commented 1 year ago

Хочу задать пару вопросов так как сам когда-то хотел реализовать подобный шаблон:

  1. Как реализовали уход от MSVC? Мне казалось, что для этого нужно соблюдение MSVC ABI. Но Rust основан на clang, а значит там llvm ABI. Я знаю, что компилятор Rust умеет собирать под MSVC ABI, но я не вижу в Cargo.toml или readme информации о таргетах;
  2. На каких операционных системах пробовал собрать? И какие контексты – клиентский или серверный?
  3. Поскольку API у 1С реализовано через наследование с virtual’ами, мне казалось, что нужно самому писать vtable’ы, чтоб платформа конкретно вызовы обрабатывала. Но в то же время, для винды мне казалось, что сборка выглядит как просто вызов функций из стандартной DLL’ки. Можешь помочь разобраться в vtable’ах? Я посмотрел сорцы и увидел код с memorymanagervtable. И хотел бы уточнить: a. Почему target_family = unix? b. Структура vtable’ов – implementation defined для компиляторов C++. Почему именно такая структура?
bapho-bush commented 1 year ago

Из переписки:

image
Sebekerga commented 1 year ago

Вот оригинальный репозиторий, там автор тоже приводит пояснения: https://github.com/medigor/example-native-api-rs Также оттуда пример с VTable в различных компиляторах: https://godbolt.org/z/KM3jaWMWs

Хорошим примером будет реализация MemoryManagerVTable - относительно маленькой структуры. В C++ выглядит так:

class IMemoryManager
{
public:
    virtual ~IMemoryManager() {}
    virtual bool ADDIN_API AllocMemory (void** pMemory, unsigned long ulCountByte) = 0;
    virtual void ADDIN_API FreeMemory (void** pMemory) = 0;
};

Получить представление VTable удобно на godbolt (https://godbolt.org/z/WGWa5E49M):

[repr(C)]

pub struct MemoryManager { vptr: &'static MemoryManagerVTable, }


Я не могу найти, где прям четко написано это, но мое понимание такое, что 1С под виндой ждет скомпилированное только MSVC, а под linux соответственно clang или gcc ([_"In general, Clang is highly compatible with the GCC inline assembly extensions, allowing the same set of constraints, modifiers and operands as GCC inline assembly."_](https://clang.llvm.org/compatibility.html))
bapho-bush commented 1 year ago

Я не могу найти, где прям четко написано это, но мое понимание такое, что 1С под виндой ждет скомпилированное только MSVC, а под linux соответственно clang или gcc

На сколько я помню, это в каком-то докладе говорилось техническом. По-моему в том, где рассказывали как потребление памяти анализируют. Там говорили, что они завязались на MSVC на винде и на gcс на лине. И ещё свой аллоктор используют, а не системный.

bapho-bush commented 1 year ago

https://docs.rs/vtable/latest/vtable/

Мне кажется для vtable'ов нужно посмотреть в сторону этого крейта. Уж очень мне не нравится формирование vtable'ов по дизасму с годболта.

И ещё смущает, что для сборки не используется msvc-target. Как бы не было UB.

Sebekerga commented 1 year ago

A #[vtable] macro to annotate a VTable struct to generate the traits and structure to safely work with it.

Этот крейт не даст возможности строить VTable'ы, их всё так же придется переность "руками". Я попробовал, крейт так же не умеет работать с #[cfg(target_family = "unix")] префиксами, т.е. здесь даже не получится особо упроситить вид кода, т.к. придется иметь две разные структуры для разных ОС.

И ещё смущает, что для сборки не используется msvc-target

Не совсем понимаю проблему. Если вы собираете компоненту для работы под Windows, вам придется ее собрать, указав через --target целевую платформу. Это может быть x86_64-pc-windows-gnu, x86_64-pc-windows-msvc, i686-pc-windows-gnu или i686-pc-windows-msvc, неважно, т.к. VTable'ы в нашем случае строго прописаны и будут соответствовать таблицам msvc.

Edit

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

bapho-bush commented 1 year ago

Не совсем понимаю проблему. Я опасаюсь, что это разные ABI. Что вопрос не только в vtable'ах в GNU и MSVC ABI.

Этот крейт не даст возможности строить VTable'ы, их всё так же придется переность "руками". Я попробовал, крейт так же не умеет работать с #[cfg(target_family = "unix")] префиксами, т.е. здесь даже не получится особо упроситить вид кода, т.к. придется иметь две разные структуры для разных ОС.

Про переносить "руками" - да, понимаю. Предложил ради остальных описанных трансформаций. Предполагал, что будут ещё полезности. Если нет - окей.

https://docs.rs/vtable/latest/vtable/attr.vtable.html

image

Sebekerga commented 1 year ago

Еще одна проблема с этим крейтом в том, что он использует extern "C", но такое не подойдет, т.к. нам нужен extern "system" для Windows:

// из библиотеки 1С, types.h
#ifdef _WINDOWS
#define ADDIN_API __stdcall
#else
#define ADDIN_API
#endif //_WINDOWS
// из библиотеки 1С, IMemoryManager.h
class IMemoryManager
{
public:
    virtual ~IMemoryManager() {}
    virtual bool ADDIN_API AllocMemory (void** pMemory, unsigned long ulCountByte) = 0;
    virtual void ADDIN_API FreeMemory (void** pMemory) = 0;
};

для референса: https://doc.rust-lang.org/reference/items/external-blocks.html

bapho-bush commented 1 year ago

т.к. нам нужен extern "system" для Windows:

Да, тогда и правда не подойдёт