среда, 25 января 2012 г.

How To build Poco for Windows

Открываем консоль и переходим в директорию проекта.
Конфигурируем среду сборки
call "%VS100COMNTOOLS%\..\..\VC\vcvarsall.bat" x86_amd64
или
call "%VS100COMNTOOLS%\..\..\VC\vcvarsall.bat" x86 
В buildwin.cmd изменяем путь до OpenSSL
set OPENSSL_DIR=c:\OpenSSL
на
set OPENSSL_DIR=path_to_home\openssl\vc10-x64

где vc10-x64 это папка куда у вас был собран OpenSSL.

В этом же скрипте читаем 
rem Usage:
rem ------
rem buildwin VS_VERSION [ACTION] [LINKMODE] [CONFIG] [PLATFORM] [SAMPLES] [DEVENV]
rem VS_VERSION: 71|80|90|100
rem ACTION:     build|rebuild|clean
rem LINKMODE:   static_mt|static_md|shared|all
rem CONFIG:     release|debug|both
rem PLATFORM:   Win32|x64|WinCE
rem SAMPLES:    samples|nosamples
rem DEVENV:     devenv|vcexpress
Открываем (в моем случае) build_vs100.cmd и приводим его в нужный вид, что то вроде
buildwin 100 build static_md release x64 nosamples

Устанавливаем переменную окружения POCO_HOME.

При сборки Poco может произойти глюк, при этом ни один из проектов не будет собираться, выхлоп такой:
...
     1>TRACKER : error TRK0002: Failed to execute command: ""C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\BIN\x86_amd64\CL.exe" @C:\Users\guest\AppData\Local\Temp\91b441a2b85846d5a04ec1eb7ab26041.rsp". The handle is invalid.
...
Build FAILED.

Лечится перезагрузкой системы.

пятница, 13 января 2012 г.

C++ extern

Mассив и указатель — это различные типы. Так, если написать в одном файле
int a[10];
а в другом
extern int *a;

компилятор, скорее всего, выдаст Вам ошибку (компилятор об этом даже не узнает, ошибку даст линкер, и только в том случае, если переменная объявлена вне блока extern "C").

в VS2010 не ошибок ни чего, просто падает при выполнении с "Access violation reading location"

среда, 17 августа 2011 г.

База для AnyMemo из lingualeo

AnyMemo - программа для заучивания слов по системе карточек.
lingualeo - сайт для изучения английского языка. Вы можете смотреть англоязычное видео, к нему прилагается транскрипция, интегрирован перевод в переводчике гугла, и прочее.

На сайте производителя AnyMemo есть конвертер для создания базы из текстового файла. Мне он не очень понравился из за своей ужастности в плане GUI (зато он более неприхотлив чем казалось бы аналогичная функция зашитая в саму программу).


AnyMemo имеет возможность импортировать слова их текстового файла в базу. Для этого текстовый файл должен быть представлен в следующем виде (в кодировке UTF-8)
"слово" "перевод" "" ""
"" "" "" ""

Между колонками знаки табуляции. Две последних это категория и доп. информация кои я не использую. Последняя строка в файле должна содержать все 4 пустые колонки. Данный формат был экспериментально получен путем экспорта готовой базы в текстовый файл.

lingualeo в разделе "Словарь" предлагает функцию "Печать (все)". Где выводит список слов в следующем формате:

# Слово Транскрипция Перевод
1 talk         [tˈɔːk]                 говорить

Копируем этот список (без шляпы таблицы) в Excell или Calc (OpenOffice). Удаляем столбец с номерами и транскрипцией. Так что бы англоязычное слово оказалось в первой(A) колонке, перевод во второй(B).

Теперь необходимо заковычеть слова. Так как для импорта в AnyMemo необходимо 4 колонки, то после перевода отступаем еще две колонки, в пятой(E) пишем формулу
= """" & A1 & """"
Выделяем ячейку я растягиваем на 4 следующих столбца и все строки со словами. Получаем 4 колонки, все заковыченные. Далее выделяем эти ячейки, копируем в текстовый редактор с поддержкой UTF8, сохраняем (расширение должно быть .txt иначе AnyMemo не увидит файл) и производим импорт.



вторник, 26 апреля 2011 г.

[bash] Построчное чтение файла и ssh

Пишем мы скрипт на баше, и нужно нам считать файл построчно, это делается вот так
cat number.txt | while read line 
do
   echo $line
done
Но вот нам потребовалось сделать в теле цикла что то по ssh. Мы смело вставляем нужный код
cat number.txt | while read line 
do
   echo $line
   ssh user@127.0.0.1 "ls"
done
(представим что у нас настроена авторизация по открытому ключу).
И... и этот код будет работать не так как нам хотелось бы. Отработает только одна итерация цикла, не зависимо от того сколько строк в файле.

Проблема заключается в том что cat делает вывод в stdin из которого конвейером данные переходят в read. Но и ssh тоже использует stdin для своих целей и сливает все данные в себя (либо просто "забывает" их). И по когда управление будет снова передано на проверку условия, в stdin уже будет пусто и мы выйдем из цикла. Неожиданно ? да :)

Так как же нам решить эту проблему ? А вот так
exec 10<$PAIR_CONFIG
while read line <&10
do
   echo $line
   ssh user@127.0.0.1 "ls"
done
Мы связываем файловый дескриптор №10 с нужным нам файлом. И далее производим чтение уже из этого потока.

среда, 6 апреля 2011 г.

[C++] Текущая директория (кроссплатформенно)

Ниже приведены три способа получить полный путь до директории из которой был запущен исполняемый файл


#ifdef _LINUX
#include <limits.h>
#include <string.h>

char path[PATH_MAX + 1] = { 0 };
ssize_t len = readlink("/proc/self/exe", path, PATH_MAX);
path[len] = 0;
char* p = strrchr(path, '/');
if(p) *(p + 1) = 0;
else path[0] = 0;
#else
#include <windows.h>

char path[_MAX_PATH];
GetModuleFileName(NULL, path, _MAX_PATH);
#endif
#include <boost/filesystem/operations.hpp>

std::string path = boost::filesystem::current_path().string();

вторник, 5 апреля 2011 г.

[Часть 2] Cmake: автоматизированная сборка и установка

Теперь рассмотрим процесс подготовки Cmake для make install.

Итак, имеем конкретный CMakeLists для сборки определенного проекта. Далее все просто и быстро
if (UNIX)
linux_install(${PROJECT_NAME})

# возможно проекту требуются какие то внешние либы
install(FILES $ENV{SOME_ROOT}/lib/release/libsome.so.1.0
DESTINATION ${PROJECT_NAME}/lib RENAME libsome.so.1)
endif()

Далее где то должна быть определена используемая функция
function(linux_install PROJECT_NAME)
set_target_properties(${PROJECT_NAME} PROPERTIES RESOURCE ${PROJECT_NAME}_ETC_FILES)

install(TARGETS ${PROJECT_NAME}
RUNTIME DESTINATION ${PROJECT_NAME}/bin
RESOURCE DESTINATION ${PROJECT_NAME}/etc
)
install(PROGRAMS ${${PROJECT_NAME}_BIN_FILES} DESTINATION ${PROJECT_NAME}/bin)
install(FILES ${${PROJECT_NAME}_LIB_FILES} DESTINATION ${PROJECT_NAME}/lib})
endfunction(linux_install)

Здесь мы как раз и использовали ранее полученные переменные имя_проекта_BIN_FILES, имя_проекта_ETC_FILES, имя_проекта_LIB_FILES

Например если у нас имеется в наличии несколько разных тестов, для разные подпроектов, то неплохо бы их собрать вместе для тестера

function(linux_install_test PROJECT_NAME PROJECT_DIR)
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${PROJECT_DIR}/bin)

install(PROGRAMS ${${PROJECT_DIR}_BIN_FILES} DESTINATION ${PROJECT_DIR}/bin)
install(FILES ${${PROJECT_DIR}_ETC_FILES} DESTINATION ${PROJECT_DIR}/etc})
install(FILES ${${PROJECT_DIR}_LIB_FILES} DESTINATION ${PROJECT_DIR}/lib})
endfunction(linux_install_test)

