Мастер-класс программирование на си под Linux. Изучаем основное API

Для Symbian 12.06.2019
Для Symbian

Стало ясно, что тема очень актуальная. Были учтены некоторые ошибки и вопросы, в результате было принято решение проведения второго мастер-класса. Дополненного и исправленного!

Мастер-класс программирование на си под Linux. Изучаем основное API.

Данный мастер-класс предназначен для людей, которые хотят изучить API *nix подобных ОС, в частности под Linux. Здесь будут рассмотрены особенности разработки под ОС Linux, которые включают в себя:


  • Ознакомление с процессом сборки ПО и специфики компилятора C из состава GCC

  • Разработка и использование разделяемых библиотек

  • Отладка программ

  • Изучение механизмов низкоуровнего файлового ввода-вывода

  • Изучение механизмов обеспечения многозадачности и межпроцессного взаимодействия

  • Применение файловых и сетевых сокетов

  • Изучение и применение механизма сигналов

  • Изучение процессов, потоков их различие, использование многопоточности, изучение механизмов синхронизации потоков и их проблем

  • Создание демонов, изучение различия между демонами и прикладным ПО

  • Изучение особенностей консольного ввода-вывода

  • Применение отображаемых в память файлов и их использование

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

Требования к участникам мастер-класса: Знание языка си, на уровне книги Б.В. Керниган,Д.М. Ричи "ЯЗЫК С".

Стоимость данного мастер-класса будет составлять 6 000 рублей.

Место проведения - город Москва, в помещении Хакспейса Нейрон.
Даты проведения: Ориентировочно 4 июля (понедельник), по 7 июля (четверг) с 10 до 17 с перерывом на обед и перерывами на чай/кофе.

Онлайн трансляции не планируется.
Количество человек в группе: 8-10.

Запись ведётся по электронной почте [email protected] либо в комментариях к этому посту. Для записи необходимо ваше Ф.И.О. (полностью) и контактные данные (номер телефона и почта). Желательно описать цели посещения этого мастер-класса, уровень подготовки и род занятий.

Подробная программа курса:

Модуль 1. Введение


  • Ознакомление со спецификой сборки ПО в GNU/Linux

  • Ознакомление с консольными текстовыми редакторами (vi,nano,mcedit)

  • Работа с отладчиком gdb

  • Ручная и автоматическая сборка ПО (Makefile)

  • Модель Клиент-Интерфейс-Сервер (КИС)

  • Статическая сборка библиотек

  • Совместно используемые библиотеки

  • Работа с переменными окружения

Модуль 2. Низкоуровневый ввод-вывод и файловые операции

  • Обзор механизмов ввода-вывода в Linux (Ubuntu)

  • Файловые дескрипторы

  • Системные вызовы: open, close, write, read и lseek

  • Типы файлов

  • Индексные дескрипторы и жесткие ссылки

  • Права доступа к файлу

  • Файловая система proc

  • Два способа прочесть содержимое директории

  • Разреженные файлы и специфика их применения

  • Блокировка областей файла

Модуль 3. Межпроцессное взаимодействие

  • Механизмы межпроцессного взаимодействия Linux (Ubuntu)

  • Неименованные каналы (pipes)

  • Именованные каналы (named pipes)

  • Сообщения (message queue)

  • Разделяемая память (shared memory)

  • Семафоры (semaphores)

Модуль 4. Сокеты

  • Сокеты в файловом пространстве имен (UNIX-сокеты)

  • Парные сокеты (pair sockets)

  • Сетевые сокеты (sockets)

Модуль 5. Сигналы

  • Знакомство с сигналами (signals)

  • Отличие сигналов от других механизмов межпроцессного взаимодействия

  • Специфика обработки сигналов (signal handling)

  • Модуль 6. Процессы

  • Клонирование процессов — fork()

  • Замена исполняемого процесса — exec()

  • Зомби (zombies) — причины возникновения и способы их устранения

