Создание Общедоступной Библиотеки с ld

 

Чтобы создавать общедоступную библиотеку от одного или большее количество PIC объектные файлы, используйте линкер ld, с -b опцией. По умолчанию, ld назовет библиотеку а.out. Вы можете изменять название с -o опцией.

Например, предположите, что Вы имеете три исходных файла C, содержащие подпрограммы, чтобы делать длину, объем, и массовые преобразования модуля. Они названы length.c, volume.c, и mass.c, соответственно. Делать общедоступную библиотеку от этих исходных файлов, сначала компилируют все три файла, использующие +z опцию, затем комбинируют заканчивающиеся.o файлы с ld. Показаны ниже команды, которые Вы использовали бы, чтобы создать общедоступную библиотеку, названную libunits.sl:

 $ cc -Aa -c + z length.c volume.c mass.c

length.c:

volume.c:

mass.c:c:    

 $ ld -b -o libunits.sl length.o volume.o mass.o

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

 $ chmod +r+x libunits.sl

Например, если Вы имеете программу c названным convert.c, который вызываетподпрограммы с libunits.sl, Вы могли бы компилироватьИ связь это с командой cc:

 

$ cc -Aa convert.c libunits.sl

 

Как только выполнимая программа создана, библиотека не должна быть перемещена потому что

абсолютное имя пути библиотеки сохранено в выполнимой программе

 

Модифицирование Общедоступной Библиотеки

 

Команда ld не может заменять или удалять объектные модули в общедоступной библиотеке. Поэтому, чтобы модифицировать общедоступную библиотеку, Вы должны повторно связать библиотеку со всеми объектными файлами, которые Вы хотите, чтобы библиотека включила. Например, предположите, что Вы устанавливаете некоторые подпрограммы в length.c (от предыдущего раздела) которые давали неправильные результаты. Чтобы модифицировать libunits.sl библиотеку, чтобы включить эти изменения(замены), Вы использовали бы этот ряд команд:д:

  $ cc -Aa -c + z length.c

$ ld -b -o libunits.sl length.o volume.o mass.o

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

Это - одно из преимуществ общедоступных библиотек по библиотекам архива: если Вы изменяете(заменяете) библиотеку архивов, Вы должны повторно связать любые программы, которые используют библиотеку архивов. С общедоступными библиотеками, Вы должны только освежить библиотеку.

 

 

Применение make

Создание программы частенько начинается с маленького однофайлового проекта. Проходит некоторое время и проект, как снежный ком, начинает обрастать файлами, заголовками, подключаемыми библиотеками, требуемыми опциями компиляции... и для его сборки становится уже недостаточным сказать "cc -o file file.c". Когда же, через пару дней, однажды набранная магическая строчка, содержащая все необходимые для сборки проекта параметры компилятора, таинственно исчезает в недрах истории вашего командного интерпретатора, рождается естественное желание увековечить свои знания в виде, к примеру, шелл скрипта. Затем, возможно, захочется сделать этот скрипт управляемым параметрами, чтобы его можно было использовать для разных целей... Однако, чудо юникса состоит в том, что если вам что-то понадобилось, значит кто-нибудь это уже сделал, и пришло время вспомнить о существовании команды make.

 

Рассмотрим несложную программу на C. Пусть программа prog состоит из пары файлов кода main.c и supp.c и используемого в каждом из них файла заголовков defs.h. Соответственно, для создания prog необходимо из пар (main.c defs.h) и (supp.c defs.h) создать объектные файлы main.o и supp.o, а затем слинковать их в prog. При сборке вручную, выйдет что-то вроде:

 

cc -c main.c defs.h

cc -c supp.c defs.h

cc -o prog main.o supp.o

 