Где PROJECT_DIR директория ресурсов для теста и она же название директории установки тестов.

И так же иметь возможность устанавливать библиотеки которые разрабатываются как часть проекта
function(linux_install_lib PROGECT_NAME)
FOREACH(INSTALL_DIR ${LIST_DIR_PROJECT})
install(TARGETS ${PROJECT_NAME}
LIBRARY DESTINATION ${INSTALL_DIR}/lib
RESOURCE DESTINATION ${INSTALL_DIR}/lib)
ENDFOREACH(INSTALL_DIR)
endfunction(linux_install_lib)

пятница, 25 марта 2011 г.

[Часть 1] Cmake: автоматизированная сборка и установка

Суть сего поста запечатлеть опыт который я получил.

Пускай есть большой проект Project состоящий из n-го числа под проектов:
project_name - основной результат проект, приложение.
project_core - основные библиотеки проекта
project_test1 - тест 1
project_test2 - тест 2
project_some -вспомогательные приложения которые сопровождаются вместе с основным проектом.
Каждый из проектов в свою очередь, помимо самого проекта, может содержать некоторые внешние данные, это могут быть конфиги, сторонние библиотеки, и прочее.
Предположим что проект пишется платформенный.
Тогда возможна следующая иерархия для вспомогательных данных
.\ - Корневая директория проекта
.\resource

.\resource\etc- конфигурационные файлы
.\resource\etc\project_name
.\resource\etc\project_name\linux - специфичные конфиги для linux
.\resource\etc\project_name\win - специфичные конфиги для window
.\resource\etc\project_name\. - общие конфиги для project_name

.\resource\etc\project_test
...
.\resource\etc\project_some
...
.\resource\etc\. - общие конфиги для всех проекто
.\resource\bin - тут например могут быть скрипты запуска
... иерархия аналогично etc
.\resource\lib - внешние библиотеки
... иерархия аналогично etc
много ? много ! Но зато все на своих места.

Далее что мы хотим сделать. А сделать мы хотим следующее.

1. Что бы cmake все это добро собрал в коталог компиляции в следующем виде
.\build\etc - все конфиги, само собой с учетом linux или win
.\build\bin - так же как etc
.\build\lib - так же как etc
2. Подготовить make install что бы в итоге получить назависимые сборки для разных подроектов
\DESTDIR\project_name\
\DESTDIR\project_name\etc
\DESTDIR\project_name\bin
\DESTDIR\project_name\lib
\DESTDIR\project_test\
...
\DESTDIR\project_some\
...
Сборка со всех файлов директории resourse/lib во едино.
set (CMAKE_SOURCE_BIN_DIR ${CMAKE_SOURCE_DIR}/resource/bin)
set (CMAKE_SOURCE_ETC_DIR ${CMAKE_SOURCE_DIR}/resource/etc)
set (CMAKE_SOURCE_LIB_DIR ${CMAKE_SOURCE_DIR}/resource/lib)

