libevent: как её прилинковать к проекту под Windows?

162
16 февраля 2018, 19:27

Господа, у меня серьезный и важный вопрос, над которым я бьюсь головой об клавиатуру уже больше недели. Я даже готов обсудить вознаграждение тому, кто мне поможет. Вопрос такой: надо меня научить правильно ставить галочки в настройках линкера под VS 2015, чтобы у меня библиотека libevent линковалась к проекту на c++ (и, возможно, правильно билдить эту библиотеку).

Предыстория вопроса: я прочитал пару мотивирующих статей насчет библиотеки libevent (напрмер, эту: https://habrahabr.ru/post/217437/ ). Начал я с того, что сделал девелоперскую машину под Ubuntu 16 LTS, куда поставл g++ и собрал библиотеку из исходников по иструкциям с гитхаба. ( https://github.com/libevent/libevent ) Потом я написал простую программу test.cpp, в которой попробовал инициализировать библиотеку:

#include <memory>
#include <cstdint>
#include <iostream>
#include <evhttp.h>
#include <string>
#include <fstream>
using namespace std;
int main(){
cout<< "Hi!" << endl ;
if ( !event_init()) 
  cout << "Failed to init libevent." << endl;
else
  cout << "libevent init successfully!" << endl;

return 0;
}

После небольшого замешательства я нормально собрал эту программу командой g++ -std=c++11 -o test.ex test.cpp -levent и запустил её. ./test.ex Всё работает. Это пркрасно. Затем я переписал из примеров немного более сложный пример... Но как только я начал писать сам - мне понадобилась отладка. И родная для меня система в этом смысле - Windows. Ну, вы понимаете... родственников не выбирают...

А под Windows все совсем не так гладко. Во первых, нужно собрать библиотеку из исходников. По инструкции я делаю это при помощи CMake:

"CMake (Windows)
Install CMake: http://www.cmake.org
 $ md build && cd build
 $ cmake -G "Visual Studio 10" ..   # Or whatever generator you want to use
 $ start libevent.sln"

Cmake при сборке ругается на отсутствие OpenSSL, и тут уже не помогают никакие танцы с бубнами: чтобы использовать OpenSSL под виндой, надо определить три магические переменные окружения

OPENSSL_ROOT_DIR
OPENSSL_INCLUDE_DIR
OPENSSL_CRYPTO_LIBRARY

а как эти переменные определять - не написано нигде. К счастью, если закрыта дверь - можно проверить окно... libevent позволяет собрать себя без поддержки OpenSSL, дописыванием ключика -DEVENT__DISABLE_OPENSSL=on, то есть командой cmake -DEVENT__DISABLE_OPENSSL=on -G "Visual Studio 14 2015" Меня, правда, немного смущают некоторые предупреждения, которые написала мне эта команда, её вывод видно здесь: Но *.sln файл создаётся, и после запуска компиляции я получил набор *.lib - файлов в директории Debug: event.lib, event_core.lib, event_extra.lib. А вот потом начались проблемы. Никакие пляски с бубном не позволяют мне прилинковать эти библиотеки к C++ проекту. Для полноты картины: в моей системе путь к этим *.lib файлам - это C:\Programs\includes\libevent\lib\Debug я засобывал их сюда: и сюда: и сюда: и даже сюда:

При последней попытке создалась иллюзия того, что что то получилось. то есть проект нормально собрался. Но при запуске я мгновенно получил ошибку:

Потом я сделал еще две жалкие попытки разобраться: слинковать (потому что сборка obj-файла проходит без ошибок, заметьте) под виндой из командной строки (результат - тот же, не видит библиотеки) и попробовать сравнить содержимой obj - файлов, воспользовавшись под линуксом утилитой nm, а под виндой - dumpbin с опцией /symbols Но разница слишком велика, я просто вижу в виндовом оьбъектном файле, что символ _event_init - UNDEFined. В общем, я не достиг успеха. Помогите, пожалуйста, например - подсказав, как определить магические переменные для OpenSSL (может, библиотека толькоприкинулась, что она нормально собрана?), или попробовав у себя собрать этот проект с этой библиотекой - возможно, у вас получится.

Заранее спасибо за советы.

Answer 1

Господа, большое спасибо за советы, они мне помогли, и особенно мне помогла подсказка на cyberforum.ru. Итак, я, как человек разумный и уже попробовавший запустить все это под linux и без усилий запустивший - утверждал, что ни о какой специальной инициализации winsock не может быть и речи, ведь библиотека же, в ней внутре всё должно быть сделано! И именно это своё мнение я писал в ответ на совет что то сделать с winsocket руками.

Оказалось, что я ошибался.

подсказка звучала так: "Глядите пример libevent/sample/hello-world.c — нужно вызывать." Точно... Да, стал сравнивать, и в отдадчике нашел, в каком месте в одном случае инициализация происходит, а в другом — не происходит. Оказалось, что под виндовс ДЕЙСТВИТЕЛЬНО надо в самом начале функции main написать

#ifdef _WIN32
    WSADATA wsa_data;
    WSAStartup(0x0201, &wsa_data);
#endif

Как говорится, никогда не было, и вот опять!

Нет, это никогда не надоедает!

Спасибо всем, кто мне помогал.

( моё личное мнение - о таких вещах надо на каждом заборе писать. чтобы выходишь с работы, видишь забор - а там про винсок под винддовс написано. )

Answer 2

Господа, у меня появились новые успехи: как выяснилось, у меня при сборке libevent создаются таки DLL-ки. Просто я их не сразу заметил. Сейчас я их копирую в тот же фолдер, где лежит EXEшник. Сейчас у меня следующая стадия: программа

    #include <memory>
    #include <cstdint>
    #include <iostream>
    #include <evhttp.h>
    using namespace std;
    int main()
    {
        if (!event_init()) {
            cout << "Failed to init libevent." << endl;
        }
        else {
            cout << "Libevent initialised!" << endl;

            char const SrvAddress[] = "192.168.10.53";
            uint16_t SrvPort = 5555;
            unique_ptr<evhttp, decltype(&evhttp_free)> Server(evhttp_start(SrvAddress, SrvPort), &evhttp_free);
            if (!Server)
            {
                cout << "Failed to init http server." << std::endl;
                return -1;
            }
            void(*OnReq)(evhttp_request *req, void *) = [](evhttp_request *req, void *)
            {
                auto *OutBuf = evhttp_request_get_output_buffer(req);
                if (!OutBuf)
                    return;
                evbuffer_add_printf(OutBuf, "<html><body><center><h1>Hello World! under Windows!</h1></center></body></html>");
                evhttp_send_reply(req, HTTP_OK, "", OutBuf);
            };
            evhttp_set_gencb(Server.get(), OnReq, nullptr);
            if (event_dispatch() == -1)
            {
                cout << "Failed to run messahe loop." << std::endl;
                return -1;
            }
        }
        return 0;
    }

собирается и запускается, а после запуска выдаёт ошибку

C:\MyProjects\Cpp\LibeEx1\Debug>LibeEx1.exe
[warn] evsig_init_: socketpair: Either the application has not called 
WSAStartup, or WSAStartup failed.
Libevent initialised!
[warn] socket: Either the application has not called WSAStartup, or 
WSAStartup failed.
Failed to init http server.

после чего завершается.

READ ALSO
Вызов метода у нулевого указателя

Вызов метода у нулевого указателя

Сегодня состоялся следующий спор с коллегамиОни утверждали, что в таком коде нет никаких проблем, и все будет работать везде одинаково:

241
Как проверить есть ли у системы возможность открыть файл?

Как проверить есть ли у системы возможность открыть файл?

есть абсолютное имя файла QString filePathНадо из программы вызвать открытие этого файла стандартной для системы утилитой

169
Не работает XOR

Не работает XOR

Второй день пытаюсь сделать шифрование Xor'ом, но все никак не получаетсяВот мой код

179
Показывает Мусор при запуске

Показывает Мусор при запуске

Ваши условия не покрывают случай, когда i или j равно n, а стало быть в ячейках с этими индексами остаются неинициализированные данныеПросто...

231