H linux одним файлом

Кунг-фу стиля Linux: автоматическое генерирование заголовочных файлов

Я пробовал много «новых» языков программирования, но как-то так получается, что всегда, когда я возвращаюсь к С++ или даже к C, это наполняет меня радостью. Правда, когда я возвращаюсь к этим языкам, кое-что меня слегка раздражает. Это — то, что мне нужны заголовочные файлы с объявлениями, а так же — отдельный файл, в котором продублирована почти та же самая информация. Я постоянно вношу в код изменения и забываю обновлять заголовочные файлы. Эти файлы не генерируются автоматически при использовании C++ и C. А инструменты, сопутствующие другим языкам, сами заботятся о подобных вещах. Это привело меня к поискам чего-либо, позволяющего автоматизировать генерирование заголовочных файлов. Конечно, некоторые IDE автоматически вставляют объявления туда, куда нужно, но меня всё это, по многим причинам, никогда полностью не устраивало. Мне хотелось что-то маленькое и быстрое, такое, что я мог бы использовать в составе множества различных наборов инструментов.

Я нашёл один довольно старый инструмент, который хорошо справляется с этой задачей. У него, правда, имеются определённые ограничения. Инструмент этот кажется немного запутанным. Поэтому я решил, что о нём стоит рассказать. Речь идёт о makeheaders. Это — часть системы управления конфигурацией программ Fossil. История программы восходит к 1993 году, когда Дуэйн Ричард Хипп (тот самый программист, который создал SQLite) написал её для собственных нужд. Эта программа не особенно сложна: вся она помещается в довольно большом C-файле. Но своё дело она делает: сканирует директорию и создаёт для всего, что найдёт, заголовочные файлы. В некоторых случаях для применения makeheaders нет нужды делать больших изменений в исходном коде, но, если есть такая необходимость, кое-что в нём можно и изменить.

Обзор проблемы

Предположим, имеются C-файлы, работающие совместно. Пусть это — файлы A.c и B.c . В файле A.c находится простая функция:

Если предполагается использовать эту функцию в файле B.c , там должно быть объявление этой функции, чтобы, когда компилируется B.c , компилятор мог бы узнать о том, что функция принимает единственный аргумент типа double и возвращает значение того же типа. В коде, написанном на ANSI C (и на C++) понадобится примерно такая конструкция:

Это — не исполняемый код. Это — всего лишь подсказка компилятору о том, как выглядит функция. Такие конструкции называют прототипами функций. Обычно создают заголовочный файл, содержащий подобный прототип. Включить этот файл можно и в A.c , и в B.c .

Проблема возникает тогда, когда меняют функцию в A.c :

double ctof(double c1, double c2) < return (9.0*(c1+c2))/5+32.0; >

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

Читайте также:  Linux как использовать терминал

Программа makeheaders

Если у вас имеется makeheaders — вы можете просто запустить эту программу, передав ей все C- и H-файлы, которые ей нужно просканировать. Обычно для этого достаточно воспользоваться glob-шаблоном *.[ch] . Программа может обрабатывать и CPP-файлы, и даже — наборы файлов разных типов. Она, по умолчанию, помещает все объявления глобальных переменных и определения глобальных функций в набор заголовочных файлов.

Почему речь идёт о «наборе заголовочных файлов»? Дело в том, что работа программы основана на одном предположении, которое, если о нём не задуматься, может показаться странным. Так как заголовочные файлы генерируются автоматически — нет смысла повторно их использовать. В результате программа помещает в них то, что нужно, располагая это в правильном порядке. Так, файл A.c будет использовать заголовочный файл A.h , а B.c — B.h . Между этими двумя файлами не будет перекрёстных зависимостей. Если что-то изменяется, makeheaders просто запускают снова и она создаёт нужные заголовочные файлы.

Что попадает в заголовочные файлы?

Вот что документация к makeheaders говорит о том, что программа копирует в заголовочные файлы:

  • Если функция определена в одном из C-файлов, прототип этой функции помещается в сгенерированный H-файл, предназначенный для любого из C-файлов, вызывающих эту функцию. Если в определении функции используется ключевое слово static — прототип в H-файле не размещается. Если там, где обычно пользуются static , используют ключевое слово LOCAL , тогда прототип генерируется, но размещается он лишь в единственном заголовочном файле, соответствующем тому файлу исходного кода, который содержит такую функцию. А в H-файлы, предназначенные для других C-файлов, прототип LOCAL -функции не попадает, так как область видимости такой функции ограничена тем файлом, в котором она определена. Если вызвать makeheaders с опцией командной строки -local — тогда программа будет воспринимать ключевое слово static как LOCAL и создаст прототипы соответствующих функций в заголовочном файле, предназначенном для файла исходного кода, содержащего определения таких функций.
  • Если в C-файле определена глобальная переменная, её объявление с ключевым словом extern помещают в заголовочные файлы, предназначенные для тех C-файлов, которые используют эту переменную. Если в H-файле, который создан вручную, встречается объявление структуры, объединения, перечисления, или прототип функции, или объявление C++-класса, всё это копируется в H-файлы, сгенерированные автоматически для всех функций, использующих то, что описано в H-файле, созданном вручную. Но объявления, встречающиеся в C-файлах, считаются внутренними, предназначенными для конкретных файлов, они не копируются в файлы, генерируемые автоматически.
  • Все конструкции #define и typedef , которые встречаются в H-файлах, созданных вручную, копируются, по необходимости, в H-файлы, созданные автоматически. Такие же конструкции, имеющиеся в C-файлах, считаются внутренними и не копируются. Если объявление структуры, объединения или перечисления расположено в H-файле — makeheaders автоматически сгенерирует конструкцию typedef , которая позволит ссылаться на объявление без использования квалификаторов struct , union или enum .
Читайте также:  Non blocking sockets linux

Пример на C++

В случае с чем-то вроде C++-классов, или, на самом деле, в случае с чем угодно, можно поместить блок кода в специальные директивы препроцессора для того чтобы программа makeheaders обработала бы этот блок. Вот — простой пример кода, который я использовал для того чтобы это проверить.

Тут стоит обратить внимание на несколько моментов:

  • Команда включения в C++-файл файла test.hpp возьмёт на себя задачу по включению в С++-файл и сгенерированного специально для него заголовочного файла.
  • Директива INTERFACE заключает в себя код, который должен попасть в заголовочный файл. Во время компиляции INTERFACE будет равно нулю, поэтому код не будет компилироваться дважды.
  • Функции-члены объявлены за пределами раздела INTERFACE с использованием ключевого слова PUBLIC (там, конечно, могут использоваться и ключевые слова PRIVATE или PROTECTED ). Это приведёт к тому, что makeheaders обратит внимание и на них.

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

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

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

Обратите внимание на то, что INTERFACE здесь, в самом конце, устанавливается в 0. А это значит, что в файле с исходным кодом раздел INTERFACE не будет подвергаться повторной компиляции. В случае с C-файлами makeheaders , кроме того, генерирует конструкции typedef для чего-то вроде структур. В C++ это, конечно, не нужно. Тут можно видеть побочный эффект наличия некоторых объявлений в разделе INTERFACE , а некоторых — в разделе реализации: тут имеется избыточный тег PUBLIC . Вреда от этого нет, этот тег не появился бы в том случае, если бы я поместил весь код за пределами раздела INTERFACE .

Это ещё не всё

Гибкий инструмент, который мы рассмотрели, умеет и кое-что ещё. Узнать об этом можно из документации по нему. Он поддерживает флаг, благодаря которому выдаётся информация об обрабатываемом коде, которую можно использовать для его документирования. Можно создавать иерархии интерфейсов. Makeheaders , кроме того, может помочь в работе над проектами, где совместно используется C++ и C. Этот инструмент достаточно интеллектуален и поддерживает условную компиляцию. Правда, стоит учитывать то, что в число поддерживаемых им механизмов C++ не входят шаблоны и пространства имён. Правда, код makeheaders открыт, поэтому вы, если хотите, можете этот инструмент доработать. Прежде чем вы решитесь на применение makeheaders в крупном проекте — учтите, что у этого инструмента есть и ещё некоторые ограничения.

Читайте также:  Find my kernel version linux

Планируете ли вы попробовать нечто вроде makeheaders , или вас устраивает ручная работа с заголовочными файлами?

Источник

H linux одним файлом

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

Заголовочные файлы подключаются к файлам исходного кода приложения по мере необходимости с помощью директивы #include.

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

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

#ifndef SUMS_H
#define SUMS_H

#endif /*SUMS_H*/

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

#if x86_64
#include «system64.h»
#elif x86
#include «system32.h»
#endif

Пример

В данном простом примере функция вывода приветствия находится в отдельном файле исходного кода (hello.c), который подключается к основному файлу исходного кода программы (hellomain.c) с помощью заголовочного файла (hello.h).

Это содержимое файла исходного кода hello.c:

Источник

linux⚓︎

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

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

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

Сборка⚓︎

Данный пакет является частью архива с ядром Linux.

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

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

Подготовьте заголовки для использования:⚓︎

Установка⚓︎

 find usr/include -name '.*' -delete rm usr/include/Makefile cp -rv usr/include $LIN/usr 

Заголовочные файлы, расположенные в системном каталоге /usr/include , должны всегда быть те, которые использовались при компиляции Glibc. Их никогда не следует заменять на чистые заголовочные файлы ядра или любые другие подготовленные заголовочные файлы.

Установленные файлы⚓︎

Данный пакет устанавливает множество заголовочных файлов, в частности /usr/include/asm/*.h, /usr/include/asm-generic/*.h, /usr/include/drm/*.h, /usr/include/linux/*.h, /usr/include/misc/*.h, /usr/include/mtd/*.h, /usr/include/rdma/*.h, /usr/include/scsi/*.h, /usr/include/sound/*.h, /usr/include/video/*.h, and /usr/include/xen/*.h

Источник

Оцените статью
Adblock
detector