пятница, 12 апреля 2013 г.

Что в имени тебе моём? "Erlang machine stopped instantly ... (Code 7023)" при запуске RabbitMQ

English version is at the end of post.

Итак, вы решили использовать брокер сообщений. Почитали отзывы, поговорили с гуру, и выбор пал на RabbitMQ. Определились с компьютером, на котором будет работать брокер, и устанавливаете на него RabbitMQ Server. Сначала ставите Erlang (установщик сервера сам предложит перейти на сайт Erlang-а, если последний ещё не установлен), а затем и сам сервер.

Ничто не предвещало беды, но... брокер не работает! Смотрим на установленные сервисы и видим, что RabbitMQ Server есть, но не запущен. Запускаем и... наблюдаем, как на наших глазах от тут же останавливается. Идём в журнал событий и видим уведомление от Service Control Manager, с кодом 7023 и параметрами "RabbitMQ" и "%%1067". <sarcasm>Ну, теперь то всё ясно!</sarcasm> Посмотрев внимательно на события замечаем, что есть ещё одно, от компонента ErlSrv, с параметрами "RabbitMQ" и причиной: "Erlang machine stopped instantly (distribution name conflict?). The service is not restarted as OnFail is set to ignore." Всё это, конечно, замечательно, но решению проблемы не особо помогает.

суббота, 2 февраля 2013 г.

pragma comment (lib, ...): Линковка разных библиотечных файлов в зависимости от конфигурации

Предположим, что вы разрабатываете какую-то очень полезную библиотеку. Или не очень полезную. Или уже разработали, давно выложили на github, и развиваете её дальше. Насколько удобно и легко будет включить вашу библиотеку в проект "постороннему" человеку? Назовём его, для определённости, Посторонним В.

Типичный набор действий В. по включению библиотеки в проект:

  1. Прописывает в свойствах проекта путь к заголовочным файлам.
  2. Прописывает в свойствах линковщика путь к библиотекам.
  3. Указывает названия необходимых библиотек.
Всё? Чаще всего, нет. Посторонним В. меняет конфигурацию проекта с Debug на Release (или наоборот), и вписывает всё то же самое. Почти, да не совсем - очень часто путь к Debug и Release версии файлов библиотеки отличается, поскольку по умолчанию названия библиотечных файлов для Debug и Release одинаковые. На случай, если наш В. использует дополнительные конфигурации - кроме стандартных Debug и Release, данное действие повторяется для всех конфигураций.

Если предоставляемая библиотека содержит целый набор LIB файлов, требуется как-то выбрать нужные (что не всегда очевидно для Посторонним). Или просто указать все библиотеки (в каждой конфигурации проекта) - мало ли, какая из них содержит требуемую функцию.

А теперь прекращаем издеваться над В. и остальными, и делаем всё по-человечески.

пятница, 1 февраля 2013 г.

Библиотека POCO и error C2039: ... : is not a member of "global namespace"

Есть проект в MSVC++. Есть файл, использующий ряд популярных WIN API вызовов - CreateProcess, CreateFile, и им подобные. Всё собирается, всё замечательно.
В какой-то момент решаем использовать функционал из прекрасной библиотеки POCO. Включаем заголовочный файл для требуемого модуля - например, "Poco/Logger.h", и наш проект перестаёт собираться, жалуясь на то, что его любимые WIN API вызовы вдруг пропали.

В процессе раскопок выяснилось, что в POCO есть файл, unwindows.h, который включается его собственными заголовками. Данный файл просто и со вкусом, через #undef, убирает ряд annoying macros (по его скромному мнению)  - да-да, те самые CreateFile, и прочие. К чести сказать, удаляет не всегда, а только в том случае, если не выставлен #define с именем POCO_NO_UNWINDOWS - другими словами, как мне кажется, в 99% случаев. Вы ведь сразу выставили данный #define для каждого проекта, в котором используете WIN API вызовы, как только стали использовать POCO? Вот и я почему-то "поленился".

Причина, возможно, в том, что весь функционал, предоставленный данными API вызовами, существует в POCO, и таким способом разработчику "ненавязчиво намекают" на переход на средства библиотеки. Кроме как "тонким издевательством" такой "пиар" назвать не могу.

четверг, 31 января 2013 г.

LNK2001, unresolved external symbol в MSVC++ при попытке сделать "cross-DLL" вызов

Есть два С++ модуля ("проекта") под одним Solution-ом, 1-й и 2-й. Во 2-м есть класс, метод которого мы хотим вызвать из первого. Оба модуля - динамические DLL. Не линкуется. Объявляем метод виртуальным - всё замечательно. Если не линкуется и после этого - скорее всего, в Project Dependencies для первого модуля, не указан второй модуль.

Как надо: метод класса делаем доступным, добавляя __declspec(dllexport) (между типом возвращаемого значения и именем функции), после чего метод доступен "снаружи". Другой способ - через .DEF файл, но он менее удобен.

Что происходит: после добавления __declspec, помимо DLL файла, для 2-го модуля компилятор создаст LIB файл - как "связующее звено", с помощью которого слинкует вызов метода из 1-го модуля с реализацией (адресом) метода во 2-м модуле. Данный LIB файл является так называемой "import library".
Глянув в настройках 1-го модуля в MSVC (Linker) в command-line, можно заметить, что при корректно выставленной зависимости 1-го модуля от 2-го, среди аргументов присутствует LIB файл 2-го модуля, даже несмотря на то, что он является динамической библиотекой.

Для вызова метода из статических библиотек, дополнительных действий не потребуется - адреса методов фиксированы и известны линковщику. Тем не менее, не стоит забывать правильно расставить зависимости модулей друг от друга (через свойства Solution).
Чуть больше подробностей, с небольшим примером кода, по ссылке.

воскресенье, 20 января 2013 г.

Organize!

Наверняка, многие из вас бывали в ситуации, когда в компании заходил разговор о фильмах, книгах, музыке, и упоминалось какое-то заинтересовавшее вас произведение. Название пишется на бумажке и... оставляется на столе, теряется, или заносится в файлик на рабочем компьютере. Про фильм или книгу мы вспоминаем уже дома, или по дороге. Какое же там было название... и где же тот листочек?.. Чёртов склероз!

Или, к примеру, натыкаетесь вы в интернете на интересную статью, видеоролик, или кто-то присылает ссылку на безумно интересный блог, и вот ведь незадача - чтение / просмотр может отнять весьма продолжительное время, и именно сейчас его у вас нет. Заносим в закладки в своём любимом хроме / огнелисе / опере / сафари (да хоть в ослике), и по дороге домой или уже дома, естественно, вспоминаем. И ведь даже интернет есть, и время. А толку?

суббота, 19 января 2013 г.

JSON как формат обмена данными между C++ и Java


Формат JSON - замечательная штука для структур данных общего вида, с вложенными объектами, массивами, и разными типами в том случае, если вам надо передать один или несколько объектов достаточно сложной структуры между разнородными компонентами - например, между C++ и Java. Как оказалось, даже есть отдельный RFC 4627, где описан JSON.

Для работы с данным форматом на "плюсах", можно воспользоваться библиотекой JSON Spirit, написанной с использованием Boost, применение которой хорошо описано. Библиотека позволяет достаточно легко написать парсер/генератор JSON на C++.

Существует также JSON Schema, которая позволяет в формате JSON описать структуру JSON данных - данные формата JSON описываются с помощью самого JSON. Одно из применений "схемы" - data validation. Кроме того, на основе "схемы" может быть сгенерирован исходный код (правда, не для всех языков). В отличие от формата JSON, "схема" на данный момент "стандартизована" на уровне IETF draft-а. Немного более поздняя версия draft-а доступна на github-е проекта (на момент этого поста - это v04).