Показаны сообщения с ярлыком unix. Показать все сообщения
Показаны сообщения с ярлыком unix. Показать все сообщения

суббота, 8 мая 2010 г.

Как получить в C++ список всех файлов из текущего каталога (в Windows, UNIX, MS-DOS)

Материал взят из http://bytes.com/topic/c/answers/545614-list-files-current-directory

Я проверял для Windows - отлично работает :)


Below is a directory lister for Windows, Unix/POSIX and MS-DOS.

#include

#ifdef _WIN32

/* Compiling for Windows */

#include

int main(void)
{
WIN32_FIND_DATA f;
HANDLE h = FindFirstFile("./*", &f);
if(h != INVALID_HANDLE_VALUE)
{
do
{
puts(f.cFileName);
} while(FindNextFile(h, &f));
}
else
{
fprintf(stderr, "Error opening directory\n");
}
return 0;
}

#else
#ifdef __unix__

/* Compiling for UNIX / POSIX */

#include
#include

int main(void)
{
DIR *dir = opendir(".");
if(dir)
{
struct dirent *ent;
while((ent = readdir(dir)) != NULL)
{
puts(ent->d_name);
}
}
else
{
fprintf(stderr, "Error opening directory\n");
}
return 0;
}

#else
#ifdef __TURBOC__

/* Compiling for MS-DOS */

#include

int main(void)
{
struct ffblk ffblk;
if(findfirst("*.*", &ffblk, 0) == 0)
{
do
{
puts(ffblk.ff_name);
} while(findnext(&ffblk) == 0);
}
else
{
fprintf(stderr, "Error opening directory\n");
}
return 0;
}

#else
#error Unsupported Implementation
#endif
#endif
#endif

вторник, 27 апреля 2010 г.

Знакомство с компилятором GCC

Средствами, традиционно используемыми для создания программ для открытых операционных систем, являются инструменты разработчика GNU. Сделаем маленькую историческую справку. Проект GNU был основан в 1984 году Ричардом Столлманом. Его необходимость была вызвана тем, что в то время сотрудничество между программистами было затруднено, так как владельцы коммерческого программного обеспечения чинили многочисленные препятствия такому сотрудничеству. Целью проекта GNU было создание комплекта программного обеспечения под единой лицензией, которая не допускала бы возможности присваивания кем-то эксклюзивных прав на это ПО. Частью этого комплекта и является набор инструментов для разработчика, которым мы будем пользоваться, и который должен входить во все дистрибутивы Linux.

 

Одним из этих инструментов является компилятор GCC. Первоначально эта аббревиатура расшифровывалась, как GNU C Compiler. Сейчас она означает – GNU Compiler Collection.

Создадим первую программу с помощью GCC. По сложившейся традиции первая программа будет просто выводить в консоли приветствие «Hello world!» – «Здравствуй Мир!».

Файлы с исходными кодами программ, которые мы будем создавать, это обычные текстовые файлы, и создавать их можно с помощью любого текстового редактора (например GEdit KWrite, Kate, а также более традиционные для пользователей Linux – vi и emacs). Помимо текстовых редакторов, существуют специализированные среды разработки со своими встроенными редакторами. Одним из таких средств является KDevelop. Интересно, что в нём есть встроенный редактор и встроенная консоль, расположенная прямо под редактором. Так что можно прямо в одной программе, не переключаясь между окнами, и редактировать код и давать консольные команды.

Создайте отдельный каталог hello. Это будет каталог нашего первого проекта. В нём создайте текстовый файл hello.c со следующим текстом:

#include < stdio.h >

 

int main(void)

{

printf("Hello world!\n");

return(0);

}

Затем в консоли зайдите в каталог проекта. Наберите команду

gcc hello.c

Теперь посмотрите внимательно, что произошло. В каталоге появился новый файл a.out. Это и есть исполняемый файл. Запустим его. Наберите в консоли:

./a.out

Программа должна запуститься, то есть должен появиться текст:

Hello world!

Компилятор gcc по умолчанию присваивает всем созданным исполняемым файлам имя a.out. Если хотите назвать его по-другому, нужно к команде на компиляцию добавить флаг -o и имя, которым вы хотите его назвать. Давайте наберём такую команду:

gcc hello.c -o hello

Мы видим, что в каталоге появился исполняемый файл с названием hello. Запустим его.

./hello

Как видите, получился точно такой же исполняемый файл, только с удобным для нас названием.

Флаг -o является лишь одним из многочисленных флагов компилятора gcc. Некоторые другие флаги мы рассмотрим позднее. Чтобы просмотреть все возможные флаги, можно воспользоваться справочной системой man. Наберите в командной строке:

man gcc

