Cygwin

Тема этой заметки будет следующая, – за что я уважаю Unix. А уважаю я его за: bash, sed, grep, find. Казалось бы, суть не в этом и профессионалы будут с пеной у рта доказывать, что сила, она, брат, в концептуальном устройстве Unix, но нам бы что попроще, на пальцах. Поэтому о самом главном как-нибудь потом, а пока пройдемся по верхам.

Есть такая вещь, которая называется Cygwin. Это – качественный порт под Win32 многих Unix’овых утилит. При этом достигается великолепная совместимость. То есть скрипты, написанные и отлаженные под Windows, с большой вероятностью будут работать под Unix и наоборот. Альтернативы Cygwin’у на данный момент практически нет, единственным соперником мог бы быть MKS Toolkit, но он продается за деньги, а нас такой вариант не устраивает. Идем качать и устанавливать Cygwin. (Тут вот проскочило некое подобие - GnuWin32. Фанаты могут посмотреть, мне – лень. 11.01.2004)

Стоп, а зачем он мне нужен?

Зачем он может пригодиться вам, я не знаю. Я могу только рассказать, зачем он нужен мне:

  • Во-первых, так уж сложилось, что я пишу программы, которые будут использоваться, как на Windows, так и на unix-платформах. При этом приходится создавать служебные скрипты, которые, например, производят компиляцию всего проекта. Так вот с использованием Cygwin я могу написать скрипты, которые одинаково запускаются и работают под обеими платформами (Win/Solaris), мне не приходится делать отдельно bat и отдельно shell-скрипты. Это сильно экономит время в момент написания и, особенно, в момент модификации скриптов. Попробуйте параллельно править обе версии, в которых различий больше чем сходства.
  • Во-вторых, я могу использовать gnumake. А это один из лучших make-ов, которые есть на данный момент. Кстати makefile будет одним и тем же для обеих платформ.
  • В-третьих, мощи CMD.EXE, который входит в Windows NT, не хватает для написание серьезного скрипта. Есть, конечно, 4DOS и 4NT, но это все равно не то. Одни регулярные выражения чего стоят (тут автор мечтательно закатывает глаза и медитирует 5 минут).
  • В-четвертых. Вам никогда не приходилось скачивать из интернета исходные тексты программ? Ага… Быть может и расширения вроде .tar.gz для вас не пустой звук? Тем, кто по молодости да по неопытности с этим никогда не сталкивался, поясню, – есть такая традиция у «юниксоидов» делать архивы с помощью двух программ – tar и gzip. Первая соединяет все нужные файлы в один, а вторая их сжимает. Степень сжатия при этом выше, чем, если сжимать все файлы по отдельности. Очень похожим образом, кстати, работает WinRar с его solid-сжатием. И все бы было хорошо, если бы не было так плохо в Windows с tar’ом и gzip’ом. А в Cygwin’е есть и tar и gzip. Все работает, все счастливы. Качайте исходники мегабайтами, учитесь.
  • В-пятых, в-шестых, …

Э-э-э, ты мне пример реального использования покажи…

Хотите примеры? Пожалуйста. Последний пример из реальной жизни.

Писал я плагин для Far’а. Причем писал на Visual C++. При этом нужно было получить список экспортируемых плагином функций. То есть из:

UpAndDown.cpp

void WINAPI _export SetStartupInfo(struct PluginStartupInfo *psi){ ... }

void WINAPI _export GetPluginInfo(struct PluginInfo *pi){ ... }

HANDLE WINAPI _export OpenPlugin(int OpenFrom,int item){ ... }

нужно получить:

UpAndDown.def

EXPORTS ; Список функций SetStartupInfo GetPluginInfo OpenPlugin

Это что ж получается – добавлю я еще одну экспортируемую функцию и мне надо не забыть еще и def-файл параллельно править? Дудки. Смотрю на свои исходники, – все экспортируемые функции выглядят очень и очень похоже, как бы их имена выдрать из исходников?

Решение программиста:

Кусок из makefile

$(DEF): $(OBJS) echo EXPORTS > $(DEF) echo ; This file was created by makefile >> $(DEF) cat .cpp | grep _export | sed "s/. (.)(./ \1/" >> $(DEF)

Как это работает. Программа cat «передает по цепочке» текст всех файлов с расширением cpp программе grep. Та оставляет только строки, в которых присутствует ключевое слово _export и эти строки отдает sed’у:

void WINAPI _export SetStartupInfo(struct PluginStartupInfo *psi){
void WINAPI _export GetPluginInfo(struct PluginInfo *pi){
HANDLE WINAPI _export OpenPlugin(int OpenFrom,int item){

Дальше – сложнее, дальше регулярные выражения. Я минут 10 пытался описать это простенькое в сущности регулярное выражение, но потом понял, что тем, кто с ними еще не знаком, мне не удастся в двух словах изложить материал. Поверьте на слово, что эта последовательность «скобочек и палочек» берет со стандартного входа строку и заменяет ее словом, «которое идет после пробела и за которым стоит открывающая круглая скобка», то есть на выходе конвейера мы получаем только имена экспортируемых функций из всех файлов, текущего каталога, что и требовалось! Они перенаправляются в def-файл, а я про него могу забыть и не вспоминать, он сам создается, сам модифицируется при необходимости.

Резюме

Лень – двигатель прогресса. Скачав и установив себе Cygwin, вы сможете написать скрипт do_all, который будет делать за вас все, причем сразу и на Solaris’е и Windows. Вам остается только курить и мечтательно плевать в потолок. Кстати, хорошая идея…