set (REGEX_BIN_FILE "[^.][a-zA-Z0-9_]*.[.a-zA-Z0-9]*")
set (REGEX_ETC_FILE "[^.][a-zA-Z0-9_]*.[.a-zA-Z0-9]*")
set (REGEX_LIB_FILE "[^.][a-zA-Z0-9_]*.[.a-zA-Z0-9]*")
# Получаем все файлы из директории ${CMAKE_SOURCE_BIN_DIR}/*
# в виде относительного пути RELATIVE ${CMAKE_SOURCE_BIN_DIR}
# от этой же директории.
# Таким образом в переменной LISTS_BIN_DIR у нас будут имена всех файлов,
# включая системные и директории, нужной нам директории CMAKE_SOURCE_BIN_DIR
FILE(GLOB LISTS_BIN_DIR RELATIVE ${CMAKE_SOURCE_BIN_DIR}
${CMAKE_SOURCE_BIN_DIR}/*)

# пробегаем по всем файлам
FOREACH(BIN_DIR ${LISTS_BIN_DIR})
# выбирая только директории (они же папки проектов)
if(IS_DIRECTORY ${CMAKE_SOURCE_BIN_DIR}/${BIN_DIR})
# сохраняем список проектов
SET(LIST_DIR_PROJECT ${LIST_DIR_PROJECT} ${BIN_DIR})

if (WIN32)
# копируем и перименовавыем все bin файлы проекта
FILE(GLOB ${BIN_DIR}_BIN_FILES
RELATIVE ${CMAKE_SOURCE_BIN_DIR}/${BIN_DIR}/win
${CMAKE_SOURCE_BIN_DIR}/${BIN_DIR}/win/${REGEX_BIN_FILE})

FOREACH(BIN_FILE ${${BIN_DIR}_BIN_FILES})
# в начале файл нужно скопировать в папку назначения
# незабываем что для VS нужно копировать в Debug и в Release
FILE(COPY ${CMAKE_SOURCE_BIN_DIR}/${BIN_DIR}/win/${BIN_FILE}
DESTINATION ${CMAKE_BINARY_DIR}/Debug/bin)
# переименовываем файл, добавляя название его проекта
FILE(RENAME ${CMAKE_BINARY_DIR}/Debug/bin/${BIN_FILE}
${CMAKE_BINARY_DIR}/Debug/bin/${BIN_DIR}_${BIN_FILE}
)
# знаете способ сделать это за одну операцию, пишите в коментах
ENDFOREACH(BIN_FILE)
#...
# повторить эту же операцию для файлов проекта
# не зависящих от архитектуры; папка: ${CMAKE_SOURCE_BIN_DIR}/${BIN_DIR}
#...

# заполняем переменную имя_проекта_BIN_FILES
FILE(GLOB ${BIN_DIR}_BIN_FILES
${CMAKE_SOURCE_BIN_DIR}/${BIN_DIR}/win/${REGEX_BIN_FILE})

else (WIN32)
# Для linux повторяем туже операцию
# ...
endif()

# добавляем к имя_проекта_BIN_FILES общие файлы проекта
FILE(GLOB ${LIB_DIR}_BIN_FILES ${${BIN_DIR}_BIN_FILES}
${CMAKE_SOURCE_BIN_DIR}/${BIN_DIR}/${REGEX_BIN_FILE})

# добавляем список файлов проекта в список всех bin файлов сборки
FILE(GLOB BIN_FILES ${BIN_FILES} ${${BIN_DIR}_BIN_FILES})

# добавляем к списку файлов проекта файлы относящиеся ко всем проектам
FILE(GLOB ${BIN_DIR}_BIN_FILES ${${BIN_DIR}_BIN_FILES
${CMAKE_SOURCE_BIN_DIR}/${REGEX_BIN_FILE})

endif()
ENDFOREACH(LIB_DIR)

# Добавляем в общий список lib файлов файлы относящиеся ко всем проектам
FILE(GLOB BIN_FILES ${BIN_FILES} ${CMAKE_SOURCE_BIN_DIR}/${REGEX_BIN_FILE})
И того мы имеет:
1. файлы всех проектов из директории resourse/bin/projectN будут скопированы в директорию build/bin и переименованы (удобно уметь для всех проектов файлы start.sh, stop.sh)
2. Для каждого из проектов будет определена своя переменная (имя_проекта_BIN_FILE) со списком всех BIN файлов требуемых для этого проекта.
3. Переменную со списком всех BIN файлов
4. Переменную LIST_DIR_PROJECT со списком всех проектов для которых существует директории в resourse/lib (это не обязательно все проекта сборки)

Такую же операцию проводим и для etc и lib файлов.
Далее нам останется сделать
list(REMOVE_DUPLICATES LIST_DIR_PROJECT)
что бы получить список всех проектов сборки (мы как бы получаем объединение всех найденных проектов в etc lib bin, т.к. некоторые из проектов могут не содержать своих директории в одной из рассматриваемых директорий, и полагаться на какую то одну не вполне надежно)