Перед вами предстанет справочная система по этой программе. Просмотрите, что означает каждый флаг. С некоторыми из них мы скоро встретимся. Выход из справочной системы осуществляется с помощью клавиши q.

Вы, конечно, обратили внимание, что, когда мы запускаем программу из нашего каталога разработки, мы перед названием файла набираем точку и слэш. Зачем же мы это делаем?

Дело в том, что, если мы наберём только название исполняемого файла, операционная система будет искать его в каталогах /usr/bin и /usr/local/bin, и, естественно, не найдёт. Каталоги /usr/bin и /usr/local/bin – системные каталоги размещения исполняемых программ. Первый из них предназначен для размещения стабильных версий программ, как правило,входящих в дистрибутив Linux. Второй – для программ, устанавливаемых самим пользователем (за стабильность которых никто не ручается). Такая система нужна,чтобы отделить их друг от друга. По умолчанию при сборке программы устанавливаются в каталог /usr/local/bin. Крайне нежелательно помещать что-либо лишнее в /usr/bin или удалять что-то оттуда вручную, потому что это может привести к краху системы. Там должны размещаться программы, за стабильность которых отвечают разработчики дистрибутива.

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

/home/dima/projects/hello/hello

Или другой вариант: прописать путь относительно текущего каталога, в котором вы в данной момент находитесь в консоли. При этом одна точка означает текущий каталог, две точки – родительский. Например, команда ./hello запускает программу hello, находящуюся в текущем каталоге, команда ../hello – программу hello, находящуюся в родительском каталоге, команда ./projects/hello/hello – программу во вложенных каталогах, находящихся внутри текущего.

Есть возможность добавлять в список системных путей к программам дополнительные каталоги. Для этого надо добавить новый путь в системную переменную PATH. Но давайте пока не будем отвлекаться от главной темы. Переменные окружения – это отдельный разговор.

Теперь рассмотрим, что же делает программа gcc. Её работа включает три этапа: обработка препроцессором, компиляция и компоновка (или линковка).

Препроцессор включает в основной файл содержимое всех заголовочных файлов, указанных в директивах #include. В заголовочных файлах обычно находятся объявления функций, используемых в программе, но не определённых в тексте программы. Их определения находятся где-то в другом месте: или в других файлах с исходным кодом или в бинарных библиотеках.

Вторая стадия – компиляция. Она заключается в превращении текста программы на языке C/C++ в набор машинных команд. Результат сохраняется в объектном файле. Разумеется, на машинах с разной архитектурой процессора двоичные файлы получаются в разных форматах, и на одной машине невозможно запустить бинарник, собранный на другой машине (разве только, если у них одинаковая архитектура процессора и одинаковые операционные системы). Вот почему программы для UNIX-подобных систем распространяются в виде исходных кодов: они должны быть доступны всем пользователям, независимо от того, у кого какой процессор и какая операционная система.

Последняя стадия – компоновка. Она заключается в связывании всех объектных файлов проекта в один, связывании вызовов функций с их определениями, и присоединением библиотечных файлов, содержащих функции, которые вызываются, но не определены в проекте. В результате формируется запускаемый файл – наша конечная цель. Если какая-то функция в программе используется, но компоновщик не найдёт место, где эта функция определена, он выдаст сообщение об ошибке, и откажется создавать исполняемый файл.

Теперь посмотрим на практике, как всё это выглядит. Напишем другую программу. Это будет примитивнейший калькулятор, способный складывать, вычитать, умножать и делить. При запуске он будет запрашивать по очереди два числа, над которыми следует произвести действие, а затем потребует ввести знак арифметического действия. Это могут быть четыре знака: «+», «–», «*», «/». После этого программа выводит результат и останавливается (возвращает нас в операционную систему, а точнее – в командный интерпретатор, из которого мы программу и вызывали).

Создадим для проекта новую папку kalkul, в ней создадим файл kalkul.c.

#include < stdio.h >

 

int main(void)

{

float num1;

float num2;

char op;

 

printf("Первое число: ");

scanf("%f",&num1);

 

printf("Второе число: ");

scanf("%f",&num2);

 

printf("Оператор ( + - * / ): ");

while ((op = getchar()) != EOF)

{

if (op == '+')

{

printf("%6.2f\n",num1 + num2);

break;

}

else if(op == '-')

{

printf("%6.2f\n",num1 - num2);

break;

}

else if(op == '*')

{

printf("%6.2f\n",num1 * num2);

break;

}

else if(op == '/')

{

if(num2 == 0)

{

printf("Ошибка: деление на ноль!\n");

break;

}

else

{

printf("%6.2f\n",num1 / num2);

break;

}

}

}

 

return 0;

}

Итак, первым делом, как было сказано, выполняется препроцессинг. Для того, чтобы посмотреть, что на этом этапе делается, воспользуемся опцией -E. Эта опция останавливает выполнение программы на этапе обработки препроцессором. В результате получается файл исходного кода с включённым в него содержимым заголовочных файлов.

В нашем случае мы включали один заголовочный файл – stdio.h – коллекцию стандартных функций ввода-вывода. Эти функции и выводили на консоль нужный текст, а также считывали с консоли вводимые нами слова.

Введите следующую команду:

gcc -E kalkul.c -o kalkul.cpp

Полученному файлу мы дали имя kalkul.cpp. Откройте его. Обратите внимание на то, что он весьма длинный. Это потому что в него вошёл весь код заголовочного файла stdio.h. Кроме того, препроцессор сюда добавил некоторые теги, указывающие компилятору способ связи с объявленными функциями. Основной текст нашей программы виден только в самом низу.

Можете заодно посмотреть, какие ещё функции объявлены в заголовочном файле stdio.h. Если вам захочется получить информацию о какой-нибудь функции, можно поинтересоваться о ней во встроенном руководстве man. Например, если вам вдруг захочется узнать, что же делает таинственная функция fopen, можно набрать:

man fopen

Много информации также есть в справочной системе info.

info fopen

Можно поинтересоваться и всем заголовочным файлом сразу.

man stdio.h

info stdio.h

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

gcc -c kalkul.c

Название получаемого файла можно не указывать, так как компилятор просто берёт название исходного и меняет расширение .c на .o (указать можно, если нам захочется назвать его по-другому).

Если мы создаём объектный файл из исходника, уже обработанного препроцессором (например, такого, какой мы получили выше), то мы должны обязательно указать явно, что компилируемый файл является файлом исходного кода, обработанный препроцессором, и имеющий теги препроцессора. В противном случае он будет обрабатываться, как обычный файл C++, без учёта тегов препроцессора, а значит связь с объявленными функциями не будет устанавливаться. Для явного указания на язык и формат обрабатываемого файла служит опция -x. Файл C++, обработанный препроцессором обозначается cpp-output.

gcc -x cpp-output -c kalkul.cpp

Наконец, последний этап – компоновка. Получаем из объектного файла исполняемый.

gcc kalkul.o -o kalkul

Можно его запускать.

./kalkul

Вы спросите: «Зачем вся эта возня с промежуточными этапами? Не лучше ли просто один раз скомандовать gcc kalkul.c -o kalkul?»

Дело в том, что настоящие программы очень редко состоят из одного файла. Как правило исходных файлов несколько, и они объединены в проект. И в некоторых исключительных случаях программу приходится компоновать из нескольких частей, написанных на разных языка. В этом случае приходится запускать компиляторы разных языков, чтобы каждый получил объектный файл из своего исходника, а затем уже эти полученные объектные файлы компоновать в исполняемую программу.

[ опубликовано 06/09/2006 ]

Дмитрий Пантелеичев (dimanix2006 at rambler dot ru) - Знакомство с компилятором GCC

Материал взят из http://www.linuxcenter.ru/lib/books/linuxdev/linuxdev1.phtml?style=print

Как сделать скрипт для компиляции и линковки сразу нескольких Xcode-проектов

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

В Мac OS в командной строке (в терминале) всё делается примерно также, как и в любой Unix-подобной системе.

Чтобы оставаться в терминале, можно даже и не открывать текстовый отдельный редактор, потому что есть встроенные редактор vi (или vim, насколько я знаю, этот редактор очень любят старые Linux-хакеры). Справку по этому редактору можно найти во многих статьях и учебниках (посвящённых Unix/Linux).

В самом верху вашего скрипта (текстового файла, содержащего все необходимые команды для выполнения) введите:

#!/bin/bash

Для того, чтобы добавить в скрипт команду для сборки (компиляции и линковки) Xcode-проекта, добавьте строку (вместо myProject.xcodeproj нужно указать правильный путь к файлу проекта):

xcodebuild -project myProject.xcodeproj -target targetname

(насчёт аргумента, который нужно ввести вместо targetname можно выяснять набрав команду
man xcodebuild

Можно заранее сделать все настройки, открыв проект в среде разработки Xcode (и поставив все необходимые опции, используя графический интерфейс). А потом уже написать в скрипте:

xcodebuild -project myProject.xcodeproj -activetarget

При выполнении этой команды всё будет компилироваться и линковаться точно также, как если бы вы снова открыли ваш проект в среде разработки и нажали на кнопочку "Build".


После того, как напишите и сохраните ваш скрипт (из команд для сборки нескольких проектов), обязательно позвольте ему стать исполняемым файлом, выполнив в терминале команду (при условии, что вместо scriptFileName указан правильный путь к файлу):

chmod +x scriptFileName

Если после компиляции+линковки (т.е. после сборки бинарника) вы видите, что дата создания бинарного файла стоит старая, то это лишь из-за того, что в исходниках или настройках проекта ничего не изменялось со времени прошлой сборки бинарника.

Ну вот собственно и всё.

Pthread Condition Variables и Windows Events (Креатив)

Материал взят из http://mejedi.livejournal.com/27180.html

Две такие похожие истории...

* Condition Variables
Жили-были процессы и была у них на всех одна открывашка. Когда процесс хочет выпить пива, он хватает открывашку. Если после этого процесс обнаруживает, что открывать ему нечего, он скрепя сердце возвращает открывашку и встает в одну из очередей.

Иногда приходит добрый дядька с пивом. Если в очереди никого нет, он тут же уходит.

1. pthread_cond_signal()
Приходит добрый дядька, приносит первому процессу в очереди бутылку пива и уходит. Процесс бежит хватать открывашку.

2. pthread_cond_broadcast()
Приходит добрый дядька, приносит всем процессам в очереди по пиву, и уходит. Процессы наперегонки бегут хватать открывашку.

Бывает так, что процессу не нравится полученное пиво. Тогда он снова встает в очередь.

* Events
Жили были процессы и была у каждого своя открывашка. Когда процессы хотят выпить пива, они выстраиваются в очереди. Очередь обслуживают двое дядек с очень разными характерами – Manual Reset Дядько и Auto Reset Дядько.

M.R. Дядько очень терпеливый. Он выдает всем стояльцем в очереди по пиву, и ждет чтобы кто-нибудь пришел еще. Всем новоприбывшим Дядько тоже дает пиво. Если управляющий не отзовет дядьку, он так и будет бесконечно всем давать пиво.

A.R. Дядько тоже терпеливый. Если он пришел – а в очереди никого, он подождет. С собой у Дядько только одна бутылка, поэтому он уйдет как только отдаст её первому процессу в очереди.

1. SetEvent()
Позвать дядьку.

2. ResetEvent()
Прогнать дядьку.

3. PulseEvent()
Управляющей звонит дядьке и говорит чтобы он принес пива. Потом перзванивает, и говорит что передумал. Потом звонит снова и говорит что пиво всё-таки надо нести. И так много раз. Дядька может сойти с ума и всех поубивать.


Между ними нет ничего общего. Auto Reset Event и pthread_cond_signal() ничем не похожи. Manual Reset Event не имеет никакого отношения к бродкастам. Отличия в самой модели. Pthread Condition Variables мгновенны, а Windows Events инерционны.

Когда сигналится condition variable, создается мгновенный и актуальный список ожидающих на c/v процессов. Далее пробуждаются или все процессы или только первый. Из-за этой мгновенности c/v всегда используется только вместе с мьютексом, чтобы не прозевать событие, которое сигналится с помощью c/v.

Семантика такова – pthread_cond_wait() принимает указатель на c/v и залоченный мьютекс. Затем атомарно разлочивается мьютекс и процесс ждет пока c/v не будет просигналена. Наконец мьютекс захватывается снова, и pthread_cond_wait() завершается. Предполагается, что если c/v просигналена пока процесс держит мьютекс, это можно безопасно проигнорировать. Обычно это на самом деле так, потому что используется мьютекс, который защищает структуру данных, изменение состояния которой сигналится с помощью c/v. Если мы взяли мьютекс, то можем спокойно проверить данные на предмет соответствия интересующему нас состоянию. Классический пример – защищенная мьютексом очередь сообщений и c/v, которая сигналится при каждом помещении собщения в очередь.

Напротив, в ОС Windows невозможно сформировать актуальный список процессов, ожидающих на определенном объекте. В процесс может быть доставлена kernel-mode APC, после чего процесс временно покинет состояние ожидания. Второй источник инерционности – это семантика функции WaitForMultipleObjects(bWaitAll=TRUE). Процесс не покинет состояние ожидания до тех пор, пока все объекты не перейдут в signaled state. Концепция этого самого signaled state напрямую диктует, что примитивы синхронизации инерционны. Объект может потерять signaled state если разблокируется ожидающий на нем процесс, просто так потерять signaled state нельзя.

Бесполезно передергивать Auto Reset Event чтобы достичь эффекта бродкаста. Manual Reset Event также бесполезно передергивать. Попытка сделать это вручную – SetEvent(); ResetEvent(); – также не даст результатов. Нет гарантий, что в промежутке между установкой и сбросом события кто-то успеет заметить изменение состояния события и разблокируется.

Это конечно не значит, что conditional variable нельзя сделать в Windows. Очевидно, придется собирать conditional variable из нескольких независимых примитивов синхронизации. Её не получится использовать в WaitForMultipleObjects() совместно с другими объектами синхронизации.

Постоянные читатели