Как скомпилировать несколько файлов gcc

Обновлено: 02.07.2024

Под Unix существует множество компиляторов и интерпретаторов, но здесь мы будем обсуждать лишь gcc как средство компиляции C-кода, и коротко коснемся использования perl в качестве примера интерпретатора.

GCC — это набор компиляторов, обладающий очень почтенным возрастом и распространяемый под лицензией GPL. Он известен как инструмент работы с программами на C и C++. Свободная лицензия и повсеместная распространенность на Unix-подобных системах стали залогом его неизменной популярности, хотя есть и более современные альтернативы, использующие инфраструктуру LLVM, такие как Clang.

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

Здесь я не буду обсуждать использование make-файлов, хотя они наверняка понадобятся для любого проекта сложнее, чем в один файл. Make-файлов я коснусь в следующей статье о средствах автоматизации сборки.

Компиляция и сборка объектного кода

Объектный код компилируется вот такой командой:

Как вариант, можно попросить gcc сразу показать итоговый ассемблерный код при помощи параметра -S:

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

Препроцессор

Препроцессор C (cpp) обычно используется для подключения заголовочных файлов и определения макросов. Это стандартная часть процесса компиляции gcc, но можно просмотреть генерируемый им код, вызвав cpp напрямую:

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

Связывание объектов

Один или несколько объектных файлов могут быть связаны в соответствующий исполняемый файл:

В этом примере gcc просто вызывает ld, линковщик GNU. Команда создаст исполняемый файл по имени example .

Компиляция, сборка и связывание

Все вышеперечисленное может быть выполнено в один шаг при помощи команды:

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

Включение внешних файлов и связывание

Файлы C и заголовочные файлы могу быть явно включены в компиляцию при помощи параметра -l:

Аналогично, если код нужно динамически связать с уже скомпилированной системной библиотекой, доступной в одной из системных папок ( /lib или /usr/lib ), например, ncurses, этого можно добиться использованием ключа -l:

Если в процессе компиляции внешних связей много, имеет смысл внести их в переменные окружения:

Кстати, Makefile затем и создан, чтобы избавить нас от беспокойства о таких мелочах.

План компиляции

Чтобы посмотреть подробности внутренней кухни gcc, можно добавить ключ -v, и план компиляции будет выведен в стандартный поток вывода ошибок:

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

Существует возможность добавить ключи -Wall и/или -pedantic, чтобы gcc предупреждал нас о случаях, которые не обязательно являются ошибками, но могут ими быть:

Удобно включать такие опции в Makefile или в определении makeprg для Vim, так как они отлично сочетаются с окном quickfix, и помогают писать читабельный, совместимый и безошибочный код.

Профилирование процесса компиляции

Вы можете включить опцию -time, чтобы gcc отображал в тексте вывода время выполения каждого из шагов:

Оптимизация

Gcc имеет ключи оптимизации, указав которые можно попросить его создавать более эффективный объектный код и связанные бинарники за счет увеличения времени компиляции. Я считаю -O2 золотой серединой для выпускаемого кода:

Подобно любой команде Bash, все это можно вызывать прямо из Vim:

Интерпретаторы

Подход к интерпретируемому коду в Unix-системах иной. В своих примерах я буду использовать Perl, но те же принципы применимы для кода, например, на Python или Ruby.

Inline-код

Можно строку Perl-кода прямо на исполнение интерпретатору любым из перечисленных ниже способов Первый, наверное, самый простой и общеупотребительный способ работы с Perl; второй использует синтаксис heredoc, а третий — это классический конвейер Unix.

Конечно, в будничной жизни мы храним код в файле, который можно вызвать прямо вот так:

Можно проверить синтаксис кода без его выполнения с помощью ключа -c:

Порой хочется использовать скрипт подобно любому исполняемому бинарнику, не беспокоясь о том, что он из себя представляет. Для этого в скрипт добавляют первой строкой так называемый "shebang", указывающий путь к интерпретатору, которому следует передать на исполнение данный файл.

Скрипту после этого можно ставить атрибут исполняемого файла вызовом chmod. Также хорошим тоном считается переименовать файл, убрав расширения, поскольку он теперь считается почти настоящим исполняемым файлом:

Затем файл можно вызывать напрямую, без указания интерпретатора:

Вся эта кухня так здорово работает, что многие стандартные утилиты Linux-систем, такие как adduser, в действительности являются скриптами на Perl или Python.

В следующей публикации я расскажу о методах работы с make для сборки проектов, сравнимых с привычными IDE.

Это далеко не все пробемы, которые могут возникнуть при наличии программы "монстра". Поэтому при разработке программ рекомендуется их разбивать на куски, которые функционально ограничены и закончены. В этом значительно помогает сам язык C++, предоставляя свой богатый синтаксис.

Для того, чтобы вынести функцию или переменную в отдельный файл надо перед ней поставить зарезервированное слово extern. Давайте для примера создадим программу из нескольких файлов. Сначала создадим главную программу, в которой будут две внешние процедуры. Назовем этот файл main.c:

Теперь создаем два файла, каждый из которых будет содержать полное определение внешней функции из главной программы. Файлы назовем f1.c и f2.c:

После этого процесс компиляции программы с помощью gcc будет выглядеть несколько иначе от описанного в "Шаг 1 - Компиляция программ на языке C/C++".

Компилировать можно все файлы одновременно одной командой, перечисляя составные файлы через пробел после ключа -c:

Или каждый файл в отдельности:

В результате работы компилятора мы получим три отдельных объектных файла:

Чтобы их собрать в один файл с помощью gcc надо использовать ключ -o, при этом линкер соберет все файлы в один:

В результате вызова полученной программы rezult командой:

На экране появится результат работы:

Теперь, если мы изменим какую-то из процедур, например f1():

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

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

Запуск gcc позволяет обработать файл с исходным кодом препроцессором и далее скомпилировать его. Однако при этом сам инструмент gcc не компилирует файл исходного кода в конечный исполняемый файл. Он компилирует его в объектный файл, после чего вызывает так называемый линковщик, или компоновщик. Но зачем надо сначала получать объектный файл, а потом из него уже исполняемый? Для программ, состоящих из одного файла, такой необходимости нет. Хотя при желании здесь также можно отказаться от компоновки, если выполнить команду gcc с ключом -c:

В результате получится файл с расширением *.o. Чтобы получить из объектного файла исполняемый, надо использовать ключ -o:

Для программ, состоящих из нескольких файлов исходного кода, получение объектных файлов является необходимым. Именно из них потом компонуется единственный исполняемый файл.

Компиляция программы, состоящей из нескольких файлов исходного кода

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

В теле функции main() заполняется массив, состоящий из строк, а также массив указателей на эти строки. Далее в функции l2r() и r2l() передаются ссылки на первый элемент массива указателей и значение символической константы N. Эти функции осуществляют вывод элементов массива строк с отступами.

Чтобы получить исполняемый файл этой программы, надо сначала получить объектные файлы из исходных:

Тоже самое можно сделать за один вызов gcc:

Или даже вот так, если в каталоге находятся только файлы текущего проекта:

В любом случае в каталоге появятся два объектных файла: superprint.o и main.o. Далее их можно скомпилировать в один исполняемый файл так:

Обратите внимание на то, что в данном случае обязательно требуется указывать имя исполняемого файла. Такой вариант недопустим:

Если теперь запустить файл myprint, то программа будет ожидать ввода пяти слов, после чего выведет их на экран два раза по-разному (с помощью функций l2r() и r2l() ):

Задумаемся, каким образом в представленной выше программе функция main() "узнает" о существовании функций l2r() и r2l() . Ведь в исходном коде файла main.c нигде не указано, что мы подключаем файл superprint.c, содержащий эти функции. Действительно, если попытаться получить из main.c отдельный исполняемый файл, т.е. скомпилировать программу без superprint.c:

, то ничего не получиться. Компилятор сообщит об ошибке вызова неопределенных идентификаторов. Получить из файла superprint.c отдельный исполняемый файл вообще невозможно, т.к. там отсутствует функция main() . А вот получить из этих файлов отдельные объектные файлы можно. Представим, что одни объектные файлы как бы "выставляют наружу" имена определенных в них функций и глобальных переменных, а другие - вызовы этих имен из тел других функций. Дальше объектные файлы "ожидают", что имена будут связаны с их вызовами. Связывание происходит при компиляции исполняемого файла из объектных.

Создание заголовочных файлов

Продолжим разбирать приведенную выше программу. Что будет, если в функции main() осуществить неправильный вызов функций l2r() и r2l() ? Например, указать неверное количество параметров. В таком случае создание объектных файлов пройдет без ошибок, и скорее всего удастся получить исполняемый файл; но вот работать программа будет неправильно. Такое возможно потому, что ничего не контролирует соответствие вызовов прототипам (объявлениям) функций.

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

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

А теперь представим, что программа у нас несколько больше и содержит десяток файлов исходного кода. Файл aa.c требует функций из файла bb.c, dd.c, ee.c. В свою очередь dd.c вызывает функции из ee.c и ff.c, а эти два последних файла активно пользуются неким файлом stars.c и одной из функций в bb.c. Программист замучится сверять, что чего вызывает откуда и куда, где и какие объявления надо прописывать. Поэтому все прототипы (объявления) функций проекта, а также совместно используемые символические константы и макросы выносят в отдельный файл, который подключают к каждому файлу исходного кода. Такие файлы называются заголовочными; с ними мы уже не раз встречались. В отличие от заголовочных файлов стандартной библиотеки, заголовочные файлы, которые относятся только к вашему проекту, при подключении к файлу исходного кода заключаются в кавычки, а не скобки. Об этом упоминалось в предыдущем уроке.

Итак, более грамотно будет не добавлять объявления функций в файл main.c, а создать заголовочный файл, например, myprint.h и поместить туда прототипы функций l2r() и r2l() . А в файле main.c следует прописать директиву препроцессора:

В принципе смысла подключать myprint.h к файлу superprint.c в данном случае нет, т.к. последний не использует никаких сторонних функций, кроме стандартной библиотеки. Но если планируется расширять программу и есть вероятность, что в файле superprint.c будут вызываться сторонние для него функции, то будет надежней сразу подключить заголовочный файл.

Обратим внимание еще на один момент. Стоит ли в описанном в этом уроке примере выносить константу N в заголовочный файл? Здесь нельзя дать однозначный ответ. Если ее туда вынести, то она станет доступна в обоих файлах, и поэтому можно изменить прототипы функций так, чтобы они принимали только один параметр (указатель), а значение N будет известно функциям их заголовочного файла. Однако стоит ли так делать? В функции r2l() второй параметр изменяется в процессе ее выполнения, что делать с константой будет невозможно. Придется переписывать тело функции. Кроме того, вдруг в последствии нам захочется использовать файл superprint.c в другом проекте, где будут свои порядки, и константы N в заголовочном файле не найдется.

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

Особенности использования глобальных переменных

Помните, если можно отказаться от использования глобальных переменных, то лучше это сделать. Желательно стремиться к тому, чтобы любой файл проекта, скажем так, "не лез к соседу за данными, а сосед не разбрасывал эти данные в виде глобальных переменных". Обмен данными между функциями должен осуществлять за счет передачи данных в качестве параметров и возврата значений с помощью оператора return . (Массивов это не касается.)

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

Начало работы с многофайловой компиляцией Linux и make-файлом

Каталог статей


В процессе программирования для нас невозможно поместить все в файл c, что значительно снизит нашу эффективность.Мы можем написать свои собственные файлы c в соответствии с различными функциями и, наконец, вызвать основную программу. Когда я впервые познакомился с vim, я знал только, что gcc можно использовать для компиляции и генерации исполняемых программ.Я всегда думал, что gcc является компилятором, но это не так.


GCC(Коллекция компиляторов GNU, Коллекция компиляторов GNU) - переводчик языков программирования, разработанный GNU. Набор компиляторов GNU включает в себя внешние интерфейсы языков C, C ++, Objective-C, Fortran, Java, Ada и Go, а также библиотеки для этих языков (например, libstdc ++, libgcj и т. Д.).
Хотя мы называем GCC компилятором языка C, процесс использования gcc для создания исполняемого файла из файла исходного кода языка C - это не просто процесс компиляции, а четыре взаимных Связанные шаги: предварительная обработка (также называемая предварительной обработкой, предварительной обработкой), компиляция, сборка и компоновка.

1. Предварительная обработка

2. Скомпилировать

Составление (составление) - это прохождение лексического и грамматического анализа. Убедившись, что все инструкции соответствуют грамматическим правилам, Переведите его в эквивалентное промежуточное представление кода или ассемблерный код. Оптимизационная обработка - относительно сложная технология в системе компиляции. Проблемы, связанные с этим, связаны не только с самой технологией компиляции, но также имеют большое отношение к аппаратной среде машины. Часть оптимизации - это оптимизация промежуточного кода, эта оптимизация не зависит от конкретного компьютера. Другая оптимизация в основном направлена ​​на генерацию целевого кода. Для первой оптимизации основная работа заключается в удалении общих выражений, оптимизации цикла (аутсорсинг кода, ослабление силы, изменение условий управления циклом, слияние известных величин и т. Д.), Распространение копий, удаление бесполезных назначений и т. Д. Последний тип оптимизации тесно связан со структурой аппаратного обеспечения машины.Самое важное соображение состоит в том, как в полной мере использовать значения переменных, хранящихся в аппаратных регистрах машины, для уменьшения количества обращений к памяти. Кроме того, как выполнять инструкции в соответствии с характеристиками аппаратного обеспечения машины (например, конвейер
line, RISC, CISC и т. д.), а также некоторые корректировки инструкций, чтобы сделать целевой код короче и повысить эффективность выполнения, что также является важной темой исследования.
Обычно используйте команду gcc -S hello.i для компиляции и создания файлов сборки, или вы можете выполнить компиляцию с помощью указанного компилятора. Когда вы используете компилятор ПК для компиляции, он создает файлы сборки x86. Компиляция компилятора будет генерировать файлы сборки ARM. Файлы сборки каждой архитектуры могут использоваться только в этой архитектуре. Мы можем выбирать разные компиляторы в соответствии с нашей архитектурой. Этопереносимость. Процесс использования кросс-компилятора ARM на ПК для создания исполняемых программ на платформе ARM называетсяКросс-компиляция。

3. Сборка

Процесс сборки (сборки) фактически относится к Процесс перевода кода на ассемблере в целевые машинные инструкции. Для каждой исходной программы на языке C, обработанной системой перевода, соответствующий целевой файл будет окончательно обработан посредством этого процесса. В целевом файле хранится машинный код целевой программы, эквивалентной исходной программе. Целевой файл состоит из сегментов. Обычно объектный файл состоит как минимум из двух разделов:
1. Сегмент кода (текстовый сегмент): этот сегмент содержит в основном инструкции программы. Этот раздел обычно доступен для чтения и выполнения, но не для записи;
2. Сегмент данных: в основном хранит различные константы, глобальные переменные и статические данные, используемые в программе. Сегменты общих данных доступны для чтения, записи и выполнения;
Мы можем создать файлы сборки с помощью команды gcc -c hello.s.

4. Ссылка

Объектный файл, созданный ассемблером, не может быть запущен сразу, и может быть много нерешенных проблем. Например, функция в исходном файле может ссылаться на символ, определенный в другом исходном файле (например, на переменную или вызов функции и т. Д.); Функция в файле библиотеки может быть вызвана в программе и так далее. Все эти проблемы могут быть решены только обработкой программы ссылки. Основная задача компоновщика - соединить связанные объектные файлы друг с другом, то есть соединить символы, на которые есть ссылки в одном файле, с определением символа в другом файле, чтобы все эти объектные файлы стали такими, которые могут быть установлены операционной системой. Введите единое целое исполнения, то есть исполняемую программу. В соответствии с методом связывания библиотечной функции, указанным разработчиком, обработку ссылок можно разделить на два типа:
1. Статическая ссылка: все функции компилируются в программу во время компиляции.
2. Динамическая ссылка: операционная система помогает переносить динамическую библиотеку в область памяти при запуске программы.
Для вызовов функций в исполняемых файлах можно использовать динамическое связывание или статическое связывание соответственно. Использование динамического связывания может сделать конечный исполняемый файл короче и сэкономить некоторую память, когда общий объект используется несколькими процессами, потому что в памяти должна храниться только одна копия кода общего объекта. Но дело не в том, что использование динамического связывания обязательно лучше статического связывания. В некоторых случаях динамическое связывание может привести к некоторому снижению производительности.

5. Динамические и статические библиотеки

Как под Windows, так и под Linux имеется большое количество библиотек. Что такое библиотеки? По сути, библиотека - это двоичная форма исполняемого кода, который может быть загружен в память и выполнен операционной системой. Обычно мы пишем некоторые функции общего назначения в виде библиотек функций, поэтому библиотека написана другим, существующим, зрелым и повторно используемым кодом. Вы можете использовать ее, но вы должны соблюдать лицензионное соглашение. В нашем реальном процессе разработки невозможно написать каждый фрагмент кода с нуля. Когда у нас есть библиотека, мы можем напрямую связать нужные нам файлы с нашей программой. Это может сэкономить нам много времени и повысить эффективность разработки. В Linux есть два типа библиотек: статические библиотеки и динамические библиотеки. Сходство между этими двумя библиотеками заключается в том, что обе библиотеки создаются из файлов .o, Давайте обсудим их различия ниже:
1. Статическая библиотека: файл статической библиотеки назван в честь «libxxx.a», «xxx» - это имя библиотеки, а «lib» добавляется впереди, чтобы указать, что это библиотека, как в Windows, так и в Linux. Суффикс «.a» указывает на статическую библиотеку. Код статической библиотеки загружается в программу во время процесса компиляции, что приводит к большой файловой памяти после компиляции.Метод связывания статической библиотеки заключается в том, что исполняемый файл, созданный после компиляции, не нуждается в поддержке внешней библиотеки функций. Если статическая библиотека обновляется, программу необходимо повторно перевести.
2. Динамическая библиотека: имя динамической библиотеки похоже на статическую библиотеку. Оно начинается с «lib», что указывает на то, что это библиотека. Суффикс-имя в Linux - «.so (общий объект)», то есть «libXXX». .так". В Windows используется суффикс «.dll (библиотека динамической компоновки)», то есть «libXXX.dll». При компиляции динамическая библиотека не компилируется в целевой код. Вместо этого соответствующая функция в библиотеке функций вызывается, когда ваша программа выполняется для соответствующей функции. Недостатком этого является то, что функция библиотеки не интегрирована в программу. , Значит, в операционной среде программы должна быть соответствующая библиотека. Преимущество состоит в том, что изменение динамической библиотеки не влияет на вашу программу, поэтому обновление динамической библиотеки более удобно.
Между ними также есть очевидные различия: когда одна и та же программа использует статические библиотеки и динамические библиотеки для создания двух исполняемых файлов, файлы, созданные статическим связыванием Занятая память намного больше, чем файлы, созданные при динамической компоновке. Это связано с тем, что статическая компоновка компилирует все функции в программу во время компиляции, в то время как динамическая компоновка использует операционную систему, чтобы помочь перенести динамическую библиотеку в пространство памяти во время работы программы. Кроме того, если динамическая библиотека и статическая библиотека существуют одновременно, компоновщик предпочтительно использует динамическую библиотеку.

6. Общие параметры компиляции gcc

Параметры Описание
-E Только предварительная обработка, а не компиляция
-S Только компилировать, а не собирать
-c Только компилировать, собирать, а не связывать
-g Скомпилированный исполняемый файл содержит отладочную информацию gdb, которая может быть отлажена с помощью gdb.
-o Укажите имя файла скомпилированного исполняемого файла
-l Укажите каталог поиска для включаемых файлов
-L Укажите путь к библиотеке (динамической или статической), необходимой для компоновки
-ansi Стандарт ANSI
-std=c99 Стандарт C99
-Werror Не различать предупреждения и ошибки и прекращать компиляцию при обнаружении любого предупреждения
-Wall Включите большинство предупреждений
–static Статическая компиляция (по умолчанию - динамическая компиляция)
-static Статическая ссылка (по умолчанию статическая ссылка)

1. Запись в несколько файлов

Если мы хотим скомпилировать несколько файлов, нам сначала нужно записать файл заголовка и файл .c функции-функции, а затем вызвать функцию-функцию в основной функции. Вот как это записать. Взгляните на пример.

①Функция функция .c файл

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

②Файл заголовка функции

③Записан основной функциональный файл

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

2. Скомпилируйте несколько файлов отдельно

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


3. Компиляция сценария оболочки

Компиляция каждого файла по отдельности - слишком большая проблема. Нам нужен одноэтапный метод компиляции. Здесь мы можем использовать сценарии оболочки.


4. makefile

Что такое make-файл? Может быть, многие программисты Windows этого не знают, потому что эти Windows IDE делают эту работу за вас. Чтобы компилировать программное обеспечение под Unix, вы должны сами написать make-файлы, и то, можете ли вы писать make-файлы, показывает с одной стороны, есть ли у человека возможность выполнять крупномасштабные проекты. Потому что make-файл связан с правилами компиляции всего проекта. Исходные файлы в проекте не учитываются. Они размещаются в нескольких каталогах в соответствии с типом, функцией и модулем. Makefile определяет ряд правил, чтобы указать, какие файлы нужно скомпилировать в первую очередь, какие файлы нужно скомпилировать позже, а какие файлы нужно перестроить. Компилировать и даже выполнять более сложные функциональные операции, потому что make-файл похож на сценарий оболочки, в котором также могут выполняться команды операционной системы. Преимущество make-файла заключается в «автоматической компиляции». После его написания требуется только одна команда make, и весь проект полностью автоматически компилируется, что значительно повышает эффективность разработки программного обеспечения. Make - это командный инструмент, который объясняет инструкции в make-файле. Вообще говоря, в большинстве IDE есть эта команда, например make в Delphi, nmake в Visual C ++ и make в GNU под Linux. Видно, что makefile превратился в метод компиляции в инженерии.

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



С помощью make-файла наша рабочая нагрузка может быть значительно уменьшена. Если в приведенном выше содержании есть какие-либо ошибки, пожалуйста, исправьте меня!


После установки необходимых инструментов разработки проверьте их с помощью одной из следующих команд:

Эти команды отобразят путь установки и версию компилятора gcc.


Компиляция и запуск программ на C, C ++ на Linux

Во-первых, давайте посмотрим, как скомпилировать и запустить простую программу, написанную на языке Си.

Напишите свой код / программу в вашем любимом редакторе CLI / GUI.

Я собираюсь написать свою программу на C, используя редактор nano.

Примечание: вам нужно использовать расширение .c для программ на C или .cpp для программ на C ++.

Нажмите Ctrl + O и Ctrl + X, чтобы сохранить и выйти из файла. Если в вашем коде / программе есть какие-либо синтаксические или семантические ошибки, они будут отображены.

Если ошибки нет, компилятор успешно сгенерирует исполняемый файл с именем itisgood в текущем рабочем каталоге.

Наконец, выполните программу, используя команду:

Вы увидите вывод, как показано ниже:

Чтобы скомпилировать несколько исходных файлов (например, source1 и source2) в исполняемый файл, запустите:

Чтобы разрешить предупреждения, отладьте символы в выводе:

Чтобы скомпилировать исходный код в инструкции ассемблера:

Чтобы скомпилировать исходный код без ссылок:

Приведенная выше команда создаст исполняемый файл с именем source.o.

Если ваша программа содержит математические функции:

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

Компиляция и запуск программ C ++

Напишите свою программу на C ++ в любом редакторе по вашему выбору и сохраните ее с расширением .cpp.

Вот простая программа на C ++.

Чтобы скомпилировать эту программу C ++ в Linux, просто запустите:

Если ошибок не было, вы можете запустить эту программу C ++ под Linux, используя команду:

Вы увидите вывод, как показано ниже:

В качестве альтернативы, мы можем скомпилировать вышеуказанную программу на C ++, используя команду «make», как показано ниже.

Я не использовал расширение .cpp в приведенной выше команде для компиляции программы.

Нет необходимости использовать расширение для компиляции программ на C ++ с помощью команды make.

Читайте также: