Closed bapho-bush closed 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):
VTable indices for 'IMemoryManager' (4 entries).
0 | IMemoryManager::~IMemoryManager() [complete]
1 | IMemoryManager::~IMemoryManager() [deleting]
2 | void IMemoryManager::AllocMemory()
3 | void IMemoryManager::FreeMemory()
Test::$vftable@:
| &Test_meta
| 0
0 | &Test::{dtor}
1 | &IMemoryManager::AllocMemory
2 | &IMemoryManager::FreeMemory
В rust переносим, вынеся все внутря в MemoryManagerVTable, т.к. :
| +--- (base class IMemoryManager)
| | {vfptr}
| +---
#[repr(C)]
struct MemoryManagerVTable {
dtor: usize,
#[cfg(target_family = "unix")]
dtor2: usize, // второй поинтер нужен только для имитации таблиц clang, а это случается только когда компилируем под unix
alloc_memory: unsafe extern "system" fn(&MemoryManager, *mut *mut c_void, c_ulong) -> bool,
free_memory: unsafe extern "system" fn(&MemoryManager, *mut *mut c_void),
}
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))
Я не могу найти, где прям четко написано это, но мое понимание такое, что 1С под виндой ждет скомпилированное только MSVC, а под linux соответственно clang или gcc
На сколько я помню, это в каком-то докладе говорилось техническом. По-моему в том, где рассказывали как потребление памяти анализируют. Там говорили, что они завязались на MSVC на винде и на gcс на лине. И ещё свой аллоктор используют, а не системный.
https://docs.rs/vtable/latest/vtable/
Мне кажется для vtable'ов нужно посмотреть в сторону этого крейта. Уж очень мне не нравится формирование vtable'ов по дизасму с годболта.
И ещё смущает, что для сборки не используется msvc-target. Как бы не было UB.
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.
Я в общем-то не против использования удобных макросов, просто самому пока что не охота заниматься этой частью. Но если будут пулл реквесты, я конечно же их приму
Не совсем понимаю проблему. Я опасаюсь, что это разные ABI. Что вопрос не только в vtable'ах в GNU и MSVC ABI.
Этот крейт не даст возможности строить VTable'ы, их всё так же придется переность "руками". Я попробовал, крейт так же не умеет работать с #[cfg(target_family = "unix")] префиксами, т.е. здесь даже не получится особо упроситить вид кода, т.к. придется иметь две разные структуры для разных ОС.
Про переносить "руками" - да, понимаю. Предложил ради остальных описанных трансформаций. Предполагал, что будут ещё полезности. Если нет - окей.
Еще одна проблема с этим крейтом в том, что он использует 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
т.к. нам нужен extern "system" для Windows:
Да, тогда и правда не подойдёт
Хочу задать пару вопросов так как сам когда-то хотел реализовать подобный шаблон: