close

Вход

Забыли?

вход по аккаунту

ПОЛОЖЕНИЕ об управляющем Совете ГОУ СОШ № 1278;doc

код для вставкиСкачать
МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ РОССИЙСКОЙ ФЕДЕРАЦИИ
Федеральное государственное бюджетное образовательное учреждение
высшего профессионального образования
«НАЦИОНАЛЬНЫЙ ИССЛЕДОВАТЕЛЬСКИЙ
ТОМСКИЙ ПОЛИТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ»
УТВЕРЖДАЮ
Проректор-директор ИК
«
»
А.В. Замятин
2013 г.
КОМПИЛЯТОРЫ. КОМПИЛЯЦИЯ ПРОГРАММНОГО
ОБЕСПЕЧЕНИЯ В ОС FreeBSD
Методические указания к выполнению лабораторных работ
по курсу «Системное программное обеспечение»
для студентов направлений 230100 «Информатика и вычислительная
техника» и 230400 «Информационные системы и технологии»
Составитель: И.И. Савенко
Издательство
Томского политехнического университета
2013
УДК 629.76
ББК 00000
А00
Савенко И.И.
А00
Компиляторы. Компиляция программного обеспечения в ОС
FreeBSD: методические указания к выполнению лабораторных работ по курсу «Системное программное обеспечение» для студентов направлений 230100 «Информатика и вычислительная техника» и 230400 «Информационные системы и технологии»
Института кибернетики
ТПУ / Cост.: И.И. Савенко; Томский политехнический университет. – Томск: Изд-во Томского политехнического университета, 2014. – 28 с.
УДК 000000
ББК 00000
Методические указания рассмотрены и рекомендованы
к изданию методическим семинаром кафедры
АиКС ИК
« 01 » сентября 2014 г.
Зав. кафедрой АиКС
доктор технических наук,
профессор
__________Г.П. Цапко
Председатель учебно-методической
комиссии
__________
Рецензент
Кандидат технических наук, доцент кафедры АиКС ИК ТПУ
А.С. Фадеев
© Составление. ФГБОУ ВПО НИ ТПУ, 2014
© Савенко И.И., составление, 2014
2
Содержание
ВВЕДЕНИЕ .....................................................................................................4
1
Процесс компиляции. Компиляторы. .....................................................5
2
Компиляция приложения, разработанного на языке С++ ....................7
2.1
Предупреждение об ошибках ...........................................................9
2.2
Оптимизация программы ..................................................................9
2.3
Разделенная трансляция ..................................................................10
2.4
Заключение .......................................................................................12
3 Автоматизация процесса компиляции, используя утилиту make
(GNU make)....................................................................................................13
3.1
Структура make-файла.....................................................................13
3.2
Использование переменных ............................................................15
3.3
Функции (GNU make) ......................................................................16
3.4
Использование переменной VPATH. .............................................17
3.5
Заключение .......................................................................................18
ЗАКЛЮЧЕНИЕ .............................................................................................19
Список используемых источников .............................................................24
Приложение 1. Исходный код демонстрационной программы ...............25
Приложение 2. Основной список ключей компилятора g++ ...................27
Приложение 3. Ключи утилиты GNU make ...............................................28
3
ВВЕДЕНИЕ
Unix-подобные операционные системы (ОС) являются основными
ОС используемыми в научных центрах. Их использование позволяет
получить максимум производительности от аппаратного обеспечения
при выполнение сложных математических расчетов. Таким образом,
разработка собственных программ для Unix-подобных ОС является одной из важных задач, которую должен уметь решать программист.
Целью данной работы является ознакомление с таким понятием как
компиляция, а также получение навыков по разработке программного
обеспечения в операционной системе FreeBSD.
4
1 Процесс компиляции. Компиляторы.
С каждым годом Unix-подобные операционные системы (ОС) становятся все более популярными в качестве ОС персональных компьютеров. Чаще всего ОС данного типа используются в качестве серверных
ОС, а также в организациях, которые не могут позволить себе использовать платные ОС либо в научных центрах, где необходимо получить
максимум от аппаратного обеспечения. Для Unix-подобных систем разработано огромное количество программного обеспечения (ПО), но их
специфическое использование и узкая направленность принуждает программистов разрабатывать собственное ПО, которое будет решать необходимые им задачи.
Языки программирования (ЯП) – это средство, позволяющее описывать вычисления понятные как для вычислительных машин, так и для
людей. Любое программное обеспечение на всех компьютерах мира
написано на том или ином ЯП. Перед тем как осуществить запуск разработанной программистом программы, ее исходный код должен быть
преобразован в вид, который сможет быть выполнен на компьютере.
Такое преобразование выполняют компиляторы. Простыми словами,
компилятор – это программа, считывающая исходный код программы, и
транслирует (преобразовывает) его в эквивалентный код на другом языке – целевом (Рис. 1). В качестве целевого языка могут выступать различные языки, это зависит от компилятора, а также от ЯП на котором
разрабатывалось ПО. Также компилятор сообщает программисту об
ошибках в исходном коде, которые были обнаружены во время трансляции.
Исходная программа
Компилятор
Целевая программа
Рис. 1. Компилятор
Исходный код программы может исчисляться миллионами строчек
кода и что чаще всего, программисты разбивают программный код на
5
модули, которые находятся в различных файлах. В таком случае одного
компилятора не достаточно, тогда при создании целевой программы используются и другие не менее важные программы (Рис. 2).
Исходная программа
Препроцессор
Модифицированная исходная
программа
Компилятор
Целевая ассемблерная программа
Ассемблер
Перемещаемый машинный код
Компоновщик/загрузчик
Библиотечные файлы
Перемещаемые объектные файлы
Целевая программа
Рис. 2. Система обработки языка
Сборка исходной программы иногда поручается отдельной программе, именуемой препроцессором. Одна из его функций это раскрытие макросов в инструкции на исходном языке. После того, как исходная программа была модифицирована препроцессором, она передается
компилятору. Как было упомянуто выше, на выходе компилятора не
обязательно может быть машинный код, на выходе может быть целевая
программа на языке ассемблера, так как в отличие от машинного кода,
его проще создать и отлаживать. Далее исходная программа, преобразованная в программу на языке ассемблера, преобразуется в перемещаемый машинный код при помощи компьютерной программы (компилятора) Ассемблер. Тут необходимо заметить, что как и сам язык
ассемблера, ассемблеры бывают различными в зависимости от архитектуры вычислительной машины, операционной системы.
Исходные программы, состоящие из нескольких модулей, чаще
всего компилируются по частям (разделенная трансляция), таким образом, полученный перемещаемый машинный код необходимо объединить (скомпоновать) с другими частями машинного кода, а также с библиотечными файлами. Этим как раз и занимаются Компоновщик
6
(Linker) и Загрузчик (Loader). Процесс компоновки не так уж и прост,
как может показаться, некоторые особенности будут рассмотрены ниже.
Выбор компилятора при разработке программ зависит как от ОС,
архитектуры ЭВМ, а также от ЯП и его версии. Наиболее популярным
компилятором при разработке приложений под ОС Windows является
MSVC++, разработанный компанией Microsoft. Что же касается Unixподобных систем, то тут чаще всего используется пакет компиляторов
GCC. В данном пакете содержатся компиляторы для различных ЯП,
например C (компилятор gcc), C++(компилятор g++), Java (компилятор
gjc), Objective C и других, а также компиляторы для различных архитектур (ARM, x86 и т.д.) [1].
В ходе лабораторной работы в качестве исходного языка для написания программы будет использоваться язык программирования C++.
Программа на языке С++ будет преобразована компилятором в машинный код. Целью данной работы не является разработка собственного
компилятора, поэтому мы не будем глубоко погружаться в структуру
компилятора и рассматривать другие существующие языковые процессоры, например, интерпретаторы. Главное понять, как осуществляется
преобразование исходного кода программы в машинный код.
2 Компиляция приложения, разработанного на языке С++
Для сборки программы разработанной на языке С++ необходимо
использовать специальный компилятор g++ из пакета компиляторов. В
отличие от компилятора gcc, данная команда (g++) по умолчанию подключает (линкует) стандартную библиотеку stdc++.
Перейдем к практике, для начала напишем простую программу, которая суммирует 2 целых числа, переданные программе через аргументы (пример вызова программы с аргументами в операционной системе
Windows: C:\demo.exe ‘аргумент 1’ ‘аргумент 2’. Для этого мы будем
использовать текстовый редактор «Easy Editor», запуск которого осуществляется командой – ee. Следующая строка, открывает для редактирования файл main.cpp в редакторе Easy Editor, в случае, если файл не
существует он будет создан автоматически.
%ee main.cpp
Листинг 1
#include <iostream> //подключение заголовочного файла
/**
* argc - содержит количество переданных аргументов
7
* argv - значения аргументов
*/
int main( int argc, const char* argv[] )
{
int x; //Инициализация переменой целочисленного типа
int y;
//
//
//
//
if
убедимся, что всего было передано 3 параметра
1 - имя самой программы (добавляется автоматически)
2 - первое слагаемое
3 - второе слагаемое
( argc == 3 ) { //условный оператор
x = atoi( argv[1] ); //функция atoi – преобразует
значение аргумента в целочисленное значение
y = atoi( argv[2] );
std::cout << x << " + " << y << " = " << x + y <<
std::endl;
}
}
В листинге 1 приведен исходный код программы на языке С++, которая осуществляет сложение двух чисел. Если приведенный в листинге
1 код вам не понятен, вы можете познакомиться с основами языка С++,
которые отлично описаны на сайте [2].
Перейдем к компиляции, чтобы откомпилировать нашу программу
необходимо вызвать компилятор g++ и указать путь к файлу с исходными данными в качестве параметра.
%g++ main.cpp
%ls
%a.out main.cpp
В результате создался исполняемый файл с именем по умолчанию
a.out, если проводить аналогию с операционной системой Windows, был
создан *.exe файл. Для того, чтобы запустить данную программу необходимо воспользоваться следующей командой.
%./a.out 45 43
45 + 43 = 88
Если вас не устраивает имя программы, присвоенное по умолчанию, то при компиляции можно задать новое, используя ключ –o.
%g++ main.cpp –o demo
Вышеуказанное - это минимальное, что можно получить от всех
возможностей компилятора. На самом деле, умение использовать определенный набор ключей компиляции, позволит разрабатывать безошибочные приложения, а также за минимальный промежуток времени. Как
8
вы могли заметить, компиляция довольно медленный процесс, даже на
примере одного файла, а представьте, сколько времени займет данный
процесс если программа состоит из нескольких тысяч файлов, поэтому
очень важно использовать правильный набор ключей, чтобы сократить
время компиляции (Приложение 2).
2.1 Предупреждение об ошибках
Как уже говорилось выше, одна из функций компилятора это уведомление программиста об ошибках или предупреждениях в исходном
коде программы. Таким потенциально опасными местами в исходном
коде могут быть: неиспользуемые переменные, неверная операция в
условном операторе и другие. Пример:
%g++ main.cpp –o demo -Wall
%main.cpp: In function 'int main()':
%main.cpp:3: warning: unused variable 'unusedVar'
Предупреждения, выдаваемые компилятором, очень важный и полезный механизм их использование позволяет программистам исключить многих не заметных ошибок, которые возникнут уже во время использования программы, что, конечно же, не понравится конечному
пользователю. Если рассматривать механизм предупреждения компилятора g++, он позволяет включать несколько десятков видов предупреждений, для каждого из которых имеется свой ключ компиляции. Полный список таких ключей можно посмотреть в руководстве, вызвав
команду:
%man g++;
2.2 Оптимизация программы
Под оптимизацией понимается процесс улучшения производительности программы: уменьшение объема памяти, занимаемой на жестком
диске программой, а также сокращение времени работы приложения.
Для того, чтобы оптимизировать приложение в компиляторе g++ присутствуют следующие ключи (шаблон –Oуровень, где уровень меняется
от 0 до 3):
 -O0 – отключает оптимизацию, основная цель данного ключа,
обеспечить высокую скорость компиляции, а так же предсказуемость результатов отладки. Этот ключ используется по умолчанию;
9




-O1 – мягкая оптимизация, незначительное увеличение скоро-
сти процесса компиляции, а также уменьшение размера целевой
программы;
-O2 – использует практически все доступные компилятору методы оптимизации, как скорости выполнения, так и размера
программы;
-O3 – максимальная оптимизация, которая включает такие методы оптимизации как развертку циклов и автоматическое
встраивание функций.
-Os – позволяет автоматизировать размер программы.
Проведем не большой эксперимент, посмотрим время, затраченное
на компиляцию без оптимизации и с оптимизацией.
%time && g++ main.cpp -o demo -std=gnu++98 && time && rm demo
81.616u 8.376s 1:02:39.41 2.3% 4220+1401k 131+0io 25pf+0w
82.706u 8.534s 1:02:40.67 2.4% 4251+1404k 131+0io 25pf+0w
Время компиляции: 0,158s
%time && g++ main.cpp -o demo -std=gnu++98 -O1 && time && rm demo
82.712u 8.535s 1:02:50.34 2.4%
83.842u 8.731s 1:02:51.67 2.4%
4250+1404k 131+0io 25pf+0w
4283+1406k 131+0io 25pf+0w
Время компиляции: 0,196s
Как вы можете заметить, время компиляции не значительно, но
увеличилось. Конечно же, данный тест нельзя считать объективным, так
как система могла быть использована другими процессами, что и могло
замедлить время компиляции. Объективнее будет взять среднее время
компиляции после нескольких попыток компилирования.
2.3 Разделенная трансляция
Рассмотрим еще один интересный момент, который необходимо
учесть при компиляции программы. Демонстрационная программа
(main.cpp), используемая в данном методическом пособии, состоит всего лишь из одного файла с исходными данными, реальные же проекты
состоят из нескольких десятков и более. Конечно же, никто не запрещает писать весь исходный код программы в одном файле, но тогда возникнут следующие проблемы:
 тяжело организовать коллективную работу над программой;
 усложняется навигация по написанному коду;
 любое изменение в тексте файла с программой приводит к полной перекомпиляции, что, конечно же, занимает длительное
время.
10
Обратите внимание на последний пункт выше приведенного списка, компилятор g++ позволяет сократить время компиляции программы,
компилируя только модифицированные файлы исходной программы,
это и есть разделенная трансляция. Для проверки разделенной трансляции усложним нашу демонстрационную программу. Для этого создадим
простейший класс, который будет осуществлять суммирование целых
чисел. Исходные коды классов представлены в Приложении 1. В результате у нас получилось 3 файла main.cpp, summ.h, summ.cpp.
Способ 1
Рассмотрим первый способ компиляции, без разделения трансляции исходных файлов программы. Все максимально просто, необходимо компилятору передать пути к файлам с расширением *.cpp.
%g++ main.cpp summ.cpp -o demo -std=gnu++98
%./demo 45 43
45 + 43 = 88
Как вы можете заметить, программа успешно откомпилирована и
может быть использована. Для справки, если файлов много, то можно
воспользоваться шаблоном поиска файлов типа: *.cpp.
%g++ *.cpp -o demo -std=gnu++98 –Os
Способ 2
Разделенная трансляция подразумевает собой разбиение процесса
компиляции на 2 стадии:
 создание объектных файлов;
 компоновка, объектных файлов в целевую программу.
Создание объектных файлов обеспечивается при помощи использования ключа –с, это делается следующим образом:
%g++ *.cpp –c
%ls -l *.o
-rw-r--r-- 1 root
-rw-r--r-- 1 root
root
root
3316 23 июн 17:07 main.o
803 23 июн 17:07 summ.o
В результате у нас получилось 2 объектных файла, которые полностью соответствуют исходным файлам программы. Далее необходимо
осуществить компоновку объектных файлов, для этого необходимо воспользоваться ключом –o.
%g++ *.o -o demo_o
%./demo_o 1 2
1 + 2 = 3
11
Таким образом, если внести изменения только в один из файлов, то
трансляции других файлов не является обязательной, достаточно создать объектный файл модифицированного файла и скомпоновать его с
уже существующими объектными файлами.
2.4 Заключение
В данном разделе вы познакомились с основными возможностями
компилятора GCC. Используя эти возможности, вы сможете в любой
момент скомпилировать простейшую программу, написанную на языке
С++ с использованием оптимизации и разделённой трансляции. В следующем разделе речь пойдет об утилите make, которая позволит автоматизировать процесс компиляции, что позволит компилировать более
сложные программы.
12
3 Автоматизация процесса компиляции, используя утилиту make
(GNU make)
Надеюсь, вы не подумали, что программист, разрабатывая программу, каждый раз с использованием консоли прописывает команды,
которые мы с Вами разобрали выше, конечно же, есть способы автоматизации данного процесса. В следующей части методического пособия
мы разберем, как работает утилита make и что такое make-файл. В ходе
лабораторной работы используется ОС FreeBSD поэтому мы будем использовать утилиту gmake, она является аналогом make, но имеет больший функционал. Так же необходимо заметить, что про использование
данной утилиты пишут целые книги, мы рассмотрим только самое важное и необходимое.
Утилита gmake предназначена для автоматизации процесса создания исполняемого файла из исходного кода, она также определяет какие
модули программы необходимо перекомпилировать. Использование
данной утилиты, значительно упрощает процесс сборки программы. В
данном методическом пособии рассмотрено минимальное количество
ключей утилиты gmake, так как утилиту gmake можно использовать и
без них, полный список приведен в приложении 3.
Сама по себе данная утилита работать не будет, ей необходимо сообщить некоторые правила, по которым необходимо скомпилировать
приложение. Файл, который содержит правила, описывающие процесс
сборки приложения, называется make-файлом. Правила создания данного файла будут описаны ниже.
Как уже было сказано, утилиту make можно запускать без ключей,
при запуске она автоматически проверяет текущую директорию на
наличие make-файла с название по умолчанию makefile. Если такой
файл отсутствует, то программист получит следующее сообщение об
ошибке:
%gmake
gmake: no target to make.
Если же вы решили всё-таки дать make-файлу другое название или
разместить его в другой директории, то для этого вам необходимо использовать ключ –f. Пример:
%gmake –f path/to/makefile
3.1 Структура make-файла
13
Структура make-файла максимально простая, он состоит из целей и
макрокоманд. Чтобы описать цель необходимо задать:
имя цели – имя файла, который должен быть создан;
список зависимости – список имен файлов, от которых зависит
достижение цели;
список команд интерпретатора shell, которые должны быть выполнены для достижения поставленной цели.
цель: зависимости
[tab] команда (где [tab] – символ табуляции)
Имя цели и список зависимостей составляют заголовок цели, записываются в одну строку и разделяются двоеточием. Цель может быть
ложная – это значит, что в качестве цели не будет выступать файл. Список команд записывается со следующей строки, причем все команды
начинаются с обязательного символа табуляции. Любая строка в последовательности списка команд, не начинающаяся с табуляции или '#' считается завершением текущей цели и началом новой. Рассмотрим
простой пример make-файла позволяющего скомпилировать демонстрационную программу:
all://ложная цель вызываемая по умолчанию
g++ main.cpp summ.cpp -o demo
Данный пример отлично работает, но при таком описании, не учитывается разделенная трансляция, что, конечно же, не верно. Модифицируем make-файл возможностью использовать разделенную трансляцию, для этого добавим еще одну цель в файл, которая будет описывать
создание объектных файлов.
Листинг 2
all: demo
demo: main.o summ.o
g++ main.o summ.o -o demo
main.o:
g++ -c main.cpp
summ.o: summ.cpp
g++ -c summ.cpp
Хочется отметить, что если в make-файле присутствует несколько
целей, то утилита make позволяет компилировать отдельные части программы, для этого достаточно указать в качестве параметра название
цели:
gmake summ.o
Давайте представим, что программа, которую мы разрабатываем,
состоит из 500 исходных файлов, при такой организации make-файла об
14
автоматизации процесса компиляции и речи быть не может. Чтобы это
исправить познакомимся с новым понятием как переменные и функции.
3.2 Использование переменных
Использование переменных позволяет избежать повторяемость некоторых участков кода make-файла. Объявление переменных осуществляется несколькими способами, мы рассмотрим только 2 популярных
способа:
Способ 1
VARIABLE = VALUE
Ниже приведен пример, как использовать переменные данного типа
Листинг 3
OCC=-O2
#объявление рекурсивной переменной CC содержащей в себе значение g++ и значение переменной OCC (переменная определяющая уровень оптимизации) Важно! Значение переменной вычисляется в момент
обращения к ней.
CC=g++ $(OCC)
all: demo
demo: main.o summ.o
$(CC) main.o summ.o -o demo
main.o:
$(CC) -c main.cpp
summ.o: summ.cpp
$(CC) -c summ.cpp
При таком способе инициализации переменной, одна и та же переменная не может одновременно использоваться, как в левой части, так и
в правой части выражения, в противном случае это может привести к
бесконечной рекурсии.
Способ 2
VARIABLE := VALUE
Ниже приведен пример, как использовать переменные данного типа
Листинг 4
CC:=g++
#Важно! Значение переменной вычисляется в момент обработки
оператора присваивания.
15
CC:= $(CC) -O2
demo: main.o summ.o
$(CC) main.o summ.o -o demo
main.o: main.cpp
$(CC) -c main.cpp
summ.o: summ.cpp
$(CC) -c summ.cpp
Использоваться может как один, так и другой способ инициализации, второй способ является оптимальным и надежным, так как нет
необходимости каждый раз вычислять значение переменной при ее использовании, но все зависит от ситуации.
Очень важный механизм утилиты gmake – это автоматические переменные. Некоторые существующие автоматические переменные приведены в Таблица 1.
Таблица 1
Список некоторых автоматических переменных
Имя автоматической переменной
[email protected]
$<
$^
Значение
Имя цели обрабатываемого правила
Имя первой зависимости обрабатываемого правила
Список всех зависимостей обрабатываемого правила
Пример использования представлен в листинге 5.
Листинг 5
CC:=g++
CC:= $(CC) -O2
demo: main.o summ.o
$(CC) $^ -o [email protected]
main.o: main.cpp
$(CC) -c $^
summ.o: summ.cpp
$(CC) -c $^
Перейдем к рассмотрению некоторых функций утилиты gmake.
3.3 Функции (GNU make)
Утилита gmake, в отличие от make, содержит большое количество
различных функций, позволяющих манипулировать строками (именами
16
файлов, переменными), например, некоторые из них: patsubst,
wildcard,
addprefix, addsuffix и notdir (dir).
Общий вид вызова функций осуществляется следующим образом:
$(имя_функции параметр1, параметр2 ...)
находит в тексте разделенные
пробелом слова, удовлетворяющие «шаблону» и заменяет их на строку
«замена»;
$(wildcard шаблон) – результатом функции wildcard является список разделенных пробелами имен существующих в данный момент
файлов, удовлетворяющих указанному «шаблону»;
$(addprefix префикс, список_слов) - функция addprefix добавляет
в начало каждого слова из списка слов, указанного вторым параметром,
строку, переданную ей в качестве первого параметра.
$(addsuffix префикс, список_слов) - функция addsuffix добавляет
в конец каждого слова из списка слов, указанного вторым параметром,
строку, переданную ей в качестве первого параметра.
$(dir список_имен) – функция для каждого имени файла из списка
имен, оставляет только имя директории, в которой этот файл расположен. Именем каталога считается часть имени до последнего встреченного символа «/» (включая и этот символ). Если имя файла не содержит
символов «/», его именем каталога считается строка «./».
$(notdir список_имен) – функция для каждого имени файла из
списка имен, оставляет только имя файла, удаляя из имени путь к файлу.
Список существующих функций утилиты GNU make намного выше, в методическом пособии указаны только самые основные необходимые для выполнения лабораторной работы.
Пример модифицированного make-файла c использования функций.
Листинг 6
$(patsubst шаблон,замена,текст) –
demo: $(patsubst %.cpp, %.o, $(wildcard *.cpp))
g++ $^ -o [email protected]
%.o: %.cpp
g++ -c $<
3.4 Использование переменной VPATH.
Переменная VPATH используется в make-файлах для указания
списка директорий (через пробел), где следует производить поиск файлов. Ниже приведенный пример, показывает, что путь поиска состоит из
17
двух каталогов «.» – текущий каталог и «src». Поиск в этих директориях осуществляется по порядку.
VPATH= . src
Если предположить, что файл summ.cpp находится в директории
«src», то следующее правило:
summ.o: summ.cpp
будет интерпретировано утилитой gmake, как:
summ.o: src/summ.cpp
3.5 Заключение
Последний пример make-файла (листинг 6) выглядит довольно интересно (разберитесь с ним самостоятельно) и, конечно же, упрощает
процесс компиляции. Мы разрабатывали make-файл для простого приложения состоящего всего лишь из трех файлов, реальные же проекты
состоят из огромного количества файлов, которые размещены по различным директориям, а также статических или динамических библиотек, что делает задачу написания make-файла не тривиальной. Существуют специальные утилиты, которые автоматически генерируют
make-файл, просматривая структуру файлов и директорий.
18
ЗАКЛЮЧЕНИЕ
Разработка программного обеспечения для unix-подобных систем
очень перспективное направление, это связано со специфичным использованием ОС данного типа, а также относительно ОС Windows небольшим количеством программного обеспечения. Полученные в ходе выполнения лабораторной работы навыки могут быть применены в вашей
профессиональной деятельности.
19
Задание
1 Изучить основные ключи компилятора g++. Для этого вызовите
команду:
%man g++;
2 Разработать ПО в соответствии с вариантом. Входные данные
для программы необходимо передавать через аргументы. В коде программы осуществить проверку входных данных на корректность. Все
команды введённые в процессе выполнения лабораторной работы необходимо документировать в письменном отчете.
Вариант 1
Разработать программу, которая определяет факториал числа.
Вариант 2
Вывести случайное число в диапазоне, минимальное и максимальное число диапазона задается через аргументы.
Вариант 3
Разработать программу для нахождения наименьшего общего
кратного двух чисел.
Вариант 4
Разработать программу для нахождения наибольшего общего делителя двух чисел.
Вариант 5
Разработать программу, которая выводит на экран ряд Фибоначчи
до числа N переданного через аргумент.
Вариант 6
Разработать программу, которая определяет количество чисел в
слове переданного через аргумент.
Вариант 7
Разработать программу, которая определяет количество гласных
символов в слове.
Вариант 8
Разработать программу, которая считает количество слов в предложении переданного через аргумент. При передаче предложения в качестве аргумента, строку необходимо поместить в двойные кавычки.
20
3 Специальным образом допустите синтаксическую ошибку в
программе. Сообщение об ошибке запишите в файл error.log в вашей
домашней директории.
4 Используя механизм предупреждения компилятора gcc, добейтесь вывода текстового сообщения (предупреждения) в рабочей программе (без использования ключа –Wall, а выбрав из списка всех возможных ключей, тот, который описывает вашу ошибку). Полученное
сообщение добавьте в файл error.log.
5 Оптимизируйте вашу программу, уменьшив объем памяти, который она занимает на жестком диске. Определите время, которое было
затрачено на компиляцию до оптимизации и после (использовать можно
любой уровень оптимизации). Проведите пять экспериментов, составьте
таблицу с полученными данными. Сделайте выводы.
6 Разработанную программу представить в виде простого класса
на языке С++. Осуществить разделенную трансляцию исходных файлов.
Изменить содержимое одного из файлов и снова осуществить компиляцию. Проанализировать результаты (зафиксировать даты изменения
файлов в файле log.txt) и сделать выводы.
7 Написать простейший make-файл, который будет автоматически собирать написанную вами программу, при компиляции необходимо использовать ключ для вывода сообщений об ошибке. Переименуйте
make-файл в любое понравившееся вам имя и снова соберите проект
(Первая версия make-файла).
8 Создайте новый make-файл с возможностью разделенной
трансляцией (Вторая версия make-файла).
8.1 После успешного компилирования (информацию, полученную в процессе компиляции, добавьте в файл log.txt) удалите один из объектных файлов, заново запустите процесс
компиляции (результат также добавьте в файл log.txt). Проанализируете полученный результат. Сделайте выводы.
8.2 Запустите утилиту make еще раз, полученное сообщение
также добавьте в файл log.txt. Сделайте выводы.
8.3 Используя ложную цель, добавьте в make-файл возможность
автоматического удаления объектных файлов после компиляции.
9 Максимально оптимизируйте вторую версию make-файла, добавив переменные (автоматические переменные) и функции, изученные
в ходе лабораторной работы (Третья версия).
10 Создайте в директории с вашей программой каталог с названием «src» переместите в него два файла описывающие ваш класс (*.h,
21
*.cpp), файл main.cpp должен остаться в текущей директории. Добейтесь
успешной компиляции, доработав make-файл (четвертая версия), используя знания, полученные в ходе лабораторной работы (Возможно,
вам пригодится ключ –I компилятора g++ и переменная VPATH).
В результате проделанной работы, в вашей домашней директории
должны содержаться:
 исходные коды программы (3 файла или более);
 корректный исполняемый файл, соответствующий вашему варианту;
 файл error.log – файл, содержащий сообщения об ошибках и
предупреждениях;
 файл log.txt – содержащий некоторую выходную информацию,
полученную в процессе выполнения работы;
 make-файлы (4 версии);
Необходимо написать отчет по лабораторной работе, продемонстрировать работу программы преподавателю, а также процесс компилирования программы с использованием последней версии make-файла.
Ответить на контрольные вопросы.
22
Контрольные вопросы
1 Что вы понимаете под компиляцией? Как вы считаете, чем отличается компилятор от интерпретатора? Приведите примеры
компилируемых и интерпретируемых языков программирования.
2
3 Ниже приведены простейшие примеры make-файлов. Что будет
выведено на экране в результате выполнения make-файла?
Задание 1
var1 = one
var2 = $(var1) two
var1 = three
all:
@echo $(var2)
Задание 2
var1 := one
var2 := $(var1) two
var1 := three
all:
@echo $(var2)
Задание 3
var1 = one
var1 = $(var1) two
all:
@echo $(var1)
Задание 4
source_dirs := src lib
search_matches := $(addsuffix /*.cpp, $(source_dirs))
all:
@echo $(search_wildcards)
23
Список используемых источников
1. Альфред В. Ахо, Моника С. Лам, Рави Сети, Джеффри Д. Ульман Компиляторы: принципы, технологии и инструментарий =
Compilers: Principles, Techniques, and Tools. - 2 изд.М.:Вильямс, 2008.
2. Основы языка программирования C++. Режим доступа:
http://cppstudio.com/cat/274/275/
24
Приложение 1
(обязательное)
Исходный код демонстрационной программы
В заголовочном файле (summ.h) будет содержаться описание
класса.
#ifndef SUMM_H
#define SUMM_H
class CSumm {
public:
CSumm(int v1, int v2);
int calculate();
private:
int a;
int b;
};
#endif
В файле (summ.cpp) будет содержаться реализация описанного
класса.
#include "summ.h"
CSumm::CSumm(int v1, int v2) {
a = v1;
b = v2;
}
int CSumm::calculate() {
return a + b;
}
Модифицированный файл main.cpp с точкой входа в программу.
#include <iostream>
#include "summ.h"
int main( int argc, const char* argv[] )
{
int x;
int y;
if ( argc == 3 )
{
x = atoi( argv[1] );
y = atoi( argv[2] );
CSumm * calc = new CSumm(x, y);
std::cout <<x<<" + "<<y<<"=" << calc->calculate() <<
std::endl;
25
}
return 0;
}
26
Приложение 2
(обязательное)
Основной список ключей компилятора g++
 v – версия компилятора
 o – путь к целевой программу
 std – указывает стандарт языка программирования (например
c++98, по умолчанию gnu++98)
 Wall – выводит любые предупреждения об ошибках.
 g – получение отладочной информации
 pipe – позволяет ускорить компиляцию, передача информации
между различными этапами осуществляется через каналы, без
использования промежуточных файлов.
27
Приложение 3
(обязательное)
Ключи утилиты GNU make
-b, -m. Эти опции игнорируются и служат для совместимости с
другими версиями make.
-C dir - Изменить каталог на dir перед чтением make_файлов или
выполнением чего-то ещё. Если указано несколько опций –C, то каждая
интерпретируется относительно предыдущей: -C / -C etc эквивалентно –
C /etc. Обычно, это используется с рекурсивными вызовами make.
-d - Печатать отладочную информацию в дополнении к нормальной. Отладочная информация показывает, какие файлы было решено
переделать, какие времена файлов сравнивались и с каким результатом,
какие файлы на самом деле должны быть переделаны, какие скрытые
правила подразумевались и какие были применены---всё интересное о
том, как make решал что делать.
-e - дать переменным из среды превосходство над переменными
из make-файлов.
-f file – Использовать file как makefile.
-i - Игнорировать все ошибки в командах, выполняемых для обновления файлов.
-I dir - В заданном каталоге dir ищутся включаемые make-файлы.
Если используется несколько опций –I для задания нескольких каталогов, то поиск осуществляется в порядке задания. В отличие аргументов
других флагов make, каталоги в –I флагах можно указывать сразу после
флага: -I dir разрешено, также как и –I dir. Этот синтаксис разрешён для
совместимости с флагом –I препроцессора C.
-j jobs - Указать число заданий (команд) выполняемых одновременно. Если есть больше чем одна –j опция, то используется последняя.
Если –j опция задана без аргумента, то make не ограничивает число заданий, которые могут выполняться одновременно.
-k - Продолжать после ошибки настолько, насколько возможно.
Несмотря на то, что объект нельзя обновить, и то, что от этого зависит,
не может быть переделано, в тоже время есть другие зависимости этого
объекта, которые могут быть обработаны.
-l load - Указывает, что новые задания (команды) не должны
начинаться, если другие задания запущены и средняя загрузка, по крайней мере, load (дробное число). Без аргументов удаляется предыдущий
предел загрузки.
28
-n - Напечатать команду, которая должна выполняться, но не выполнять её.
-o file - Не переделывать файл file, даже если он старее, чем его зависимости, и ничего не переделывать за счёт изменений в file. По существу, файл трактуется как очень старый и его правила игнорируются.
-p - Напечатать базу данных (правила и значения переменных) полученную при чтении make-файлов; затем выполняться, как обычно или
как указано иначе. Это также печатает информацию о версии, даваемую
переключателем –v (смотри ниже). Чтобы напечатать базу данных без
попыток пересобрать любые файлы, используется make –p -f/dev/null.
-q – «Режим запроса». Никаких команд не запускается и ничего не
печатается; только возвращается код завершения, который равен нулю,
если заданный объект уже самый новый, иначе не ноль.
-r - Исключить использование встроенных скрытых правил. Также
очистить список суффиксов по умолчанию для правил суффиксов.
-s -Тихая работа; не печатать команды при их выполнении.
-S - Отменить действие опции -k . Этого никогда не требуется,
кроме как при рекурсиях make где –k может быть унаследована от верхнего уровня make через MAKEFLAGS или если –k установлена в
MAKEFLAGS среды.
-t - Прикоснуться к файлам (пометить их как новые без действительного их изменения) вместо запуска команд к ним. Это используется,
чтобы симулировать, что команды выполнены, чтобы обмануть будущие вызовы make.
-v - Напечатать версию программы make плюс copyright, список
авторов и уведомление об отказе от гарантий.
-w - Напечатать сообщение, содержащее рабочий каталог перед и
после других работ. Это может быть полезно для отслеживания ошибок
при сложных вложенных рекурсивных make командах.
-W file - Сделать вид, что объект file только что был модифицирован. Когда еще используется –n флаг, то это покажет, чтобы случилось,
если бы этот файл был изменён. Без -n, это почти тоже самое, что как
запустить команду touch с данным файлом перед запуском make, кроме
того, что время модификации изменилось только в представлении make.
29
Учебное издание
САВЕНКО Игорь Игоревич
КОМПИЛЯТОРЫ. КОМПИЛЯЦИЯ ПРОГРАММНОГО
ОБЕСПЕЧЕНИЯ В ОС FreeBSD
Методические указания к выполнению лабораторных работ
по курсу «Системное программное обеспечение»
для студентов направлений 230100 «Информатика и вычислительная
техника» и 230400 «Информационные системы и технологии»
Отпечатано в Издательстве ТПУ в полном соответствии
с качеством предоставленного оригинал-макета
Подписано к печати 00.00.2013. Формат 60х84/16. Бумага «Снегурочка».
Печать XEROX. Усл. печ. л. 9,01. Уч.-изд. л. 8,16.
Заказ 000-13. Тираж 100 экз.
Национальный исследовательский Томский политехнический университет
Система менеджмента качества
Издательства Томского политехнического университета сертифицирована
NATIONAL QUALITY ASSURANCE по стандарту BS EN ISO 9001:2008
. 634050, г. Томск, пр. Ленина, 30
Тел./факс: 8(3822)56-35-35, www.tpu.ru
30
1/--страниц
Пожаловаться на содержимое документа