Модуль 7. Потоки

  • Потоки и процессы

  • Специфика построения многопоточных приложений (multithreading)

  • Досрочное завершение потока

Модуль 8. Потоки (продолжение)

  • Создание обработчика завершения потока

  • Средства синхронизации потоков (synchronize primitives)

  • Атрибуты потоков

Модуль 9. Демоны (службы)

  • Отличие демона от консольной утилиты

  • Специфика разработки демонов (daemons)

  • Создание демона использующего сетевые сокеты

Модуль 10. Консольный ввод-вывод

  • Специфика разработки консольных приложений

  • Предотвращение перенаправления вывода

  • Управление терминалом

  • Сокрытие пароля пользователя при аутентификации

  • Управление терминалом с помощью ESC-последовательностей

Модуль 11. Отображаемая память

  • Отображение обычного файла

  • Совместный доступ к файлу

  • Частные отображения

  • Другие применения mmap

Модуль 12. Домашнее задание

  • Специфика разработки 64-битных приложений

  • Использование библиотеки ncurses

Ведущий курса: Долин Сергей. Электронщик, разработчик ПО linux (прикладное, тестового ПО для железа, драйвера). Разработчик ПО для встраиваемых систем. Программист linux с 2011 года. Работал в ОАО "НИЦЭВТ", АО «Концерн «Системпром», ООО "ПРОСОФТ" (в дочерней компании "Доламант").

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

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

В этой статье мы рассмотрим, как выполняется компиляция программ Linux, как происходит процесс компиляции, а также рассмотрим насколько гибко вы сможете все настроить.

Мы будем компилировать программы, написанные на Си или С++, так как это наиболее используемый язык для программ, которые требуют компиляции. Мы уже немного рассматривали эту тему в статье установка из tar.gz в Linux, но та статья ориентирована больше на новичков, которым нужно не столько разобраться, сколько получить готовую программу.

В этой же статье тема рассмотрена более детально. Как вы понимаете, для превращения исходного кода в команды процессора нужно специальное программное обеспечение. Мы будем использовать компилятор GCC. Для установки его и всех необходимых инструментов в Ubuntu выполните:

sudo apt install build-essential manpages-dev git automake autoconf

Затем вы можете проверить правильность установки и версию компилятора:

Но перед тем как переходить к самой компиляции программ рассмотрим более подробно составляющие этого процесса.

Как выполняется компиляция?

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

На первом этапе, еще до того как начнется непосредственно компиляция, специальный инструмент должен проверить совместима ли ваша система с программой, а также есть ли все необходимые библиотеки. Если чего-либо нет, то будет выдана ошибка и вам придется устранить проблему.

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

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

Компиляция программ Linux

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

Получение исходников

Первое что нам понадобиться, это исходные коды программы, которые можно взять на GitHub. Вы можете найти исходники для большинства программ Linux на GitHub. Кроме того, там же есть инструкции по сборке:

Давайте загрузим сами исходники нашей программы с помощью утилиты git:

git clone https://github.com/vim/vim

Также, можно было скачать архив на сайте, и затем распаковать его в нужную папку, но так будет удобнее. Утилита создаст папку с именем программы, нам нужно сделать ее рабочей:

Настройка configure

Дальше нам нужно запустить скрипт, который проверит нашу программу на совместимость с системой и настроит параметры компиляции. Он называется configure и поставляется разработчиками программы вместе с исходниками. Весь процесс компиляции описан в файле Makefile, его будет создавать эта утилита.

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

./bootstrap
$ ./autogen.sh

Также для создания этого скрипта можно воспользоваться утилитой automake:

aclocal
$ autoheader
$ automake --gnu --add-missing --copy --foreign
$ autoconf -f -Wall

Утилита automake и другие из ее набора генерируют необходимые файлы на основе файла Mackefile.am. Этот файл обязательно есть в большинстве проектов.

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

./configure --help

Рассмотрим наиболее часто используемые, стандартные для всех программ опции:

  • --prefix=PREFIX - папка для установки программы, вместо /, например, может быть /usr/local/, тогда все файлы будут распространены не по основной файловой системе, а в /usr/local;
  • --bindir=DIR - папка для размещения исполняемых файлов, должна находится в PREFIX;
  • --libdir=DIR - папка для размещения и поиска библиотек по умолчанию, тоже в PREFIX;
  • --includedir=DIR - папка для размещения man страниц;
  • --disable-возможность - отключить указанную возможность;
  • --enable-возможность - включить возможность;
  • --with-библиотека - подобно enable активирует указанную библиотеку или заголовочный файл;
  • --without-библиотека - подобное disable отключает использование библиотеки.

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

Во время настройки утилита будет проверять, есть ли все необходимые библиотеки в системе, и если нет, вам придется их установить или отключить эту функцию, если это возможно. Например, может возникнуть такая ошибка: no terminal library found checking for tgetent()... configure: error: NOT FOUND!

В таком случае нам необходимо установить требуемую библиотеку. Например, программа предлагает ncurses, поэтому ставим:

sudo apt install libncurces-dev

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

Сборка программы

Когда настройка будет завершена и Makefile будет готов, вы сможете перейти непосредственно к сборке программы. На этом этапе выполняется непосредственно преобразование исходного кода в машинный. Утилита make на основе Makefile сделает все необходимые действия:

После этого программа будет установлена в указанную вами папку, и вы сможете ее использовать. Но более правильный путь - создавать пакет для установки программы, это делается с помощью утилиты checkinstall, она позволяет создавать как deb, так и rpm пакеты, поэтому может использоваться не только в Ubuntu. Вместо make install выполните:

Затем просто установите получившийся пакет с помощью dpkg:

sudo dpkg install vim.deb

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

Если вы устанавливали программу с помощью make install, то удалить ее можно выполнив в той же папке обратную команду:

sudo make uninstall

Команда удалит все файлы, которые были скопированы в файловую систему.

Выводы

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

На завершение видео о том, что такое компилятор и интерпретатор:

Помню, когда я только начинал программировать, у меня возник вопрос: «Как скомпилировать программу на C в Ubuntu?» Для новичков это не легкая задача, как может показаться на первый взгляд.

Мой путь изучения C начался с бестселлера «Брайан Керниган, Деннис Ритчи, Язык программирования C, 2-е издание» . Там рассказывается как скомпилировать программу в операционной системе Unix, но этот способ не работает в Linux. Авторы книги выкрутились, написав следующее:

В других системах это процедура будет отличаться. Обратитесь к справочнику или специалисту за подробностями.

Побуду специалистом:) и расскажу в данной статье, как скомпилировать первые программы на C и заодно на C++ в терминале Ubuntu.

Текстовый редактор gedit

Для написания первых программ подойдет обычный, используемый по умолчанию в Ubuntu, текстовый редактор с подсветкой синтаксиса — gedit.

Рис. 1. Запуск текстового редактора.

Первой программой по традиции является «Hello, World!» , выводящее приветствие на экран:

#include int main(int argc, char **argv) { puts("Hello, world!"); return 0; }
Печатаем или копируем текст программы в gedit и сохраняем в файл Hello.c , например, на рабочий стол. Не самое лучше место для сохранения, но это позволит рассмотреть случай, когда в имени директории содержится пробел.


Рис. 2. Программа hello, World.

Компиляция программы на C

Теперь запускаем терминал, можно через Dash, а можно с помощью горячих клавиш + + . Здесь в начале установим инструменты сборки, куда входят необходимые компиляторы gcc для языка C и g++ для языка C++:

Sudo apt install build-essential
Для установки требуется ввести пароль, при вводе которого может сложиться впечатление, что ничего не происходит, но на самом деле терминал просто в целях безопасности не отображает символы.

Далее в терминале нам необходимо перейти в директорию, куда сохранили файл с текстом программы. Перемещение выполняется командой cd (англ. change directory — изменить каталог). Чтобы воспользоваться командой в начале пишется cd , затем через пробел путь, куда нужно перейти.

