IPB

Здравствуйте, гость ( Вход | Регистрация )

 
Ответить в эту темуОткрыть новую тему
> Разработка программного обеспечения для Linux. Инструментарий., О сборке программ из исходного кода
Поделиться
and
сообщение 14.10.2013, 8:36
Сообщение #1


Мастер
******

Группа: Пользователь
Сообщений: 530
Регистрация: 22.8.2007
Вставить ник
Цитата
Пользователь №: 317
Страна: Россия
Город: Не указан
Пол: Муж.



Репутация: 6


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


Разработка программного обеспечения для Linux. Инструментарий.

[ впервые опубликовано 06/09/2006 ]
Дмитрий Пантелеичев (dimanix2006 at rambler dot ru)

Этот курс предназначен для тех, кто желает вступить в ряды сообщества разработчиков Open Source, но никогда раньше не программировал под Linux, и нуждается в получении самых начальных знаний в этой области. Здесь будут рассмотрены основы основ любого программирования – пользование программистскими инструментами. Освоив эти уроки, человек сможет приступить к углублённому изучению любого аспекта программирования в Linux, и уже не будет бояться программного кода или
мучиться над вопросом «как это собрать и запустить».

Думаю, что в наше время многие хорошо знают про идеологию Open Source, и хотели бы попробовать себя в этой интереснейшей области, но чувствуют нехватку знаний, и не знают, с чего начать учиться. Для них-то и предназначен этот курс.

В качестве языка программирования будет использован язык C – стандартный язык для UNIX-подобных операционных систем, который и был создан специально для написания первых версий UNIX, а также будем использовать его позднейшее расширение – С++. Настоятельно рекомендуется прежде изучения этого материала (или параллельно с ним) пройти также курс по основам языков C/C++.

Содержание.

Знакомство с компилятором GCC
Пример проекта из нескольких файлов
Make-файлы
Компилятор G++
Средства обеспечения переносимости и распространения
Библиотеки, утилита libtool
Подготовка библиотеки к распространению
Программы с оконным интерфейсом
Знакомство с отладчиком gdb

Сообщение отредактировал and - 20.10.2013, 21:42
Вернуться в начало страницы
 
+Ответить с цитированием данного сообщения
and
сообщение 18.10.2013, 11:40
Сообщение #2


Мастер
******

Группа: Пользователь
Сообщений: 530
Регистрация: 22.8.2007
Вставить ник
Цитата
Пользователь №: 317
Страна: Россия
Город: Не указан
Пол: Муж.



Репутация: 6


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

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

Одним из этих инструментов является компилятор GCC. Первоначально эта аббревиатура расшифровывалась, как GNU C Compiler. Сейчас она означает – GNU Compiler Collection.
Создадим первую программу с помощью GCC. По сложившейся традиции первая программа будет просто выводить в консоли приветствие «Hello world!» – «Здравствуй Мир!».
Файлы с исходными кодами программ, которые мы будем создавать, это обычные текстовые файлы, и создавать их можно с помощью любого текстового редактора (например GEdit KWrite, Kate, а также более традиционные для пользователей Linux – vi и emacs). Помимо текстовых редакторов, существуют специализированные среды разработки со своими встроенными редакторами. Одним из таких средств является IDE Geany. Интересно, что в ней есть встроенная консоль, расположенная прямо под редактором. Так что можно прямо в одной программе, не переключаясь между окнами, и редактировать код и давать консольные команды. Надо только убедиться,
что в меню Правка/Настройки/Терминал отмечен пункт "Следовать пути текущего файла"

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

Код
#include <stdio.h>
int main(void)
{
printf("Hello world!\n");
return(0);
}


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

gcc hello.c

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

./a.out

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

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

Флаг -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.
CODE
#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?»

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



Сообщение отредактировал and - 18.10.2013, 11:55
Вернуться в начало страницы
 
+Ответить с цитированием данного сообщения
and
сообщение 18.10.2013, 11:44
Сообщение #3


Мастер
******

Группа: Пользователь
Сообщений: 530
Регистрация: 22.8.2007
Вставить ник
Цитата
Пользователь №: 317
Страна: Россия
Город: Не указан
Пол: Муж.



Репутация: 6


Пример проекта из нескольких файлов.

Напишем теперь программу, состоящую из двух исходных файлов и одного заголовочного. Для этого возьмём наш калькулятор и переделаем его. Теперь после введения первого числа надо сразу вводить действие. Если действие оперирует только с одним числом (как в случае синуса, косинуса, тангенса, квадратного корня), результат сразу будет выведен. Если понадобится второе число, оно будет специально запрашиваться.
Создадим каталог проекта kalkul2. В нём создадим три файла: calculate.h, calculate.c, main.c.

Файл calculate.h:
Код
///////////////////////////////////////
// calculate.h
#ifndef CALCULATE_H_
#define CALCULATE_H_
float Calculate(float Numeral, char Operation[4]);
#endif /*CALCULATE_H_*/


Файл calculate.c:
CODE

////////////////////////////////////
// calculate.c
#include <stdio.h>
#include <math.h>
#include <string.h>
#include "calculate.h"
float Calculate(float Numeral, char Operation[4])
{
float SecondNumeral;
if(strncmp(Operation, "+", 1) == 0)
{
printf("Второе слагаемое: ");
scanf("%f",&SecondNumeral);
return(Numeral + SecondNumeral);
}
else if(strncmp(Operation, "-", 1) == 0)
{
printf("Вычитаемое: ");
scanf("%f",&SecondNumeral);
return(Numeral - SecondNumeral);
}
else if(strncmp(Operation, "*", 1) == 0)
{
printf("Множитель: ");
scanf("%f",&SecondNumeral);
return(Numeral * SecondNumeral);
}
else if(strncmp(Operation, "/", 1) == 0)
{
printf("Делитель: ");
scanf("%f",&SecondNumeral);
if(SecondNumeral == 0)
{
printf("Ошибка: деление на ноль! ");
return(HUGE_VAL);
}
else
return(Numeral / SecondNumeral);
}
else if(strncmp(Operation, "pow", 3) == 0)
{
printf("Степень: ");
scanf("%f",&SecondNumeral);
return(pow(Numeral, SecondNumeral));
}
else if(strncmp(Operation, "sqrt", 4) == 0)
return(sqrt(Numeral));
else if(strncmp(Operation, "sin", 3) == 0)
return(sin(Numeral));
else if(strncmp(Operation, "cos", 3) == 0)
return(cos(Numeral));
else if(strncmp(Operation, "tan", 3) == 0)
return(tan(Numeral));
else
{
printf("Неправильно введено действие ");
return(HUGE_VAL);
}
}



Файл main.c:
Код
////////////////////////////////////////
// main.c
#include <stdio.h>
#include "calculate.h"
int main(void)
{
float Numeral;
char Operation[4];
float Result;
printf("Число: ");
scanf("%f",&Numeral);
printf("Арифметическое действие (+,-,*,/,pow,sqrt,sin,cos,tan): ");
scanf("%s",&Operation);
Result = Calculate(Numeral, Operation);
printf("%6.2f\n",Result);
return 0;
}

У нас есть два файла исходного кода (c-файлы) и один заголовочный (h-файл). Заголовочный включается в оба c-файла.
Скомпилируем calculate.c.

gcc -c calculate.c

Получили calculate.o. Затем main.c.

gcc -c main.c

И вот он main.o перед нами! Теперь, как вам уже, наверное, подсказывает интуиция, надо из этих двух объектных файлов сделать запускаемый.

gcc calculate.o main.o -o kalkul

Упс... и не получилось... Вместо столь желаемого запускаемого файла, в консоли появилась какая-то ругань:

calculate.o: In function `Calculate':
calculate.c:(.text+0x17a): undefined reference to `pow'
calculate.c:(.text+0x1c2): undefined reference to `sqrt'
calculate.c:(.text+0x1fb): undefined reference to `sin'
calculate.c:(.text+0x22d): undefined reference to `cos'
calculate.c:(.text+0x25f): undefined reference to `tan'
collect2: ld returned 1 exit status

Давайте разберёмся, за что нас так отругали. Undefined reference означает ссылку на функцию, которая не определена. В данном случае gcc не нашёл определения функций pow, sqrt, sin, cos, tan. Где же их найти?

Как уже говорилось раньше, определения функций могут находиться в библиотеках. Это скомпилированные двоичные файлы, содержащие коллекции однотипных операций, которые часто вызываются из многих программ, а потому нет смысла многократно писать их код в программах.
Стандартное расположение файлов библиотек – каталоги /usr/lib и /usr/local/lib (при желании можно добавить путь). Если библиотечный файл имеет расширение .a, то это статическая библиотека, то есть при компоновке весь её двоичный код включается в исполняемый файл. Если расширение .so, то это динамическая библиотека. Это значит в исполняемый файл программы помещается только ссылка на библиотечный файл, а уже из него и запускается функция.

Когда мы писали программу hello, мы использовали функцию printf для вывода текстовой строки. Однако, как вы помните, мы нигде не писали определения этой функции. Откуда же она тогда вызывается?
Просто при компоновке любой программы компилятор gcc по умолчанию включает в запускаемый файл библиотеку libc. Это стандартная библиотека языка C. Она содержит рутинные функции, необходимые абсолютно во всех программах, написанных на C, в том числе и функцию printf.
Поскольку библиотека libc нужна во всех программах, она включается по умолчанию, без необходимости давать отдельное указание на её включение.
Остальные библиотеки надо требовать включать явно. Ведь нельзя же во все программы помещать абсолютно все библиотеки. Тогда исполняемый файл раздуется до немыслимо крупных размеров.

Одним программам нужны одни функции, другим – другие. Зачем же засорять их ненужным кодом! Пусть остаётся только то, что реально необходимо. Нам в данном случае нужна библиотека libm. Именно она содержит все основные математические функции. Она требует включения в текст программы заголовочного файла <math.h>.
Помимо этого дистрибутивы Linux содержат и другие библиотеки, например:

libGL Вывод трёхмерной графики в стандарте OpenGL. Требуется заголовочный файл <GL/gl.h>.
libcrypt Криптографические функции. Требуется заголовочный файл <crypt.h>.
libcurses Псевдографика в символьном режиме. Требуется заголовочный файл <curses.h>.
libform Создание экранных форм в текстовом режиме. Требуется заголовочный файл <form.h>.
libgthread Поддержка многопоточного режима. Требуется заголовочный файл <glib.h>.
libgtk Графическая библиотека в режиме X Window. Требуется заголовочный файл <gtk/gtk.h>.
libhistory Работы с журналами. Требуется заголовочный файл <readline/readline.h>.
libjpeg Работа с изображениям в формате JPEG. Требуется заголовочный файл <jpeglib.h>.
libncurses Работа с псевдографикой в символьном режиме. Требуется заголовочный файл <ncurses.h>.
libpng Работа с графикой в формате PNG. Требуется заголовочный файл <png.h>.
libpthread Многопоточная библиотека POSIX. Стандартная многопоточная библиотека для Linux.
Требуется заголовочный файл <pthread.h>.
libreadline Работа с командной строкой. Требуется заголовочный файл <readline/readline.h>.
libtiff Работа с графикой в формате TIFF. Требуется заголовочный файл <tiffio.h>.
libvga Низкоуровневая работа с VGA и SVGA. Требуется заголовочный файл <vga.h>.
А также многие-многие другие.

Обратите внимание, что названия всех этих библиотек начинаются с буквосочетания lib-. Для их явного включения в исполняемый файл, нужно добавить к команде gcc опцию -l, к которой слитно прибавить название библиотеки без lib-. Например, чтобы включить библиотеку libvga надо указать опцию -lvga.
Нам нужны математические функции pow, sqrt, sin, cos, tan. Они, как уже было сказано, находятся в математической библиотеке libm. Следовательно, чтобы подключить эту библиотеку, мы должны указать опцию -lm.

gcc calculate.o main.o -o kalkul -lm

Ура! Наконец-то наш запускаемый файл создан!

Сообщение отредактировал and - 18.10.2013, 12:05
Вернуться в начало страницы
 
+Ответить с цитированием данного сообщения
and
сообщение 18.10.2013, 11:53
Сообщение #4


Мастер
******

Группа: Пользователь
Сообщений: 530
Регистрация: 22.8.2007
Вставить ник
Цитата
Пользователь №: 317
Страна: Россия
Город: Не указан
Пол: Муж.



Репутация: 6


Make-файлы.

У вас, вероятно, появился вопрос: можно ли не компилировать эти файлы по отдельности, собрать
сразу всю программу одной командой? Можно.

gcc calculate.c main.c -o kalkul -lm

Вы скажете, что это удобно? Удобно для нашей программы, потому что она состоит всего из двух c-
файлов. Однако профессиональная программа может состоять из нескольких десятков таких файлов.
Каждый раз набирать названия их всех в одной строке было бы делом чрезмерно утомительным. Но
есть возможность решить эту проблему. Названия всех исходных файлов и все команды для сборки
программы можно поместить в отдельный текстовый файл. А потом считывать их оттуда одной
короткой командой.

Давайте создадим такой текстовый файл и воспользуемся им. В каталоге проекта kalkul2 удалите все
файлы, кроме calculate.h, calculate.c, main.c. Затем создайте в этом же каталоге новый файл, назовите
его Makefile (без расширений). Поместите туда следующий текст.
Код
kalkul: calculate.o main.o
    gcc calculate.o main.o -o kalkul -lm
calculate.o: calculate.c calculate.h
    gcc -c calculate.c
main.o: main.c calculate.h
    gcc -c main.c
clean:
    rm -f kalkul calculate.o main.o
install:
    cp kalkul /usr/local/bin/kalkul
uninstall:
    rm -f /usr/local/bin/kalkul

Обратите внимание на строки, введённые с отступом от левого края. Этот отступ получен с помощью
клавиши Tab. Только так его и надо делать! Если будете использовать клавишу «Пробел», команды не
будут исполняться.
Затем дадим команду, состоящую всего из одного слова:

make

И сразу же в нашем проекте появляются и объектные файлы и запускаемый. Программа make как раз
и предназначена для интерпретации команд, находящихся в файле со стандартным названием
Makefile. Рассмотрим его структуру.
Makefile является списком правил. Каждое правило начинается с указателя, называемого «Цель».
После него стоит двоеточие, а далее через пробел указываются зависимости. В нашем случае ясно,
что конечный файл kalkul зависит от объектных файлов calculate.o и main.o. Поэтому они должны
быть собраны прежде сборки kalkul. После зависимостей пишутся команды. Каждая команда должна
находиться на отдельной строке, и отделяться от начала строки клавишей Tab. Структура правила
Makefile может быть очень сложной. Там могут присутствовать переменные, конструкции ветвления,
цикла. Этот вопрос требует отдельного подробного изучения.
Если мы посмотрим на три первых правила, то они нам хорошо понятны. Там те же самые команды,
которыми мы уже пользовались. А что же означают правила clean, install и uninstall?

В правиле clean стоит команда rm, удаляющая исполняемый и объектные файлы. Флаг -f означает,
что, если удаляемый файл отсутствует, программа должна это проигнорировать, не выдавая никаких
сообщений. Итак, правило clean предназначено для «очистки» проекта, приведения его к такому
состоянию, в каком он был до команды make.
Запустите
make

Появились объектные файлы и исполняемый. Теперь
make clean

Объектные и исполняемый файлы исчезли. Остались только c-файлы, h-файл и сам Makefile. То есть,
проект «очистился» от результатов команды make.
Правило install помещает исполняемый файл в каталог /usr/local/bin – стандартный каталог
азмещения пользовательских программ. Это значит, что её можно будет вызывать из любого места
простым набором её имени. Но помещать что-либо в этот каталог можно только, зайдя в систему под
«суперпользователем». Для этого надо дать команду su и набрать пароль «суперпользователя». В
противном случае система укажет, что вам отказано в доступе. Выход из «суперпользователя»
осуществляется командой exit. Итак,

make
su
make install
exit

Теперь вы можете запустить это программу просто, введя имя программы, без прописывания пути.
kalkul

Можете открыть каталог /usr/local/bin. Там должен появиться файл с названием kalkul.
Давайте теперь «уберём за собой», не будем засорять систему.

su
make uninstall
exit

Посмотрите каталог /usr/local/bin. Файл kalkul исчез. Итак, правило uninstall удаляет программу из
системного каталога.


Сообщение отредактировал and - 19.10.2013, 11:06
Вернуться в начало страницы
 
+Ответить с цитированием данного сообщения
and
сообщение 19.10.2013, 11:09
Сообщение #5


Мастер
******

Группа: Пользователь
Сообщений: 530
Регистрация: 22.8.2007
Вставить ник
Цитата
Пользователь №: 317
Страна: Россия
Город: Не указан
Пол: Муж.



Репутация: 6


Компилятор G++

Первым делом проверим есть ли он в системе скомандовав в консоли g++. Если компилятор не найден, ставим соответствующие пакеты. Для Альт-Линукс это gcc-c++ и libstdc++-devel-static. Номера их версий должны совпадать с версиями установленного компилятора gcc, например 4.5 или 4.7.

Давайте снова переделаем нашу программу, но на этот раз уже напишем её на C++.
Создайте новый каталог проекта kalkulcpp, а в нём три файла: problem.h, problem.cpp, main.cpp.

Файл problem.h

CODE

#ifndef PROBLEM_H_
#define PROBLEM_H_
#include <string>
using namespace std;
class CProblem
{
private:
float Numeral;
float SecondNumeral;
string Operation;
float Result;
string Error;
bool Calculate();

public:
void SetValues();
void Solve();
};
#endif /*PROBLEM_H_*/

Файл problem.cpp
CODE

#include <iostream>
#include <cmath>
#include "problem.h"
using namespace std;


void CProblem::SetValues()
{
cout << "Число: ";
cin >> Numeral;
cout << "Арифметическое действие (+,-,*,/,pow,sqrt,sin,cos,tan): ";
cin >> Operation;
}
bool CProblem::Calculate()
{
if(Operation == "+")
{
cout << "Второе слагаемое: ";
cin >> SecondNumeral;
Result = Numeral + SecondNumeral;
return true;
}
else if(Operation == "-")
{
cout << "Второе слагаемое: ";
cin >> SecondNumeral;
Result = Numeral - SecondNumeral;
return true;
}
else if(Operation == "*")
{
cout << "Множитель: ";
cin >> SecondNumeral;
Result = Numeral * SecondNumeral;
return true;
}
else if(Operation == "/")
{
cout << "Делитель: ";

cin >> SecondNumeral;
if(SecondNumeral == 0)
{
Error = "Ошибка: деление на ноль.";
return false;
}
else
{
Result = Numeral/SecondNumeral;
return true;
}
}
else if(Operation == "pow")
{
cout << "Степень: ";
cin >> SecondNumeral;
Result = pow(Numeral,SecondNumeral);
return true;
}
else if(Operation == "sqrt")
{
Result = sqrt(Numeral);
return true;
}
else if(Operation == "sin")
{
Result = sin(Numeral);
return true;
}
else if(Operation == "cos")
{
Result = cos(Numeral);
return true;
}
else if(Operation == "tan")
{
Result = tan(Numeral);
return true;
}
else
{
Error = "Ошибка ввода действия.";
return false;
}
}
void CProblem::Solve()
{
if(Calculate() == true)
cout << Result << "\n";
else
cout << Error << "\n";
}

Файл main.cpp
Код
#include <iostream>
#include "problem.h"
using namespace std;
int main(void)
{
CProblem *Problem;
Problem = new CProblem;
Problem->SetValues();
Problem->Solve();
delete Problem;
return(0);
}

Для сборки программ на C++ в наборе GNU имеется другой компилятор – G++. Он отличается от GCC тем, что по умолчанию подключает не стандартную библиотеку C, а стандартную библиотеку C++. Все флаги и опции у G++ такие же точно, как и у GCC. Воспользуемся компилятором G++.

g++ problem.cpp main.cpp -o kalkul

Обратите внимание, что никаких дополнительных библиотек мы не подключали. Это означает, что математические функции входят в стандартную библиотеку C++. Вообще, в тех случаях, когда программа пишется на C++, рекомендуется использовать именно G++.

Вы уже знаете, что собирать программы таким простым способом можно только в учебных целях. В профессиональной же работе ваши проекты будут включать большое количество файлов, и вам придётся пользоваться утилитой make. Создадим Makefile.
Код
kalkul: problem.o main.o
    g++ problem.o main.o -o kalkul
problem.o: problem.cpp problem.h
    g++ -c problem.cpp
main.o: main.cpp problem.h
    g++ -c main.cpp
clean:
    rm -f kalkul problem.o main.o
install:
    cp kalkul /usr/local/bin/kalkul
uninstall:
    rm -f /usr/local/bin/kalkul

И соберём эту же программу снова, но уже «правильным» способом.

make

«Инсталлируем» её, предварительно зайдя в систему, как суперпользователь.

su
make install

exit

«Деинсталлируем».

su
make uninstall
exit

И очистим дистрибутив.

make clean

Сообщение отредактировал and - 19.10.2013, 11:16
Вернуться в начало страницы
 
+Ответить с цитированием данного сообщения
and
сообщение 19.10.2013, 18:21
Сообщение #6


Мастер
******

Группа: Пользователь
Сообщений: 530
Регистрация: 22.8.2007
Вставить ник
Цитата
Пользователь №: 317
Страна: Россия
Город: Не указан
Пол: Муж.



Репутация: 6


Средства обеспечения переносимости и распространения.

А теперь мы должны рассмотреть вопросы переносимости программ. Переносимость в мире UNIX имеет чрезвычайно большое значение. Количество реализаций UNIX, её клонов и UNIX-подобных систем весьма велико, и невозможно заранее предвидеть, на какой из них будет работать ваша программа. В разных реализациях могут быть разные версии компилятора, может быть по-разному организована система стандартных каталогов для исполняемых файлов. Предлагать пользователю самостоятельно редактировать make-файлы в соответствии со своей системой – дело недопустимое. Необходимо, чтобы пользователь мог установить программу всего за несколько простых шагов. Следовательно, разработчик должен приложить к программе скрипт, который исследовал бы платформу пользователя и, в соответствии с ней, автоматически сгенерировал наиболее подходящий make-файл.
Ясно, что такой скрипт будет очень сложным по структуре, и написание его вручную чревато многочисленными ошибками. К счастью, этого делать и не надо. В наборе инструментов GNU имеются средства, автоматически создающие такой скрипт (иногда они упоминаются под собирательным названием Autotools).
Итак, пользователь получает ваш дистрибутив, состоящий из файлов исходного кода, среди этих файлов должен быть и тот самый вышеуказанный скрипт. Его общепринятое название – configure.
Далее перед пользователем стоят всего две задачи. Первая – запустить этот скрипт.
./configure

В результате должен сгенерироваться Makefile. А, поскольку есть Makefile, то вторая задача – запустить хорошо знакомую нам программу make.
make

Будет собран запускаемый файл вашей программы. Пользователь может поместить его в стандартный каталог с исполняемыми программами с помощью команды make install (предварительно зайдя в систему в режиме суперпользователя), удалить его оттуда командой make uninstall, очистить дистрибутив от сгенерированных файлов командой make clean и т. д.
Итак, задача разработчика – подготовить скрипт configure.
Вначале создадим в каталоге проекта всего два простых файла: Makefile.am и configure.ac (желательно перед этим удалить оттуда, все файлы, что мы создавали раньше, оставить только problem.h, problem.cpp, main.cpp).

Файл Makefile.am:
Код
bin_PROGRAMS=kalkul
kalkul_SOURCES=problem.h problem.cpp main.cpp

Файл configure.ac:
Код
AC_INIT(main.cpp)
AM_INIT_AUTOMAKE(kalkul,0.1)
AC_PROG_CC
AC_PROG_CXX
AC_PROG_INSTALL
AC_OUTPUT(Makefile)

Этого вполне достаточно для формирования нужного нам скрипта. Значения этих записей, наверное, интуитивно понятны. bin_PROGRAMS=kalkul указывает, как должен называться конечный запускаемый файл. kalkul_SOURCES=problem.h problem.cpp main.cpp указывает на все исходные файлы, участвующие в сборке этой программы. Если бы наша программа называлась как-нибудь по-другому (например reader), то вместо kalkul_SOURCES стояло бы reader_SOURCES и т. д.
Скрипт configure.ac должен всегда начинаться директивой AC_INIT и заканчиваться AC_OUTPUT. Его команды означают следующее.
AC_INIT(main.cpp) является инициализацией этого скрипта. Ему в качестве параметра передаётся название любого из исходных файлов. Он проверяет, находится ли в данном каталоге такой файл. И, если он находится, значит каталог действительно является рабочим.
AM_INIT_AUTOMAKE(kalkul,0.1) указывает, что мы будем использовать утилиту automake. Параметры указывают на название и версию, которые программа должна получить после сборки.
AC_PROG_CC и AC_PROG_CXX указывают, каким синтаксисом и с применением каких библиотек программа написана. Это помогает выбрать соответствующий компилятор. Наша программа написана целиком на C++ и использует стандартную библиотеку C++, поэтому здесь мы можем оставить только AC_PROG_CXX. Если бы мы использовали предыдущую, C-версию программы, можно было бы оставить только AC_PROG_CC. В крупных программах, где используются элементы и того и другого, пишутся обе директивы.
AC_PROG_INSTALL указывает, что надо в make-файле сформировать цель install, чтобы пользователь мог командой make install установить программу в системный каталог.
AC_OUTPUT завершает скрипт и указывает, что конечный файл должен называться Makefile.
Теперь в консоли заходим в каталог проекта, и даём по очереди следующие команды:
Код
aclocal
autoconf
touch README AUTHORS NEWS ChangeLog
automake -a
./configure
make

После всего этого, если всё прошло нормально, в проекте должен появиться исполняемый файл. Теперь, если вы хотите сформировать дистрибутив для распространения, дайте команду
make dist

В папке проекта должен появиться архив kalkul-0.1.tar.gz
Можете теперь его выкладывать в интернете или рассылать друзьям по электронной почте. :-)
Что же должен сделать получатель вашего творения? Вначале распаковать архив.
gunzip kalkul-0.1.tar.gz
tar xf kalkul-0.1.tar

Затем зайти в каталог с дистрибутивом.
cd kalkul-0.1

Автоматически сформировать Makefile, который будет зависеть от конфигурации его операционной системы.
./configure

Затем собрать программу.
make

И установить её в системном каталоге, предварительно зайдя в режиме суперпользователя.
su
make install
exit

Чтобы удалить её, нужно указать make uninstall в режиме суперпользователя:
su
make uninstall
exit

Разберём команды, которые мы сейчас вводили:

aclocal сканирует файл configure.ac и, в зависимости от его директив, формирует макросы, предназначенные для autoconf и automake; эти макросы сохраняются в файле aclocal.m4;
autoconf формирует скрипт configure в зависимости от содержимого configure.ac;
automake формирует скрипт Makefile.in в зависимости от содержимого Makefile.am; в дальнейшем пользователь, запустив configure, сформирует Makefile на основании Makefile.in. Флаг -a означает, что, если программа не найдёт в каталоге проекта файлов install-sh, missing, INSTALL, COPYING, depcomp, она автоматически создаёт их.
Если мы просто запустим команды в таком порядке, то automake выдаст много «жалоб» и откажется работать. Дело в том, что дополнительная задача automake – проверка соответствия нашего дистрибутива стандартам GNU. В соответствии с этими стандартами, в дистрибутиве обязательно должны присутствовать файлы NEWS, README, AUTHORS, ChangeLog. Чтобы избавить себя от выслушивания жалоб, создадим эти файлы командой touch NEWS README AUTHORS ChangeLog. Системная утилита touch меняет время модификации файла на текущее. Если указанного файла нет, то он создаётся пустым.
Вообще, если уж мы начали разговор о стандартах GNU, нам придётся признать, что мы сейчас сделали всё неправильно. Мы сильно упростили задачу, чтобы сделать её более наглядной.
По стандарту в корневом каталоге проекта расположены только текстовые файлы README, INSTALL, AUTHORS, THANKS, ChangeLog, COPYING, а также файлы, имеющие отношение к сборке программы. Все основные файлы проекта обычно располагаются во вложенных каталогах. Вложенные каталоги обычно следующие:
src – содержит все файлы исходного кода;
lib – необязательный каталог; содержит исходные коды библиотек, используемых сразу несколькими программами, а также участков кода, имеющих отношение к переносимости программ;
doc – содержит документацию к программе;
m4 – содержит макросы для autoconf, которые вы, возможно, захотите передать другим разработчикам;
intl – содержит участки программы, отвечающие за интернационализацию программы, то есть перевода её интерфейса на разные человеческие языки;
po – содержит списки сообщений, с помощью которых программа общается с пользователем; здесь же – варианты этих сообщений на языках разных народов, предназначенные для интернационализации.
Возможны и другие варианты.

Давайте создадим в нашем проекте каталог src и перенесём туда файлы problem.h, problem.cpp, main.cpp. Все остальные файлы и каталоги удалим.
В корневом каталоге проекта создадим файл Makefile.am. Поместим в него следующий текст.

SUBDIRS = src

В каталоге src создадим другой файл с точно таким же названием Makefile.am. Его содержимое:
Код
bin_PROGRAMS=kalkul
kalkul_SOURCES=problem.h problem.cpp main.cpp

В корневом каталоге создадим файл configure.ac. Текст его следующий.
Код
AC_INIT(src/main.cpp)
AM_INIT_AUTOMAKE(kalkul,0.1)
AC_PROG_CC
AC_PROG_CXX
AC_PROG_INSTALL
AC_OUTPUT(Makefile src/Makefile)

Обратите внимание: в начальном макросе AC_INIT мы указываем, что исходные файлы расположены в каталоге src, а в конечном AC_OUTPUT указываем сразу на оба формируемых файла Makefile.
Сгенерируем конфигурационный скрипт обычным образом.
Код
aclocal
autoconf
touch README AUTHORS NEWS ChangeLog
automake -a

Соберём программу.
./configure
make

В папке src появился исполняемый файл. Теперь создадим архив.
make dist

Обратите внимание на такую строку в сгенерированном make-файле:

DEFS = -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE=\"kalkul\" -DVERSION=\"0.1\"

Таким путём make-файл указывает на имя и версию нашего пакета. Мы передали эти параметры с помощью директивы AM_INIT_AUTOMAKE(kalkul, 0.1) в файле configure.ac. Мы можем таким же образом передать и много других параметров. Если их будет слишком много, то эта строка в make-файле станет слишком длинной. Это чревато следующими трудностями. Во-первых, в такой длинной строке трудно визуально найти ошибки. Во-вторых, некоторые UNIX-системы имеют лимит на длину строки в скриптах, и, если мы превысим этот лимит, скрипт не будет обрабатываться.
Существует и другой способ, при котором эти параметры указываются в заголовочном файле config.h с помощью макроса #define. Давайте перепишем сборочные скрипты с использованием этого заголовочного файла. Сам файл будет сформирован автоматически. Нам же нужно внести небольшие изменения в скрипты.
Удалите из проекта все файлы, кроме исходников (problem.h, problem.cpp, main.cpp).
В начало каждого из этих файлов исходников необходимо вставить макрос, требующий включения в них заголовочного файла config.h (и добавить к нему макрос защиты от повторного включения того же файла). Самого файла, правда, пока нет. Ну ничего, к моменту компиляции он будет сгенерирован.
Включите следующий текст в начало файлов main.cpp, problem.cpp, problem.h
Код
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

В корневом каталоге проекта создайте новый configure.ac.
Код
AC_INIT(src/main.cpp)
AM_CONFIG_HEADER(src/config.h)
AM_INIT_AUTOMAKE(kalkul,0.1)
AC_PROG_CC
AC_PROG_CXX
AC_PROG_INSTALL
AC_OUTPUT(Makefile src/Makefile)

От предыдущего он отличается только тем, что содержит директиву AM_CONFIG_HEADER(src/config.h), указывающую, что такой заголовочный файл должен быть сформирован. Оба файла Makefile.am остаются без изменений.
В корневом каталоге проекта:

SUBDIRS = src

В каталоге src:
Код
bin_PROGRAMS=kalkul
kalkul_SOURCES=problem.h problem.cpp main.cpp

Команды по формированию конфигурационного скрипта те же, за исключением того, что к ним добавляется autoheader. Обратите внимание: эти команды должны даваться строго в порядке, указанном ниже:
Код
aclocal
autoconf
touch NEWS README AUTHORS ChangeLog
autoheader
automake -a

В результате, помимо всего прочего, сформировался файл config.h.in, в котором указаны все макросы препроцессора, которые войдут в будущий заголовочный файл config.h. Сам же config.h будет формироваться на машине пользователя по команде ./configure, и его структура будет зависеть от конфигурации компьютера пользователя. Давайте проделаем работу пользователя.

./configure
make

Посмотрим теперь на Makefile. Вместо длинной строки, указанной выше, мы видим компактную запись, указывающую, что необходимую информацию можно найти в заголовочном файле.
DEFS = -DHAVE_CONFIG_H
Теперь, как обычно, создадим дистрибутив.

make dist

Давайте теперь всю эту же процедуру проделаем с предыдущей версией нашего калькулятора, написанной на языке C. Если вы помните, там мы вынуждены были явным образом подключать математическую библиотеку libm, потому что компилятор C неявно её не подключает.
Собственно, здесь нам всего лишь нужно добавить одну строчку. Но рассмотрим всё по порядку.

Создадим новый каталог для проекта kalkulc. Внутри него создадим вложенный каталог src, и перенесём в каталог src все три файла от C-версии нашего калькулятора. Это main.c, calculate.c, calculate.h. Только обратите внимание, что в прошлый раз, работая с этой версией калькулятора, мы не пользовались заголовочным конфигурационным файлом config.h, поскольку мы тогда не пользовались инструментами автогенерации make-файла. Теперь же мы будем пользоваться всеми полученными знаниями в полном объёме, так что этот заголовочный файл нам понадобится.
Вставьте в самое начало каждого из этих трёх файлов (main.c, calculate.c и calculate.h) макрос, требующий включения этого файла. И, заодно, защиту от его повторного включения.
Код
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

В каталоге проекта создадим файл configure.ac со следующим текстом.
Код
AC_INIT(src/main.c)
AM_CONFIG_HEADER(src/config.h)
AM_INIT_AUTOMAKE(kalkul,0.1)
AC_PROG_CC
AC_PROG_CXX
AC_PROG_INSTALL
AC_OUTPUT(Makefile src/Makefile)

Как видите, он аналогичен тому, что мы делали в C++-версии.

Здесь же создаём файл Makefile.am с одной строчкой.

SUBDIRS = src

А внутри каталога src – ещё один Makefile.am.
Код
bin_PROGRAMS = kalkul
kalkul_SOURCES = calculate.h calculate.c main.c
kalkul_LDADD = -lm


Как видите, что он отличается от C++-версии только строчкой kalkul_LDADD = -lm Эта строчка и указывает, какую библиотеку следует подключить при компиляции.
Все остальные шаги вам уже хорошо знакомы.
Код
aclocal
autoconf
touch NEWS README AUTHORS ChangeLog
autoheader
automake -a
./configure
make



Сообщение отредактировал and - 20.10.2013, 21:40
Вернуться в начало страницы
 
+Ответить с цитированием данного сообщения
and
сообщение 20.10.2013, 21:40
Сообщение #7


Мастер
******

Группа: Пользователь
Сообщений: 530
Регистрация: 22.8.2007
Вставить ник
Цитата
Пользователь №: 317
Страна: Россия
Город: Не указан
Пол: Муж.



Репутация: 6


Библиотеки, утилита libtool.

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

В нашем калькуляторе мы содержимое исходника calculate.c целиком включали в исполняемый файл. Следовательно, если мы захотим те же функции использовать в другой программе, мы должны писать их заново. Можно, конечно, воспользоваться широко известными командами Выделить-Копировать-Вставить. Но, всё равно, это – лишние телодвижения, лишнее увеличение в размерах исполняемого файла вследствие засорения его рутинными функциями. Да и самого исходника может не оказаться под рукой. А, может быть, я захочу внести в эти функции улучшение. Это значит, придётся переделывать все программы, в которых эти функции используются, чтобы во всех этих программах были новые версии функций. Нельзя ли, чтобы они находились где-нибудь в одном месте, и их можно было брать оттуда для всех программ, когда они понадобятся?

Как вы, наверное, догадываетесь, мы будем делать из исходника calculate.c библиотеку, которую потом будем подключать к исполняемой программе, полученной из одного main.c.

Итак, берёмся за очередную переделку нашего калькулятора.

Простейший способ создать библиотеку из файла calculate.c следующий:
Код
gcc -c calculate.c
ar cru libcalculate.a calculate.o
ranlib libcalculate.a


Здесь gcc с флагом -c получает известный уже нам объектный файл, команда ar создаёт архив, в виде которых библиотеки и существуют. А команда ranlib генерирует индекс функций, содержащихся в библиотеке, и сохраняет этот индекс в её же файле. Эту процедуру всегда рекомендуется проделывать, поскольку индекс ускоряет процедуру связывания библиотеки с программой.

В дальнейшем этот файл можно вручную поместить в стандартный каталог библиотек (это /usr/lib и /usr/local/lib) и можно связывать её с помощью флага -lcalculate (обратите внимание, что название библиотек должно начинаться с префикса lib-).
Но понятно, что это нерациональный способ в отношении производительности труда. Давайте рассмотрим более практичные варианты. Для этого мы познакомимся с ещё одним компонентом набора инструментов GNU – libtool. Его предназначение – автоматизировать рутинные операции по работе с библиотеками и обеспечивать разработчику удобство при их написании и тестировании.

Создайте новый каталог проекта libtooldemo. Перенесите в него файлы calculate.c и main.c из C-версии калькулятора. Только обязательно удалите из каждого из них три строчки, требующие подключения заголовочного файла config.h. Пока мы пользоваться этим заголовочным файлом не будем.
Код
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

Вышеуказанные строки должны быть удалены!

А что же файл calculate.h?
О нём особый разговор. Наша библиотека будет компилироваться компилятором C. Но вызываться она может и из программы,написанной на С++. А компилятор C++ имеет такую особенность – он изменяет названия функций при компиляции. Следовательно, название функции в вызывающей программе будет не совпадать с названием функции в библиотеке.

Чтобы избежать такой ситуации, надо в заголовочном файле, включаемом в код исполняемой программы явно указать, что библиотечная функция написана на C. Таким образом, наш новый заголовочный файл calculate.h будет выглядеть так:
Код
///////////////////////////////////////
// calculate.h

#ifndef CALCULATE_H_
#define CALCULATE_H_
#ifdef __cplusplus
extern "C" {
#endif /*__cplusplus*/

float Calculate(float Numeral, char Operation[4]);
#ifdef __cplusplus
}
#endif /*__cplusplus*/

#endif /*CALCULATE_H_*/


Давайте создадим подключаемую библиотеку из исходника calculate.c. Для этого вначале создадим объектный файл. Пробуем способ 2006 года:
Код
libtool gcc -c calculate.c

Похоже, что для Альта он устарел, т. к. система сообщает:
libtool-default: error: you must specify a MODE.

Не беда, почитав помощь libtool - -help пробуем иначе:
Код
libtool --mode=compile gcc -c calculate.c

Но в ответ приходит другое сообщение:

/usr/bin/libtool-default: line 1835: i586-alt-linux-gfortran: command not found
libtool-default: compile: unable to infer tagged configuration
libtool-default: compile: specify a tag with `--tag'

С нас зачем-то требуют компилятор Фортрана и указать некий тег. Вероятно он и выбирает нужный тип компилятора? Да, так и есть, и для языка Си тег должен равняться CC. Подробности см. на http://lists.gnu.org/archive/html/libtool/...7/msg00001.html

Пробуем снова:
Код
libtool --mode=compile --tag=CC gcc -c calculate.c

Вот теперь все получилось.

Посмотрите, что появилось в каталоге проекта. Это, во-первых, уже знакомый нам объектный файл calculcate.o. Во-вторых, это скрипт calculate.lo, сгенерированный утилитой libtool. Он будет указывать, как собрать библиотеку из объектных файлов. Больше ничего не видите? Тогда наберите:
Код
cd .libs

И вы обнаружите, что перешли во вложенный каталог .libs, который не виден в файловом менеджере, потому что по умолчанию в нём не видны все файлы и папки, названия которых начинаются с точки. В этом вложенном каталоге находится другая версия объектного файла calculate.o. Разница между ними в том, то один имеет позиционно-независимый код, а другой – позиционно-зависимый. Но позвольте пока не вдаваться в подробности об этом. Утилита libtool сама решит за нас, какой вариант лучше взять для формирования библиотеки при данной конфигурации системы.

Наконец сформируем саму библиотеку.
Код
libtool --mode=link --tag=CC  gcc -rpath /usr/local/lib -o libcalculate.la calculate.lo


В проекте появился файл libcalculate.la. Это скрипт, который понадобится программе libtool. Сама же библиотека находится во вложенном каталоге .libs. Если вы туда зайдёте, вы обнаружите файл с расширением статической библиотеки libcalculate.a и файлы с расширением динамической библиотеки libcalculate.so (мы уже в своё время упоминали что эти типы библиотек имеют именно такие расширения файлов).
Содержимое файла libcalculate.a связывается с программой при компоновке, но библиотечных функций этот файл не содержит. Она содержит лишь ссылку на другой файл – libcalculate.so, который содержит библиотечные функции и связывается с программой динамически, то есть, по требованию в процессе выполнения программы.

Опция -rpath с указанием пути к стандартному каталогу библиотек указывает компоновщику, что необходимо создать библиотеку с динамическим связыванием, то есть предусмотреть оба – и a-файл и so-файл, и что они при инсталляции будут помещаться именно в тот каталог, который указан после -rpath. Путь к этому каталогу будет сохранён в a-файле, и именно по этому пути будет осуществляться поиск динамической библиотеки.

Можно указать компоновщику, что нужно создать статическую библиотеку. Для этого следует воспользоваться опцией -static.
Код
libtool --mode=link --tag=CC gcc -static -o libcalculate.la calculate.lo

Как вы видите, опции -rpath здесь нет. Она и не нужна, так как все библиотечные функции будут включены в исполняемый файл и нет необходимости что-либо откуда-либо вызывать динамически.
В каталоге .libs вы so-файла уже не найдёте, так как всё его содержимое включено в статически подключаемый a-файл.
Давайте теперь создадим исполняемый файл, который будет связан с этой библиотекой.
Код
libtool --mode=link --tag=CC gcc -o kalkul main.c libcalculate.la -lm

Можно при желании сделать так, чтобы математические функции входили в нашу библиотеку. Для этого перекомпонуем её, с указанием обязательного включения libm.
Код
libtool --mode=link --tag=CC gcc -rpath /usr/local/lib -o libcalculate.la calculate.lo -lm

Тогда к исполняемой программе можно уже не подключать libm.
Код
libtool --mode=link --tag=CC gcc -o kalkul main.c libcalculate.la

Поскольку мы исполняемый файл kalkul формировали с помощью libtool, он также помещается в каталог .libs, а в каталоге проекта формируется скрипт с таким же названием kalkul. Но это не должно вас беспокоить. Эти скрипты создаются в целях обеспечения главного удобства libtool. Главное удобство в том, что она позволяет одновременно в одном каталоге работать и с исполняемыми программами и с необходимыми им библиотеками. Попробуйте запустить исполняемую программу. Программа без проблем найдёт и откроет библиотеку, хотя эта библиотека расположена не в системном каталоге. Это позволяет избежать лишнего обращения к системному каталогу на этапе разработки.
Она также даёт возможность одномоментно установить все файлы библиотеки в системный каталог. Давайте установим библиотеку libcalculate в каталог /usr/local/lib (предварительно зайдя от имени суперпользователя).
Если при этой команде выдаются ошибки, просто повторите с начала всю процедуру компиляции и сборки библиотеки. Возможно, при каких-то манипуляциях вы потеряли некоторые вспомогательные файлы. Проще всего удалить все файлы, кроме исходных и заново выполнить последовательность команд:
Код
libtool  --mode=compile --tag=CC gcc -c calculate.c
libtool --mode=link --tag=CC gcc -rpath /usr/local/lib -o libcalculate.la calculate.lo -lm
su
libtool --mode=install --tag=CC cp libcalculate.la /usr/local/lib
exit

Теперь также с помощью libtool сделаем по-новому исполняемый файл.
Код
libtool --mode=link --tag=CC gcc -o kalkul main.c -lcalculate

Скопируем его в системный каталог.
Код
su
libtool --mode=install --tag=CC  cp kalkul /usr/local/bin
exit

Запустим его /usr/local/bin/kalkul

Почему же пришлось задавать полный путь? Очень просто, в моем дистрибутиве Альта в переменной окружения $PATH почему-то не задан путь поиска исполняемых программ /usr/local/bin. Ну и ладно, это не принципиально.

Однако, в некоторых дистрибутивах может случится неприятный сюрприз – программа первый раз не запустится. Она выдаст сообщение:

error while loading shared libraries: libcalculate.so.0: cannot open shared object file: No such file or directory

То есть, линкер знает путь /usr/local/lib, а загрузчик динамических библиотек его не знает. Путь к загружаемым библиотекам придётся добавлять в систему вручную. Это ужасно неудобно. Человек, впервые столкнувшийся с этой проблемой, будет долго думать, в чём дело. Сделано так, вероятно, в целях безопасности, чтобы «левая» библиотека, случайно установленная невнимательным пользователем, не вступила в конфликт с системными библиотеками. Разумеется, вы должны очень подробно описать эту ситуацию для пользователя в файле README.

Добавим вручную нужный нам путь. Для этого надо задать системной переменной LD_LIBRARY_PATH значение /usr/local/lib (по умолчанию эта переменная в большинстве версий Linux вообще отсутствует).
Код
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH

Снова запускаем kalkul. Наконец-то он заработал!

Замести следы своих экспериментов можно следующим образом:
Код
su
libtool --mode=uninstall rm /usr/local/lib/libcalculate.la
libtool --mode=uninstall rm /usr/local/bin/kalkul
exit



Сообщение отредактировал and - 21.10.2013, 9:12
Вернуться в начало страницы
 
+Ответить с цитированием данного сообщения
and
сообщение 21.10.2013, 9:12
Сообщение #8


Мастер
******

Группа: Пользователь
Сообщений: 530
Регистрация: 22.8.2007
Вставить ник
Цитата
Пользователь №: 317
Страна: Россия
Город: Не указан
Пол: Муж.



Репутация: 6


Подготовка библиотеки к распространению.

Давайте теперь подготовим нашу библиотеку для распространения.
Создадим новый каталог проекта libcalculate. В нём – каталог lib. В него поместим файлы calculate.c, calculate.h из предыдущего проекта. Только теперь, поскольку мы будем использовать autoheader, мы снова должны включить в оба файла строки:
Код
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

Создадим в корневом каталоге проекта файл configure.ac
Код
AC_INIT(lib/calculate.c)
AM_CONFIG_HEADER(lib/config.h)
AM_INIT_AUTOMAKE(libcalculate,0.1)
AC_PROG_LIBTOOL
AC_PROG_CC
AC_PROG_CXX
AC_PROG_INSTALL
AC_OUTPUT(Makefile lib/Makefile)

В нём имеется незнакомая ранее директива AC_PROG_LIBTOOL. Она означает, что компиляция будет производиться с использованием утилиты libtool.

Здесь же – файл Makefile.am
Код
SUBDIRS = lib

В каталоге lib – другой файл Makefile.am
Код
lib_LTLIBRARIES=libcalculate.la
libcalculate_la_SOURCES=calculate.h calculate.c
libcalculate_la_LIBADD=-lm

Если вы вспомните, как выглядел аналогичный файл в проекте исполняемой программы, то разница очевидна. Вместо bin_XXX пишем lib_XXX. Вместо XXX_LDADD пишем XXX_LIBADD.

Собираем библиотеку.
Код
aclocal
libtoolize
autoconf
touch NEWS AUTHORS README ChangeLog
autoheader
automake -a
./configure
make

Устанавливаем её в системе.
Код
su
make install
exit

Посмотрите внимательно на каталог /usr/local/lib. Там появились файлы библиотеки: a-файл, предназначенный для связывания с исполняемыми программами, и so-файлы, предназначенные для динамической загрузки. Все библиотеки, устанавливаемые пользователем, должны располагаться именно здесь, а в каталоге /usr/lib должны помещаться только библиотеки, входящие в дистрибутив Linux, за стабильность которых отвечают разработчики дистрибутива.

Да, и ещё обязательно не забудьте про переменную LD_LIBRARY_PATH.
Теперь создадим исполняемую программу. Пока для краткости не будем пользоваться инструментами для распространения.

Найдём наш файл main.c и сделаем из него запускаемую программу.

gcc main.c -o kalkul -lcalculate

Здесь должно быть вам всё знакомо. Параметр -lcalculate подключает к исполняемому файлу библиотеку libcalculate, которую найдёт по стандартному адресу /usr/local/lib.

Запустим его

./kalkul

Давайте теперь подготовим к распространению эту программу. Но теперь добавим в неё одну «фишку», которую до сих пор не делали ни разу – страницу помощи. Вы уже знаете, как пользоваться страницами man, можете, если что-то непонятно, набрать, например, man gcc. Давайте и наших пользователей не лишим такой возможности, обеспечим хоть мизерным, но руководством.

Страницы помощи для программ, поставляемых с дистрибутивом,находятся в каталоге /usr/share/man. Если вы заглянете туда, то увидите, что там находятся многие вложенные каталоги с такими названиями, как fr, de, ru, ar, es, man1, man2, man3 и так далее. Что же в них находится?

Каталоги fr, de, ru, ar, es и другие подобные предназначены для страниц помощи локализованных версий программ (французских, немецких, русских, арабских, испанских). А man1, man2, man3, man4 и т. д. просто предназначены для разделения страниц помощи по тематике, чтобы они не были свалены в одну кучу, так как их количество обычно очень велико. Такое разделение стандартно для всех UNIX-подобных систем.

man1 содержит описание программ, доступных всем пользователям системы.
man2 – функций системы, которые программисты могут использовать в своих программах.
man3 – функций различных библиотек, а также функций языков программирования, отличных от C.
man4 – описания устройств.
man5 – описания конфигурационных файлов.
man6 – описания игр.
man7 – разное.
man8 – описания программ, доступных администратору системы.
man9 – в Linux не используется.

Программы, полученные из интернета или из других «левых» источников, естественно, должны располагаться в другом каталоге, чтобы не перемешиваться со страницами, полученными из дистрибутива Linux. Таким каталогом является /usr/local/man. Туда мы и будем устанавливать страницу помощи к нашей программе.

Продолжение следует...

Сообщение отредактировал and - 21.10.2013, 9:13
Вернуться в начало страницы
 
+Ответить с цитированием данного сообщения
and
сообщение 29.10.2013, 12:51
Сообщение #9


Мастер
******

Группа: Пользователь
Сообщений: 530
Регистрация: 22.8.2007
Вставить ник
Цитата
Пользователь №: 317
Страна: Россия
Город: Не указан
Пол: Муж.



Репутация: 6


Программы с оконным интерфейсом

Многие современные программы имеют оконный интерфейс (или просто GUI – Graphical User Interface). Он делает намного удобнее общение с пользователем, позволяет ускорить выполнение ряда рутинных процедур, да и просто GUI – это эстетично и современно. После того, как мы посмотрели, как компилировать и распространять консольные программы, логично было бы проделать то же самое с оконными.
Мы создадим две очень коротких программы. Задача не в том, чтобы научиться создавать программы с оконным интерфейсом (этому будут потом посвящены отдельные руководства), а в том, чтобы продемонстрировать, что их сборка и распространение принципиально не отличаются от того, что мы видели в случае с консольными программами.
Ключевым звеном оконных программ является X-сервер. Он отвечает за прорисовку графических элементов. Программы, имеющие оконный интерфейс должны обращаться к X-серверу. Для обращения к нему служит специальный интерфейс (он называется Xlib). Однако существуют средства, позволяющие избежать непосредственного обращения к низкоуровневому интерфейсу (а работа с ним занимает длительное время). Два наиболее распространённых таких средства – это библиотеки GTK и Qt.
Напишем очень короткую программу с оконным интерфейсом с использованием библиотеки GTK+ 2.0.
Текст её будет выглядеть так (файл main.c).
CODE

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <gtk/gtk.h>

static void on_destroy (GtkWidget * widget, gpointer data)
{
gtk_main_quit();
}

int main(int argc, char *argv[] )
{
GtkWidget *window;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (on_destroy), NULL);
gtk_widget_show (window);
gtk_main ();

return 0;
}

Чтобы простым способом её скомпилировать, нужно воспользоваться обычным компилятором gcc, сообщив ему, что надо подключить библиотеку GTK+. Для этого мы вызываем утилиту pgk-config. Эта утилита ищет установленные в системе библиотеки и возвращает путь к ним. В данном случае нам нужна библиотека gtk+, что мы и указываем в параметре.
gcc main.c -o gtkdemo `pkg-config --cflags --libs gtk+-2.0`

Заметим, что во многих дистрибутивах библиотека GTK-2 уже заменена более новой библиотекой GTK-3. В этом случае достаточно слегка изменить команду:
gcc main.c -o gtkdemo `pkg-config --cflags --libs gtk+-3.0`

Теперь давайте подготовим эту программку для распространения. Создайте каталог проекта. Назовите его gtkdemo. В нём, как обычно, каталог src. В каталоге src – вышеуказанный файл main.c. В корневом каталоге создайте файл configure.ac
Код
AC_INIT(src/main.c)
AM_CONFIG_HEADER(src/config.h)
AM_INIT_AUTOMAKE(gtkdemo,0.1)
AC_PROG_CC
AC_PROG_CXX
AC_PROG_INSTALL

PKG_CHECK_MODULES(DEPS, gtk+-2.0 >= 2.2 glib-2.0 >= 2.2)
AC_SUBST(DEPS_CFLAGS)
AC_SUBST(DEPS_LIBS)

AC_OUTPUT(Makefile src/Makefile)

Вы, конечно, заметили, что, помимо уже знакомых строк мы сюда включаем директиву PKG_CHECK_MODULES. Эта директива запускает уже знакомую утилиту pkg-config. Путь к заголовочным файлам библиотеки gtk+ сохраняется в переменной DEPS_CFLAGS. Путь к библиотечным файлам – в переменной DEPS_LIBS.
Ещё в корневом каталоге создайте файл Makefile.am
Код
SUBDIRS = src

А в каталоге src – другой файл Makefile.am
Код
bin_PROGRAMS = gtkdemo
gtkdemo_SOURCES = main.c
gtkdemo_LDADD = $(DEPS_LIBS)
AM_CPPFLAGS = $(DEPS_CFLAGS)

Здесь указывается, что адреса, найденные и сохранённые в этих двух переменных, должны быть подключены к проекту.
Всё! Собираем, как обычно:
aclocal
autoconf
touch NEWS README AUTHORS ChangeLog
autoheader
automake -a
./configure
make
make dist


В случае с Qt всё гораздо проще. Вместе с библиотекой Qt поставляется программа qmake, которая берёт на себя роль autoconf, autoheader, automake и других. Только убедитесь, что qmake установлена в вашей системе! Если окажется, что у вас её нет, её придётся устанавливать отдельно: или (лучше всего) из дистрибутива, или (если её нет и в дистрибутиве) из других источников.
Создадим простую программу, аналогичную той, что выше, с использованием библиотеки Qt4. Создайте каталог qtdemo, в нём – каталог src, а в нём – файл main.cpp.
Код
#include <QApplication>
#include <QPushButton>

int main(int argc, char *argv[])
{
     QApplication app(argc, argv);

     QPushButton hello("Hello world!");
     hello.resize(200, 60);

     hello.show();
     return app.exec();
}

Дальше всё просто. Программа qmake с параметром -project просматривает все файлы с исходным кодом, находящиеся в текущем каталоге, создаёт новый проект (файл с расширением .pro), даёт ему такое же имя, как у текущего каталога, и подключает все найденные файлы к проекту. Далее, командой qmake (без параметров) создаётся Makefile. Итак зайдите в корневой каталог проекта и набирайте:
qmake -project
qmake
make


Далее можете при желании инсталлировать программу.
make install

Или подготовить дистрибутив.
make dist

В этот дистрибутив будет входить и файл проекта (qtdemo.pro). Поэтому пользователи, получив такой пакет не должны запускать configure. Всё, что им надо, это дать следующие команды:
qmake
make


Хотя qmake не требует обязательного присутствия в дистрибутиве файла README, желательно такой файл создать, и описать подробно, как правильно устанавливать программу. Будет неприятно, если пользователь будет источать на вас весь запас бранных слов только из-за того, что у него не установлена библиотека Qt, или из-за того, что его не предупредили, что в данном пакете не надо запускать ./configure.
Примечательно, что никто вам не запрещает пользоваться утилитой qmake для сборки самых обычных консольных программ, не имеющих никакого отношения к Qt. Например, мы можем взять тот же самый проект kalkul, удалить оттуда все файлы, кроме файлов исходных кодов, зайти туда в консоли, дать команды qmake:
qmake -project
qmake
make
make dist


Если мы возьмём нашу последнюю версию, то там к программе требовалось подключить библиотеку libcalculate. Это делается следующим образом:
qmake -project "LIBS+=-lcalculate"
qmake
make
make dist


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

Сообщение отредактировал and - 29.10.2013, 13:18
Вернуться в начало страницы
 
+Ответить с цитированием данного сообщения
and
сообщение 29.10.2013, 16:31
Сообщение #10


Мастер
******

Группа: Пользователь
Сообщений: 530
Регистрация: 22.8.2007
Вставить ник
Цитата
Пользователь №: 317
Страна: Россия
Город: Не указан
Пол: Муж.



Репутация: 6


Знакомство с отладчиком gdb.

Ошибки, к сожалению, встречаются в любой программе, каким бы крутым профессионалом её разработчик ни был. Поэтому, нравится это вам или нет, пользоваться отладчиком вам всё равно придётся. Жизнь заставит. И чем больше времени вы сейчас потратите на изучение работы с ним, тем больше времени это вам сэкономит в дальнейшем.
Мы рассмотрим отладчик GDB, входящий в комплект программ GNU.
Для того, чтобы им пользоваться, нужно сначала скомпилировать программу так, чтобы её двоичный файл содержал отладочную информацию. Эта информация включает в себя, в частности, описание соответствий между адресами исполняемого кода и строками в исходном коде.
Такая компиляция достигается путём добавления флага -g к команде на компиляцию. Например, если бы мы собирали программу kalkul без применения Makefile, мы бы дали такую команду:
g++ main.cpp problem.cpp -o kalkul -g

Если же мы пользуемся командой make, то надо поставить опцию CFLAGS=-g. Тогда все команды на компиляцию, содержащиеся в Make-файле, автоматически получат флаг -g.
Давайте возьмём программу, которую мы создали из файлов main.cpp, problem.cpp и problem.h (мы тогда называли этот каталог проекта kalkulcpp). У нас Makefile уже сформирован. Воспользуемся им.
Очистим пакет от результатов предыдущей сборки.
make clean

Соберём программу снова, но уже с включением отладочной информации.
make CFLAGS=-g

Запустим отладчик GDB, загрузив в него нашу программу для отладки. (Если помните, исполняемая программа у нас находилась в каталоге src.)
gdb ./src/kalkul

Чтобы запустить программу внутри отладчика,даётся команда run.
run

Чтобы посмотреть исходный код, даётся команда list.
list

Если дать эту команду без параметров, то она первые девять строк исходного кода главного файла (то есть такого, в котором имеется функция main). Чтобы просматривать файл дальше, надо снова набирать list. Чтобы посмотреть конкретные строки, надо указать два параметра: с какой строки начинать просмотр, и с какой строки заканчивать.
list 12,15

Чтобы просмотреть другие файлы проекта, надо перед номерами строк указать название нужного файла и отделить его от номеров строк двоеточием.
list problem.cpp:20,29

Поставим точку останова на строке номер 21. Точка останова – это метка, указывающая, что программа, дойдя до этого места, должна остановиться.
list problem.cpp:20,27
break 21


Посмотреть, где вы поставили точки останова, можно с помощью команды info breakpoints.
info breakpoints

(При желании можно вместо номера строки указать название функции,тогда программа остановится перед входом в функцию.)
Запустим программу.
run

Введём первое число 5 и знак математического действия « + ». Программа дойдёт до точки останова и остановится, выведя нам строку, у которой эта точка расположена.
Нам, конечно, интересно знать,в каком именно месте мы остановились, и что программа уже успела выполнить. Даём команду backtrace.
backtrace

Отладчик выдаёт нам следующую информацию:
#0 CProblem::Calculate (this=0x804b008) at problem.cpp:21
#1 0x08048e00 in CProblem::Solve (this=0x804b008) at problem.cpp:93
#2 0x08048efc in main () at main.cpp:15

Это означается, что мы находимся внутри выполняющейся функции Calculate, являющейся функцией-членом класса CProblem. Она была вызвана из функции Solve того же класса, а та, в свою очередь, из функции main. Таким образом, команда backtrace показывает весь стек вызываемых функций от начала программы до текущего места.
Посмотрим, чему же равно на этом этапе значение переменной Numeral.
print Numeral

И нам сразу выводится число 5, которое мы и вводили в программу. (Значение, введённое нами с клавиатуры, присвоилось именно этой переменной.)
Если мы вместо print будем пользоваться командой display, то величина этой переменной будет показываться каждый раз, когда программа останавливается, без специального указания.
display Numeral

Добавим ещё одну точку останова на строке 25 файла problem.cpp.
break problem.cpp:25

Продолжим выполнение программы.
continue

Команда Continue продолжает выполнение программы с текущего адреса. Если бы мы набрали run, программа начала бы выполняться с начала. Поскольку на строке 24 имеется команда cin >> SecondNumeral, то нам придётся ввести второе слагаемое. Введём, например,число 2. После этого программа опять остановится на строке 25 (наша вторая точка останова).
Посмотрим, чему равны значения наших переменных Numeral, SecondNumeral и Operation. Если вы помните, именно такие переменные мы объявляли в классе CProblem.
print Numeral
print Operation
print SecondNumeral


У нас получится 5, « + », 2. Так и должно быть. Но давайте теперь «передумаем» и лучше присвоим переменной SecondNumeral значение 4. Отладчик GDB позволяет прямо во время выполнения программы изменить значение любой переменной.
set SecondNumeral=4

Если не верим, что её значение изменилось,можно проверить.
print SecondNumeral

Теперь мы ожидаетм, что результат будет 9. Давайте выполним программу до конца.
continue

Результат действительно равен 9.
Давайте теперь уберём наши точки останова. Мы, кажется, создали две таких точки. Но это можно проверить.
info breakpoints

Удалим их.
delete 1
delete 2


У нас не должно остаться ни одной точки останова. Проверяем.
info breakpoints

Действительно не осталось ни одной.
Теперь давайте пошагово пройдём всю программу (благо, она у нас небольшая).
Поставим точку останова на десятой строке главного файла.
break main.cpp:10

Запустим программу
run

Дойдя до десятой строчки, она остановится. Теперь проходим её, останавливаясь на каждой строчке, с помощью команды step.
step

Чтобы не набирать каждый раз s-t-e-p, можно просто вводить букву s. Как только программа доходит до команды Problem->SetValues(), она сразу переходит в файл problem.cpp, где находится определение функции-члена CProblem::SetValues() и проходит код этой функции. То же самое, когда она дойдёт до вызова Problem->Solve().
Чтобы при вызове функции, программа не входила в неё, а продолжала дальше выполняться только на текущем уровне стека, вместо step даётся команда next или просто n.
next

Если мы вошли в функцию, но не хотим дальше проходить её по шагам, а хотим, чтобы она отработала и вернула нас на предыдущий уровень стека (то есть, обратно в функцию, вызвавшую её), мы пользуемся командой finish.
finish

Таким образом, можно просмотреть, как выполняется вся программа или любой участок программы. На любом шаге можно проверять значение любой переменной. Чтобы перестать проходить программу по шагам и запустить её до конца, надо дать команду continue.
Дадим короткий список наиболее часто встречающихся команд отладчика GDB. За более подробной информацией вы, конечно, всегда можете обратиться к встроенному описанию программы (info gdb) или руководством по пользованию (man gdb).

backtrace – выводит весь путь к текущей точке останова, то есть названия всех функций, начиная от main(); иными словами, выводит весь стек функций;
break – устанавливает точку останова; параметром может быть номер строки или название функции;
clear – удаляет все точки останова на текущем уровне стека (то есть в текущей функции);
continue – продолжает выполнение программы от текущей точки до конца;
delete – удаляет точку останова или контрольное выражение;
display – добавляет выражение в список выражений, значения которых отображаются каждый раз при остановке программы;
finish – выполняет программу до выхода из текущей функции; отображает возвращаемое значение,если такое имеется;
info breakpoints – выводит список всех имеющихся точек останова;
info watchpoints – выводит список всех имеющихся контрольных выражений;
list – выводит исходный код; в качестве параметра передаются название файла исходного кода, затем, через двоеточие, номер начальной и конечной строки;
next – пошаговое выполнение программы, но, в отличие от команды step, не выполняет пошагово вызываемые функции;
print – выводит значение какого-либо выражения (выражение передаётся в качестве параметра);
run – запускает программу на выполнение;
set – устанавливает новое значение переменной
step – пошаговое выполнение программы;
watch – устанавливает контрольное выражение, программа остановится, как только значение контрольного выражения изменится.

Сообщение отредактировал and - 29.10.2013, 16:35
Вернуться в начало страницы
 
+Ответить с цитированием данного сообщения

Ответить в эту темуОткрыть новую тему
( Гостей: 1 )
Пользователей: 0

 



RSS Текстовая версия Сейчас: 28.3.2024, 16:00