Если мы в последствии изменим defs.h, нам понадобится полная перекомпиляция, а если изменим supp.c, то повторную компиляцию main.о можно и не выполнять. Казалось бы, если для каждого файла, который мы должны получить в процессе компиляции указать, на основе каких файлов и с помощью какой команды он создается, то пригодилась бы программа, которая во-первых, собирает из этой информации правильную последовательность команд для получения требуемых результирующих файлов и, во-вторых, инициирует создание требуемого файла только в случае, если такого файла не существует, или он старше, чем файлы от которых он зависит. Это именно то, что делает команда make! Всю информацию о проекте make черпает из файла Makefile, который обычно находится в том же каталоге, что и исходные файлы проекта.

 

Простейший Makefile состоит из синтаксических конструкций всего двух типов: целей и макроопределений.

 

Цель в Makefile - это файл(ы), построение которого предполагается в процессе компиляции проекта. Описание цели состоит из трех частей: имени цели, списка зависимостей и списка команд интерпретатора sh, требуемых для построения цели. Имя цели - непустой список файлов, которые предполагается создать. Список зависимостей - список файлов, из которых строится цель. Имя цели и список зависимостей составляют заголовок цели, записываются в одну строку и разделяются двоеточием. Список команд записывается со следующей строки, причем все команды начинаются с обязательного символа табуляции. Возможна многострочная запись заголовка или команд через применение символа "\" для экранирования конца строки. При вызове команды make, если ее аргументом явно не указана цель, будет обрабатываться первая найденная в Makefile цель, имя которой не начинается с символа ".". Примером для простого Makefile может послужить уже упоминавшаяся программа prog:

 

prog: main.o supp.o

                cc -o prog main.o supp.o

main.o supp.o: defs.h

 

В прведенном примере можно заметить ряд особенностей: в имени второй цели указаны два файла и для этой же цели не указана команда компиляции, кроме того, нигде явно не указана зависимость объектных файлов от "*.c"-файлов. Дело в том, что команда make имеет предопределенные правила для получения файлов с определенными суффиксами. Так, для цели - объектного файла (суффикс ".o") при обнаружении соответствующего файла с суффиксом ".c", будет вызван компилятор "сс -с" с указанием в параметрах этого ".c"-файла и всех файлов - зависимостей. Более того, в этом случае явно не указанные ".c"-файлы make самостоятельно внесет в список зависимостей и будет реагировать их изменение так же, как и для явно указанных зависимостей. Впрочем, ничто не мешает указать для данной цели альтернативную команду компиляции.

 

Вы вероятно заметили, что в приведенном Makefile одни и те же объектные файлы перечисляются несколько раз. А что, если к ним добавится еще один? Для упрощения таких ситуаций make поддерживает макроопределения.

 

Макроопределение имеет вид "ПЕРЕМЕННАЯ = ЗНАЧЕНИЕ". ЗНАЧЕНИЕ может являться произвольной последовательностью символов, включая пробелы и обращения к значениям уже определенных переменных. В дальнейшем, в любом месте Makefile, где встретится обращение к переменной-макроопределению, вместо нее будет подставлено ее текущее значение. Обращение к значению переменной в любом месте Makefile выглядит как $(ПЕРЕМЕННАЯ) (скобки обязательны, если имя переменной длиннее одного символа). Значение еще не определенных переменных - пустая строка. С учетом сказанного, можно преобразовать наш Makefile:

 

OBJS = main.o supp.o

prog: $(OBJS)

                cc -o prog $(OBJS)

$(OBJS): defs.h

 

Теперь предположим, что к проекту добавился второй заголовочный файл supp.h, который включается только в supp.c. Тогда Makefile увеличится еще на одну строчку:

 

supp.o: supp.h

 

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

 

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

 

OBJS = main.o supp.o

prog: $(OBJS)

                cc -o prog $(OBJS)

main.o: defs.h

supp.o: defs.h supp.h

 

