Введение
В данном практическом руководстве подробно разбирается весь жизненный цикл сборки исполняемых бинарных файлов на языке C с применением штатного интерфейса компилятора cc в Linux. Шаг за шагом мы развернем инструментарий разработчика, скомпилируем простую монолитную программу, разберем ключевые флаги предупреждений и оптимизации (-o, -Wall, -O2), а также освоим модульную раздельную сборку проекта из нескольких исходных файлов.
Подготовка среды разработки и проверка доступности cc
Первым делом необходимо снабдить систему Ubuntu базовым комплектом утилит, включающим компилятор, компоновщик и заголовочные файлы стандартной библиотеки. Для этого выполним синхронизацию репозиториев и инсталляцию метапакета build-essential:

После завершения установки выясним, по какому системному пути зарегистрирован используемый по умолчанию компилятор cc:

Команда cc транслирует исходный код C в машинные инструкции и формирует готовый бинарник. Чтобы узнать сборку и версию установленного компилятора, запустим утилиту с флагом --version:
⚙️ [Ключевые флаги компилятора]
-o : задает произвольное имя результирующего исполняемого файла.-c : компилирует исходный код в объектный модуль (.o), минуя стадию компоновки.-Wall : выводит подробный список предупреждений обо всех потенциальных проблемах в коде.-g : внедряет отладочные символы для анализа программы через отладчики вроде gdb.-O2 : включает оптимизацию среднего уровня для повышения производительности исполняемого кода.

Создание первого исходника и базовый запуск компилятора
Организуем рабочее пространство: создадим изолированную папку для учебных программ и сразу перейдем в нее:

Сгенерируем простейший исходный файл hello.c, выводящий строку приветствия в консоль:

Скомпилируем созданный код базовым вызовом cc hello.c. Если не передавать параметры вывода, утилита по умолчанию создаст в текущей директории исполняемый файл a.out:

Убедимся в корректности полученного бинарника, запустив его на исполнение через ./a.out:

Настройка имени бинарника (-o) и оптимизация сборки (-Wall, -O2)
Создадим файл calc.c, в котором будет производиться простая математическая операция:

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

Проверим атрибуты созданного исполняемого файла с помощью команды ls -l calc_app. В выводе четко видны установленные права на запуск (x) и объем программы:

Протестируем работу готового приложения:

Раздельная компиляция объектных модулей (-c) и компоновка
Масштабные проекты в Linux принято разделять на независимые модули. Сначала создадим заголовочный файл message.h с объявлением внешней функции:

Реализуем объявленную функцию в отдельном исходном файле message.c:

Напишем главный файл main.c, служащий точкой входа и вызывающий внешнюю процедуру:

Выполним раздельную трансляцию исходных текстов без объединения в готовый исполняемый файл. Для этого воспользуемся опцией -c:

Убедимся, что в каталоге сформировались скомпилированные объектные модули message.o и main.o:

Слинкуем полученные объектные файлы воедино, создав финальное приложение modular_app:

Запустим собранную программу и проверим успешность межмодульного взаимодействия:

Мы разобрали весь практический фундамент работы с компилятором cc в Ubuntu — от первоначальной настройки системы до сборки распределенного проекта из объектных файлов. Применяйте рассмотренные опции для создания надежных и быстрых программ на C в среде Linux.