В некоторых уроках LLVM я видел, где это довольно легко связать функцию C с пользовательским языком, основанным на LLVM. LLVM передает программисту указатель на функцию, которая затем может быть смешана с кодом, генерируемым LLVM.
Какой лучший способ сделать это с C ++ библиотеки. Позвольте скажем, у меня есть довольно сложная библиотека, такая как Qt или Boost, которую я хочу привязать к своему пользовательскому языку. Нужно ли создавать библиотеку-заглушку (как требуют Python или Lua), или LLVM предлагает какой-то интерфейс сторонних функций (FFI)?
В моем LLVM-коде я создаю extern "C"
функции-обертки для этого, и вставляю объявления LLVM-функций в модуль, чтобы вызвать их. Затем, хороший способ заставить LLVM узнать о функциях - не позволять ему использовать dlopen
и искать имя функции в исполняемом двоичном файле (это боль в заднице, поскольку имена функций должны быть в секции .dynsym
, и это тоже медленно), а сделать отображение вручную, используя ExecutionEngine::addGlobalMapping.
Просто получите llvm::Function*
этого объявления и адрес функции, который в C++ задается &functionname
, преобразованным в void*
, и передайте эти две вещи LLVM. Тогда JIT, выполняющий ваш материал, будет знать, где найти эту функцию.
Например, если вы хотите обернуть QString
, вы можете создать несколько функций, которые создают, уничтожают и вызывают функции такого объекта
extern "C" void createQString(void *p, char const*v) {
new (p) QString(v); // placement-new
}
extern "C" int32_t countQString(void *p) {
QString *q = static_cast<QString*>(p);
return q->count();
}
extern "C" void destroyQString(void *p) {
QString *q = static_cast<QString*>(p);
q->~QString();
}
И создать соответствующие объявления и отображение. Затем вы можете вызывать
эти функции, передавая область памяти, соответствующим образом выровненную и размерную для QString
(возможно, alloca
'ed) и i8*
, указывающую на данные строки C для инициализации.
Если вы скомпилируете часть кода на C++ и часть на другом языке в биткод LLVM, должно быть вполне возможно связать их вместе и позволить одному вызывать другой... в теории.
На практике вам понадобится код для преобразования типов разных языков (например, в C++ нет эквивалента строки Python, если вы не используете CPython, поэтому для того, чтобы void reverse(std::string s)
можно было вызвать с помощью str
, необходимо преобразование - хуже того, вся объектная модель сильно отличается). И конкретно в Qt есть много магии, которая может потребовать гораздо больше усилий для раскрытия после компиляции. Кроме того, могут быть и другие потенциальные проблемы, о которых я не знаю.
И даже если это работает, это потенциально очень некрасиво в использовании. В PyQt все еще есть get*
и set*
функции, несмотря на очень удобные дескрипторы Python - и в PyQt было приложено много усилий, они не просто создали какие-то заглушки.