понеділок, 30 травня 2016 р.

Ручна компіляція C++ програм

Перш ніж приступати до вивчення C++, нам потрібно навчитися компілювати написані нами програми. Компіляцією називається процес при якому код програми транслюється (переводиться) у машинний код. Для компіляції програмного коду існують спеціальні програми, які так і називаються – компілятори.

Зміст

1. Процес компіляції

Процес компіляції складається з двох етапів:

  1. Власне сама компіляція (трансляція). На цьому етапі, всі вихідні (початкові) файли з C++ кодом транслюються у, так звані, об’єктні файли;
  2. Компоновка (лінковка). На цьому етапі, всі об’єктні файли, які були отримані на етапі трансляції, зв’язуються в один виконуваний файл.

Схематично, ми можемо зобразити цей процес таким малюнком:

Нас, як програмістів, не цікавить яким чином відбувається процес трансляції та лінковки. Усе, що нам необхідно вміти, це запустити компілятор з потрібними параметрами. Саме цим ми і займемося в цьому уроці.

Догори

2. Необхідне програмне забезпечення

Для того, щоб виконувати наведені нижче приклади, нам знадобиться встановити на комп’ютер деяке програмне забезпечення, а саме:

  1. Компілятор g++;
  2. Утиліту make;
  3. Утиліту CMake;
  4. Середовище розробки QtCreator.

Догори

2.1. Для Ubuntu

Для Ubuntu, щоб встановити перші три пункта, достатньо виконати в терміналі команду:

$ sudo apt-get install build-essential cmake

QtCreator встановлюється за допомогою інсталятора.

Догори

2.2. Для Windows

Так само, як для *NIX-подібних систем існує пакет build-essential із компілятором g++ і утилітою make, так і для Windows розроблено пакет MinGW. Єдина відміність, що в MinGW утиліта make називається mingw32-make.

Сам пакет MinGW іде в поставці із QtCreator і встановлюється за допомогою звичайного інсталятора, а от утиліту CMake, доведеться встановлювати вручну.

Отже, почнемо з QtCreator. Завантажте інсталятор QtCreator для Windows із компілятором MinGW. Встановіть QtCreator із параметрами по замовченню і пропишіть у змінну середовища PATH шлях до каталога: C:\Qt\Qt5.5.1\Tools\mingw492_32\bin (каталог mingw492_32 змінюється залежно від версії).

Тепер, встановимо утиліту CMake. Завантажте архів з офф-сайту та розпакуйте його в корінь диска C:\ під назвою cmake. До змінної середовища PATH додайте шлях C:\cmake\bin.

Маючи в наявності необхідне програмне забезпечення, ми можемо приступити до написання своєї першої програми на C++.

Догори

3. Проект leap

Наша перша програма на C++ буде простою — ми визначатимемо чи заданий рік є високосним, чи ні.

Догори

3.1. Створення проекту

Отже, створимо деінде каталог під назвою leap в якому ми розмістимо наш проект. Запустимо Qt Creator і створимо в цьому каталозі файл main.cpp з наступним кодом:

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

$ g++ -c main.cpp
g++ -c main.cpp

Задаючи ключ -c, ми вказуємо компілятору транслювати файл main.cpp у об’єктний файл. По замовченню, об’єктний файл буде мати таку ж назву, як і файл з кодом, тобто, в нашому випадку, ми отримаємо файл main.o. Цю поведінку компілятора можна змінити, додавши до команди ключ -o з назвою об’єктного файла. Наведену вище команду ми можемо переписати з використанням цього ключа таким чином:

$ g++ -c main.cpp -o object.o
g++ -c main.cpp -o object.o

В цьому випадку, компілятор транслює файл main.cpp в об’єктний файл object.o.

Сам б’єктний файл не є ще виконуваною програмою. Щоб зробити з нього виконувану програму, яку можна запустити, ми повинні скомпонувати (злінкувати) його. Для цього, слід виконати у терміналі команду:

$ g++ main.o -o leap
g++ main.o -o leap

В результаті, ми отримаємо виконуваний файл з назвою, яку ми вказали після ключа -o, тобто – leap. Запустити нашу програму ми можемо виконавши у терміналі команду:

$ ./leap
leap.exe

Таким чином, маючи код програми у файлі main.cpp, ми змогли скомпілювати його у виконуваний файл двома командами:

$ g++ -c main.cpp
$ g++ main.o -o leap
g++ -c main.cpp
g++ main.o -o leap

Слід зауважити, що ми могли б добитися такого ж результату без проміжних, об’єктних файлів. Отримати той самий виконуваний файл leap ми могли б виконавши лише одну команду:

$ g++ main.cpp -o leap
g++ main.cpp -o leap
Зверніть увагу, що в цій команді ми не використовуємо ключ -c.

