Компіляція програми: як це працює

Виконання програм

Виконувані файли (executable files), які ми звикли бачити (і які, мають різний формат в залежності від операційної системи) містять набір машинних інструкцій та даних, а також інформацію про те, де ці інструкції та дані знаходяться всередині файлу.

Під час запуску програми, операційна система вантажить її у оперативну пам'ять. Як саме відбувається заванатаження залежить від формату цього файлу. Різні операційні системи можуть підтримувати різні формати виконуваного файлу. Тож, зазвичай, виконувані файли з Windows не можна запустити на ОС Linux, та навпаки (хоча, можливо і таке, якщо якось "навчити" операційну систему розуміти їх формат і виконувати такі файли, див. наприклад Wine).

Після завантаження у пам'ять файлу, операційна система передає виконання на початок програми (пам'ятаємо про функцію main()?). Машинні інструкції є спеціальним кодом, зрозумілим для процесора. Різні процесори мають різний набір машинних інструкцій. Наприклад, виконувані файли, які запускаються на процесорах Intel (який містять велика частина сучасних лептопів) не можна запустити на міні-комп'ютерах Raspberry Pi остащених процесором з архітектурою ARM, хоча і там і там може бути встановлена OS Linux.

Машинні інструкції зручні лише для машин. Людині зрозуміти їх неймовірно важко, оскільки виглядають вони як набір цифр. Щоб упоратись з цим, кожній машинній команді задають скорочення. Цю мову для зручнішого текстового виразу машинних команд називають мовою Асемблеру (assembler).

Але й це не надто зручно. Набагато легше мислити словами та абстрактними поняттями. Тож були розроблені мови програмування, які дають нам можливість оформити ідеї синтаксично згідно з заданими правилами, а далі перетворити їх з допомогою програми, яка зветься компілятором (compiler). Відповідно, процес аналізу програми з наступним перетворенням у набір машинних команд та даних називають компіляцією (compilation).

С++: процес компіляції

Процес створення виконуваного файлу з програми на мові С++ проходить у два важливі етапи:

  • Спочатку програма компілюється (compile). Опрацьовується окремо кожен файл, який входить до складу програми.

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

    • Компілятор перевіряє текст програми на наявність синтаксичних помилок. Якщо вони є, то процес компіляції зупиняється.

    • Компілятор перетворює текст мовою С++ у набір машинніх кодів. До прикладу, ось як виглядає перетворений текст нашої найменьшої програми мовою С++. У правій манелі ми можемо побачити текст на асемблері та відповідний машинний код у шістнадцятковій системі числення.

  • Далі, усі скомпільовані файли (якщо їх було кілька) об'єднуються та перетворюються у викоуваний файл. Цей процес називається зв'язуванням (лінкуванням, linking). І виконується програмою, яка зветься лінкер (linker). Цей крок виконується окремо тому, що це дає змогу повторно використовувати скомпільований код, використовувати бібліотеки готових функцій та багато чого іншого, про що ми поговоримо якось у наступних розділах книги.

Живий приклад: GCC - компілюємо найменьшу програму у консолі

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

  1. Найперше, нам необхідно створити файл з текстом нашої програми:

    ~ touch main.cpp
  2. Далі ми можемо відкрити та поредагувати цей файл, додавши текст програми.

    Можна зробити це прямо з консолі з допомогою команди nano main.cpp (команда доступна у нашій суперконсолі на Windows або консолі Linux\Mac якщо встановлено консольний редактор nano).

    Інший варіант - відкрити файл у будь-якому зручному текстовому редакторі (Для того, щоб відкрити поточну теку з файлом скористайтеся командою explorer . на Windows чи open . на Mac OS X (зауважте, у цих командах в кінці крапка, що означає поточну теку!)).

  3. Введіть текст програми. Наприклад:

    #include <iostream>
    
    int main()
    {
        std::cout << "Hello!";
    }
  4. Збережіть зміни та відкрийте знов командний рядок (у редакторі nano ctrl+s для збереження та ctrl+x для виходу з редактора).

    Переконайтеся, що ви маєте встановлений компілятор для мови С++. Для того, щоб переконатися чи встановлено компілятор GCC виконайте команду g++ --version.Якщо компілятор встановлено - ви побачите інформацію про його версію.

    ~ g++ --version
    g++.exe (Rev1, Built by MSYS2 project) 7.3.0
    Copyright (C) 2017 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.  There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

    Якщо ж ні - встановіть пакет компіляторів GCC на Linux з допомогою вашого пакетного менеджера, а на Windows скористайтеся командою install-dev-env у суперконсолі, яка встановить усе необхідне програмне забезпечення (буде запит на підтвердження встановлення - просто натисніть Enter). На Mac OS X - встановіть середовище розробки XCode та запустіть його після встановлення (після цього відкрийте консоль заново і слідуйте інструкціям далі).

  5. Скомпілюйте програму:

    ~ g++ -o main main.cpp

    Тут ми викликаємо компілятор мови С++ (g++) з параметрами -o <назва виконуваного файлу>, а останнім параметром передаємо шлях до файлу програми. Команда має виконатись без повідомлень (будь які повідомлення можуть означати помилку у тексті програми чи під час компіляції).

  6. Запустіть програму та переконайтеся, що вона виводить повідомлення Hello! у консоль.

    • На Windows (суперконсоль):

      ~ ./main.exe 
      Hello!
    • На Linux\MacOS:

      ~ ./main
      Hello!

Last updated