Как создать файл main c

Обновлено: 02.07.2024

в этом пошаговом руководстве показано, как создать традиционное Windows классическое приложение в Visual Studio. в примере приложения, которое вы создадите, будет использоваться Windows API для вывода "Hello, Windows desktop!". "Hello, World!". Код, созданный в этом пошаговом руководстве, можно использовать в качестве шаблона для создания других классических приложений Windows.

Для краткости в тексте пропущены некоторые операторы кода. В разделе Построение кода в конце документа показан полный код.

Предварительные требования

Компьютер под управлением Microsoft Windows 7 или более поздних версий. Для обеспечения оптимальной среды разработки рекомендуется использовать Windows 10.

Копия Visual Studio. Сведения о скачивании и установке Visual Studio см. в этой статье. Когда вы запускаете установщик, убедитесь, что установлена рабочая нагрузка Разработка классических приложений на C++ . Не беспокойтесь, если вы не установили эту рабочую нагрузку при установке Visual Studio. Вы можете снова запустить установщик и установить ее сейчас.

Подробные сведения о рабочей нагрузке Разработка классических приложений на C++ в Visual Studio Installer.

Базовые значения об использовании интегрированной среды разработки Visual Studio. Если вы уже использовали классические приложения для Windows, вы, вероятно, справитесь. Общие сведения см. в обзоре возможностей интегрированной среды разработки Visual Studio.

Основные навыки владения языком C++. Не волнуйтесь, мы не будем делать ничего сложного.

создание проекта Windows классических приложений

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

создание проекта Windows desktop в Visual Studio 2019

В главном меню выберите Файл > Создать > Проект, чтобы открыть диалоговое окно Создание проекта.

в верхней части диалогового окна задайте для параметра язык значение C++, задайте для параметра платформа значение Windows и задайте для параметра Project тип значение рабочий стол.

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

В Обозреватель решений щелкните правой кнопкой мыши проект Десктопапп , выберите Добавить, а затем выберите новый элемент.

снимок экрана: диалоговое окно "добавление нового элемента" в Visual Studio 2019 с установленным > Visual C и плюсом, а также параметр файла c плюсом/с выделенным.

Теперь проект создан и исходный файл открыт в редакторе. Чтобы продолжить, перейдите к созданию кода.

создание проекта Windows desktop в Visual Studio 2017

В меню Файл выберите команду Создать, а затем пункт Проект.

в левой области диалогового окна создание Project разверните узел установленные > Visual C++ и выберите пункт Windows рабочий стол. в средней области выберите мастер рабочего стола Windows.

снимок экрана: диалоговое окно "создание Project" в Visual Studio 2017 с установленным > Visual C плюс плюс > Windows рабочего стола, выбранный параметр "мастер настольных систем Windows" и десктопапп введено в текстовом поле "имя".

В Обозреватель решений щелкните правой кнопкой мыши проект Десктопапп , выберите Добавить, а затем выберите новый элемент.

снимок экрана: диалоговое окно "добавление нового элемента" в Visual Studio 2017 с установленным > Visual C и плюсом, а также параметр файла c плюсом/с выделенным.

Теперь проект создан и исходный файл открыт в редакторе. Чтобы продолжить, перейдите к созданию кода.

создание проекта Windows desktop в Visual Studio 2015

В меню Файл выберите команду Создать, а затем пункт Проект.

в левой области диалогового окна создание Project разверните узел установленные > шаблоны > Visual C++, а затем выберите пункт Win32. В средней области выберите шаблон Проект Win32.

снимок экрана: диалоговое окно "создание Project" в Visual Studio 2015 с установленными шаблонами > > Visual C плюс плюс > win32, выделенный параметр win32 Project и десктопапп, введенные в текстовом поле имя.

На странице Обзор мастера приложений Win32 нажмите кнопку Далее.

Создание Десктопапп на странице обзора мастера приложений Win32.

на странице Параметры приложений в разделе тип приложения выберите Windows приложение. В разделе Дополнительные параметры снимите флажок предкомпилированный заголовок, а затем выберите пустой проект. Чтобы создать проект, нажмите кнопку Готово.

В Обозреватель решений щелкните правой кнопкой мыши проект десктопапп, выберите Добавить, а затем выберите новый элемент.

