Jakie są różnice między .so i .dylib na OSX?

214

.dylib jest dynamicznym rozszerzeniem biblioteki dla OSX, ale nigdy nie było dla mnie jasne, kiedy nie mogę / nie powinienem używać tradycyjnego współdzielonego obiektu .so.

Niektóre z moich pytań:

  • Na poziomie koncepcyjnym, jakie są główne różnice między .so i .dylib?
  • Kiedy mogę / powinienem stosować jeden na drugim?
  • Wskazówki i porady dotyczące kompilacji (na przykład zastąpienie gcc -shared -fPIC, ponieważ to nie działa w systemie OSX)
Trent Davies
źródło

Odpowiedzi:

206

Format plików obiektowych Mach-O używany przez Mac OS X w plikach wykonywalnych i bibliotekach rozróżnia biblioteki współdzielone i moduły ładowane dynamicznie . Użyj, otool -hv some_fileaby zobaczyć typ pliku some_file.

Biblioteki współdzielone Mach-O mają typ pliku MH_DYLIBi mają rozszerzenie .dylib. Można je połączyć ze zwykłymi statycznymi flagami linkera, np. -lfooDla libfoo.dylib. Można je utworzyć, przekazując -dynamiclibflagę do kompilatora. ( -fPICjest ustawieniem domyślnym i nie trzeba go określać).

Moduły ładowalne nazywane są „pakietami” w mowie Mach-O. Mają typ pliku MH_BUNDLE. Mogą nosić dowolne przedłużenie; rozszerzenie .bundlejest zalecane przez Apple, ale większość portowanych programów używa .soze względu na kompatybilność. Zazwyczaj używasz pakietów do wtyczek rozszerzających aplikację; w takich sytuacjach pakiet łączy się z plikiem binarnym aplikacji, aby uzyskać dostęp do eksportowanego interfejsu API aplikacji. Można je utworzyć, przekazując -bundleflagę do kompilatora.

Oba dylibs i zestawy mogą być załadowane dynamicznie przy użyciu dlAPI (np dlopen, dlclose). Nie można połączyć się z pakietami tak, jakby były bibliotekami współdzielonymi. Możliwe jest jednak, że pakiet jest połączony z prawdziwymi bibliotekami współdzielonymi; zostaną one załadowane automatycznie po załadowaniu pakietu.

Historycznie różnice były bardziej znaczące. W Mac OS X 10.0 nie było możliwości dynamicznego ładowania bibliotek. Zestaw API dyld (na przykład NSCreateObjectFileImageFromFile, NSLinkModule) wprowadzono 10,1 do wkładania i wyjmowania pakietów, ale nie dla dylibs. dlopenBiblioteki zgodność, że współpracuje z wiązek dodano 10,3; w 10.4 dlopenzostał przepisany na natywną część dyld i dodano obsługę ładowania (ale nie rozładowywania) dylibs. Wreszcie, 10.5 dodało obsługę używania dlclosez dylibs i przestało działać różne interfejsy API.

W systemach ELF, takich jak Linux, oba używają tego samego formatu pliku ; dowolny fragment współdzielonego kodu może być wykorzystywany jako biblioteka i do dynamicznego ładowania.

Na koniec należy pamiętać, że w systemie Mac OS X „pakiet” może również odnosić się do katalogów o ustandaryzowanej strukturze, która zawiera kod wykonywalny i zasoby używane przez ten kod. Istnieje pewne koncepcyjne nakładanie się (szczególnie w przypadku „pakietów ładowalnych”, takich jak wtyczki, które zazwyczaj zawierają kod wykonywalny w postaci pakietu Mach-O), ale nie należy ich mylić z omówionymi powyżej pakietami Mach-O.

Dodatkowe referencje:

Miles
źródło
1
Dziękuję za ten obszerny komentarz :) Czy rozumiem to poprawnie, że jeśli załaduję jeden pakiet z innego pakietu (tj. Ścieżka to aplikacja -> pakiet A -> pakiet B), wówczas pakiet B nie będzie mógł zobaczyć żadnego symbole w pakiecie A? A jeśli tak, czy są jakieś sposoby na rozwiązanie tego problemu? Właśnie trafiłem, tak myślę: stackoverflow.com/questions/4193539/…
Michaił Edoshin
4
@noloader: -dynamiclibjest flagą GCC. Powoduje to, że kompilator przechodzi -dylibdo ld.
Miles
Zaktualizowany URL strony podręcznika
manpages.info/macosx/ld.1.html
18

Plik .so nie jest rozszerzeniem UNIX dla biblioteki współużytkowanej.

To się po prostu zdarza.

Sprawdź wiersz 3b na stronie sharedlib ArnaudRecipes

Zasadniczo .dylib to rozszerzenie pliku mac używane do wskazania wspólnej biblioteki.

Martin York
źródło
9
@ninefingers. Poprawny. Ale niektóre narzędzia będą używać wartości domyślnych, chyba że coś jest bardzo wyraźne. np. Kompilatory użyją tam specyficznego dla platformy wspólnego rozszerzenia libray, gdy używana jest flaga -l <lib> (rzeczywista flaga może się bardzo różnić w różnych kompilatorach).
Martin York
14

Różnica między plikami .dylib i .so w systemie Mac OS X polega na sposobie ich kompilacji. Dla plików .so używasz -shared, a dla .dylib używasz -dynamiclib. Zarówno .so, jak i .dylib są wymienne jako dynamiczne pliki bibliotek i albo mają typ DYLIB, albo BUNDLE. Oto odczyt różnych plików, które to pokazują.

libtriangle.dylib:
Mach header
      magic cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
MH_MAGIC_64  X86_64        ALL  0x00       DYLIB    17       1368   NOUNDEFS DYLDLINK TWOLEVEL NO_REEXPORTED_DYLIBS



libtriangle.so:
Mach header
      magic cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
MH_MAGIC_64  X86_64        ALL  0x00       DYLIB    17       1256   NOUNDEFS DYLDLINK TWOLEVEL NO_REEXPORTED_DYLIBS

triangle.so:
Mach header
      magic cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
MH_MAGIC_64  X86_64        ALL  0x00      BUNDLE    16       1696   NOUNDEFS DYLDLINK TWOLEVEL

Oba są równoważne w systemie Mac OS X ze względu na wsteczną kompatybilność z innymi programami systemu UNIX, które kompilują się do typu pliku .so.

Uwagi dotyczące kompilacji: niezależnie od tego, czy kompilujesz plik .so, czy plik .dylib, musisz wstawić poprawną ścieżkę do biblioteki dynamicznej podczas etapu łączenia. Robisz to, dodając -install_name i ścieżkę pliku do polecenia łączenia. Jeśli tego nie zrobisz, napotkasz problem widoczny w tym poście: Mac Dynamic Library Craziness (może być tylko Fortran) .

Zachary Kraus
źródło
w jaki sposób mogę ./configuregenerować .dylibpliki zamiast łączyć pliki .so? ./configure --enable-sharednie wykonuje tego zadania.
Admia
z mojego doświadczenia wynika, że ​​większość plików konfiguracyjnych na komputerze Mac zbuduje plik .so lub plik biblioteki statycznej, ponieważ pliki konfiguracyjne używają standardowych nazw plików unix / linux.
Zachary Kraus
4

To tylko obserwacja, którą właśnie poczyniłem, budując naiwny kod w OSX za pomocą cmake:

cmake ... -DBUILD_SHARED_LIBS=OFF ...

tworzy pliki .so

podczas

cmake ... -DBUILD_SHARED_LIBS=ON ...

tworzy pliki .dynlib .

Być może to pomaga każdemu.

użytkownik2996950
źródło