Догори

3.2. Організація коду на *.h і *.cpp файли

Як правило, більш-менш серйозна програма складається не з одного файлу, а з декількох ─ файли заголовків, з розширенням .h і файли реалізації з розширенням .cpp. Ми можемо організувати наш проект подібним чином, винісши метод isLeapYear() у інший файл. Отже, створимо файл заголовків lib.h з наступним вмістом:

і файл реалізації lib.cpp:

Тепер, головний файл main.cpp, набуде такого вигляду:

При такій організації проекту, щоб отримати виконуваний файл, нам потрібно послідовно виконати такі команди:

$ g++ -c lib.cpp -o lib.o
$ g++ -c main.cpp -o main.o
$ g++ main.o lib.o -o leap
g++ -c lib.cpp -o lib.o
g++ -c main.cpp -o main.o
g++ main.o lib.o -o leap

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

$ g++ main.cpp lib.cpp -o leap
g++ main.cpp lib.cpp -o leap

Догори

3.3. Організація файлової структури проекту

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

  1. leap/src - буде містити файли з розширенням *.cpp, *.h, тобто, файли з програмним кодом;
  2. leap/obj - буде містити усі проміжні об’єктні файли, з розширенням *.o;
  3. leap/bin - буде містити результуючий виконуваний файл.

В результаті такої реорганізації, файлова структура нашого проекту матиме наступний вигляд:

При цьому, усі команди, які ми раніше використовували для компіляції, не будуть працювати. Їх потрібно дещо видозмінити:

$ g++ -c src/lib.cpp -o obj/lib.o
$ g++ -c src/main.cpp -o obj/main.o
$ g++ obj/main.o obj/lib.o -o bin/leap
g++ -c src\lib.cpp -o obj\lib.o
g++ -c src\main.cpp -o obj\main.o
g++ obj\main.o obj\lib.o -o bin\leap

Догори

4. Утиліти Make і CMake

Уявіть собі ситуацію, коли ваш C++ проект має більше 20 файлів. В такому випадку, ручна компіляція перетворюється на, доволі таки, громіздкий та рутинний процес. Щоб уникнути цієї рутини існують спеціальні утиліти (допоміжні програми), які автоматизовують і значно спрощують процес компіляції. Найбільш відомими серед таких утиліт є ─ Make та CMake.

Догори

4.1. Утиліта Make

Принцип роботи утиліти Make простий. Ми повинні створити файл з назвою Makefile, який містить спеціальні правила компіляції нашого проекту. Отже, в каталозі leap створимо файл з назвою Makefile, вміст якого буде наступний:

Більш детально про створення Makefile-лів можна прочитати, наприклад, тут.

Щоб протестувати створений нами Makefile, ми видалимо всі файли з папок obj і bin, перейдемо у каталог leap і запустимо команду:

$ make
mingw32-make

При цьому, в каталозі obj з’явиться два об’єктних файла, а в каталозі bin ─ виконуваний файл leap. Схематично, для нашого прикладу, роботу утиліти Make можна представити таким малюнком:

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

Догори

4.2. Утиліта CMake

Утиліта CMake була розроблена для того, щоб спростити процес створення Makefile-ів. По суті, вона сама створює готовий до використання Makefile.

Принцип роботи цієї утиліти нагадує принцип роботи утиліти Make. Ми повинні створити файл під назвою CMakeLists.txt зі спеціальними інструкціями, після чого запустити утиліту. В результаті, CMake створить нам готовий до використання Makefile. Маючи Makefile ми власноруч запускаємо утиліту make, яка скомпілює наш проект.

Слід відмітити, що вміст файла CMakeLists.txt, у порівнянні із вмістом Makefile, значно простіший і більш зрозуміліший. Наприклад, для нашого проекту, у найпростішому випадку, він може виглядати таким чином:

Опис деяких оголошень, які використовуються у файлі CMakeLists.txt, можна знайти тут і тут.

Давайте, спробуємо утиліту CMake на ділі. В папці src нашого проекту, створимо файл з назвою CMakeLists.txt і додамо в нього вище вказані інструкції. Створимо в папці leap каталог build і перейдемо в нього. З цього каталога запустимо таку команду:

$ cmake ../src
cmake -G "MinGW Makefiles" ..\src

В результаті, в папці build, утиліта створить Makefile. Тепер, ми можемо скомпілювати нашу програму командою:

$ make
mingw32-make

Як бачите, утиліта CMake ніяк не заміняє собою утиліту Make, а лише створює для неї Makefile. Схематичний малюнок, представлений нижче, зображує принцип роботи утиліти CMake:

Успіхів!

Догори

Немає коментарів:

Дописати коментар