- ENTRYPOINT vs CMD: назад к основам
- Факт 1: Требуется определить хотя бы одну инструкцию ( ENTRYPOINT или CMD ) (для запуска).
- Факт 2: Если во время выполнения определена только одна из инструкций, то и CMD и ENTRYPOINT будут иметь одинаковый эффект.
- Факт 3: И для CMD , и для ENTRYPOINT существуют режимы shell и exec.
- Факт 4: Режим exec является рекомендуемым.
- Факт 5: Нет оболочки? Нет переменных окружения.
- Факт 6: Аргументы CMD присоединяются к концу инструкции ENTRYPOINT … иногда.
- Факт 6a: Если вы используете режим shell для ENTRYPOINT , CMD игнорируется.
- FACT 6b: При использовании режима exec для ENTRYPOINT аргументы CMD добавляются в конце.
- Факт 6c: При использовании режима exec для инструкции ENTRYPOINT необходимо использовать режим exec и для инструкции CMD . Если этого не сделать, Docker попытается добавить sh -c в уже добавленные аргументы, что может привести к некоторым непредсказуемым результатам.
- Факт 7: Инструкции ENTRYPOINT и CMD могут быть переопределены с помощью флагов командной строки.
- Достаточно фактов… Что же делать мне?
- Очистка
- Обратная связь
- Джон Закконе
- Linux Kernel Library: ядро Linux в форм-факторе so или dll
- Первичное знакомство
- Попробуем что-нибудь написать
- Усложняем эксперимент
- Настраиваем параметры сборки LKL
- Позвольте, а где обещанные готовые программки?
- Немного про кросс-платформенность
- Русские Блоги
- Linux Programe/Dynamic Shared Library Entry/Exit Point && Glibc Entry Point/Function
ENTRYPOINT vs CMD: назад к основам
Название ENTRYPOINT всегда меня смущало. Это название подразумевает, что каждый контейнер должен иметь определенную инструкцию ENTRYPOINT . Но после прочтения официальной документации я понял, что это не соответствует действительности.
Факт 1: Требуется определить хотя бы одну инструкцию ( ENTRYPOINT или CMD ) (для запуска).
Если вы не определите ни одной из них, то получите сообщение об ошибке. Давайте попробуем запустить образ Alpine Linux, для которого не определены ни ENTRYPOINT , ни CMD .
Факт 2: Если во время выполнения определена только одна из инструкций, то и CMD и ENTRYPOINT будут иметь одинаковый эффект.
Мы получим те же результаты, если будем использовать CMD вместо ENTRYPOINT .
Хотя этот пример и показывает, что между ENTRYPOINT и CMD нет никакой разницы, её можно увидеть, сравнив метаданные контейнеров.
Например, первый файл Dockerfile (с определенной ENTRYPOINT ):
Факт 3: И для CMD , и для ENTRYPOINT существуют режимы shell и exec.
ENTRYPOINT имеет два режима выполнения:
- ENTRYPOINT [«executable», «param1», «param2»] (исполняемая форма, предпочтительно)
- ENTRYPOINT command param1 param2 (форма оболочки)
До сих пор мы использовали режим shell, или оболочки. Это означает, что наша команда ls -l запускается внутри /bin/sh -c . Давайте попробуем оба режима и изучим запущенные процессы.
Затем изучим процессы:
Обратите внимание, что процесс sh -c имеет PID, равный 1. Теперь то же самое, используя режим «exec»:
Мы видим, что при использовании режима exec команда ping www.google.com работает с идентификатором процесса PID, равным 1, а процесс sh -c отсутствует. Имейте в виду, что приведенный выше пример работает точно так же, если использовать CMD вместо ENTRYPOINT .
Факт 4: Режим exec является рекомендуемым.
Это связано с тем, что контейнеры задуманы так, чтобы содержать один процесс. Например, отправленные в контейнер сигналы перенаправляются процессу, запущенному внутри контейнера с идентификатором PID, равным 1. Очень познавательный опыт: чтобы проверить факт перенаправления, полезно запустить контейнер ping и попытаться нажать ctrl + c для остановки контейнера.
Контейнер, определенный с помощью режима exec, успешно завершает работу:
При использовании режима «shell» контейнер работает не так, как ожидалось.
Помогите, я не могу выйти! Сигнал SIGINT , который был направлен процессу sh , не будет перенаправлен в подпроцесс ping , и оболочка не завершит работу. Если по какой-то причине вы действительно хотите использовать режим shell, выходом из ситуации будет использовать exec для замены процесса оболочки процессом ping .
Факт 5: Нет оболочки? Нет переменных окружения.
Проблема запуска НЕ в режиме оболочки заключается в том, что вы не можете воспользоваться преимуществами переменных среды (таких как $PATH ) и прочими возможностями, которые предоставляет использование оболочки. В приведенном ниже файле Dockerfile присутствуют две проблемы:
Первая проблема: поскольку вы не можете воспользоваться переменной среды $PATH , нужно указать точное расположение исполняемого java-файла. Вторая проблема: символы подстановки интерпретируются самой оболочкой, поэтому строка *.jar не будет корректно обработана. После исправления этих проблем итоговый файл Dockerfile выглядит следующим образом:
Факт 6: Аргументы CMD присоединяются к концу инструкции ENTRYPOINT … иногда.
Вот тут-то и начинается путаница. В руководстве есть таблица, цель которой – внести ясность в этот вопрос.
Попытаюсь объяснить на пальцах.
Факт 6a: Если вы используете режим shell для ENTRYPOINT , CMD игнорируется.
Строка blah blah blah blah была проигнорирована.
FACT 6b: При использовании режима exec для ENTRYPOINT аргументы CMD добавляются в конце.
Аргумент /var был добавлен к нашей инструкции ENTRYPOINT , что позволило эффективно запустить команду ls/usr/var .
Факт 6c: При использовании режима exec для инструкции ENTRYPOINT необходимо использовать режим exec и для инструкции CMD . Если этого не сделать, Docker попытается добавить sh -c в уже добавленные аргументы, что может привести к некоторым непредсказуемым результатам.
Факт 7: Инструкции ENTRYPOINT и CMD могут быть переопределены с помощью флагов командной строки.
Флаг —entrypoint может быть использован, чтобы переопределить инструкцию ENTRYPOINT :
Все, что следует после названия образа в команде docker run , переопределяет инструкцию CMD :
Все вышеперечисленные факты справедливы, но имейте в виду, что разработчики имеют возможность переопределять флаги в команде docker run . Из этого следует, что .
Достаточно фактов… Что же делать мне?
Ok, если вы дочитали статью до этого места, то вот информация, в каких случаях использовать ENTRYPOINT , а в каких CMD .
Это решение я собираюсь оставить на усмотрение человека, создающего Dockerfile, который может быть использован другими разработчиками.
Используйте ENTRYPOINT , если вы не хотите, чтобы разработчики изменяли исполняемый файл, который запускается при запуске контейнера. Вы можете представлять, что ваш контейнер – исполняемая оболочка. Хорошей стратегией будет определить стабильную комбинацию параметров и исполняемого файла как ENTRYPOINT . Для нее вы можете (не обязательно) указать аргументы CMD по умолчанию, доступные другим разработчикам для переопределения.
Запуск с параметрами по умолчанию:
Переопределение CMD собственными параметрами:
Используйте только CMD (без определения ENTRYPOINT ), если требуется, чтобы разработчики могли легко переопределять исполняемый файл. Если точка входа определена, исполняемый файл все равно можно переопределить, используя флаг —entrypoint . Но для разработчиков будет гораздо удобнее добавлять желаемую команду в конце строки docker run .
Ping – это хорошо, но давайте попробуем запустить контейнер с оболочкой вместо команды ping .
Я предпочитаю по большей части этот метод, потому что он дает разработчикам свободу легко переопределять исполняемый файл оболочкой или другим исполняемым файлом.
Очистка
После запуска команд на хосте осталась куча остановленных контейнеров. Очистите их следующей командой:
Обратная связь
Буду рад услышать ваши мысли об этой статье ниже в комментариях. Кроме того, если вам известен более простой способ поиска в выдаче докера с помощью jq, чтобы можно было сделать что-то вроде docker inspect [id] | jq * .config , тоже напишите в комментариях.
Джон Закконе
Капитан Докера и инженер по облачным технологиям в IBM. Специализируется на Agile, микросервисах, контейнерах, автоматизации, REST, DevOps.
Источник
Linux Kernel Library: ядро Linux в форм-факторе so или dll
Когда-то читал статью о выборе файловых систем «чтоб везде-везде работало». В ней в очередной раз увидел жалобы, что Ext4 замечательная файловая система, но на Windows есть только кривые неточные проприетарные драйверы. Но отмотаем ленту ещё на пару лет назад: тогда на Хабре (а в те времена — Гиктаймсе) пролетала новость про LibOS — попытку превратить Linux kernel в обычную библиотеку пользовательского режима. Упор там делался на вынос сетевого стека в user space. Как-то раз я решил поглядеть, а жив ли вообще проект, и в их блоге увидел ссылку на своего рода конкурента — проект Linux Kernel Library (LKL). По сути, это порт ядра, так сказать, на аппаратную архитектуру «библиотека пользовательского режима POSIX / Win32».
Чем интересна LKL? Во-первых тем, что она живёт и здравствует, пусть и не в основной кодовой базе ядра. Во-вторых, это более-менее честная поддержка «архитектуры», автоматически делающая доступной бОльшую часть ядра. Более того, прямо в комплекте идут утилиты-примеры: cptofs / cpfromfs , fs2tar , lklfuse . В этой статье мы протестируем LKL на хостовом Linux, заглянем в файл с образом Ext4 (Btrfs, XFS. ) без рута и виртуалок и коротко обсудим, как её можно попробовать на Windows.
DISCLAIMER 1: Захотите попробовать — делайте бекапы. Если вы захотите проделать такое с разделом с важными данными — на свой страх и риск. Впрочем, здесь хотя бы драйверы будут реально родные.
DISCLAIMER 2: Уважайте лицензии. Вероятно, линковка с LKL делает вашу программу GPL’ной.
Первичное знакомство
Репозиторий LKL (lkl/linux на GitHub) представляет из себя форк обычного Linux kernel, в котором добавлена поддержка ещё одной архитектуры, в основном мы будет видеть это в каталогах arch/lkl и tools/lkl . Сделаем клон репозитория и попробуем собрать по инструкции. Для экспериментов я буду использовать shallow clone, который содержит не всю историю репозитория, а лишь указанное количество последних коммитов:
Пришлось чуточку поправить исходник, но в итоге получилась библиотека tools/lkl/lib/liblkl.so (а ещё — статическая tools/lkl/liblkl.a ):
А где же системные вызовы, спросите вы. Без паники, они спрятаны за общей точкой входа lkl_syscall . Это такой аналог функции syscall для LKL. В реальной же ситуации в большинстве случаев вы будете использовать типизированные обёртки lkl_sys_ . Также мы видим всякие функции для настройки «ядра», добавления в него виртуальных устройств, а также обёртки над «сложными» системными вызовами, в обычной системе предоставляемые libc. Например, есть такой системный вызов getdents , но… «These are not the interfaces you are interested in.» — с порога говорит нам man-страница. В обычных же случаях предполагается использовать стандартную библиотечную функцию readdir (3) , но не путайте её с readdir (2) — древним системным вызовом, который на x86_64 даже не реализован. В случае же работы с LKL вам потребуются обёртки lkl_opendir / lkl_readdir / lkl_closedir .
Попробуем что-нибудь написать
Напоминаю, уважайте лицензии. Сам Linux kernel распространяется под GPL2, будет ли программа, дёргающая за относительно публичные интерфейсы LKL считаться производной работой — я не знаю.
Что же, давайте попробуем слинковаться с библиотекой. Предполагается, что переменной $LKL присвоен путь до репозитория со скомпилированной LKL.
Можно даже видеть по timestamp’ам, что ядро не просто «выплюнуло» в консоль этот текст, а красиво постепенно грузилось как настоящее .
Усложняем эксперимент
Давайте теперь попробуем как-то по-настоящему использовать эту библиотеку — всё-таки целое ядро ОС! Попробуем чисто в user space прочитать файл с Ext4-раздела. Причём «родным» драйвером! За основу возьмём tools/lkl/cptofs.c и реализуем только самое необходимое (для наглядности):
Обратите внимание на переименованные define’ы с префиксами LKL_ (например, LKL_O_RDONLY ): на Linux-хосте они, скорее всего, совпадают с теми, что без префиксов, а вот на других системах — не факт.
Ух ты, работает! А что-нибудь более экзотическое?
Ой! Хотя, постойте, мы же, наверное, просто не включили в наше ядро-библиотеку поддержку SquashFS!
Настраиваем параметры сборки LKL
Для себя я выработал такую последовательность команд, которая работает для LKL — возможно, её можно сократить вплоть до традиционного make defconfig , make menuconfig , make .
В данном случае, правда, даже перекомпилировать read-file.c едва ли было нужно — библиотека-то динамическая.
Позвольте, а где обещанные готовые программки?
И действительно, в каталоге tools/lkl лежат cptofs.c , fs2tar.c и ещё много интересного, но оно не собирается! Порывшись в Makefile’ах я обнаружил, что есть некий Makefile.autoconf , который ищет требуемые заголовочные файлы, и Makefile.conf , куда это всё записывается.
Так-с, кто-то хочет libarchive , кто-то libfuse — ну что же, поставим libarchive-dev , libfuse-dev (в случае Ubuntu) и пересоберём. Всё равно не получается… А если удалить Makefile.conf … Опа, собралось!
Итак, что же теперь у нас есть? Теперь в каталоге tools/lkl у нас есть cptofs , fs2tar и lklfuse .
Для начала скопируем cptofs под именем cpfromfs :
Как говорится, «Как вы яхту назовёте. ». Запускаем.
Хмм… Надо посмотреть… Впрочем, для интерактивного использования оно всё равно неудобно, поскольку каждый раз приходится ждать около секунды, пока ядро загрузится. Зато fs2tar работает без проблем:
Но самая интересная программа здесь на мой взгляд — это lklfuse :
По-моему, впечатляет: можно без рута (но тут зависит от настроек системы) подмонтировать файловую систему через FUSE, поработать с ней, отмонтировать — а потом подключить к хостовому ядру (уже с рутом) и продолжить, как ни в чём не бывало.
Мало того, что lklfuse позволяет обычному пользователю подмонтировать раздел с помощью штатного драйвера ядра. Хостовое ядро вообще не обязано быть собрано с поддержкой этой ФС. Да что уж там, не удивлюсь, если это всё точно так же заведётся на OS X.
Немного про кросс-платформенность
А что же с доступом к линуксовым ФС из других операционных систем? На OS X, думаю, будет попроще: всё-таки она полноценный UNIX, да и поддержка FUSE, вроде, есть. Так что есть надежда, что оно заведётся с ходу. Если нет, я бы посмотрел в сторону проверки того, везде ли в системные вызовы LKL передаются константы с префиксами LKL_ , а не их хостовые аналоги.
С Windows несколько сложнее: во-первых, там банально может не быть некоторых привычных в мире UNIX библиотек (например, для разбора аргументов командной строки). Во-вторых, нужно понять, как подмонтироваться к хостовому дереву файловых систем. Самое простое было бы — так же через FUSE. Говорят, когда-то был некий Dokan, сейчас тоже что-то есть, но нужно гуглить. Главное, что сама LKL на Windows собирается, нужно только учесть, что ей требуется 64-битный тип long для работы в 64-битном режиме, поэтому не каждый компилятор подойдёт (по крайней мере, так написано в текущем readme проекта).
Источник
Русские Блоги
Linux Programe/Dynamic Shared Library Entry/Exit Point && Glibc Entry Point/Function
содержание
1. Введение
0x1: glibc
glibc — это библиотека libc, выпущенная GNU, то есть библиотека времени выполнения c. glibc — это самый низкий api в системе Linux, и почти любая другая библиотека времени выполнения будет зависеть от glibc. Помимо инкапсуляции системных служб, предоставляемых операционной системой Linux, сама glibc также обеспечивает реализацию многих других необходимых функциональных служб. Поскольку glibc включает почти все распространенные стандарты UNIX, ее содержание является всеобъемлющим. И, как и в других системах UNIX, содержащиеся в нем группы файлов разбросаны по древовидной структуре каталогов системы, поддерживая всю операционную систему как скобку.
Основные функции, реализованные в Glibc, следующие:
0x2: Код инициализации и завершения
Следует понимать, что для исполняемых файлов и общих объектов они, по сути, представляют собой набор исполняемого кода, единственная разница в том, что
Независимо от выполнения исполняемого файла или общего объекта, загружаемого в исполняемый файл, все они имеют соответствующий «код инициализации» и «код завершения».
Инициализация и завершение ELF объединены библиотекой времени выполнения Glibc.
0x3: Базовый процесс работы программы Linux
Relevant Link:
Процесс запуска Glibc сильно различается в разных ситуациях, разница между статическим / динамическим glibc и исполняемыми файлами / файлами общей библиотеки. 4 ситуации можно комбинировать
2. Библиотека времени выполнения C / C ++
Библиотека времени выполнения (Runtime Library) в области компьютерного программирования относится к специальной библиотеке компьютерных программ, используемой компилятором для реализации встроенных функций языка программирования для обеспечения поддержки выполнения (выполнения) языковой программы. Такие библиотеки обычно включают поддержку базового ввода и вывода или управления памятью. Это группа функций, которые поддерживают запущенную программу и взаимодействуют с операционной системой для обеспечения таких функций, как математические операции, ввод и вывод, так что программистам не нужно «изобретать колесо» и эффективно использовать предоставленные функции. операционной системой
Библиотека времени выполнения определяется компилятором для обеспечения самых основных потребностей выполнения языка программирования.
0x1: библиотека времени выполнения на языке C
Любая программа на C имеет за собой огромную библиотеку кода, чтобы программа работала нормально. Такая библиотека коллекции кода называется «Библиотека времени выполнения», а библиотека времени выполнения языка C, которая называется библиотекой времени выполнения C (CRT), эта библиотека кода. включает
Среди компонентов этих библиотек времени выполнения стандартная библиотека языка C. Стандартная библиотека языка C — это базовая библиотека функций, стандартизированная языком C. Например, printf, exit и т. Д. Являются частью стандартной библиотеки. Стандартная библиотека определяет набор функций, которые повсеместно используются в языке C. Программисты могут напрямую использовать функции, указанные в стандартной библиотеке, не беспокоясь о переносе кода на другие платформы. Соответствующая платформа не предоставляет эту функцию.
Стандартная библиотека ANSI C состоит из 24 файлов заголовков C. В отличие от стандартных библиотек многих других языков (например, java), стандартная библиотека языка C очень легкая. Она содержит только математические функции, обработку символов / строк, I / O и другие основные аспекты, такие как
0x2: glibc && MSVC CRT
Библиотека времени выполнения зависит от платформы и очень тесно интегрирована с операционной системой. Библиотека времени выполнения языка C — это уровень абстракции между языком C и различными платформами операционных систем из определенной программы. Она абстрагирует различные API-интерфейсы операций в одну и ту же библиотечную функцию. Например, программисты могут использовать fread для чтения на разных платформах. Получение файлов без учитывая, что реализация на уровне операционной системы другая. Хотя библиотеки времени выполнения языка C на различных платформах предоставляют множество функций, они часто ограничены. Например, контроль разрешений пользователя, создание потока операционной системы и другие операции не являются частью стандартной библиотеки времени выполнения языка C. В этом случае у нас есть для обхода среды выполнения языка C для прямого вызова API системного вызова операционной системы или использования других библиотек. Это также вызывает смешанное использование API времени выполнения C и API системных вызовов в программе.
Glibc (библиотека GNU C) — основная библиотека времени выполнения на платформе Linux, MSVCRT (среда выполнения Microsoft Visual C)
Relevant Link:
3. Статическая функция ввода / завершения исполняемого файла Glibc &&
В случае статического Glibc, скомпилированного в исполняемый файл, программной записью glibc является _start (), которая указывается скриптом ссылки по умолчанию для компоновщика ld. _start () реализуется сборкой и зависит от платформы
\glibc-2.18\sysdeps\i386\start.S
Таким образом, мы можем переписать _start в более читаемый псевдокод.
Функция, которая фактически выполняет код, — это __libc_start_main.
\glibc-2.18\csu\libc-start.c
Последняя функция _exit реализуется сборкой и связана с платформой. Это может быть перехваченное прерывание или вызов sysenter. Видно, что функция _exit () предназначена только для вызова системного вызова выхода. После вызова _exit, процесс будет сразу End, программа завершится нормально в 2 случаях
Стоит отметить, что в конце _start и _exit есть инструкция hlt. Это связано с тем, что в Linux процесс должен быть завершен с помощью системного вызова eixt. После вызова exit выполнение программы будет прекращено.
Инструкция hlt в _exit предназначена для проверки успешности системного вызова exit. В случае сбоя программа не завершится. Функция инструкции hlt — принудительно остановить программу. То же самое и с hlt в _start. Чтобы предотвратить бесполезный выход и возврат к _start (например, выход в конце __libc_main_start был ошибочно удален)
Relevant Link:
4. Функция динамического ввода / завершения исполняемого файла Glibc &&
5. Статическая функция входа / завершения в разделяемой библиотеке Glibc &&
6. Функция динамического входа / завершения работы с разделяемой библиотекой Glibc &&
Мы знаем, что инициализация исполняемой программы ELF выполняется Glibc, а загрузка и инициализация динамической разделяемой библиотеки выполняется «динамическим загрузчиком (ld-linux-so.2)».
Точкой входа динамического компоновщика является _start, который определен в макросе RTLD_START в glibc / sysdeps / i386 / dl-machine.h. Сначала он вызывает _dl_start ()
_dl_start () сначала перемещает сам динамический компоновщик и, наконец, вызывает _dl_start_final ()
_dl_start_final()Собрав некоторую базовую информацию о времени выполнения, позвоните_dl_sysdep_start()
dl_main () очень длинный. Основная задача — загрузить все общие объекты, от которых зависит исполняемый файл, построить таблицу символов и выполнить перемещение во время загрузки (некоторые перемещения могут быть отложены до тех пор, пока они не понадобятся, это называется перемещением времени выполнения)
После завершения перемещения вернитесь к _dl_sysdep_start (), затем вернитесь к _dl_start_final (), затем вернитесь к _dl_start (), продолжайте возвращаться к _start
После завершения задачи динамического компоновщика управление будет передано пользовательской программе. В это время пользовательская программа только начинает выполняться. Весь процесс выглядит следующим образом
0x1: функция инициализации и завершения разделяемой библиотеки
В Win32 DllMain можно использовать для инициализации и завершения работы, в то время как в Linux нет соответствующей ему функции. Однако некоторые методы могут использоваться для моделирования некоторых его функций, то есть для реализации двух функций _init / _fini.
Однако мы напрямую переписываем / реализуем эти две функции в программе, например: test.c
Видно, что эти два символа были подхвачены строительным кодом компилятора, и мы больше не можем их использовать. Эти две функции используются для инициализации / уничтожения инициализированных глобальных переменных / объектов, вытеснение этих двух функций может привести к инициализации / уничтожению инициализации глобальных переменных / объектов, ошибок.
В C ++ мы можем использовать конструктор и деструктор класса для завершения инициализации и завершения, но в языке C вообще нет конструкции и деструктора, мы можем использовать расширение gcc
Relevant Link:
0x2: Влияние метода объявления функции инициализации / завершения разделяемого объекта на последовательность вызовов инициализации / завершения.
1. Используйте модификатор GCC, чтобы объявить функцию инициализации (нестандартное имя функции).
Используйте этот метод, чтобы объявить функцию инициализации. Следует отметить, что вызов функции инициализации «do_init» не будет выполнен до того, как будут вызваны другие функции so.
2. Используйте модификатор GCC, чтобы объявить функцию инициализации (стандартное имя функции).
3. Объявите функцию инициализации напрямую (стандартное имя функции).
Relevant Link:
7. Статическая библиотека / общая библиотека -> компилировать / использовать, динамическая загрузка
0x1: статическая библиотека
Суть статической библиотеки состоит в том, чтобы упаковать несколько объектных файлов в один файл. Связывание статической библиотеки при использовании означает копирование вызываемого кода в библиотеке в вызывающий модуль. Преимущество заключается в том, что код, использующий статическую библиотеку, не должен полагаться на библиотеку во время выполнения, а эффективность выполнения высока. Недостатком является то, что статическая библиотека занимает большое пространство, и код в библиотеке необходимо повторно связать один раз. это модифицировано
1. Скомпилируйте и сгенерируйте статическую библиотеку.
math.h (интерфейсный файл)
calc.c (модуль расчета)
show.c (модуль дисплея)
Компилировать исходные файлы C в объектные файлы
Упакуйте целевой файл в файл статической библиотеки
После успешного создания статической библиотеки вам нужно только предоставить libmath.a и math.h сторонним пользователям, потому что libmath.a содержит код логики реализации функции и оператор объявления, который необходимо объявить перед использованием. находится в math.h
2. Используйте статические библиотеки.
Вместе со статическим файлом библиотеки (скопируйте соответствующий код из статической библиотеки в основную программу) для генерации исполняемого файла
0x2: общая библиотека
Самая большая разница между общей библиотекой и статической библиотекой заключается в том, что для связывания общей библиотеки не требуется копировать вызываемый код в библиотеке в вызывающий модуль. Напротив, то, что встроено в вызывающий модуль, — это только относительный адрес вызываемый код в общей библиотеке. Если код в общей библиотеке используется несколькими процессами одновременно, во всем пространстве памяти необходим только один экземпляр общей библиотеки. В этом смысл совместного использования. Преимущество общей библиотеки в том, что она занимает небольшое пространство, даже если библиотека была изменена. Код, пока интерфейс остается неизменным, нет необходимости повторно связывать. Недостаток заключается в том, что код, который использует общую библиотеку, должен полагаться на библиотеку во время выполнения, а выполнение КПД немного ниже.
1. Создание общих библиотек
Источник