Обычно Makefile пишется так, чтобы простой запуск make приводил к компиляции проекта, однако, помимо компиляции, Makefile может использоваться и для выполнения других вспомогательных действий, напрямую не связанных с созданием каких-либо файлов. К таким действиям относится очистка проекта от всех результатов компиляции, или вызов процедуры инсталляции проекта в системе. Для выполнения подобных действий в Makefile могут быть указаны дополнительные цели, обращение к которым будет осуществляться указанием их имени аргументом вызова make (например, "make install"). Подобные вспомогательные цели носят название фальшивых, что связанно с отсутствием в проекте файлов, соответствующих их именам. Фальшивая цель может содержать список зависимостей и должна содержать список команд для исполнения. Поскольку фальшивая цель не имеет соответствующего файла в проекте, при каждом обращении к ней make будет пытаться ее построить. Однако, возможно возникновение конфликтной ситуации, когда в каталоге проекта окажется файл с именем, соответствующим имени фальшивой цели. Если для данного имени не определены файловые зависимости, он будет всегда считаться актуальным (up to date) и цель выполняться не будет. Для предотвращения таких ситуаций make поддерживает "встроенную" переменную ".PHONY", которой можно присвоить список имен целей, которые всегда должны считаться фальшивыми.

 

Теперь можно привести пример полного Makefile, пригодного для работы с проектом prog и принять во внимание некоторые часто применяемые приемы:

 

OBJS = main.o supp.o

BINS = prog

PREFIX = /usr/local

 

INSTALL = install

INSOPTS = -s -m 755 -o 0 -g 0

CC = gcc

.PHONY = all clean install

 

all: $(BINS)

 

prog: $(OBJS)

                $(CC) -o prog $(OBJS)

 

main.o: defs.h

 

supp.o: defs.h supp.h

 

clean:

                rm -f $(BINS)

                rm -f $(OBJS)

                rm -f *~

                    

install: all

                for $i in $(BINS); do \

                 $(INSTALL) $(INSOPTS) $$i $(PREFIX)/bin; \

                done

 

Итак, у нас появились три фальшивых цели: all, clean и install. Цель all обычно используется как псевдоним для сборки сложного проекта, содержащего несколько результирующих файлов (исполняемых, разделяемых библиотек, страниц документации и т.п.). Цель clean используется для полной очистки каталога проекта от результатов компиляции и "мусора" - резервных файлов, создаваемых текстовыми редакторами (они обычно заканчиваются символом "~"). Цель install используется для инсталляции проекта в операционной системе (приведенный пример расчитан на установку только исполняемых файлов). Следует отметить повсеместное использование макроопределений - помимо всего, этот прием повышает читабельность. Обратите также внимание на определение переменной $(CC) - это встроенная переменная make и она неявно "сработает" и при компиляции объектных файлов.

Внутренние макросы
Мake поддерживает пять внутренних макросов, полезных при написании правил построения целевых файлов:

$*

Этот макрос является именем файла без расширения из текущей зависимости; вычисляется только для подразумеваемых правил (см. Суффиксы).

$@

Этот макрос заменяется на полное имя целевого файла; вычисляется только для явно заданных зависимостей.

$<

Вычисляется только для подразумеваемых правил или для правила.DEFAULT. Этот макрос заменяется на имя файла, от которого по умолчанию зависит целевой файл. Так, в правиле.c.o макрос $< будет заменен на имя файла с расширением.c. Например, правило для изготовления оптимизированного об ектного файла из файла с расширением.c может быть таким:

 

       .c.o:

 

          cc -c -O $*.c

 

или

 

         .c.o:

 

           cc -c -O $<

 

$?

Макрос $? можно использовать в явных правилах make-файла. Этот макрос заменяется на список файлов-источников, которые изменялись позднее целевого файла.

$%

Этот макрос применяется только тогда, когда целевой файл указан в виде библ(файл.o), что означает, что он находится в библиотеке библ. В этом случае $@ заменяется на библ (имя архива), а $% заменяется на настоящее имя файла, файл.o.

Четыре из этих макросов имеют альтернативную форму. Если к любому из этих макросов добавлено F, то он заменяется на соответствующее макросу имя файла без имени каталога; если же добавлено D, то макрос заменяется на остальную часть значения первоначального макроса без последнего символа /, то есть на имя каталога. Так, $(@D) соответствует каталогу из $@. Если каталог не указан, то генерируется текущий каталог (.). Только макрос $? не имеет альтернативной формы.


Библиотеки

Если целевой файл или имя из списка зависимостей содержит скобки, то оно рассматривается как имя архивной библиотеки, а цепочка символов в скобках - как имя элемента библиотеки. Так, и библ(файл.o), и $(БИБЛ)(файл.o) обозначают библиотеку, содержащую файл.o (предполагается, что макрос БИБЛ был предварительно определен). Выражение $(БИБЛ)(файл1.o файл2.o) недопустимо. Правила обработки библиотечных файлов имеют вид.XX.a, где XX - суффикс, по которому будет получен элемент библиотеки. К сожалению, в текущей реализации требуется, чтобы XX отличался от суффикса элемента библиотеки. Например, нельзя, чтобы библ(файл.o) зависел от файл.o явно. Наиболее общее использование интерфейса работы с библиотеками следующее (предполагается, что исходными являются файлы на языке C):

 

 

lib: lib(file1.o) lib(file2.o) lib(file3.o)

 

   @echo lib is now up-to-date

 

.c.a:

 

   $(CC) -c $(CFLAGS) $<

 

   $(AR) $(ARFLAGS) $@ $*.o

 

   rm -f $*.o

 

 

Фактически, правило.c.a, приведенное выше, встроено в make. Более интересный, но более ограниченный пример конструкции, поддерживающей работу с библиотеками:

 

 

lib: lib(file1.o) lib(file2.o) lib(file3.o)

 

   $(CC) -c $(CFLAGS) $(?:.o=.c)

 

   $(AR) $(ARFLAGS) lib $?

 

   rm $? @echo lib is now up-to-date

 

.c.a:;

 

 

Здесь используется режим подстановки расширений макросов. Список $? определен как множество имен об ектных файлов (в библиотеке lib), чьи исходные C-файлы были изменены. Подстановка заменяет.o на.c. (К сожалению, нельзя еще трансформировать в.c~; однако, это может стать возможно в будущем). Заметим также, что запрещается правило.c.a:, создающее каждый об ектный файл один за другим. Эта конструкция значительно ускоряет обновление библиотек, но становится весьма громоздкой, если библиотека содержит как программы на C, так и на ассемблере.

 

Отладчик ADB

Вызов ADB

Dызываетcz ADB, выполняя adb (1) команду. Синтаксис:

adb [-w] [-k] [-Idir] [-Ppid ] [objfile [corefile]

Где:

-w                        Разрешает запись в объектный файл.                                                                                                        

-k                        Сообщает ADB, что объектные и основные файлы являются файлами ядра, так что ADB может исполнять соответствующее управление памятью.                                                                                                                                  

-Idir                    Определяет каталоги, который содержит команды для ADB.                                                          

-Ppid                   "Принимают" уже процесс выполнения для отладки.                                                                          

objfile                Называет выполнимый объектный файл.                                                                                                

corefile               Называет основной загрузочный модуль.                                                                                               

Обычно, вызывая ADB:

Adb a.out core

Или более просто:

Adb

Потому что настройка по умолчанию для объектного файла - a.out, и core файл - core.

Поставка знаку "минус" (-) для средств названия(имени) файла " игнорирует этот параметр, " как в:

Adb a.out -

Чтобы записывать в объектный файл при игнорировании core файла, можна напечатать:

Adb -w a.out -

Чтобы отлаживать выполняющийся в настоящее время процесс, вызовите ADB, печатая:

Adb -Ppid a.out

Pid или " идентификатор процесса " может быть получен, используя ps (1) команда.

Потому что ADB прерывает нажатия клавиши, Вы не можете использовать сигнал выхода из, чтобы выйти от ADB. Вы должны использовать явный запрос ADB $q или $Q (или CONTROL D) чтобы выйти от ADB.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: