русс | укр

Мови програмуванняВідео уроки php mysqlПаскальСіАсемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование


Linux Unix Алгоритмічні мови Архітектура мікроконтролерів Введення в розробку розподілених інформаційних систем Дискретна математика Інформаційне обслуговування користувачів Інформація та моделювання в управлінні виробництвом Комп'ютерна графіка Лекції


Шановні українці! Матеріал був перекладений з російської мови. Тому можуть бути незначні помикли...

Компілятор GCC

Одним із інструментів створення програм є компілятором GCC. Спочатку ця абревіатура розшифровується, пяк GNU C Compiler. Зараз вона означає - GNU Compiler Collection.

пРассмотрим приклад створення програми «Hello world!» - «Привіт Світ!».
Файли з текстами програм, які ми будемо створювати, це звичайні текстові файли, та створювати їх можна за допомогою будь-якого текстового редактора (наприклад GEdit KWrite, Kate, а також більш традиційні для користувачів Linux - vi і emacs). Крім текстових редакторів, існують спеціалізовані середовища розробки зі своїми вбудованими редакторами. пОдним з таких засобів є KDevelop. Цікаво, що в ньому є вбудований редактор і вбудована консоль, прасположенная прямо під редактором. Так що можна прямо в одній програмі, не перемикаючись між вікнами, та редагувати код і давати пконсольные команди.

пДля проби можете створити окремий каталог hello і в ньому - текстовий файл hello.c з наступним текстом:

#include <stdio.h>

int void main ()
{
 printf("Hello world!\n");
 return(0);
}

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

gcc hello.c

У каталозі з'явився новий файл a.out. Це і є виконуваний файл. Запустимо його. Наберіть в консолі:

/.a.out

Програма повинна запуститися, тобто повинен з'явитися текст:

Hello world!

Компілятор gcc за замовчуванням присвоює всім створеним виконуваним файлів ім'я a.out. Якщо хочете назвати його по-іншому, потрібно до команди на компіляцію додати прапор-o та ім'я, яким ви хочете його назвати.

gcc hello.c-o hello

У каталозі з'явиться виконуваний файл з назвою hello. Для його запуску наберіть в консолі:

/.hello

Прапор-o є лише одним з численних прапорів компілятора gcc. Деякі інші прапори були наведені раніше, деякі ми розглянемо пізніше.

Щоб переглянути всі можливі прапори, можна скористатися довідковою системою man. Введіть у командному рядку:

man gcc

Перед вами постане довідкова система по цій програмі. Вихід з довідкової системи здійснюється за допомогою клавіші q.

пТочку і слеш перед назвою виконуваного файлу означає шлях до файлу, тобто файл знаходиться в поточному каталозі.
пнатисніть запустити програму, яка знаходиться в іншому місці, треба прописати повний шлях до неї, наприклад так:

/home/user/projects/hello/hello

Або інший варіант: прописати шлях відносно поточного каталогу, в якому ви в даній момент знаходитесь в консолі. При цьому одна точка поточний каталог, дві точки - батьківський. Наприклад, команда ./hello запускає програму hello, що знаходиться в поточному каталозі, команда ../hello - програму hello, що знаходиться в батьківському каталозі.

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

пТакже є можливість додавати в список системних шляхів шляху до своїх програм. пДля цього треба додати новий шлях в системну змінну оточення PATH.

 

Розглянемо, що ж робить програма gcc

Робота gcc включає три етапи: обробка препроцессором, компіляція та компонування (або лінкування).

Препроцесор включає в основний файл вміст всіх заголовних файлів, вказаних у директивах #include. пВ заголовних файлах зазвичай знаходяться оголошення функцій, що використовуються у програмі, але не визначених у тексті програми. піх визначення знаходяться десь в іншому місці або в інших файлах з вихідним кодом або в бінарних бібліотеках.

пДля того, щоб подивитися, що на цьому етапі робиться, скористаємося опцією-E. Ця опція зупиняє виконання програми на етапі побработки препроцессором. У результаті виходить файл вихідного коду з включеним у нього вмістом заголовних файлів. пВ прикладі hello.c підключається один файл заголовків на мові - stdio.h - колекція стандартних функцій введення-виведення.
Введіть наступну команду:

gcc-E hello.c-o hello.cpp
пПолученному файлу ми дали ім'я hello.cpp. Відкривши його, ви побачите, що він досить довгий. Це тому, що в нього ввійшов увесь пкод файлу заголовків stdio.h. Крім того, препроцесор сюди додав деякі теги, які вказують компілятору спосіб зв'язку пс оголошеними функціями. Основний текст нашої програми видно тільки в самому низу.

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