Для перехода на рабочий стол, команда будет следующей:

Cd ~/Рабочий\ стол
Обратите внимание на символ обратной косой черты \ в имени директории Рабочий стол. Обратная косая экранирует пробел, и сообщает команде cd , что пробел и следующие за ним символы являются частью имени. Символ ~ в начале пути обозначает путь до домашней папки пользователя.

Для просмотра содержимого директории применяется команда ls (сокращение от англ. list).

Команда компиляции для программы на C выглядит следующим образом:

Gcc -Wall -o hello hello.c
где:

  • gcc — компилятор для языка программирования C;
  • -Wall — ключ вывода всех предупреждений компилятора;
  • -o hello — с помощью ключа -o указывается имя выходного файла;
  • hello.c — имя нашего исходного файла, который компилируем.
Выполнив команду ls , увидим, что появилась наша скомпилированная программа hello , отмеченная цветом, обозначающим исполняемые программы.

В завершение запустим hello , вводом имени программы с префиксом./ :

./hello
Префикс./ сообщает терминалу о необходимости выполнить программу с заданным именем в текущем каталоге. (Точка — это условное название текущего каталога.)

Компиляция программы на С++

Программы на C++ компилируются аналогично, как и программы на C. «Hello, World!» на C++ можно написать так:

#include int main(int argc, char **argv) { std::cout << "Hello, World!" << std::endl; return 0; }
Сохраняем текст программы в файл под именем hello2.cpp . Таким образом, команда компилирования будет иметь вид:

G++ -Wall -o hello2 hello2.cpp
Для запуска результата вводим в терминале:

Заключение

Данный способ позволяет скомпилировать программу лишь из одного файла с исходным кодом. Но этого вполне достаточно, чтобы начать изучение языков программирования C/C++ по книгам или по статьям в интернете.

Более подробно об программировании в Ubuntu или в любом другом дистрибутиве Linux можно прочитать в книгах:

  • Иванов Н. Н. — Программирование в Linux. Самоучитель. — 2-е издание;
  • Нейл Метьэ, Ричард Стоунс — Основы программирования в Linux: Пер. с англ. — 4-е издание;
  • Колисниченко Д. Н. — Разработка Linux-приложений.

Всем привет! Это первая статья о программировании на Си, в котором мы настроим тестовый редактор и узнаем немного о истории языка Си, возможностях, преимуществах и недостатках.

Языку Си в 2012 году исполнилось 40 лет. Си стал родоначальником C++, Java, Perl, C#, JavaScript и тд. Это самый популярный язык программирования в мире. Си процедурный язык программирования. Файлы кода имеют расширение.c а заголовочные файлы.h. На Си вы можете программировать для Linux, Windows, Windows Phone, Mac OS, iOS, Android и тд. Любой программист должен владеть языком программирования Си. Что бы стать программистом читать одних книг и статей мало. Нужно еще и практиковать. Поэтому мы рассмотрим наши уроки обязательно с примерами. Если у вас возникнет какие то вопросы, то можете задавать в комментариях. Так же этим мануалом могут пользоваться пользователи Windows и Mac OS. Пользователи других ОС могут пользоваться например NetBeans в качестве компилятора (NetBeans поддерживает не только Си но и Java, PHP, C++, Python и Ruby)

Настройка

Для программирования на понадобится текстовый редактор (gedit) и компилятор (gcc - входит в состав Ubuntu). Компилятор настраивать не нужно, а вот текстовый редактор настроим сейчас.

Откройте Правка -> Настройки . Установите галочки на следующие пункты:

  • Показывать номера строк;
  • Подсвечивать текущую строку;
  • Подсвечивать парные скобки;
  • Можно так же изменить тему в вкладке Шрифты и цвета.

Пара выполненных «махинаций» с gedit упростят на работу с текстовым редактором. А в дальнейшем мы рассмотрим какой-нибудь IDE (интегрирования среда разработки).

Операционная система (ОС) Linux/Unix и язык C - "близненцы-братья". Вспомните, что язык программирования C был создан (Д.Ритчи, 1972 г) специально для написания ОС Unix, и с тех пор и "каноническая" ОС Unix, а также все ее клоны и подобные ей ОС пишутся на языке C. Поэтому во всех версиях Unix и Unix-подобных систем компилятор языка C в большинстве случаев входит в комплект поставки системы.

Одним из первых программных продуктов, созданных в рамках проекта GNU, также явился компилятор языка С с открытым кодом. Этот компилятор включается в поставку всех версий ОС Linux.

Таким образом, среда, в которой выполняется наш лабораторный практикум предоставляет в Ваше распоряжение 4 компилятора на выбор:

  • cc - стандартный компилятор языка C;
  • c++ - стандартный компилятор языка C++;
  • gcc - GNU-компилятор языка C;
  • g++ - GNU-компилятор языка C++.

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

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

Файлы с исходными текстами C-программ должны иметь расширение.c , например: hello.c . Результатом компиляции является файл, содержащий объектный модуль, его имя совпадает с именем исходного модуля, а расширение - .o , например: hello.o . Для файла, содержащего исполняемый модуль стандартного расширения не существует. При компиляции программы, состоящей из единственного исходного модуля, объектный модуль автоматически удаляется после создания компилятором исполняемого модуля.

Общий формат команды вызова компилятора имеет следующий вид (компилирование в linux):

Gcc [опции] [выходной_файл] файл1 [файл2:]

Наиболее часто употребляемые опции компилятора следующие:

-c Подавляет фазу редактирования связей, создает объектный модуль для каждого исходного модуля из перечисленных в параметрах вызова. Выходной_файл с этой опцией не задается. Опция может применяться вместе с опцией -I
   
-o Компиляция и редактирование связей. Cоздает объектный модуль для каждого исходного модуля из перечисленных в параметрах вызова и имеющих расширение.c . Файлы с расширением.c рассматриваются как исходные модули и компилируются; файлы, имеющие расширение.o , рассматриваются как объектные модули и подключаются при редактировании связей. Параметр выходной_файл задает имя файла исполняемого модуля. Опция может применяться вместе с опциями -L , -l , -I .
   
-L каталог Добавить каталог в список каталогов, которые содержат объектные библиотечные модули.
   
-l библиотека При редактировании связей подключить модули из библиотеки .
   
-I каталог Искать включаемые (#include) файлы, имена которых не начинаются с / сначала в каталоге , а лишь затем - в стандартных каталогах для включаемых файлов.
   
-E Выполнить обработку указанных исходных модулей только препроцессором, результат направляется в стандартный вывод. Выходной_файл с этой опцией не задается. Опция может применяться вместе с опцией -I .
   
-w Подавить выдачу предупреждающих сообщений.

Примеры использования компилятора:

gcc hello.c gcc -c hello.c gcc -o hello hello.o gcc -o hello hello.o hello1.c
Компиляция исходного модуля hello.c с выдачей сообщений об ошибках на стандартный вывод. Файл объектного модуля не создается.
   
Компиляция исходного модуля hello.c с выдачей сообщений об ошибках на стандартный вывод. При успешной компиляции объектный модуль записывается в файл hello.o .
   
Редактирование связей для объектного модуля hello.o , исполняемый модуль записывается в файл hello .
   
Создание исполняемого модуля в файле hello из объектного модуля hello.o и модуля hello1.c (последний модуль является исходным, он предварительно компилируется.
   
gcc -o hello hello.o hello1.o -l hellolib Создание исполняемого модуля в файле hello из объектных модулей hello.o и hello1.o c с подключением объектных модулей из библиотеки hellolib .
   
gcc -o hello hello1.с -lm Создание исполняемого модуля в файле hello из исходного модуля hello.с с выдачей сообщений об ошибках на стандартный вывод с подключением бибилиотеки math.h . Файл объектного модуля не создается.


Рекомендуем почитать

Наверх