Компиляция и make (1110642), страница 2
Текст из файла (страница 2)
Каким связыванием обладают fmtS, fmtP, main, scanf, printf?2. Какие изменения необходимо внести в программу и процесс сборки, чтобы собиратьпрограмму под Windows?Задача 26-3Написать на Ассемблере функцию countof(), считающую количество вхождений символа встроку, ограниченную \0. Функция должна использовать соглашение cdecl и иметь следующийпрототип.intcountof(const char *s, char c);Реализовать на языке Си функцию main(), считыюващую две строки без пробелов, не более 80символов каждая, и выводящую ту из них, которая имеет больше вхождений символа $.Указать команды, необходимые для сборки программы. Вынести объявление функции взаголовчный файл.Решение: файл countof.h.intcountof(const char *s, char c);Решение: файл countof.asm.SECTION .textGLOBAL countofcountof:PUSHEBPMOVEBP, ESP; стандартный прологXORMOVMOVEAX, EAXCL, BYTE [EBP + 12]EDX, DWORD [EBP + 8]; счётчик; символ в CL; адрес очередного символа строки в EDXCMPJEBYTE [EDX], 0.2; проверяем на конец строкиCMPJNEBYTE [EDX], CL.2; проверяем на совпадениеINCEAX; совпало, увеличиваем счётчикINCJMPEDX.1; идём дальше по строке.1:.2:.3:LEAVERET; стандартный эпилогРешение: файл main.c.#include <stdio.h>#include "countof.h"intmain(void){char a[81], b[81];int na, nb;scanf("%s %s", a, b);na = countof(a, '$'); nb = countof(b, '$');printf("%s\n", na > nb ? a : b);return 0;}Решение: последовательность команд для сборки.gcc -c -I.
-o main.o main.cnasm -f elf32 -o countof.o countof.asmgcc -o program main.o countof.oУтилита makemake — утилита, автоматизирующая процесс преобразования файлов из одной формы в другую.Чаще всего это компиляция исходного кода в объектные файлы и последующая компоновка висполняемые файлы или библиотеки. Утилита использует специальные make-файлы, в которыхуказаны зависимости файлов друг от друга и правила для их удовлетворения. На основеинформации о времени последнего изменения каждого файла make определяет и запускаетнеобходимые программы.Использование: make [ -f make-файл ] [ цель ] ...Если опция -f не указана, используется имя по умолчанию для make-файла — Makefile (однако,в разных реализациях make кроме этого могут проверяться и другие файлы, напримерGNUmakefile).make открывает make-файл, считывает правила и выполняет команды, необходимые длясоздания указанной цели.Стандартные цели для сборки дистрибутивов GNU:all — выполнить компиляцию пакета (цель по умолчанию)install — установить пакет из дистрибутива (производит копирование исполняемых файлов,библиотек и документации в системные директории)uninstall — удалить пакет (производит удаление исполняемых файлов и библиотек из системныхдиректорий)clean — очистить дистрибутив (удалить из дистрибутива объектные и исполняемые файлысозданные в процессе компиляции)distclean — очистить все созданные при компиляции файлы и все вспомогательные файлысозданные утилитой ./configure в процессе настройки параметров компиляции дистрибутиваMake-файлПрограмма make выполняет команды согласно правилам, указанным в специальном файле.
Этотфайл называется make-файл (makefile, мейкфайл). Как правило, make-файл описывает, какимобразом нужно компилировать и компоновать программу.make-файл состоит из правил и переменных. Правила имеют следующий синтаксис:цель1 цель2 ...: реквизит1 реквизит2 ...команда1команда2...Правило представляет собой набор команд, выполнение которых приведёт к сборке файловцелей из файлов-реквизита.Правило сообщает make, что файлы, получаемые в результате работы команд (цели) являютсязависимыми от соответствующих файлов-реквизита.
make никак не проверяет и не используетсодержимое файлов-реквизита, однако, указание списка файлов-реквизита требуется только длятого, чтобы make убедилась в наличии этих файлов перед началом выполнения команд и дляотслеживания зависимостей между файлами.Обычно цель представляет собой имя файла, который генерируется в результате работыуказанных команд. Целью также может служить название некоторого действия, которое будетвыполнено в результате выполнения команд (например, цель clean в make-файлах длякомпиляции программ обычно удаляет все файлы, созданные в процессе компиляции).Строки, в которых записаны команды, должны начинаться с символа табуляции.Рассмотрим несложную программу на Си.
Пусть программа program состоит из пары файловкода — main.c и lib.c, а также из одного заголовочного файла — defines.h, который подключён воба файла кода. Поэтому, для создания program необходимо из пар (main.c defines.h) и (lib.cdefines.h) создать объектные файлы main.o и lib.o, а затем скомпоновать их в program. Присборке вручную требуется дать следующие команды:cc -c main.ccc -c lib.ccc -o program main.o lib.oЕсли в процессе разработки программы в файл defines.h будут внесены изменения, потребуетсяперекомпиляция обоих файлов и линковка, а если изменим lib.c, то повторную компиляциюmain.о можно не выполнять.Таким образом, для каждого файла, который мы должны получить в процессе компиляциинужно указать, на основе каких файлов и с помощью какой команды он создаётся.
Программаmake на основе этих данных выполняет следующее:собирает из этой информации правильную последовательность команд для получениятребуемых результирующих файлов;и инициирует создание требуемого файла только в случае, если такого файла не существует, илион старше, чем файлы от которых он зависит.Если при запуске make явно не указать цель, то будет обрабатываться первая цель в make-файле,имя которой не начинается с символа «.».Для программы program достаточно написать следующий make-файл:program: main.o lib.occ -o program main.o lib.omain.o lib.o: defines.hСтоит отметить ряд особенностей.
В имени второй цели указаны два файла и для этой же целине указана команда компиляции. Кроме того, нигде явно не указана зависимость объектныхфайлов от «*.c»-файлов. Дело в том, что программа make имеет предопределённые правила дляполучения файлов с определёнными расширениями. Так, для цели-объектного файла(расширение «.o») при обнаружении соответствующего файла с расширением «.c» будет вызванкомпилятор «сс -с» с указанием в параметрах этого «.c»-файла и всех файлов-зависимостей.Предположим, что к проекту добавился второй заголовочный файл lib.h, который включаетсятолько в lib.c. Тогда make-файл увеличится ещё на одну строчку:lib.o: lib.hТаким образом, один целевой файл может указываться в нескольких целях.
При этом полныйсписок зависимостей для файла будет составлен из списков зависимостей всех целей, в которыхон участвует, создание файла будет производиться только один раз.Директивы условной компиляцииИмеется несколько директив, которые дают возможность выборочно компилировать частиисходного кода вашей программы.
Этот процесс называется условной компиляцией и широкоиспользуется фирмами, живущими за счет коммерческого программного обеспечения — теми,которые поставляют и поддерживают многие специальные версии одной программы.Директивы #if, #else, #elif и #endifВозможно, самыми распространенными директивами условной компиляции являются #if, #else,#elif и #endif. Они дают возможность в зависимости от значения константного выражениявключать или исключать те или иные части кода.В общем виде директива #if выглядит таким образом:#if константное выражениепоследовательность операторов#endifЕсли находящееся за #if константное выражение истинно, то компилируется код, которыйнаходится между этим выражением и #endif. В противном случае этот промежуточный кодпропускается. Директива #endif обозначает конец блока #if.Например, в следующем фрагменте для определения знака денежной единицы используетсязначение ACTIVE_COUNTRY (для какой страны):#define US 0#define ENGLAND 1#define FRANCE 2#define ACTIVE_COUNTRY US#if ACTIVE_COUNTRY == USchar currency[] = "dollar";#elif ACTIVE_COUNTRY == ENGLANDchar currency[] = "pound";#elsechar currency[] = "franc";#endifДирективы #ifdef и #ifndefДругой способ условной компиляции — это использование директив #ifdef и #ifndef, которыесоответственно означают "if defined" (если определено) и "if not defined" (если не определено).
Вобщем виде #ifdef выглядит таким образом:#ifdef имя_макросапоследовательность операторов#endifБлок кода будет компилироваться, если имя макроса было определено ранее в операторе #define.В общем виде оператор #ifndef выглядит таким образом:#ifndef имя_макросапоследовательность операторов#endifБлок кода будет компилироваться, если имя макроса еще не определено в операторе #define.И в #ifdef, и в #ifndef можно использовать оператор #else или #elif. Например,#include <stdio.h>#define TED 10int main(void){#ifdef TEDprintf("Привет, Тед\n");#elseprintf("Привет, кто-нибудь\n");#endif#ifndef RALPHprintf("А RALPH не определен, т.ч. Ральфу не повезло.\n");#endifreturn 0;}выведет Привет, Тед, а также A RALPH не определен, т.ч.
Ральфу не повезло.Написать Makefile для сборки следующей многомодульной программы. Также указать, что будетвыведено на экран в результате работы итоговой программы (в случае неоднозначности указать всевозможные варианты).main.cAsm1.asmAsm2.asm#include <stdio.h>section .textsection .text#include "Asm1.h"#include "Asm2.h"int main() {printf("%d",F1( )+F2( ));return 0;}global F1F1:xor eax,eaxor eax, 25retglobal F2F2:mov eax, 40inc eaxretAsm1.hint F1(void);Asm2.hint F2(void);program: main.o asm1.o asm2.ogcc -o program main.o asm1.o asm2.omain.o: asm1.h asm2.hasm1.o: asm1.asmnasm -f win32 -o asm1.o asm1.asmasm2.o: asm2.asmnasm -f win32 -o asm2.o asm2.asmВывод: 66.