yum --color=always search your_text | less -R
По умолчанию когда обнаруживается pipe цвета автоматически отключаются. Флаг --color=always говорит, что отключать их не нужно даже в пайпе. Флаг -R сообщает less, что нужно отображать входные цветовые escape последовательности, т.е. подсвечивать текст.
среда, 9 января 2013 г.
Подсветка синтаксиса в less
Есть команда выводящая результаты с подсветкой / раскраской - скажем это yum search, но выхлоп очень большой и нужно использовать пейджер less. Однако текст, прошедший через less становится одноцветным. Как сделать так, чтобы он оставался цветным. Вот ответ:
вторник, 25 декабря 2012 г.
Удаление указателей из контейнера и их уничтожение
Предположим что ваш последовательный контейнер хранит указатели и вам нужно удалить и уничтожить обьекты удовлетворяющие некоторому критерию. Если указатели не являются умными, то идиому remove + erase использовать не получится поскольку обьекты будут только удалены, но не будут уничтожены. Удаление поштучно является неплохой идеей для std::list, но это будет накладно для std::vector и std::deque, поскольку контейнеру придется многократно перемещать оставшиеся элементы так, чтоб на месте удаленный элементов не оставалось дыр, т.е. в совокупности понадобится O( N2 ) перемещений.
Ниже описано решение проблемы с использованием std::stable_partition в паре с erase. Идея в том, чтобы сначала переместить всех кандидатов на удаление в конец коллекции (оптимизация под вектор), а затем вызвать erase для всех их.
Алгоритмическая сложность: N сравнений + N перестановок в случае, если std::stable_partition сможет использовать внутренний буффер или N log N перестановок в противном случае.
Сначала обьявим функтор для уничтожения элементов в контейнере
Если ваш модуль подключает библиотеку QtCore то вы можете избавиться от функтора DeletePointer заменив вторую строчку в теле delete_erase_if на вызов qDeleteAll.
К минусам приведенной выше реализации относится то, что функция не принимает указатели на функции в качестве предиката. Для того, чтобы обойти данное ограничение, нужно просто обернуть указатель на функцию-предикат в std::ptr_fun.
Ниже описано решение проблемы с использованием std::stable_partition в паре с erase. Идея в том, чтобы сначала переместить всех кандидатов на удаление в конец коллекции (оптимизация под вектор), а затем вызвать erase для всех их.
Алгоритмическая сложность: N сравнений + N перестановок в случае, если std::stable_partition сможет использовать внутренний буффер или N log N перестановок в противном случае.
Сначала обьявим функтор для уничтожения элементов в контейнере
template< class TPointer >
struct DeletePointer
{
Затем переходим к определению самой функции, удаляющей и уничтожающей элементы контейнера
struct DeletePointer
{
void operator () ( TPointer item ) { delete item; }
};
template< class Collection, class Predicate >
void delete_erase_if( Collection& c, Predicate pred ) {
Поскольку stable_partition переставлят все элементы, удовлетворяющие предекату, в начало, а нам нужно переставлять их в конец, то нам приходится как-то инвертировать предикат. Для этого в теле функции используется std::not1 из модуля <functional>.
void delete_erase_if( Collection& c, Predicate pred ) {
typename Collection::iterator removeBegin = std::stable_partition( c.begin(), c.end(), std::not1 ( pred ) );
std::for_each( removeBegin, c.end(), DeletePointer< typename Collection::value_type > () );
c.erase( removeBegin, c.end() );
}
std::for_each( removeBegin, c.end(), DeletePointer< typename Collection::value_type > () );
c.erase( removeBegin, c.end() );
Если ваш модуль подключает библиотеку QtCore то вы можете избавиться от функтора DeletePointer заменив вторую строчку в теле delete_erase_if на вызов qDeleteAll.
К минусам приведенной выше реализации относится то, что функция не принимает указатели на функции в качестве предиката. Для того, чтобы обойти данное ограничение, нужно просто обернуть указатель на функцию-предикат в std::ptr_fun.
Ярлыки:
коллекция указателей,
указатель,
c++,
delete,
delete by predicate,
erase,
pointer,
predicate,
remove
понедельник, 24 декабря 2012 г.
Указатель на функцию как параметр шаблона
Предположим, что нужно взять указатель на функцию-член класса и параметризовать ею шаблон. Для этого делаем следующее:
Для удобства обьявляем тип указателя на функцию:
Для удобства обьявляем тип указателя на функцию:
typedef QDateTime ( QDateTime::*DateTimeIncrement ) ( int ) const;
Обьявляем шаблон (функцию или класс), принимающий указатель на функцию как параметр
template <DateTimeIncrement Increment>
QDateTime add( QDateTime dateTime, int delta )
{
А потом можно заюзать шаблон...
QDateTime add( QDateTime dateTime, int delta )
{
return ( dateTime.*Increment )( delta );
}
inline QDateTime addDays( QDateTime dateTime, int delta ) { return add< &QDateTime::addDays >( dateTime, delta ); }
...
QDateTime tomorrow = addDays( QDateTime::currentDateTime(), 1 );
...
QDateTime tomorrow = addDays( QDateTime::currentDateTime(), 1 );
воскресенье, 25 ноября 2012 г.
Linux, как указать программе путь к .so библиотеке
Пока я разрабатывал одну библиотеку, мне нужно было как-то тестировать ее без копирования в соответствующие системные каталоги.
Идеальным выглядело решение, когда исполнительный файл с тестами и тестируемая библиотека лежат в одном каталоге, как в Windows. Проблема была в том, что в Linux это не работало - экзешник не мог найти библиотеку.
Решается это просто. экзешник нужно запускать следующей командой (при условии, что текущим каталогом является тот, где лежит экзешник с библиотекой/библиотеками):
Если и это не помогает, то попробуйте посмотреть какую именно библиотеку пытается найти ваш экзешник, вызвав команду
или
Скорее всего просто напросто требуется библиотека с четко прописанной версией в ее названии. Например: libMyLib.so.1 вместо libMyLib.so.1.0.0
Лечится это символическими ссылками:
Идеальным выглядело решение, когда исполнительный файл с тестами и тестируемая библиотека лежат в одном каталоге, как в Windows. Проблема была в том, что в Linux это не работало - экзешник не мог найти библиотеку.
Решается это просто. экзешник нужно запускать следующей командой (при условии, что текущим каталогом является тот, где лежит экзешник с библиотекой/библиотеками):
$ LD_LIBRARY_PATH=`pwd` ./executable_name
Если и это не помогает, то попробуйте посмотреть какую именно библиотеку пытается найти ваш экзешник, вызвав команду
$ ldd executable_name
или
$ readelf -d executable_name
Скорее всего просто напросто требуется библиотека с четко прописанной версией в ее названии. Например: libMyLib.so.1 вместо libMyLib.so.1.0.0
Лечится это символическими ссылками:
$ ln -s libMyLib.so.1.0.0 libMyLib.so.1
суббота, 31 марта 2012 г.
Hello RPM
Here I'm giving a brief guidance how to create a simplest RPM file for a QT4 based application. If you want this post to be translated to English just contact me and I will do it upon first request with giving you all possible assistance in urgent case. In return I will expect your help with checking it on grammatical mistakes.
В интернете можно найти много литературы по RPM, о формате .spec файла и о том как пользоваться rpmbuild.
В интернете можно найти много литературы по RPM, о формате .spec файла и о том как пользоваться rpmbuild.
В этом посте я приведу краткое руководство о том как создать простейший RPM пакет не углубляясь в детали. Пост будет особенно интересен тем, кому нужно создать RPM для проекта написанного на Qt.
Итак, у меня есть приложение HelloWorld, написанное на QT 4.8 и доступное для загрузки отсюда. Минимальные требования, для сборки проекта - наличие Qt4.8 и qmake (qt и qt-devel пакеты для Fedora Linux соответственно).
Комментарии к исходникам:
- Когда распакуете архив с исходниками обратите внимание что корневая папка называется "helloworld-1.0". Это первый важный момент. "helloworld" - это название приложения и название пакета, который мы сейчас будем создавать. Нужно чтобы название приложения совпадало с названием пакета. "1.0" - это версия нашего продукта. "-" между названием и версией соответствует соглашению о построении полных названий пакетов. Очень важно чтобы корневая папка именовалась как [название приложения/пакета]-[версия приложения]. Без этого вы получите ошибку на стадии %prep при сборке. От пакетов требуется, чтобы все символы названия были в нижнем регистре поэтому позаботьтесь, чтобы исполнителный файл тоже соответствовал этому требованию.
- В файле HelloWorld.pro обратите внимание на строчки:
unix {
На основании этой строки qmake сгенерируют инструкцию в Makefile для команды "make install". Назначение макроса DESTDIR я поясню позже. Сейчас же обратите внимание, что он начинается с символа "/". Он необходим, инача qmake допишет в Makefile еще и путь к файлу проекта, что приведет к проблемам на фазе %install.
target.path = /$(DESTDIR)
INSTALLS += target
} - В корневом каталоге лежит скрипт configure который просто вызывает qmake. Этот скрипт будет автоматически вызываться на стадии %prep и его назначение в том, чтобы подготовить Makefile. Именно поэтому я поместил в него вызов qmake. Проследите, чтобы этот скрипт был помечен как исполняемый файл (chmod +x configure)
Для создания и проверки правильности rpm пакетов вам понадобятся rpmdevtools и rpmlint. Устанавливаем их командой
sudo yum install rpmdevtools rpmlint
Теперь создаем дерево сборки командой
rpmdev-setuptree
В результате у вас появится каталог ~/rpmbuild с дочерними каталогами SPECS, SOURCES, RPMS, SRPMS, BUILD и BUILDROOT. Информацию о назначении каталогов вы найдете на rpm.org. Полученное дерево каталогов вы можете использовать для построения rpm пакетов для произвольных версий любых программних продуктов.
Скопируйте архив с исходниками в ~/rpmbuild/SOURCES.
Теперь переходим к самому главному. Скачайте spec файл перейдя по следующей ссылке (скачать) и положите его в папку ~/rpmbuild/SPECS.
Перейдите в этот каталог (cd ~/rpmbuild/SPECS) и запустите на исполнение команду
Несколько комментариев к spec файлу:
В данном посте я не затронул тему патчей потому, что я в них сам еще не разобрался. Вернее практически все ясно за исключением того почему нужно класть самые старые исходники в папку с самой последней версией в названии, а потом на все на это накатывать патчи. Как-то немного странно это. Когда все выясню для себя напишу об этом.
Кроме того у описаной процедуры есть недостаток. Если нужно установить несколько файлов из одного пакета в разные места назначения, передача usr/bin через DESTDIR не очень подходит. Возможно лучше было бы захардкодить /usr/bin в HelloWorld.pro. Другое решение расширить набор входных параметров. В общем тут тоже есь над чем подумать.
Если этот пост был полезен вам, чиркните пару слов. Также буду признателен тем кто будет давать дополнительную полезную информацию на данную тему.
Скопируйте архив с исходниками в ~/rpmbuild/SOURCES.
Теперь переходим к самому главному. Скачайте spec файл перейдя по следующей ссылке (скачать) и положите его в папку ~/rpmbuild/SPECS.
Перейдите в этот каталог (cd ~/rpmbuild/SPECS) и запустите на исполнение команду
rpmbuild -ba helloworld.specВ результате в папке RPMS (со смещением на текущую архитектуру) будет лежать ваш RPM с бинарниками, а в папке SRPMS - с исходниками и spec файлом. Если вам нужен только RPM с бинарниками замените -ba на -bb.
Несколько комментариев к spec файлу:
- Поле Name содержит имя rpm файла, который будет сгенерирован. Это имя должно совпадать с названием приложения.
- Поле Source0 содержит название нашего архива с исходниками
- Обратите внимание на строку
make install DESTDIR=$RPM_BUILD_ROOT%{_bindir}
в разделе %install. Помните, что в HelloWorld.pro мы устанавливали target.path в /$(DESTDIR)? Теперь же мы инициализируем эту переменную путем взятым из контекста сборки и передаем ее команде make install, которая в свою очередь создаст такой каталог (он будет находиться по адресу ~/rpmbuild/BUILDROOT/[полное имя пакета]/usr/bin) и скопирует туда собранный исполняемый файл. - Строка %{_bindir}/%{name} в разделе %files инструктирует сборщик, что в результирующий RPM необходимо включить файл с именем helloworld (именно в это значение развернется макрос %name) лежащий со смещением usr/bin (значение макроса %_bindir) относительно $RPM_BUILD_ROOT (т.е. ~/rpmbuild/BUILDROOT/[полное имя пакета]). Без этой строки ваш RPM файл останется пустым.
В данном посте я не затронул тему патчей потому, что я в них сам еще не разобрался. Вернее практически все ясно за исключением того почему нужно класть самые старые исходники в папку с самой последней версией в названии, а потом на все на это накатывать патчи. Как-то немного странно это. Когда все выясню для себя напишу об этом.
Кроме того у описаной процедуры есть недостаток. Если нужно установить несколько файлов из одного пакета в разные места назначения, передача usr/bin через DESTDIR не очень подходит. Возможно лучше было бы захардкодить /usr/bin в HelloWorld.pro. Другое решение расширить набор входных параметров. В общем тут тоже есь над чем подумать.
Если этот пост был полезен вам, чиркните пару слов. Также буду признателен тем кто будет давать дополнительную полезную информацию на данную тему.
четверг, 2 июня 2011 г.
Qyoto Signals Emission
Классы Qyoto, являются обертками над соответствующими классами Qt. У некоторых Qt-шных классов имеются сигналы которые нужно как-то эмитить из managed кода.
Например, если вы реализуете класс, наследующий QAbstractItemModel, вам наверняка понадобится эмитить сигнал dataChanged(...).
Делается это просто. Любой класс, наследующий managed QObject имеет унаследованное свойство Emit типа IObjectSignals. Для QAbstractItemModel сущестует интерфейс IQAbstractItemModelSignals, содержащий все необходимые сигналы класса QAbstractItemModel.
Все, что вам нужно сделать в вашем классе, наследующем QAbstractItemModel это, в месте где необходимо послать сигнал, выполнить следующий код:
Например, если вы реализуете класс, наследующий QAbstractItemModel, вам наверняка понадобится эмитить сигнал dataChanged(...).
Делается это просто. Любой класс, наследующий managed QObject имеет унаследованное свойство Emit типа IObjectSignals. Для QAbstractItemModel сущестует интерфейс IQAbstractItemModelSignals, содержащий все необходимые сигналы класса QAbstractItemModel.
Все, что вам нужно сделать в вашем классе, наследующем QAbstractItemModel это, в месте где необходимо послать сигнал, выполнить следующий код:
IQAbstractItemModelSignals emt = (IQAbstractItemModelSignals)Emit;
emt.DataChanged(...);
Для остальных Qyoto классов подход будет аналогичным.
Пример того, как нужно создавать обработчики сигналов и как подписываться на сигналы вы можете найти по указанной ссылке: http://misc-sonofagun.blogspot.com/2010/12/qyoto-and-gc-issues.html
Пример того, как нужно создавать обработчики сигналов и как подписываться на сигналы вы можете найти по указанной ссылке: http://misc-sonofagun.blogspot.com/2010/12/qyoto-and-gc-issues.html
среда, 1 июня 2011 г.
QVariant( String )
В текущей версии Qyoto (ver. 4.5.0.0, 2011-06-01) конструктор класса QVariant(String) имеет баг из-за которого QVariant не поддерживает юникодные строки. Связано это с тем, что внутри managed QVariant вызывается не тот unmanaged конструктор:
QVariant(const char*)вместо
QVariant(const QString&)
Лечится это довольно просто: создается managed класс, назовем его QVariantQString, наследующий QVariant с единственным конструктором принимающим System.String и вызывающим внутри нужный unmanaged конструктор. Далее везде, где нужно создать QVariant( String ), нужно создавать QVariantQString( String ).
Ниже приведен полный работающий код этого класса:
Ниже приведен полный работающий код этого класса:
using System;
namespace Qyoto
{
[SmokeClass("QVariant")]
internal class QVariantQString : QVariant
{
protected QVariantQString(Type dummy) : base(dummy) {}
protected new void CreateProxy()
{
interceptor = new SmokeInvocation(typeof(QVariantQString), this);
}
public QVariantQString(string str) : this((Type) null)
{
CreateProxy();
interceptor.Invoke("QVariant$", "QVariant(const QString&)", typeof(void), typeof(string), str);
}
} //class
} //namespace
* This source code was highlighted with Source Code Highlighter.
Подписаться на:
Сообщения (Atom)