man fopen

info fopen

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

пОбъектный файл являє собою «dostac» переклад нашого програмного коду на машинний мову, ппока без зв'язку викликаних функцій з їх визначеннями. Для формування об'єктного файлу служить опція-c.r

gcc-c hello.c

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

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

gcc-x cpp-output-c hello.cpp

Остання стадія - компонування. Вона полягає у зв'язуванні всіх об'єктних файлів проекту в один, зв'язуванні викликів функцій пс їх визначеннями, і приєднанням до бібліотечних файлів, що містять функції, які викликаються, але не визначені в проекті. пВ результаті формується виконуваний файл - наша кінцева мета. Якщо якась функція програми використовується, пно компонувальник не знайде місце, де ця функція визначена, він видасть повідомлення про помилку, і відмовиться створювати виконуваний файл.

пДля отримання з об'єктного файлу виконуваного використовується опція-o:

gcc hello.o-o helo

Отриманий виконуваний файл можна запускати:

/.hello

Ви запитаєте: «Навіщо вся ця метушня з проміжними етапами? пНе чи краще просто один раз скомандувати

gcc kalkul.c-o kalkul?

Справа в тому, що ці програми дуже рідко складаються з одного файлу. Як правило вихідних файлів кілька, і вони об'єднані в проект. І в деяких виняткових випадках програму доводиться компонувати з декількох частин, написаних на різних мови. В цьому випадку доводиться запускати компілятори різних мов, щоб кожен отримав об'єктний файл зі свого джерела, а потім вже ці отримані об'єктні файли компонувати в виконувану програму.

 

 

Приклад проекту з декількох файлів

Розглянемо програму, що складається з двох вихідних файлів та одного заголовків. пДля цього візьмемо як приклад примитивнй калькулятор, здатний додавати, віднімати, множити і ділити. пякщо запуску він буде запитувати два числа, над якими слід провести дію, та пзнак арифметичного дії. Це можуть бути дії: «+», «-», «*», «/», pow, sqrt, sin, cos, tan. після цього програма виводить результат і зупиняється (повертає нас в операційну систему, а точніше - в командний інтерпретатор, з якого ми програму і викликали).

При цьому після введення першого числа треба відразу вводити в дію. Якщо дія оперує тільки з одним числом (як у випадку синуса, косінуса, тангенса, квадратного кореня), результат відразу буде виведено. пякщо знадобиться друге число, воно буде спеціально запитуватися

пСоздадим каталог проекту 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: //////////////////////////////////// // 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 void main () { float Numeral; char Operation[4]; float Result; printf("Число: "); scanf("%f",&Numeral); printf("Арифметичне дію (+,-,*,/,pow,sqrt,sin,cos,tan): "); scanf("%s",&Operation); Calculate Result = (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(.text+0x1b5): In function `Calculate":
calculate.c: undefined reference to `pow"
calculate.o(.text+0x21e):calculate.c: undefined reference to `sqrt"
calculate.o(.text+0x274):calculate.c: undefined reference to `sin"
calculate.o(.text+0x2c4):calculate.c: undefined reference to `cos"
calculate.o(.text+0x311):calculate.c: 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>.r libcrypt Криптографічні функції. Потрібно файл заголовків на <crypt.h>. libcurses Псевдографика у символьному режимі. Потрібно файл заголовків на <curses.h>.r libform Створення екранних форм у текстовому режимі. Потрібно файл заголовків на <form.h>.r libgthread Підтримка багатопоточного режиму. Потрібно файл заголовків на <glib.h>.r libgtk Графічна бібліотека в режимі X Window. Потрібно файл заголовків на <gtk/gtk.h>.r libhistory Роботи з журналами. Потрібно файл заголовків на <readline/readline.h>.r libjpeg Робота з зображень у форматі JPEG. Потрібно файл заголовків на <jpeglib.h>.r libncurses Робота з псевдографикой у символьному режимі. Потрібно файл заголовків на <ncurses.h>.r libpng Робота з графікою у форматі PNG. Потрібно файл заголовків на <png.h>.r libpthread Багатопотокова бібліотека POSIX. Стандартна багатопотокова бібліотека для Linux. Потрібно файл заголовків на <pthread.h>.r libreadline Робота з командним рядком. Потрібно файл заголовків на <readline/readline.h>.r libtiff Робота з графікою у форматі TIFF. Потрібно файл заголовків на <tiffio.h>.r 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

Ура! Виконуваний файл створений! Запустимо його:
.kalkul

Переглядів: 10302

Повернутися в зміст:ОС Linux




Онлайн система числення Калькулятор онлайн звичайний Науковий калькулятор онлайн