Как скомпилировать с в linux
Перейти к содержимому

Как скомпилировать с в linux

  • автор:

Как написать и запустить программу на языке C в Linux

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

Для компиляции простой программы на языке C мы используем инструмент командной строки Linux — терминал. Чтобы открыть терминал, вы можете использовать Ubuntu Dash или комбинацию клавиш Ctrl+Alt+T.

Шаг 1: Установите необходимые для сборки пакеты

Для компиляции и выполнения программы на языке C необходимо, чтобы в вашей системе были установлены необходимые пакеты. Введите следующую команду от имени root в терминале Linux:

Установка пакетов build-essential с помощью apt

Вам будет предложено ввести пароль для root; после этого начнется процесс установки. Пожалуйста, убедитесь, что вы подключены к интернету.

Шаг 2: Напишите простую программу на языке C

После установки необходимых пакетов, давайте напишем простую программу на языке C.

Откройте графический текстовый редактор Ubuntu и напишите или скопируйте в него следующий пример программы:

Затем сохраните файл. В этом примере я назвал свою программу на языке Си как sampleProgram.c

Пример программы на Си

Шаг 3: Скомпилируйте программу на языке C с помощью компилятора gcc

В терминале введите следующую команду, чтобы создать исполняемую версию написанной вами программы:

Шаг 4: Запуск программы

Последний шаг — запуск скомпилированной программы на языке C. Для этого используйте следующий синтаксис:

Запуск нашей скомпилированной программы

Вы можете видеть, как программа выполняется в приведенном выше примере, отображая текст, который мы написали для печати через нее.

Из этой статьи вы узнали, как написать, скомпилировать и запустить простую программу на языке C в Linux.

Как начать писать программный код Си в ОС Linux (Руководство для совсем начинающих)

Добрый день. Этот материал рассчитан на людей, будущих программистов, которые только начинают разбираться в программировании под ОС Linux. Я попробую здесь показать прямое руководство к действию на примере тех простых инструментов, которые использовал некогда сам при изучении Си в процессе знакомства с Linux. На самом деле, с теми или иными поправками, это руководство можно использовать в большинстве дистрибутивов. Руководство однозначно подходит для всех deb-based дистрибутивов.

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

Итак: у Вас сейчас установлен дистрибутив ОС, как говорится, «из коробки». Перед глазами пособие для разработчика/учебник/просто_хорошая_книга по «Языку программирования Си». И никакой вменяемой, полноценной подробной информации о том, как же собственно откомпилировать и выполнить, написанный в книге, исходный код. Быстрый осмотр тематических ресурсов уже показал Вам, что, необходимо установить компилятор Си, запустить его с нужными параметрами и потом запустить компилированный бинарный код. Примерно с этого момента мы и начнём.

Установка компилятора

Я имею ввиду, что Вы скорее всего (бывший) пользователь ОС Windows и действия в чёрном/синем окошке при помощи клавиатуры оканчивались где-то на команде ping, кажутся неким таинством. Однако отмечу, что всё банально просто и текстовой интерфейс предоставляет намного более гибкие возможности (скорее всего Вы неоднократно Вы слышали это ранее). Приступим:

Я подразумеваю, что с понятием компиляции и о том что такое компилятор Вас уже познакомила правильная книга.

На этом этапе всё будет очень быстро и просто. Открываем терминал и пишем:

(На всякий случай: вставка в gnome-terminal ctrl+shift+v)

Сразу поясню, что текст слева от курсора — это приглашение командного интерпретатора и оно выглядит следующим образом:

Далее я буду указывать только команды интерпретатору без приглашения.

Данная строка «говорит» интерпретатору: «от имени суперпользователя запустить менеджер пакетов для установки пакета gcc».

Система попросит Вас ввести пароль суперпользователя и приступит к установке компилятора.

Если же он уже установлен, то менеджер пакетов apt просто укажет на это примерно следующим образом:

Установка редактора

Обычно с дистрибутивом Ubuntu поставляется весьма интересный текстовой редактор gedit . Однако в других дистрибутивах возможно придётся установить этот редактор:

Создание файла с исходным кодом

Теперь пришло то самое время нашего классического «hello world»! Давайте сделаем это в стиле linux. Просто наберите в консоли:

Более подробно Вы обязательно прочитайте в профильных ресурсах и в документации, я только отмечу, что символ «тильда» возвращает полный путь к домашнему каталогу пользователя ОС. Соответственно будет создан файл в вашем домашнем каталоге с указанным именем.

И далее наш программный код на языке Си в редакторе:

(Стоит отметить, что в редакторе gedit есть подсветка синтаксиса для различных языков программирования. Переключить режимы подсветки можно в нижней части окна редактора.)

Не забываем сохранить изменения нажатием ctrl+s. Обратите внимание, что вопросов об имени файла не последовало, так как имя было уже указано параметром при запуске редактора из командной строки терминала.

Компиляция и запуск

Закрываем окно редактора нажатием Alt+F4 и запустим же то сокровенное ради чего все тут и собрались:

И в ответ только новое приглашение. В отличие от стиля в ОС Windows, когда консоль, жутко подробно по-умолчанию, комментирует выполняемые действия — большинство программ в ОС семейства *nix сообщают только об исключительных ситуациях, ошибках и тому подобных вещах. То есть если «в ответ тишина» — то всё прошло хорошо.

Теперь в домашнем каталоге у нас появился файл a.out — он и есть файл с исполнимым кодом.

Для запуска этого файла на исполнение — назначим ему атрибут: «исполнимый»:

и теперь запустим получившееся приложение:

(Для запуска исполнимого файла интерпретатору требуется указать полный путь к файлу. Как в случае с «тильдой» символ «точка» возвращает полный путь к текущему каталогу. В данном конкретном случае правомерно так же запустить через

/a.out Это не имеет значения здесь, так как файл создан в домашнем каталоге пользователя.)

И мы получаем вывод в терминале:

Для выполнения всех повторных действий: изменение кода и снова компиляция, — Вы можете не вводить все эти команды каждый раз заново, а использовать стрелки вверх и вниз, для быстрого выбора команд из истории. И, кстати, вывод списка истории всех введённых команд можно выполнить командой (на самом деле программой) history .

Минутка автоматизации

Теперь приступим к очень интересному моменту связанному с творчеством в духе *nix. Каждый раз вводить много скучных команд неинтересно, возможно, даже вредно. Мы расширим функционал редактора gedit и доработаем его «напильником» до состояния примитивной среды разработки: запустим gedit и откроем меню параметров,

Главное меню gedit

Главное меню gedit

где на вкладке «Расширения» добавляем «Внешние инструменты»

"Настройки" - "Расширения"

«Настройки» — «Расширения»

И затем, из того же главного меню gedit выбираем «Управление внешними инструментами».

"Управление внешними инструментами"

«Управление внешними инструментами»

Как Вы уже поняли — здесь можно выполнить доработку функциональности текстового редактора. Создадим новый инструмент: «Компиляция и запуск», В качестве вывода используем нижнюю область редактора. Инструмент назначим для файлов C и C++. Назначим клавишу F5 (дело вкуса) на применение инструмента и собственно сам код инструмента в виде скрипта bash:

Разберёмся в том, что тут происходит:

#!/bin/bash — указание командного интерпретатора для выполнения скрипта.

gcc -o a.out $GEDIT_CURRENT_DOCUMENT_NAME — здесь мы запускаем компилятор, где в параметре -o указываем имя выходного файла. Пускай он будет таким же как и по-умолчанию.

$GEDIT_CURRENT_DOCUMENT_NAME — через эту переменную gedit передаёт имя файла.

Дальше Вы уже знаете — назначение атрибута «исполнения», запуск файла и потом:

rm ./a.out — удаление созданного исполнимого файла.

Попробуем инструмент в деле:

Теперь можно продолжать изучать пособие для разработчика/учебник/просто_хорошую_книгу по «Языку программирования Си» на практике.

Заключение

На самом деле в ОС Linux полно возможностей по доработке и использованию различного ПО. Само ПО является максимально гибким. Необязательно использовать предложенные мною средства, скорее методы, разработки.

В дальнейшем Вам обязательно понадобятся более серьёзные средства. А на первое время Вы можете дополнительно посмотреть другие редакторы, вплоть до больших и серьёзных сред разработки. Однако обязательно обратите внимание на редактор vim.

Как скомпилировать с в linux

В прошлой теме было рассмотрено создание первой программы на Windows. Теперь рассмотрим создание первой программы на Linux, в частности, в среде Ubuntu 16.04. На Linux также популярным компилятор для создания программ является g++. Поэтому в данном случае также будем использовать этот компилятор.

Как правило, многие дистрибутивы Linux, в том числе и Ubuntu, уже по умолчанию содержат установленный компилятор g++, который мы сразу же можем использовать. Но даже если вдруг он не установлен, то его можно доустановить в терминале через команду:

В остальном, если мы будем использовать для компиляции компилятор g++, все будет аналогично созданию программы на Windows.

Определим в файловой системе каталог для исходных файлов с кодом на С++ и создадим в нем новый файл hello.cpp со следующим кодом:

И это тот же код, что был в случае с Windows, потому что программы на С++ на уровне исходного кода в большей степени обладают переносимостью.

Для вывода строки на консоль необходимо подключить нужный функционал. Для этого в начале файла идет строка

Данная строка представляет директиву препроцессора, которая позволяет подключить библиотеку iostream. Эта библиотека нужна для вывода строки на консоль.

Далее идет определение функции main . Функция main должна присутствовать в любой программе на С++, с нее собственно и начинается выполнение приложения.

Функция main состоит из четырех элементов:

Тип возвращаемого значения . В данном случае это тип int . Этот тип указывает, что функция должна возвращать целое число.

Имя функции . В данном случае функция называется main.

Список параметров . После имени функции в скобках идет список параметров. Но в данном случае скобки пустые, то есть функция main не принимает параметров.

Тело функции . После списка параметров в фигурных скобках идет тело функции. Здесь и определяются собственно те действия, которые выполняет функция main.

В теле функции происходит вывод строки на консоль. Для обращения к консоли используется стандартный поток вывода std::cout . С помощью оператора << в этот поток (в данном случае фактически на консоль) передается строка символов, которую надо вывести на консоль, то есть «Hello World!». В конец строки добавлена специальная управляющая последовательность «\n», которая позволит после вывода текста перевести курсор на новую строку.

В функции осуществляем выход из функции с помощью оператора return . Так как функция должна возвращать целое число, то после return указывается число 0. Ноль используется в качестве индикатора успешного завершения программы.

После каждой инструкции в языке C++ ставятся точка с запятой.

Первая программа на C++ на Linux

Перейдем к терминалу и вначале с помощью команды cd перейдем к каталогу, где расположен файл с исходным кодом.

Сборка проекта на С++ в GNU/Linux

Язык С++ является компилируемым, то есть трансляция кода с языка высокого уровня на инструкции машинного кода происходит не в момент выполнения, а заранее — в процессе изготовления так называемого исполняемого файла (в ОС Windows такие файлы имеют расширение .exe , а в ОС GNU/Linux чаще всего не имеют расширения).

hello.cpp

Пример простой программы на С++, которая печатает «Привет, Мир!»:

Для вывода здесь используется стандартная библиотека iostream , поток вывода std::cout .

Исполняемые операторы в программах на С++ не могут быть сами по себе — они должны быть обязательно заключены в функции.

Функция main() — это главная функция, выполнение программы начинается с её вызова и заканчивается выходом из неё. Возвращаемое значение main() в случае успешных вычислений должно быть равно 0, что значит «ошибка номер ноль», то есть «нет ошибки». В противном процесс, вызвавший программу, может посчитать её выполнившейся с ошибкой.

Чтобы выполнить программу, нужно её сохранить в текстовом файле hello.cpp и скомпилировать следующей командой:

Опция -o сообщает компилятору, что итоговый исполняемый файл должен называться hello . g++ — это компилятор языка C++, входящий в состав проекта GCC (GNU Compiler Collection). g++ не является единственным компиляторм языка C++. Помимо него в ходе курса мы будет использовать компилятор clang , поскольку он обладает рядом преимуществ, из которых нас больше всего интересует одно — этот компилятор выдаёт более понятные сообщения об ошибках по сравнению с g++ .

Упражнение №1

Скомпилируйте и выполните данную программу.

Ввод и вывод на языке С++

В Python и в С ввод и вывод синтаксически оформлены как вызов функции, а в С++ — это операция над объектом специального типа — потоком.

Потоки определяются в библиотеке iostream, где определены операции ввода и вывода для каждого встроенного типа.

Вывод

Все идентификаторы стандартной библиотеки определены в пространстве имен std , что означает необходимость обращения к ним через квалификатор std:: .

Заметим, что в С++ мы не прописываем типы выводимых значений, компилятор неким (пока непонятным) способом разбирается в типе выводимого значения и выводит его соответствующим образом.

Вывод в один и тот же поток можно писать в одну строчку:

Для вывода в поток ошибок определён поток std::cerr .

Поток ввода с клавиатуры называется std::cin , а считывание из потока производится другой операцией — >> :

Тип считываемого значения определяется автоматически по типу переменной x .

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

Например для введенной строки «Иван Иванович Иванов»,

считает в name только первое слово «Иван».

Считать всю строку целиком можно с помощью функции getline() :

Считывать несколько значений можно и в одну строку:

Упражнение №2

Напишите программу, которая считает гипотенузу прямоугольного треугольника по двум катетам. Ввод и вывод стандартные.

Ввод Вывод
3 4 5

Сумма первых n натуральных чисел

Пример программы, которая подсчитывает сумму первых n натуральных чисел:

Как известно, если сложную задачу разбить на несколько простых подзадач, то её решение сильно упрощается. Поэтому не стоит писать весь код в одной функции main() . Лучше разбивать код на отдельные функции, каждая из которых решает свою несложную подзадачу, но делает это хорошо. Например, в предыдущем примере можно вынести функциональность подсчёта суммы первых n натуральных чисел в отдельную функцию:

Эмперическое правило: каждая функция не должна превышать по размеру 1 экран вашего монитора.

Этапы сборки: препроцессинг, компиляция, компоновка

Компиляция исходных текстов на Си в исполняемый файл происходит в три этапа.

Препроцессинг

Эту операцию осуществляет текстовый препроцессор.

Исходный текст частично обрабатывается — производятся:

  1. Замена комментариев пустыми строками
  2. Текстовое включение файлов — #include
  3. Макроподстановки — #define
  4. Обработка директив условной компиляции — #if , #ifdef , #elif , #else , #endif

Компиляция

Процесс компиляции состоит из следующих этапов:

  1. Лексический анализ. Последовательность символов исходного файла преобразуется в последовательность лексем.
  2. Синтаксический анализ. Последовательность лексем преобразуется в дерево разбора.
  3. Семантический анализ. Дерево разбора обрабатывается с целью установления его семантики (смысла) — например, привязка идентификаторов к их декларациям, типам, проверка совместимости, определение типов выражений и т. д.
  4. Оптимизация. Выполняется удаление излишних конструкций и упрощение кода с сохранением его смысла.
  5. Генерация кода. Из промежуточного представления порождается объектный код.

Результатом компиляции является объектный код.

Объектный код — это программа на языке машинных кодов с частичным сохранением символьной информации, необходимой в процессе сборки.

При отладочной сборке возможно сохранение большого количества символьной информации (идентификаторов переменных, функций, а также типов).

Компоновка

Компоновка также называется связывание или линковка. На этом этапе отдельные объектные файлы проекта соединяются в единый исполняемый файл.

На этом этапе возможны так называемые ошибки связывания: если функция была объявлена, но не определена, ошибка обнаружится только на этом этапе.

Упражнение №3

Выполните в консоли для ранее созданного файла hello.cpp последовательно операции препроцессинга, компиляции и компоновки:

  1. Препроцессинг:
  1. Компиляция:
  1. Компоновка:

Принцип раздельной компиляции

Компиляция — алгоритмически сложный процесс, для больших программных проектов требующий существенного времени и вычислительных возможностей ЭВМ. Благодаря наличию в процессе сборки программы этапа компоновки (связывания) возникает возможность раздельной компиляции.

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

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

Пример модульной программы с раздельной компиляцией на С++

Рассмотрим пример: есть желание вынести часть кода в отдельный файл — пользовательскую библиотеку.

program.cpp

Подключение пользовательской библиотеки в С++ на самом деле не так просто, как кажется.

Сама библиотека должна состоять из двух файлов: mylib.hpp и mylib.cpp :

mylib.hpp

mylib.cpp

Препроцессор С++, встречая #include «mylib.hpp» , полностью копирует содержимое указанного файла (как текст) вместо вызова директивы. Благодаря этому на этапе компиляции не возникает ошибок типа Unknown identifier при использовании функций из библиотеки.

Файл mylib.cpp компилируется отдельно.

А на этапе компоновки полученный файл mylib.o должен быть включен в исполняемый файл program .

Cреда разработки обычно скрывает весь этот процесс от программиста, но для корректного анализа ошибок сборки важно представлять себе, как это делается.

Упражнение №4

Давайте сделаем это руками:

Теперь, если изменения коснутся только mylib.cpp , то достаточно выполнить только команды 1 и 3. Если только program.cpp, то только команды 2 и 3. И только в случае, когда изменения коснутся интерфейса библиотеки, т.е. заголовочного файла mylib.hpp , придётся перекомпилировать оба объектных файла.

Утилита make и Makefile

Утилита make предназначена для автоматизации преобразования файлов из одной формы в другую. По отметкам времени каждого из имеющихся объектных файлов (при их наличии) она может определить, требуется ли их пересборка.

Правила преобразования задаются в скрипте с именем Makefile , который должен находиться в корне рабочей директории проекта. Сам скрипт состоит из набора правил, которые в свою очередь описываются:

  1. целями (то, что данное правило делает);
  2. реквизитами (то, что необходимо для выполнения правила и получения целей);
  3. командами (выполняющими данные преобразования).

В общем виде синтаксис Makefile можно представить так:

То есть, правило make это ответы на три вопроса:

Несложно заметить что процессы трансляции и компиляции очень красиво ложатся на эту схему:

Простейший Makefile

Для компиляции hello.cpp достаточно очень простого мэйкфайла:

Данный Makefile состоит из одного правила, которое в свою очередь состоит из цели — hello , реквизита — hello.cpp , и команды — gcc -o hello hello.cpp .

Теперь, для компиляции достаточно дать команду make в рабочем каталоге. По умолчанию make станет выполнять самое первое правило, если цель выполнения не была явно указана при вызове:

Makefile для модульной программы

Попробуйте собрать этот проект командой make или make hello . Теперь измените любой из файлов .cpp и соберите проект снова. Обратите внимание на то, что во время повторной компиляции будет транслироваться только измененный файл.

После запуска make попытается сразу получить цель program , но для ее создания необходимы файлы program.o и mylib.o , которых пока еще нет. Поэтому выполнение правила будет отложено и make станет искать правила, описывающие получение недостающих реквизитов. Как только все реквизиты будут получены, make`вернется к выполнению отложенной цели. Отсюда следует, что `make выполняет правила рекурсивно.

Фиктивные цели

На самом деле в качестве make целей могут выступать не только реальные файлы. Все, кому приходилось собирать программы из исходных кодов, должны быть знакомы с двумя стандартными в мире UNIX командами:

Командой make производят компиляцию программы, командой make install — установку. Такой подход весьма удобен, поскольку все необходимое для сборки и развертывания приложения в целевой системе включено в один файл (забудем о скрипте configure ). Обратите внимание на то, что в первом случае мы не указываем цель, а во втором целью является вовсе не создание файла install , а процесс установки приложения в систему. Проделывать такие фокусы нам позволяют так называемые фиктивные (phony) цели. Вот краткий список стандартных целей:

Для того чтобы make не искал файлы с такими именами, их следует определить в Makefile , при помощи директивы .PHONY . Далее показан пример Makefile с целями all , clean , install и uninstall :

Теперь мы можем собрать нашу программу, произвести ее инсталлцию/деинсталляцию, а так же очистить рабочий каталог, используя для этого стандартные make цели.

Обратите внимание на то, что в цели all не указаны команды; все что ей нужно — получить реквизит program . Зная о рекурсивной природе make, не сложно предположить, как будет работать этот скрипт. Также следует обратить особое внимание на то, что если файл program уже имеется (остался после предыдущей компиляции) и его реквизиты не были изменены, то команда make ничего не станет пересобирать. Это классические грабли make. Так, например, изменив заголовочный файл, случайно не включенный в список реквизитов (а надо включать!), можно получить долгие часы головной боли. Поэтому, чтобы гарантированно полностью пересобрать проект, нужно предварительно очистить рабочий каталог:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *