5440
Комментарий:
|
18085
|
Удаления помечены так. | Добавления помечены так. |
Строка 102: | Строка 102: |
|| <<MiniPage({{{#!highlight c\n#include <stdio.h>\n#include "outlib.h"\nint main(int argc, char *argv[]) {\n int i;\n if((Count = argc)>1) {\n output("<INIT>");\n for(i=1; i<argc; i++)\n output(argv[i]);\n output("<DONE>");\n }\n else\n usage(argv[0]);\n return 0;\n}\n}}})>> || <<MiniPage({{{#!highlight c\n#include <stdio.h>\n#include "outlib.h"\nvoid output(char *str) {\n printf("%d: %s\012", Count++, str);\n}\n\nvoid usage(char *prog) {\n fprintf(stderr, "%s: Print all arguments\012\t"\\n "Usage: %s arg1 [arg2 […]]\012", prog, prog);\n}\n}}})>> || | || <<MiniPage({{{#!highlight c\n#include <stdio.h>\n#include "outlib.h"\nint main(int argc, char *argv[]) {\n int i;\n if((Count = argc)>1) {\n output("<INIT>");\n for(i=1; i<argc; i++)\n output(argv[i]);\n output("<DONE>");\n }\n else\n usage(argv[0]);\n return 0;\n}\n}}})>> || <<MiniPage({{{#!highlight c\n#include <stdio.h>\n#include "outlib.h"\nvoid output(char *str) {\n printf("%d: %s\012", Count++, str);\n}\n\nvoid usage(char *prog) {\n fprintf(stderr, "%s v%.2f: Print all arguments\012\t"\\n "Usage: %s arg1 [arg2 […]]\012", prog, VERSION, prog);\n}\n}}})>> || |
Строка 104: | Строка 104: |
|| <<MiniPage({{{#!highlight c\nint Count=0;\n}}})>> || <<MiniPage({{{#!highlight c\nvoid output(char *);\nvoid usage(char *);\nextern int Count;\n}}})>> || | || <<MiniPage({{{#!highlight c\nint Count=0;\n}}})>> || <<MiniPage({{{#!highlight c\nvoid output(char *);\nvoid usage(char *);\nextern int Count;\n#define VERSION 0.0\n}}})>> || |
Строка 106: | Строка 106: |
|||| <<MiniPage( {{{#!highlight makefile\nGENERATES = prog README\nTRASH = *.o *~ o.*\n\n%.o: %.c\n cc $< -c -o $@\n\nall: README prog\n\nprog: const.o fun.o prog.o\n cc $^ -o $@\n\nREADME: prog\n ./$< 2> $@\n\nclean:\n rm -f $(TRASH)\n\ndistclean: clean\n rm -rf $(GENERATES)\n}}})>> || * Следуя традиции, мы разделили генераты на совсем ненужные (`TRASH` и собственно целевые файлы проекта (`GENERATES`), которые всё равно стоит удалять, если в репозитории должны остаться только исходники |
||||<(><<MiniPage( {{{#!highlight makefile\nGENERATES = prog README\nTRASH = *.o *~ o.*\n\n%.o: %.c\n cc $< -c -o $@\n\nall: README prog\n\nprog: const.o fun.o prog.o\n cc $^ -o $@\n\nREADME: prog\n ./$< 2> $@\n\nclean:\n rm -f $(TRASH)\n\ndistclean: clean\n rm -rf $(GENERATES)\n}}})>> || * Следуя традиции, мы разделили генераты на совсем ненужные (`TRASH`) и собственно целевые файлы проекта (`GENERATES`), которые всё равно стоит удалять, если в репозитории должны остаться только исходники * Традиционно же цель `all:` в начале файла перечисляет всё, что должно быть собрано (цель в начале считается целью по умолчанию, если `make` запущен без явно заданной цели) * Теперь сама наша программа участвует в генерации файла `README`! Поэтому сборка начнётся не с `README`, а с `prog`, несмотря на то, что в списке целей `all` раньше стоит `README`: {{{#!highlight console $ make cc const.c -c -o const.o cc fun.c -c -o fun.o cc prog.c -c -o prog.o cc const.o fun.o prog.o -o prog ./prog 2> README }}} 1. В нашем Makefile есть недочёт: не все зависимости учтены. Например, при изменении `outlib.h` надо перекомпилировать все файлы, который его включают. Как минимум, `fun.c`, потому что в нём используется константа `VERSION`. Но про это ничего не сказано: {{{#!highlight console $ make … $ vim outlib.h …hack-hack-hack… $ make make: Цель «all» не требует выполнения команд. $ # :(( }}} * Добавим частную зависимость `fun.o: outlib.h` (без рецепта) в `Makefile`, и задача решена: {{{#!highlight console $ touch outlib.h $ make cc fun.c -c -o fun.o cc const.o fun.o prog.o -o prog ./prog 2> README }}} 1. В действительности у `make` есть огромное количество правил по умолчанию, их можно посмотреть с помощью `make -p` * Для шаблонов компиляции используется слегка другой синтаксис (`.c.o:` вместо `%.o: %.c` (выдержка из `make -p`): {{{ .c.o: $(COMPILE.c) $(OUTPUT_OPTION) $< }}} * Действительная команда, которая приводит к компиляции, получается подстановкой переменных `COMPILE.c` и `OUTPUT_OPTION`, которые сами тоже суть результат подстановки… но если коротко, то всё смотрится неплохо: {{{#!highlight make GENERATES = prog README TRASH = *.o *~ o.* all: README prog prog: const.o fun.o prog.o README: prog ./$< 2> $@ fun.o: outlib.h clean: rm -f $(TRASH) distclean: clean rm -rf $(GENERATES) }}} * Мы воспользовались не только шаблоном компиляции, но и шаблоном линковки (у цели `prog` нет рецепта, но `make` догадался, что `.o` надо сделать из `.c`, а `prog` — из этих `.o`): {{{#!highlight console $ make distclean all rm -f *.o *~ o.* rm -rf prog README cc -c -o prog.o prog.c cc -c -o const.o const.c cc -c -o fun.o fun.c cc prog.o const.o fun.o -o prog ./prog 2> README }}} 1. Использование шаблонов довольно гибко управляется: можно подменять флаги сборки на Си (`CFLAGS`) и других языках, флаги компоновки (`LDFLAGS`), название компилятора (`GCC`) и компоновщика, подключаемые библиотеки (`LDLIBS`) и т. п. * Добавим в `Makefile` строку `CFLAGS = -Wall` и пересоберём проект: {{{#!highlight console $ make distclean all rm -f *.o *~ o.* rm -rf prog README cc -Wall -c -o prog.o prog.c cc -Wall -c -o const.o const.c cc -Wall -c -o fun.o fun.c cc prog.o const.o fun.o -o prog ./prog 2> README }}} * Переменные `make` можно переопеределять из командной строки: {{{#!highlight console $ touch fun.c $ make CFLAGS=-Werror LDLIBS=-lm cc -Werror -c -o fun.o fun.c cc prog.o const.o fun.o -lm -o prog ./prog 2> README }}} 1. Статическая библиотека собирается с помощью ''архиватора'' (т. е. программы, которая складывает много файлов в один) `ar`. Так что собрать нашу программу можно и с помощью библиотеки: {{{#!highlight console $ nm *.o const.o: 0000000000000000 B Count fun.o: U Count U fprintf 0000000000000000 T output U printf U stderr 0000000000000033 T usage prog.o: U Count 0000000000000000 T main U output U usage $ ar -rcs libout.a const.o fun.o $ ls -l libout.a -rw-r--r-- 1 frbrgeorge frbrgeorge 3144 окт 5 15:52 libout.a $ ar -tv libout.a rw-r--r-- 500/500 976 Oct 5 15:52 2020 const.o rw-r--r-- 500/500 1944 Oct 5 15:52 2020 fun.o $ nm libout.a const.o: 0000000000000000 B Count fun.o: U Count U fprintf 0000000000000000 T output U printf U stderr 0000000000000033 T usage $ cc -L. -lout prog.o -o prog /usr/bin/ld.default: prog.o: in function `main': prog.c:(.text+0x14): undefined reference to `Count' /usr/bin/ld.default: prog.c:(.text+0x1a): undefined reference to `Count' /usr/bin/ld.default: prog.c:(.text+0x29): undefined reference to `output' /usr/bin/ld.default: prog.c:(.text+0x51): undefined reference to `output' /usr/bin/ld.default: prog.c:(.text+0x67): undefined reference to `output' /usr/bin/ld.default: prog.c:(.text+0x78): undefined reference to `usage' collect2: error: ld returned 1 exit status $ cc -L. prog.o -lout -o prog frbrgeorge@linuxprac ~/LinuxDev2020/04_Multifile_class $ ./prog qwe ert 3: <INIT> 4: qwe 5: ert 6: <DONE> $ nm prog | grep output 00000000004011a5 T output }}} * `.a` — это обычный архив, в который сложен объектники, однако `nm` (анализатор объектников) и `ld` (компоновщик) могут туда залезать! * Обратите внимание на то, какие символы в каком файле определены (`T`) или требуются, но не определены (`U`) * Ключ компоновщика `-lБИБЛИОТЕКА` заставляет искать файл вида `libБИБЛИОТЕКА.a` (или `.so`) в стандартных каталогах с библиотеками. А если каталог нестандартный (например, текущий)), его надо передать с ключом `-LПУТЬ`. * Порядок файлов в компоновке имеет значение: неопределённые символы компоновщик накапливает, а затем ищет в библиотеке, и если библиотека идёт в начала, она игнорируется * В файле `prog` присутствует функция `output`, которая попала туда вместе с `fun.o` * Таким образом у нас получилась '''статическая''' библиотека, которая целиком компонуется с кодом исходной программы 1. Динамическая (`.so`) библиотека имеет совсем другой тип (в некоторых случаях её даже можно запустить), и она подгружется в память в момент запуска программы, а в самой программе не содержится. Собрать её можно, передав компоновщику ключ `-shared`: {{{#!highlight console $ cc -shared fun.o const.o -o libout.so /usr/bin/ld.default: fun.o: перемещение R_X86_64_PC32 для символ «Count» не может использоваться при создании общий объект; перекомпилируйте с параметром -fPIC /usr/bin/ld.default: final link failed: раздел, непредставимый для вывода collect2: error: ld returned 1 exit status $ make distclean CFLAGS=-fPIC prog.o const.o fun.o rm -f *.o *~ o.* *.a *.so rm -rf prog README cc -fPIC -c -o prog.o prog.c cc -fPIC -c -o const.o const.c cc -fPIC -c -o fun.o fun.c $ cc -shared fun.o const.o -o libout.so $ readelf --dyn-syms libout.so Таблица символов «.dynsym» содержит 11 элементов: Чис: Знач Разм Тип Связ Vis Индекс имени 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab 2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.2.5 (2) 3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND fprintf@GLIBC_2.2.5 (2) 4: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 5: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable 6: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.2.5 (2) 7: 0000000000000000 0 OBJECT GLOBAL DEFAULT UND stderr@GLIBC_2.2.5 (2) 8: 0000000000001115 59 FUNC GLOBAL DEFAULT 12 output 9: 000000000000402c 4 OBJECT GLOBAL DEFAULT 23 Count 10: 0000000000001150 57 FUNC GLOBAL DEFAULT 12 usage $ cc -L. prog.o -lout -o prog $ ./prog ./prog: error while loading shared libraries: libout.so: cannot open shared object file: No such file or directory $ LD_DEBUG=libs ./prog 19737: find library=libout.so [0]; searching 19737: search cache=/etc/ld.so.cache 19737: search path=/lib64/tls/haswell/x86_64:/lib64/tls/haswell:/lib64/tls/x86_64:/lib64/tls:/lib64/haswell/x86_64:/lib64/haswell:/lib64/x86_64:/lib64:/usr/lib64/tls/haswell/x86_64:/usr/lib64/tls/haswell:/usr/lib64/tls/x86_64:/usr/lib64/tls:/usr/lib64/haswell/x86_64:/usr/lib64/haswell:/usr/lib64/x86_64:/usr/lib64 (system search path) 19737: trying file=/lib64/tls/haswell/x86_64/libout.so 19737: trying file=/lib64/tls/haswell/libout.so 19737: trying file=/lib64/tls/x86_64/libout.so 19737: trying file=/lib64/tls/libout.so 19737: trying file=/lib64/haswell/x86_64/libout.so 19737: trying file=/lib64/haswell/libout.so 19737: trying file=/lib64/x86_64/libout.so 19737: trying file=/lib64/libout.so 19737: trying file=/usr/lib64/tls/haswell/x86_64/libout.so 19737: trying file=/usr/lib64/tls/haswell/libout.so 19737: trying file=/usr/lib64/tls/x86_64/libout.so 19737: trying file=/usr/lib64/tls/libout.so 19737: trying file=/usr/lib64/haswell/x86_64/libout.so 19737: trying file=/usr/lib64/haswell/libout.so 19737: trying file=/usr/lib64/x86_64/libout.so 19737: trying file=/usr/lib64/libout.so 19737: ./prog: error while loading shared libraries: libout.so: cannot open shared object file: No such file or directory $ LD_LIBRARY_PATH=`pwd` ./prog sdfsdfs sde 3: <INIT> 4: sdfsdfs 5: sde 6: <DONE> }}} * Разделяемая библиотека получается не из всякого объектника: код должен быть скомпилирован так, чтобы его можно было загрузить в ''любое место'' памяти (статический код может доверять абсолютным адресам). Это касается всех `.o` файлов проекта * Разделяемая библиотека имеет сложную структуру [[WP:Executable_and_Linkable_Format]] * При запуске программы система ищет разделяемые библиотеки в стандартных каталогах (подробнее тут: [[man8:ld.so]]), и если место нестандартное, надо указывать `LD_LIBRARY_PATH` |
Пример написания и использования Makefile
Начнём с таких вот файлов:
prog.c |
fun.c |
|
|
const.c |
outlib.h |
1 int Count=0;
|
|
Их можно собрать в один файл просто с помощью cc *.c -o prog
- Напишем простейший Makefile для этого:
- Помните о табах!
Заодно сделаем цель clean. Пробуем make, make clean.
- Так можно и скриптом было сделать. Обеспечим раздельную компиляцию и компоновку.
- Раздельная компиляция работает:
1 $ make clean 2 rm -f prog a.out *.o 3 $ make prog 4 cc const.c -c -o const.o 5 cc fun.c -c -o fun.o 6 cc prog.c -c -o prog.o 7 cc const.o fun.o prog.o -o prog 8 $ touch fun.c 9 $ make prog 10 cc fun.c -c -o fun.o 11 cc const.o fun.o prog.o -o prog 12 $ touch fun.o 13 $ make prog 14 cc const.o fun.o prog.o -o prog 15
- Кстати, вот альтернативная форма, в которой нет табуляций. Она малочитаема, не будем ей пользоваться:
- (а табуляции и пробелы становятся обычными разделителями)
- И ещё одна. На этот раз полями рецепта определяются не табуляции, а тильды (а табуляции и пробелы становятся обычными разделителями):
- Раздельная компиляция работает:
Хорошо бы задать правило по умолчанию, как делать .o файлы из .c.
Конструкции, начинающиеся с $ — подстановки значения некоторых переменных Make:
$@ означает цель (похожа на цель в тире)
$< означает первую из зависимостей
$^ означает список всех зависимостей
- В Make есть и нормальные переменные, только их подстановка должна заключаться в круглые скобки. Заодно усложним и нашу программу.
prog.c
fun.c
|
|
const.c |
outlib.h |
1 int Count=0;
|
|
Makefile |
|
|
Следуя традиции, мы разделили генераты на совсем ненужные (TRASH) и собственно целевые файлы проекта (GENERATES), которые всё равно стоит удалять, если в репозитории должны остаться только исходники
Традиционно же цель all: в начале файла перечисляет всё, что должно быть собрано (цель в начале считается целью по умолчанию, если make запущен без явно заданной цели)
Теперь сама наша программа участвует в генерации файла README! Поэтому сборка начнётся не с README, а с prog, несмотря на то, что в списке целей all раньше стоит README:
В нашем Makefile есть недочёт: не все зависимости учтены. Например, при изменении outlib.h надо перекомпилировать все файлы, который его включают. Как минимум, fun.c, потому что в нём используется константа VERSION. Но про это ничего не сказано:
Добавим частную зависимость fun.o: outlib.h (без рецепта) в Makefile, и задача решена:
В действительности у make есть огромное количество правил по умолчанию, их можно посмотреть с помощью make -p
Для шаблонов компиляции используется слегка другой синтаксис (.c.o: вместо %.o: %.c (выдержка из make -p):
.c.o: $(COMPILE.c) $(OUTPUT_OPTION) $<
Действительная команда, которая приводит к компиляции, получается подстановкой переменных COMPILE.c и OUTPUT_OPTION, которые сами тоже суть результат подстановки… но если коротко, то всё смотрится неплохо:
Мы воспользовались не только шаблоном компиляции, но и шаблоном линковки (у цели prog нет рецепта, но make догадался, что .o надо сделать из .c, а prog — из этих .o):
Использование шаблонов довольно гибко управляется: можно подменять флаги сборки на Си (CFLAGS) и других языках, флаги компоновки (LDFLAGS), название компилятора (GCC) и компоновщика, подключаемые библиотеки (LDLIBS) и т. п.
Добавим в Makefile строку CFLAGS = -Wall и пересоберём проект:
Переменные make можно переопеределять из командной строки:
Статическая библиотека собирается с помощью архиватора (т. е. программы, которая складывает много файлов в один) ar. Так что собрать нашу программу можно и с помощью библиотеки:
1 $ nm *.o 2 const.o: 3 0000000000000000 B Count 4 fun.o: 5 U Count 6 U fprintf 7 0000000000000000 T output 8 U printf 9 U stderr 10 0000000000000033 T usage 11 prog.o: 12 U Count 13 0000000000000000 T main 14 U output 15 U usage 16 $ ar -rcs libout.a const.o fun.o 17 $ ls -l libout.a 18 -rw-r--r-- 1 frbrgeorge frbrgeorge 3144 окт 5 15:52 libout.a 19 $ ar -tv libout.a 20 rw-r--r-- 500/500 976 Oct 5 15:52 2020 const.o 21 rw-r--r-- 500/500 1944 Oct 5 15:52 2020 fun.o 22 $ nm libout.a 23 const.o: 24 0000000000000000 B Count 25 fun.o: 26 U Count 27 U fprintf 28 0000000000000000 T output 29 U printf 30 U stderr 31 0000000000000033 T usage 32 $ cc -L. -lout prog.o -o prog 33 /usr/bin/ld.default: prog.o: in function `main': 34 prog.c:(.text+0x14): undefined reference to `Count' 35 /usr/bin/ld.default: prog.c:(.text+0x1a): undefined reference to `Count' 36 /usr/bin/ld.default: prog.c:(.text+0x29): undefined reference to `output' 37 /usr/bin/ld.default: prog.c:(.text+0x51): undefined reference to `output' 38 /usr/bin/ld.default: prog.c:(.text+0x67): undefined reference to `output' 39 /usr/bin/ld.default: prog.c:(.text+0x78): undefined reference to `usage' 40 collect2: error: ld returned 1 exit status 41 $ cc -L. prog.o -lout -o prog 42 frbrgeorge@linuxprac ~/LinuxDev2020/04_Multifile_class $ ./prog qwe ert 43 3: <INIT> 44 4: qwe 45 5: ert 46 6: <DONE> 47 $ nm prog | grep output 48 00000000004011a5 T output 49
.a — это обычный архив, в который сложен объектники, однако nm (анализатор объектников) и ld (компоновщик) могут туда залезать!
Обратите внимание на то, какие символы в каком файле определены (T) или требуются, но не определены (U)
Ключ компоновщика -lБИБЛИОТЕКА заставляет искать файл вида libБИБЛИОТЕКА.a (или .so) в стандартных каталогах с библиотеками. А если каталог нестандартный (например, текущий)), его надо передать с ключом -LПУТЬ.
- Порядок файлов в компоновке имеет значение: неопределённые символы компоновщик накапливает, а затем ищет в библиотеке, и если библиотека идёт в начала, она игнорируется
В файле prog присутствует функция output, которая попала туда вместе с fun.o
Таким образом у нас получилась статическая библиотека, которая целиком компонуется с кодом исходной программы
Динамическая (.so) библиотека имеет совсем другой тип (в некоторых случаях её даже можно запустить), и она подгружется в память в момент запуска программы, а в самой программе не содержится. Собрать её можно, передав компоновщику ключ -shared:
1 $ cc -shared fun.o const.o -o libout.so 2 /usr/bin/ld.default: fun.o: перемещение R_X86_64_PC32 для символ «Count» не может использоваться при создании общий объект; перекомпилируйте с параметром -fPIC 3 /usr/bin/ld.default: final link failed: раздел, непредставимый для вывода 4 collect2: error: ld returned 1 exit status 5 $ make distclean CFLAGS=-fPIC prog.o const.o fun.o 6 rm -f *.o *~ o.* *.a *.so 7 rm -rf prog README 8 cc -fPIC -c -o prog.o prog.c 9 cc -fPIC -c -o const.o const.c 10 cc -fPIC -c -o fun.o fun.c 11 $ cc -shared fun.o const.o -o libout.so 12 $ readelf --dyn-syms libout.so 13 14 Таблица символов «.dynsym» содержит 11 элементов: 15 Чис: Знач Разм Тип Связ Vis Индекс имени 16 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 17 1: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab 18 2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.2.5 (2) 19 3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND fprintf@GLIBC_2.2.5 (2) 20 4: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 21 5: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable 22 6: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.2.5 (2) 23 7: 0000000000000000 0 OBJECT GLOBAL DEFAULT UND stderr@GLIBC_2.2.5 (2) 24 8: 0000000000001115 59 FUNC GLOBAL DEFAULT 12 output 25 9: 000000000000402c 4 OBJECT GLOBAL DEFAULT 23 Count 26 10: 0000000000001150 57 FUNC GLOBAL DEFAULT 12 usage 27 $ cc -L. prog.o -lout -o prog 28 $ ./prog 29 ./prog: error while loading shared libraries: libout.so: cannot open shared object file: No such file or directory 30 $ LD_DEBUG=libs ./prog 31 19737: find library=libout.so [0]; searching 32 19737: search cache=/etc/ld.so.cache 33 19737: search path=/lib64/tls/haswell/x86_64:/lib64/tls/haswell:/lib64/tls/x86_64:/lib64/tls:/lib64/haswell/x86_64:/lib64/haswell:/lib64/x86_64:/lib64:/usr/lib64/tls/haswell/x86_64:/usr/lib64/tls/haswell:/usr/lib64/tls/x86_64:/usr/lib64/tls:/usr/lib64/haswell/x86_64:/usr/lib64/haswell:/usr/lib64/x86_64:/usr/lib64 (system search path) 34 19737: trying file=/lib64/tls/haswell/x86_64/libout.so 35 19737: trying file=/lib64/tls/haswell/libout.so 36 19737: trying file=/lib64/tls/x86_64/libout.so 37 19737: trying file=/lib64/tls/libout.so 38 19737: trying file=/lib64/haswell/x86_64/libout.so 39 19737: trying file=/lib64/haswell/libout.so 40 19737: trying file=/lib64/x86_64/libout.so 41 19737: trying file=/lib64/libout.so 42 19737: trying file=/usr/lib64/tls/haswell/x86_64/libout.so 43 19737: trying file=/usr/lib64/tls/haswell/libout.so 44 19737: trying file=/usr/lib64/tls/x86_64/libout.so 45 19737: trying file=/usr/lib64/tls/libout.so 46 19737: trying file=/usr/lib64/haswell/x86_64/libout.so 47 19737: trying file=/usr/lib64/haswell/libout.so 48 19737: trying file=/usr/lib64/x86_64/libout.so 49 19737: trying file=/usr/lib64/libout.so 50 19737: 51 ./prog: error while loading shared libraries: libout.so: cannot open shared object file: No such file or directory 52 $ LD_LIBRARY_PATH=`pwd` ./prog sdfsdfs sde 53 3: <INIT> 54 4: sdfsdfs 55 5: sde 56 6: <DONE> 57
Разделяемая библиотека получается не из всякого объектника: код должен быть скомпилирован так, чтобы его можно было загрузить в любое место памяти (статический код может доверять абсолютным адресам). Это касается всех .o файлов проекта
Разделяемая библиотека имеет сложную структуру Executable_and_Linkable_Format
При запуске программы система ищет разделяемые библиотеки в стандартных каталогах (подробнее тут: ld.so), и если место нестандартное, надо указывать LD_LIBRARY_PATH