снимок экрана: диалоговое окно "добавление нового элемента" в Visual Studio 2015 с установленным > Visual C и плюсом, а также параметр файла c плюсом/с выделенным.

Теперь проект создан и исходный файл открыт в редакторе.

Создание кода

далее вы узнаете, как создать код для Windows классического приложения в Visual Studio.

Запуск классического приложения Windows

точно так же, как у каждого приложения C и C++ должна быть main функция в качестве начальной точки, каждое Windows классическое приложение должно иметь WinMain функцию. WinMain имеет следующий синтаксис:

Сведения о параметрах и возвращаемом значении этой функции см. в разделе WinMain Entry Point.

Что такое дополнительные слова, такие как, или, или WINAPI CALLBACK HINSTANCE _In_ ? традиционный API Windows использует определения типов и макросов препроцессора, чтобы изменялись некоторые сведения о типах и коде, зависящем от платформы, такие как соглашения о вызовах, __declspec объявления и директивы pragma компилятора. в Visual Studio можно использовать функцию " быстрые сведения " IntelliSense, чтобы увидеть, что определяются этими определениями и макросами. Наведите указатель мыши на интересующую слово или выберите его и нажмите клавиши CTRL + K, CTRL + I для небольшого всплывающего окна, содержащего определение. Дополнительные сведения см. в разделе Using IntelliSense. Параметры и возвращаемые типы часто используют аннотации SAL , чтобы помочь в перехвате ошибок программирования. Дополнительные сведения см. в разделе Использование аннотаций SAL для сокращения числа дефектов кода C/C++.

для Windows настольных приложений требуется <> Windows. h. <в файле Tchar. h> определен TCHAR макрос, который в конечном итоге разрешается в, wchar_t Если в проекте ОПРЕДЕЛЕН символ Юникода, в противном случае — значение char . Если вы всегда создаете Юникод с включенным параметром UNICODE, то не нужно использовать TCHAR и может быть просто использоваться wchar_t напрямую.

наряду с WinMain функцией, каждое Windows классическое приложение также должно иметь функцию window-procedure. Эта функция обычно называется WndProc , но вы можете назвать ее по своему усмотрению. WndProc имеет следующий синтаксис:

Дополнительные сведения см. в разделе Процедуры окна.

Добавление функциональных возможностей в функцию WinMain

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

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

Теперь можно создать окно. Используйте функцию CreateWindowEx .

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

на этом этапе окно было создано, но нам по-прежнему нужно сообщить Windows, чтобы сделать его видимым. Вот что делает этот код:

На этом этапе функция WinMain должна напоминать приведенный ниже код.

Добавление функциональных возможностей в функцию WndProc

HDC в коде — это обработчик контекста устройства, который используется для рисования в клиентской области окна. Используйте BeginPaint функции и EndPaint для подготовки и завершения рисования в клиентской области. BeginPaint Возвращает маркер контекста устройства отображения, используемый для рисования в клиентской области. EndPaint завершает запрос на рисование и освобождает контекст устройства.

Сборка кода

Как обещано, вот полный код для рабочего приложения.

Сборка примера

Удалите код, введенный в хелловиндовсдесктоп. cpp в редакторе. Скопируйте этот пример кода и вставьте его в хелловиндовсдесктоп. cpp:

В меню Построение выберите Построить решение. Результаты компиляции должны появиться в окне вывод в Visual Studio.

Чтобы запустить приложение, нажмите клавишу F5. окно, содержащее текст "Hello, Windows desktop!" должно отображаться в левом верхнем углу экрана.

Снимок экрана выполняемого Project Десктопапп.

Поздравляем! вы выполнили это пошаговое руководство и создали традиционное Windows классическое приложение.

Д ля начала, необходимо установить программное обеспечение. В принципе не важно, каким ПО вы будете пользоваться, также как не важна и операционная система. Но в течение всего курса я буду приводить примеры на MS Visula Studio 2012 Express Edition. Visual Studio 2012 Express Edition бесплатный и его за глаза хватит для изучения всего курса. Кроме того, как показала практика, он гораздо строже относится к коду и даёт более полноценное описание ошибок и предупреждений. При изучении языка можно использовать Borland (он же CodeGEAR, он же Embarcadero и т.д.), Dev Cpp, MinGW, или gcc, или что вы ещё захотите.

Пример для MS Visual Studio

1. Открываем IDE, заходим Файл | Создать проект.

2. Выбираем консольное приложение и даём ему имя. В данном случае first_program

4. Ставим галочку "Пустой проект".

5. После чего получаем пустую структуру проекта. Добавим новый элемент: правый клик мыши по папке
"Файлы исходного кода" | Добавить | Создать элемент.

Добавляем новый cpp файл, но сохраняем его с расширением .c

Я назвал файл main.c Всё, готово, можно писать программу. Пропустите шаги для других платформ.

Borland

У меня установлен только Code Gear C++Builder 2007, но в остальных (и предыдущих) релизах всё делается также.

1. Создадим новый проект File | New | Other.

2. Добавляем консольное приложение

3. Выбираем язык си

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

Пример для cc/gcc для терминала

О ткройте ваш любимый текстовый редактор и скопируйте туда код программы.

Если вы сохранили программу в файле с именем hello.c, то наберите в терминале команду

cc hello.c -o hello

либо

gcc hello -o hello

При этом, очевидно, вы должны находиться в папке с программой. gcc создаст исполняемый файл с именем hello. Запустите его, и он выведет Hello, World!

./hello

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

chmod 760 hello

Если у вас несколько файлов, то необходимо будет перечислить имена всех си файлов по порядку. Например, если у вас есть ещё два файла simple.h и simple.c, то нужно прописать

cc hello.c simple.c -o hello

Код программы

Принято в первой программе выводить Hello, World! на экран.

Запустите программу ( Run | Run или F9 для борланда, Построение | Построить решение или F5 для MS) Программа выведет Hello, World! и будет ждать, когда вы нажмёте на любую клавишу.

Рассмотрим код подробнее. Первые две строки

директивы компилятору на подключение стандартных библиотек stdio (Standard Input Output - стандартная библиотека ввода вывода) и conio (Console Input Output - стандартная библиотека консоли вывода вывода). Расширение .h указывает, что это заголовочные файлы (header files). Компилятор копирует код библиотек conio и stdio, и даёт возможность использовать функции, описанные в этих библиотеках.

Это функция main. Она отличается от остальных функций, которые вы можете определить тем, что является точкой входа - с неё начинается выполнение программы.

Функция main имеет два параметра - число параметров argc и массив переданных параметров argv. Эти аргументы необязательные, поэтому можно их не писать. Об их использовании поговорим позже. Функция main должна возвращать целое число. Если это 0, то функция отработала без ошибок. В современном стандарте си можно не возвращать 0, и описать функцию как void main. Наша программа теперь выглядит совсем просто. Строка выводит строку Hello, World! на экран монитора. ожидает нажатия на клавишу.

Давайте сделаем что-нибудь посложнее, чтобы научиться добавлять новые файлы в программу. Сейчас для вас важно научиться добавлять новые файлы, если часть кода останется непонятной, это не беда.
1. Создайте новый заголовочный файл в папке "Заголовочные файлы", назовите его simple.h
2. Создайте новый файл simple.c в папке "Файлы исходного кода".
3. Добавьте в simple.h

Здесь мы объявили новую функцию doSomething. У неё отсутствует тело, оно будет описано в файле simple.c. Здесь же мы подключаем и библиотеки stdio и conio
Добавьте в simple .c

Мы включаем в файл simple.c заголовочный файл. Он пишется в двойных кавычках, потому что это не файл из стандартной библиотеки. Файлы стандартной библиотеки обычно располагаются в папке include самой IDE. Если поместить туда наши файлы, то их тоже можно будет объявлять в угловых скобках. В двойных кавычках можно также прописывать абсолютные пути к файлам. Так как мы уже включили библиотеки conio и stdio в .h файле, то они "видны" и в .c файле.
Далее, в main.c

Мы подключаем только заголовочный файл. Содержимое simple.c будет добавлено автоматически. Собираем проект (F5 или F9, или что там у вас за среда. ) Если у вас всё заработало то отлично, вы научились добавлять новые файлы в проект.

email

Всё ещё не понятно? – пиши вопросы на ящик

Вот мой make-файл:

И вот мой главный cpp:

Он компилируется без предупреждения, когда я запускаю «make», но во время выполнения он сообщает мне: «ошибка при загрузке общих библиотек: libhts.so.2 не может открыть файл общих объектов»

Любая помощь приветствуется! Заранее спасибо.

Решение

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

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

-lfoo опция сообщит компоновщику ссылку в библиотеку с именем foo , -Lsome/dir опция скажет компоновщику найти эту библиотеку foo в каталоге some_dir ,

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

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

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

Компоновщик во время выполнения просматривает различные места, о которых можно узнать, прочитав его документацию; например, в GNU / Linux временный компоновщик называется ld.so так что вы можете читать документы с man ld.so ,

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

Если вы просто хотите жестко прописать путь для поиска во время компиляции / компоновки, вы можете добавить -Rsome/dir вариант для вашей линии связи, по одному для каждого -L вариант, вот так:

Это будет хорошо работать, пока SAMTOOLS а также HTSLIB каталоги существуют и до сих пор содержат правильные общие библиотеки в них. Очевидно, что это большое ограничение, но мы не можем догадаться, каковы ваши конечные требования.

Чтобы сразу начать программировать, создадим еще один клон известной программы "Hello World". Что делает эта программа, вы знаете. Откройте свой любимый текстовый редактор и наберите в нем следующий текст:

Я назвал свой файл hello.c. Вы можете назвать как угодно, сохранив суффикс .c. Содержимое файла hello.c - это исходный код программы ('program source', 'source code' или просто 'source'). А hello.c - это исходный файл программы ('source file'). Hello World - очень маленькая программа, исходный код которой помещается в одном файле. В "настоящих" программах, как правило, исходный код разносится по нескольким файлам. В больших программах исходных файлов может быть больше сотни.

Наш исходный код написан на языке программирования C. Языки программирования были придуманы для того, чтобы программист мог объяснить компьютеру, что делать. Но вот беда, компьютер не понимает ни одного языка программирования. У компьютера есть свой язык, который называют машинным кодом или исполняемым кодом ('executable code'). Написать Hello World в машинном коде можно, но серьезные программы на нем не пишутся. Исполняемый код не только сложный по своей сути, но и очень неудобный для человека. Программа, которую можно написать за один день на языке программирования будет писаться целый год в машинном коде. Потом программист сойдет с ума. Чтобы этого не случилось, был придуман компилятор ('compiler'), который переводит исходный код программы в исполняемый код. Процесс перевода исходного кода программы в исполняемый код называют компиляцией.

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

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

Мы рассмотрели идеальный случай, когда программа написана без синтаксических ошибок. Попробуем намеренно испортить программу таким образом, чтобы она не отвечала канонам языка C. Для этого достаточно убрать точку с запятой в конце вызова функции printf(): Теперь, если попытаться откомпилировать программу, то компилятор выругается, указав нам на то, что он считает неправильным: В первой строке говорится, что в файле hello.c (у нас он единственный) в теле функции main() что-то произошло. Вторая строка сообщает, что именно произошло: седьмая строка файла hello.c вызвала ошибку (error). Далее идет расшифровка: синтаксическая ошибка перед закрывающейся фигурной скобкой.

Заглянув в файл hello.c мы с удивлением обнаружим, что нахулиганили мы не в седьмой, а в шестой строке. Дело в том, что компилятор обнаружил нелады только в седьмой строке, но написал 'before' (до), что означает "прокручивай назад".

Естественно, пока мы не исправим ошибку, ни о каком бинарнике не может идти и речи. Если мы удалим старый бинарник hello, доставшийся нам от прошлой компиляции, то увидим, что компиляция испорченного файла не даст никакого результата. Однако иногда компилятор может лишь "заподозрить" что-то неладное, потенциально опасное для нормального существования программы. Тогда вместо 'error' пишется 'warning' (предупреждение), и бинарник все-таки появляется на свет (если в другом месте нет явных ошибок). Не следует игнорировать предупреждения, за исключением тех случаев, когда вы на 100% знаете, что делаете.

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

2.2. Мультифайловое программирование

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

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

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

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

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

В Linux в качестве линковщика используется программа ld, обладающая приличным арсеналом опций. К счастью gcc самостоятельно вызывает компоновщик с нужными опциями, избавляя нас от "ручной" линковки.

Попробуем теперь, вооружившись запасом знаний, написать мультифайловый Hello World. Создадим первый файл с именем main.c: Теперь создадим еще один файл hello.c со следующим содержимым:

Здесь функция main() вызывает функцию print_hello(), находящуюся в другом файле. Функция print_hello() выводит на экран заветное приветствие. Теперь нужно получить два объектных файла. Опция -c компилятора gcc заставляет его отказаться от линковки после компиляции. Если не указывать опцию -o, то в имени объектного файла расширение .c будет заменено на .o (обычные объектные файлы имеют расширение .o): Итак, мы получили два объектных файла. Теперь их надо объединить в один бинарник: Компилятор "увидел", что вместо исходных файлов (с расширением .c) ему подбросили объектные файлы (с расширением .o) и отреагировал согласно ситуации: вызвал линковщик с нужными опциями.

Давайте разберемся, что же все-таки произошло. В этом нам поможет утилита nm. Я уже оговорился, что объектные файлы содержат таблицу символов. Утилита nm как раз позволяет посмотреть эту таблицу в читаемом виде. Те, кто пробовал программировать на ассемблере знают, что в исполняемом файле буквально все (функции, переменные) стоит на своей позиции: стоит только вставить или убрать из программы один байт, как программа тут же превратиться в груду мусора из-за смещенных позиций (адресов). У объектных файлов особая роль: они хранят в таблице символов имена некоторых позиций (глобально объявленных функций, например). В процессе линковки происходит стыковка имен и пересчет позиций, что позволяет нескольким объектным файлам объединиться в один бинарник. Если вызвать nm для файла hello.o, то увидим следующую картину: О смысловой нагрузке нулей и литер U,T мы будем говорить при изучении библиотек. Сейчас же важным является то, что в объектном файле сохранилась информация об использованных именах. Своя информация есть и в файле main.o: Таблицы символов объектных файлов содержат общее имя print_hello. В процессе линковки высчитываются и подставляются в нужные места адреса, соответствующие именам из таблицы. Вот и весь секрет.

2.3. Автоматическая сборка

В предыдущем разделе для создания бинарника из двух исходных файлов нам пришлось набрать три команды. Если бы программу пришлось отлаживать, то каждый раз надо было бы вводить одни и те же три команды. Казалось бы выход есть: написать сценарий оболочки. Но давайте подумаем, какие в этом случае могут быть недостатки. Во-первых, каждый раз сценарий будет компилировать все файлы проекта, даже если мы исправили только один из них. В нашем случае это не страшно. Но если речь идет о десятках файлов! Во-вторых, сценарий "намертво" привязан к конкретной оболочке. Программа тут же становится менее переносимой. И, наконец, простому скрипту не хватает функциональности (задание аргументов сборки и т. п.), а хороший скрипт (с многофункциональными прибамбасами) плохо модернизируется.

Выход из сложившейся ситуации есть. Это утилита make, которая работает со своими собственными сценариями. Сценарий записывается в файле с именем Makefile и помещается в репозиторий (рабочий каталог) проекта. Сценарии утилиты make просты и многофункциональны, а формат Makefile используется повсеместно (и не только на Unix-системах). Дошло до того, что стали создавать программы, генерирующие Makefile'ы. Самый яркий пример - набор утилит GNU Autotools. Самое главное преимущество make - это "интеллектуальный" способ рекомпиляции: в процессе отладки make компилирует только измененные файлы.

То, что выполняет утилита make, называется сборкой проекта, а сама утилита make относится к разряду сборщиков.

Любой Makefile состоит из трех элементов: комментарии, макроопределения и целевые связки (или просто связки). В свою очередь связки состоят тоже из трех элементов: цель, зависимости и правила.

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

Связки определяют: 1) что нужно сделать (цель); 2) что для этого нужно (зависимости); 3) как это сделать (правила). В качестве цели выступает имя или макроконстанта. Зависимости - это список файлов и целей, разделенных пробелом. Правила - это команды передаваемые оболочке.

Теперь рассмотрим пример. Попробуем составить сценарий сборки для рассмотренного в предыдущем разделе мультифайлового проекта Hello World. Создайте файл с именем Makefile: Обратите внимание, что в каждой строке перед вызовом gcc, а также в строке перед вызовом rm стоят табуляции. Как вы уже догадались, эти строки являются правилами. Формат Makefile требует, чтобы каждое правило начиналось с табуляции. Теперь рассмотрим все по порядку.

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

Первая связка имеет цель hello. Цель отделяется от списка зависимостей двоеточием. Список зависимостей отделяется от правил символом новой строки. А каждое правило начинается на новой строке с символа табуляции. В нашем случае каждая связка содержит по одному правилу. В списке зависимостей перечисляются через пробел вещи, необходимые для выполнения правила. В первом случае, чтобы скомпоновать бинарник, нужно иметь два объектных файла, поэтому они оказываются в списке зависимостей. Изначально объектные файлы отсутствуют, поэтому требуется создать целевые связки для их получения. Итак, чтобы получить main.o, нужно откомпилировать main.c. Таким образом файл main.c появляется в списке зависимостей (он там единственный). Аналогичная ситуация с hello.o. Файлы main.c и hello.c изначально существуют (мы их сами создали), поэтому никаких связок для их создания не требуется.

Особую роль играет целевая связка clean с пустым списком зависимостей. Эта связка очищает проект от всех автоматически созданных файлов. В нашем случае удаляются файлы main.o, hello.o и hello. Очистка проекта бывает нужна в нескольких случаях: 1) для очистки готового проекта от всего лишнего; 2) для пересборки проекта (когда в проект добавляются новые файлы или когда изменяется сам Makefile; 3) в любых других случаях, когда требуется полная пересборка (напрмиер, для измерения времени полной сборки).

Теперь осталось запустить сценарий. Формат запуска утилиты make следующий: Опции make нам пока не нужны. Если вызвать make без указания целей, то будет выполнена первая попавшаяся связка (со всеми зависимостями) и сборка завершится. Нам это и требуется: В процессе сборки утилита make пишет все выполняемые правила. Проект собран, все работает.

Теперь давайте немного модернизируем наш проект. Добавим одну строку в файл hello.c: Теперь повторим сборку: Утилита make "пронюхала", что был изменен только hello.c, то есть компилировать нужно только его. Файл main.o остался без изменений. Теперь давайте очистим проект, оставив одни исходники: В данном случае мы указали цель непосредственно в командной строке. Так как целевая связка clean содержит пустой список зависимостей, то выполняется только одно правило. Не забывайте "чистить" проект каждый раз, когда изменяется список исходных файлов или когда изменяется сам Makefile.

2.4. Модель КИС

Любая программа имеет свой репозиторий - рабочий каталог, в котором находятся исходники, сценарии сборки (Makefile) и прочие файлы, относящиеся к проекту. Репозиторий рассмотренного нами проекта мультифайлового Hello World изначально состоит из файлов main.c, hello.c и, собственно, Makefile. После сборки репозиторий дополняется файлами main.o, hello.o и hello. Практика показывает, что правильная организация исходного кода в репозитории не только упрощает модернизацию и отладку, но и предотвращает возможность появления многих ошибок.

Модель КИС (Клиент-Интерфейс-Сервер) - это элегантная концепция распределения исходного кода в репозитории, в рамках которой все исходники можно поделить на клиенты, интерфейсы и серверы.

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

Часто бывает, что клиент сам становится сервером, точнее начинает играть роль промежуточного сервера. Хороший пример - наш мультифайловый Hello World. Здесь функция print_hello() (клиент) пользуется услугами стандартной библиотеки языка C (сервер), вызывая функцию printf(). Однако в дальнейшем функция print_hello() сама становится сервером, предоставляя свои услуги функции main(). В языке C++ довольно часто клиент создает производный класс, который наследует некоторые механизмы базового класса сервера. Таким образом клиент сам становится сервером, предоставляя услуги своего производного класса.

Клиент с сервером должны "понимать" друг друга, иначе взаимодействие невозможно. Интерфейс (протокол) - это условный набор правил, согласно которым взаимодействуют клиент и сервер. В нашем случае (мультифайловый Hello World) интерфейсом (протоколом) является общее имя в таблице символов двух объектных файлов. Такой способ взаимодействия может привести к неприятным последствиям. Клиент (функция main()) не знает ничего, кроме имени функции print_hello() и, наугад вызывает ее без аргументов и без присваивания. Иначе говоря, клиент не знает до конца правил игры. В нашем случае прототип функции print_hello() неизвестен.

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