Здравствуйте, не получается загрузить, через CFFI, собственную dll.
Сам CFFI работает:
Загрузка системной dll.
CL-USER>
(cffi:load-foreign-library "user32.dll")
STYLE-WARNING: Undefined alien: "xor_int"
#<CFFI:FOREIGN-LIBRARY USER32.DLL-935 "user32.dll">
Тестовый вызов сишной функции:
CL-USER>
(cffi:foreign-funcall "strlen" :string "hello" :int)
5
Но при попытке загрузить собственную библиотеку (:search-path крутить пробовал, безуспешно, подсовывание dll в system32 тоже не работает):
(cffi:load-foreign-library "D:/AutLib.dll")Получаю:
Unable to load foreign library
(AUTLIB.DLL-944).
Error opening shared object "D:\\AutLib.dll":
193.
[Condition of type CFFI:LOAD-FOREIGN-LIBRARY-ERROR]
...
Backtrace:
0:
(CFFI::FL-ERROR "Unable to load foreign library (~A).~% ~A" #:AUTLIB.DLL-944 "Error opening shared object \"D:\\\\AutLib.dll\":\n 193.")
1:
(CFFI::REPORT-SIMPLE-ERROR #:AUTLIB.DLL-944 #<SIMPLE-ERROR "Error opening shared object ~S:~% ~A." {10030C4273}>)
2:
(CFFI::LOAD-FOREIGN-LIBRARY-PATH #:AUTLIB.DLL-944 "D:/AutLib.dll" NIL)
3:
((FLET CFFI::%DO-LOAD :IN CFFI::%DO-LOAD-FOREIGN-LIBRARY) #<CFFI:FOREIGN-LIBRARY AUTLIB.DLL-944> #:AUTLIB.DLL-944 "D:/AutLib.dll")
4:
(CFFI::%DO-LOAD-FOREIGN-LIBRARY "D:/AutLib.dll" NIL)
5:
(CFFI:LOAD-FOREIGN-LIBRARY "D:/AutLib.dll" :SEARCH-PATH NIL)
6:
(SB-INT:SIMPLE-EVAL-IN-LEXENV (CFFI:LOAD-FOREIGN-LIBRARY "D:/AutLib.dll") #<NULL-LEXENV>)
7:
(EVAL (CFFI:LOAD-FOREIGN-LIBRARY "D:/AutLib.dll"))Сама библиотека создана правильно вроде (все функции в extern "C" обёрнуты + _declspec(dllexport)) и в LispWorks, через FLI, отлично дёргается.
зависимости, компиляторы?
Зависимостей нет левых. В либе используются только стандартные сишные функции. Собираю с помощью VS2012, в принципе можно пересобрать с помощью minGW, который идёт вместе с QtCreator.
Собственно собрал с помощью gcc из поставки QtCreator:
C:\Windows\system32>g++ --version
g++ (GCC) 4.4.0
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Эффект тот же.
Сейчас собрал этот же код под Linux:norgat@ubuntu:~$ g++ --version
g++ (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2
Всё отлично заработало:
CL-USER> (cffi:load-foreign-library "~/libALib.so")
#<CFFI:FOREIGN-LIBRARY LIBALIB.SO-960 "libALib.so">
CL-USER> (cffi:foreign-funcall "xor_int" :int 1 :int 2 :int)
1
Интересно, где косяк с CFFI под Windows...
QtCreator? А в либе C++ ?
с CFFI косяк очень вряд ли, на самом деле
а SBCL какой, sbcl-win32-threads от Антона Коваленко?
Либа написана на C++, но реально там нету крестов, т.е. всё, что там внутри и торчит наружу можно переписать на чистом C(раньше там был заюзан STL, но потом был выкинут к чертям). Как уже говорилось, все внешние функции завёрнуты в extern "C".
sbcl-win32-threads от Антона Коваленко?Да, он.
Самое смешное, что под Linux тот же код (один в один, за исключением __declspec(dllexport)), собранный тем же QtCreator, отлично грузится через CFFI и работает, как и в винде, но из LispWorks с тамошним FFI. Может я что-то с путями поиска не то делаю и CFFI банально не видит мою либу?
> CFFI банально не видит мою либу?
Попытка открытия файлов диагностируется программой filemon из sysinternals.
В DllMain что-нибудь есть?Линковка с libstd++ какая? статическая/динамическая?
Если собрать с MSVC++ - работает?
Просто библиотеки на обычном Си грузит? Системные, как я понимаю - грузит.
Если написать тупо какой-нибудь helloworld.dll, скомпилировать тем же компилятором, и экспортировать оттуда одну функцию?
Короче, сдается проблема в линковке с libgcc и libstdc++
Системные грузит, мои - нет. Тест с простейшей dll делал.
header.h:
extern "C" {
_declspec(dllexport) int echo (int a);
}
source:
#include "header.h"
int echo (int a) { return a + 1; }
CFFI один фиг выдаёт 193 ошибку загрузки shared object'а. Компилировал MSVC ест. (про QtCreator вообще забудь, я им компилировать попробовал ради теста).
А вот в LispWorks всё работало опять же.
P.S. DllMain пустой у меня. Это кусок числодробилки, там нечего инициализировать.
P.S.S. Вообще говоря, мне это надоело и я переполз под Linux. Там CFFI работает отлично. Хотя понять почему вылезает эта проблема было бы не плохо.
Спасибо за наводку. Правда FileMon устарел, теперь предлагается использовать Process Monitor, но не суть важно.
SBCL к либе лезет.
Делает:
Имя операции -> Результат
QueryOpen -> SUCCESS
CreateFile -> SUCCESS
CreateFileMapping -> FILE_LOCKED_WITH_ONLY_READERS
CreateFileMapping -> SUCCESS
CloseFile -> SUCCESS
Т.е. с путями проблем нет как я понимаю.
Имхо проблема где-то в районе линковки со стандартной библиотекой. (то есть DLL то он находит, я вижу)
Если собирать с /TC (используем Си, а не C++) - она имхо отпадет. Если собрать с /MT (статическая линковка со стандартной библиотекой) - имхо тоже.
Кстати, какая винда?
То есть если бы проблемы была с SBCL - системные либы то тоже бы не грузились, и вообще, т.к. sbcl-win32-threads активно использует WinAPI, он бы просто не работал.
У меня вот проект на C++ тоже.
https://github.com/Lovesan/D3DWorkshop
Собираю MSVC++ - всё ништяк, и SBCL в том числе отлично всё грузит, естественно.
Может SBCL криво собран? Вот попробуй мою сборку:
https://dl.dropbox.com/u/5521262/sbcl-1.1.0.36.mswinmt.1201-284e340.msi
Про D3DW:
(in-package #:cl-user)(defpackage #:d3dw-app
(:use #:cl #:cffi)
(:export #:main))(in-package #:d3dw-app)(define-foreign-library ole32
(t (:default "ole32")))(define-foreign-library d3dw
(t (:default "D:/Dev/D3DW/D3DWorkshop/Bin/D3DW"))) ;; 0.1.1.1
(use-foreign-library ole32)(use-foreign-library d3dw)(defconstant cw-use-default #x80000000)(defcfun ("OleInitialize" ole-initialize
:convention :stdcall
:library ole32)
:int32
(reserved :pointer))(defcfun ("OleUninitialize" ole-uninitialize
:convention :stdcall
:library ole32)
:void)(defcfun ("D3DWCreateWindow" d3dw-create-window
:convention :stdcall
:library d3dw)
:int32
(width :uint)
(height :uint)
(x :uint)
(y :uint)
(parent :pointer)
(pp-out :pointer))(defun %iunknown-release (p)
(foreign-funcall-pointer
(mem-aref (mem-ref p :pointer) :pointer 2) (:convention :stdcall)
:pointer p
:uint32))(defun %id3dwwindow-show-dialog (p)
(let ((hr (foreign-funcall-pointer
(mem-aref (mem-ref p :pointer) :pointer 15) (:convention :stdcall)
:pointer p
:int32)))
(if (minusp hr)
(error "Failed to show dialog. HRESULT: ~8,'0X"
(logand #xFFFFFFFF hr))
T)))(defun %id3dwwindow-set-title (p title)
(let ((hr (foreign-funcall-pointer
(mem-aref (mem-ref p :pointer) :pointer 19) (:convention :stdcall)
:pointer p
(:string :encoding :utf-16/le) title
:int32)))
(if (minusp hr)
(error "Failed to set title. HRESULT: ~8,'0X"
(logand #xFFFFFFFF hr))
T)))(defun main ()
(when (minusp (ole-initialize (null-pointer)))
(error "Unable to initialize COM runtime"))
(unwind-protect
(with-foreign-object (pp-out :pointer)
(when (minusp (d3dw-create-window
cw-use-default
cw-use-default
cw-use-default
cw-use-default
(null-pointer)
pp-out))
(error "Unable to create ID3DWWindow"))
(let ((window (mem-ref pp-out :pointer)))
(unwind-protect
(progn
(%id3dwwindow-set-title window "Hello from SBCL!")
(%id3dwwindow-show-dialog window))
(%iunknown-release window))))
(ole-uninitialize)))Кстати, есть еще один вариант.Какая винда, я имею ввиду, 64 бит или нет? И какие, соответственно, версии битности SBCL, и библиотеки?
/TC /MT есть. Сейчас попробуй твой проект собрать и загрузить, посмотрим что получится.
Винда - W7 x64. SBCL x86_64, либа x86.
Ах, смена SBCL на твою помогла, теперь моя либа грузится.
Собственно сборка, с которой Не работало: sbcl-1.1.0.36.mswinmt.1201-284e340-x86-64
Брал тут: https://github.com/akovalenko/sbcl-win32-threads/wiki
О, ну я так и думал.
Я имею ввиду, x86-64 SBCL и x86-библиотека. Битность разная. Кстати, моя либа, если говорить о файлах проекта MSVC++ - тоже x86. Но ее, разумеется, можно и под x64 скомпилить, достаточно 64-битного компилятора MSVC++, и создания конфигурации под x64 в студии.
Если x86-64 версию своей либы собрать? Ну или взять x86 SBCL чтобы использовать x86 библиотеку.
А LW почему работает - так он в бесплатной версии(я так понимаю, именно она юзается) - только 32-битный.
Соответственно, либу, которая тоже 32-бит - отлично грузит.
К 64-битной программе 32-битную либу прилинковать нельзя.
Ну я так и думал, как я уже сказал - просто битность разная.
Моя сборка SBCL - x86, то есть 32 бит. А у тебя была x64.
Соответственно, ответ на то, почему под линуксом работает.Под линуксом GCC по дефолту компилирует под ту платформу, на которой работает.
То есть, и SBCL там 64 бит, и твоя либа получается 64 бит, и все нормально.
А если бы разрядности не совпадали, тоже не грузилось бы.
И кстати насчет системных либ. Системные библиотеки на винде существуют в двух вариантах - для 32 бит, и для 64 бит. Чтобы можно было запускать программы и для x86 и для x86-64.Но, это два параллельных мира(32 и 64), и они никак между собой не взаимодействуют, кроме как через IPC только если.
На линуксе то же самое.