レむアりト、䟝存関係の地獄、埌方互換性に぀いお

この蚘事では、レむアりトの抂芁を説明したす。 Linux、BSD *、Mac OS X、Windows䞊のアプリケヌションが䟝存する共有ラむブラリはどこにありたすか 埌方互換性をどうするか 䞭毒地獄に察凊する方法



読者は、「コンパむラ」、「オブゞェクトファむル」、「リンカヌ」、「静的ラむブラリ」、「動的ラむブラリ」、「動的ロヌダヌ」などの文字セットに粟通しおいるず想定されるため、䜕も噛みたせん。



動的ラむブラリの静的ロヌドの問題



  1. main.exeはversion-0.3.dllおよびbar.dllに䟝存しおいたす。 䞀方、バヌはバヌゞョン0.3ずバむナリ互換ではないバヌゞョン0.2.dllに䟝存しおいたす文字が存圚しないだけでなく、名前が䞀臎したすが、匕数の数が異なるか、異なる性質のオブゞェクトを䜜成するなど。 version-0.2.dllの文字はversion-0.3.dllから削陀されたすか ラむブラリの静的バヌゞョンたずえばversion-0.2.libず動的バヌゞョンversion-0.3.dllを䜿甚する堎合にも同じ問題が発生したす。
  2. ロヌミングアプリケヌションの䜜成ダむナミックロヌダヌは、前の段萜のアプリケヌションのversion-0.?.dllおよびbar.dllをどこで怜玢したすか 別のフォルダヌに移動した堎合、main.exeの䟝存関係を怜出したすか main.exeをアセンブルしお、実行可胜ファむルに察しお䟝存関係を怜玢する方法は
  3. 䟝存関係の地獄同じラむブラリの2぀のバヌゞョン/opt/kde3/lib/libkdecore.soおよび/opt/kde4/lib/libkdecore.soこれによりプラズマが萜ちなくなりたす、プログラムの半分が最初を必芁ずし、プログラムの残りの半分が2番目を必芁ずしたす。 䞡方のラむブラリを1぀のスコヌプ1぀のディレクトリに配眮するこずはできたせん。 バヌゞョンラむブラリの2぀のバヌゞョンを同じディレクトリに配眮する必芁があるため、ポむント1にも同じ問題が存圚したす。


最初の段萜を読んだ埌、読者は叫ぶかもしれたせん。 圌らはそうしたせん ラむブラリの1぀のバヌゞョンを䜿甚する必芁がありたす”はい、そうですが、人生ではすべおが起こりたす。 最も単玔な䟋アプリケヌションはラむブラリaずサヌドパヌティのクロヌズドラむブラリこれは他の誰かの有料補品を匷調したす bを䜿甚したす。



巚倧なプロゞェクトのフレヌムワヌクのもう1぀の䟋は、さたざたな郚分のリリヌスには異なる期間があるずいう事実です私たちのチヌムが遭遇し、このテキストが䞀般的に曞かれた原因。 したがっお、䞻な補品は、パラグラフ1で説明した構成でずきどき出おくるこずがありたす。



䟝存関係の地獄は、システムラむブラリずオペレヌティングシステムの開発者にずっおより重芁ですが、アプリケヌション領域でも発生する可胜性がありたす。 繰り返したすが、いく぀かの実行可胜プログラムがある巚倧なプロゞェクトがあるずしたす。 それらはすべお1぀のラむブラリに䟝存しおいたすが、バヌゞョンが異なりたす。 これはステップ1ず同じ状況ではありたせん1぀のプロセスに同じラむブラリの2぀のバヌゞョンがロヌドされ、ここでは1぀だけが各プロセスにロヌドされたすが、それぞれ独自のバヌゞョンを䜿甚したす。



地獄からの脱出


答えは簡単です。バヌゞョンをラむブラリファむル名に远加する必芁がありたす。 これにより、ラむブラリファむルを1぀のディレクトリに配眮できたす。 同時に、APIではなくABIバヌゞョンを远加するこずをお勧めしたす。これにより、2぀の䞊行バヌゞョンブランチずそれに察応する困難が䜜成されたす。



バヌゞョン管理は非垞に日垞的な仕事です。 xyzスキヌムを怜蚎しおください。



ファむル名にxyを含めるこずは劥圓ですが、マむナヌバヌゞョンを増やしながら互換性が維持されおいる堎合は、察応するシンボリックリンクを䜜成するだけで十分です。

version-1.1.dll

version-1.0.dll→version-1.1.dll



version-1.1.0を䜿甚するアプリケヌションずversion-1.0.xを䜿甚するアプリケヌションの䞡方が機胜したす。



互換性が壊れおいる堎合、システムには2぀のファむルがあり、再びすべおが機胜したす。



䜕らかの理由でバグ修正䞭に互換性が倱われた堎合、マむナヌバヌゞョンを増やす必芁がありたすお気に入りのQtのチヌムが行ったように、倱敗するものは䜕もありたせん [1] 。



ずころで、APIバヌゞョンを含めるこずを犁止する人はいたせん。そうすれば、より倚くのシンボリックリンクが䜜成されたす。 倚くの堎合、互換性が維持されたす。 しかし、この堎合、蚀及されたQtファむルは簡単に解決され、マむナヌバヌゞョンを匷制的に増やすこずはありたせん。



これはすべおのプラットフォヌムに圓おはたりたす。



残りの2぀の問題の解決策は、OSによっお異なりたす。



ELFGNU ldLinux、* BSDなど


ELF圢匏の共有ラむブラリには、いわゆるSONAMEがありたす [2] [3] 。 これは、DT_SONAMEセクションのバむナリファむルに曞き蟌たれる文字列です。 ラむブラリのSONAMEは、たずえば次のように衚瀺できたす。
$ objdump -p /path/to/file | grep SONAME
      
      





fazプログラム/ラむブラリがSONAME = baz-0.dllのbazラむブラリにリンクされおいる堎合、 baz-0.dll行はDT_NEEDEDセクションのバむナリfazファむルにハヌドコヌドされ、開始時にダむナミックロヌダヌはbazずいう名前のファむルを探したす。 -0.dll この堎合、ファむルに異なる名前を付けるこずを誰も犁止しおいたせん



実行可胜ファむルが䟝存するSONAMEを衚瀺できたす。
 $ objdump -x /path/to/file | grep NEEDED
      
      





ダむナミックロヌダヌは、次の堎所でDT_NEEDEDセクションからこの順序でラむブラリを怜玢したす [4] [5] 

  1. DT_RPATHセクションのディレクトリのリスト。実行可胜ファむルにハヌドコヌディングされおいたす。 ほずんどの* nixシステムでサポヌトされおいたす。 セクションDT_RUNPATHが存圚する堎合は無芖されたす。
  2. LD_LIBRARY_PATH-環境倉数。ディレクトリのリストも含たれおいたす。
  3. DT_RUNPATH-DT_RPATHず同じ。LD_LIBRARY_PATHの埌にのみ衚瀺されたす。 最新のUnixラむクシステムでのみサポヌトされおいたす。
  4. /etc/ld.so.conf-ダむナミックロヌダヌld.soの構成ファむル。ラむブラリのあるフォルダヌのリストが含たれおいたす。
  5. ハヌドワむダヌドパス-通垞/ libおよび/ usr / lib。


RPATH、LD_LIBRARY_PATH、およびRUNPATHのデヌタ圢匏は、PATHの堎合ず同じですコロンで区切られたパスのリスト。 たずえば、次のようにRUNPATHを衚瀺できたす。
 $ objdump -x /path/to/file | egrep 'R(|UN)PATH'
      
      





R [UN] PATHには特別なラベル$ ORIGINが含たれおいる堎合がありたす。これは、ダむナミックロヌダヌがロヌドされた゚ンティティぞの完党な絶察パスに展開したす。 ここでは、䞀郚の開発者がRUNPATHに「。」期間を远加するこずに泚意しおください。 これは$ ORIGINず同じではありたせん ポむントは珟圚の䜜業ディレクトリに展開され、本質ぞのパスず自然に䞀臎する必芁はありたせん



曞かれおいる内容を瀺すために、 p。1のスキヌムgithubのストレヌゞぞのリンク github.com/gshep/linking-sample に埓っおアプリケヌションを開発したす。 システム党䜓を構築するには、フォルダヌのルヌトに移動しお./linux_make_good.sh



を呌び出す./linux_make_good.sh



で、結果はresult



フォルダヌに./linux_make_good.sh



されたす。 いく぀かの組み立お手順を以䞋で説明したす。



バヌゞョン-0.xラむブラリをリンクする段階で、SONAMEが蚭定されたす
 $ gcc -shared -Wl,-soname,version-0.3.dll -o version-0.3.dll version.o
      
      





システムラむブラリのみに䟝存するため、R [UN] PATHセクションは䞍芁です。



barラむブラリはすでにバヌゞョン0.2に䟝存しおいるため、RPATHを指定する必芁がありたす。
 $ gcc -shared -Wl,-rpath-link,/path/to/version-0.2/ -L/path/to/version-0.2/ -l:version-0.2.dll -Wl,-rpath,\$ORIGIN/ -Wl,--enable-new-dtags -Wl,-soname,bar.dll -o bar.dll bar.o
      
      





--enable-new-dtags



は、DT_RUNPATHセクションに入力するようリンカヌに指瀺したす。



-Wl,-rpath,...



は、R [UN] PATHセクションを埋め-Wl,-rpath,...



。 パスのリストを指定するには、パラメヌタヌを耇数回指定するか、コロンですべおのパスをリストしたす。
 $ gcc -Wl,-rpath,/path/1/ -Wl,-rpath,/path/2 ... $ gcc -Wl,-rpath,/path/1:/path/2 ...
      
      





これで、結果フォルダヌのすべおのコンテンツたたはフォルダヌ党䜓をファむルシステム内で自由に移動できたすが、ダむナミックロヌダヌを起動するずすべおの䟝存関係が怜出され、プログラムが実行されたす。
 $ ./result/main.exe Hello World! bar library uses libversion 0.3.0, number = 3 version::get_version result = 0 But I uses liversion 0.3.0 number = 3
      
      





そこで、キャラクタヌをマッシュする問題に取り掛かりたす バヌは、get_numberが2を返すversion-0.2.dllず、同じ関数が既に3を返すアプリケヌションversion-0.3.dllを䜿甚したす。アプリケヌションの出力によるず、get_number関数の1぀のバヌゞョンは別のバヌゞョンによっお䞊曞きされたす。



事実は [6; 動的リンクず読み蟌み、動的リンクのアプロヌチの比范] GNU ldELFはむンポヌトされた文字の名前空間ずしおSONAMEたたはファむル名を䜿甚したせん

異なるラむブラリが同じ名前の゚ンティティを゚クスポヌトするず、それらのいく぀かは他のものを粉砕し、最良の堎合はプログラムがクラッシュしたす。



ラむブラリの1぀が静的である堎合は単玔に解決されたす。静的ラむブラリのすべおのシンボルを非衚瀺にする必芁がありたす [7、2.2.2グロヌバル可芖性の定矩] 。



残念ながら、動的ラむブラリの堎合、事態はそれほど単玔ではありたせん。 GNU Linker / Loaderには、盎接バむンディングなどの機胜がありたせん [8] 。 誰かがゲントでこの機䌚を芋たした [9]しかし、すべおが死んだようです。 ディヌれル燃料で圌女は [10] [11]しかし、゜リアルカ自身は死にたした...



1぀のオプションは、キャラクタヌ自䜓をバヌゞョン管理するこずです [7、2.2.5゚クスポヌトマップの䜿甚] 。 これは実際にはキャラクタヌを食るようなものです。 C ++でプログラミングしおいるリヌダヌが今叫んでいるものしか想像できない...



この方法は、すべおの゚クスポヌトおよび非衚瀺の゚ンティティをリストする、いわゆるバヌゞョン管理されたスクリプトを䜜成するこずから成りたす [12] [13] 。 バヌゞョン0.3のスクリプトの䟋

  VERSION_0.3 {
    グロヌバル
         get_version;
         get_version2;
         get_number;
    ロヌカル
         *;
 }; 


ビルド段階で、 --version-script=/path/to/version.script



パラメヌタヌを䜿甚しおこのファむルを指定したす。 その埌、そのようなlibに関連付けられるアプリケヌションは、NEEDEDのversion-0.3.dllず、むンポヌトテヌブルの未定矩文字get_number@@VERSION_0.3



をget_number@@VERSION_0.3



たすが、int get_numberはただヘッダヌファむルにありたす。



glibcを䜿甚するプログラムでnmを蚭定するず、明確に衚瀺されたす



バヌゞョン-0.xラむブラリヌのバヌゞョン管理文字を䜿甚しお䟋をビルドするには、 use_version_script



パラメヌタヌを指定しおuse_version_script



ルヌトスクリプトを実行したす。
 $ ./linux_make_good.sh use_version_script $ ./result/main.exe Hello World! bar library uses libversion 0.2.0, number = 2 version::get_version result = 0 But I uses liversion 0.3.0 number = 3 $ nm ./result/main.exe // 
 U get_number@@VERSION_0.3 U get_version@@VERSION_0.3 0000000000401008 T main U memset@@GLIBC_2.2.5 $ nm ./result/bar.dll // 
 U get_number@@VERSION_0.2 U get_version2@@VERSION_0.2 0000000000000800 t register_tm_clones U strcat@@GLIBC_2.2.5
      
      





http://nooooooooooooooooo.com/



はい、私たちのチヌムが遭遇した刑務所の埌、船長は匷い意思決定を䞋し、今では1぀のバヌゞョンのlibのみが䜿甚されおいたす正確にはLinuxのため。



Macの状況はどうですか


Mac Axisは、実行可胜ファむル、および文字の怜玢に2レベルの名前空間のMach-o圢匏を䜿甚したす [14、2レベルの名前空間] [16] 。 珟圚はこれがデフォルトですが、フラットな名前空間でビルドするか、プログラムの起動時に完党に無効にするこずができたす [15、FORCE_FLAT_NAMESPACE] 。 このコマンドは、名前空間をサポヌトするバむナリが構築されおいるかどうかを確認するのに圹立ちたす。
 $ otool -hv /path/to/binary/file
      
      





぀たり、名前の远加の装食を济びる必芁はありたせん-ファむル名にバヌゞョンを含めるだけです



しかし、䟝存関係の怜玢はどうでしょうか



マコシでは、ほずんどすべおが䌌おいたすが、異なる方法で呌ばれおいたす。



SONAMEの代わりに、ラむブラリIDたたはむンストヌル名がありたす。 たずえば、次のように衚瀺できたす。
 $ otool -D /usr/lib/libstdc++.dylib
      
      



install_name_toolを䜿甚しお倉曎できたす。

ラむブラリにリンクする堎合、そのIDはバむナリで曞き蟌たれたす。



バむナリ䟝存関係は次のように衚瀺できたす。
 $ otool -L /path/to/main.exe
      
      



たたは
 $ dyldinfo -dylibs /path/to/main.exe
      
      





起動時に、dyldは「id」ずいう名前のファむルを開こうずしたす [15、動的ラむブラリのロヌド] 、぀たり、むンストヌル名を䟝存関係ぞの絶察パスず芋なしたす。 倱敗した堎合、環境倉数DYLD_LIBRARY_PATHLD_LIBRARY_PATHの完党な類䌌物にリストされおいるディレクトリで、名前/サフィックス "id"を持぀ファむルを怜玢したす。



DYLD_LIBRARY_PATHでの怜玢が結果を返さなかった堎合、dyldは同様にさらに2、3の環境倉数を調べたす [15] 、その埌、暙準カタログでlibを怜玢したす。



このスキヌムでは、ロヌミングアプリケヌションを収集できたせん。そのため、id@ executable_path /で蚘述できる特別なラベルが導入されたした。 起動時のこのマヌクは、実行可胜ファむルぞの絶察パスに展開されたす。



次に、完成したバむナリの䟝存関係を倉曎できたす。
 $ install_name_tool -change /usr/lib/libstdc++.dylib @executable_path/libstdc++.dylib main.exe
      
      





これで、ロヌダヌはたずmain.exeず同じフォルダヌでこれを怜玢したす。 完成したバむナリを倉曎しないようにするには、libstdc ++。Dylib lib with id = @ executable_path / libstdc ++。リンク䞭にDylibをスリップする必芁がありたす。



さらに、1぀、たたは2぀の問題が発生したす。 そのような階局があるずしたす



main.binはlibrary.dllに䟝存しおいたすが、tools / auxiliary.binもそれに䟝存しおいたす。

同時に、id = @ executable_path / library.dllであり、䞡方のバむナリが単にそれにリンクされおいたした。 次に、auxiliary.binを起動するず、ブヌトロヌダヌは/path/to/tools/library.dllを探したすが、圓然それを芋぀けられたせん もちろん、リンクした埌にツヌルでツヌル/auxiliary.binを修正するか、゜フトリンクをスロヌするこずもできたすが、やはり䞍䟿です



さらに良いこずに、プラグむンに関しおは問題が珟れたす



1.pluginには@ executable_path / helper.dylibずいう゚ントリがありたすが、起動時には1.pluginではなくmain.binぞの絶察パスに展開されたす



この問題を解決するために、Axis 10.4のYablokoは新しいマヌカヌ@ loader_path /を導入したした。 䟝存関係の読み蟌み䞭、このマヌカヌは、䟝存関係をプルするバむナリぞの絶察パスに展開されたす。



最埌の難点は、リンクされたラむブラリの2぀のバヌゞョンが必芁なこずです。䞀郚はシステムにむンストヌルされ、id = /usr/lib/libfoo.dylibになりたすが、その他はプロゞェクトのビルドに䜿甚され、id = @ loader_path / libfoo.dylibになりたす。 これはinstall_name_toolで簡単に解決できたすが、面倒です。 したがっお、バヌゞョン10.5から、@ rpath /ラベルを入力したした。 ラむブラリはid = @ rpath / libfoo.dylibで構築され、どこにでもコピヌされたす。 バむナリは䟝存関係を探すためのパスのリストを䜿甚しおコンパむルされ、@ {executable、loader} _path /が蚱可されたす。
 $ gcc ... -Xlinker -rpath -Xlinker '@executable_path/libs' -Xlinker -rpath -Xlinker '/usr/lib' ...
      
      





これは、ELFのRPATH / RUNPATHに䌌おいたす。 バむナリが起動するず、行@ rpath / libfoo.dylibは@ executable_path / libs / libfoo.dylibに展開されたすが、これはすでに絶察パスに展開されおいたす。 たたは、/ usr / lib / libfoo.dylibにデプロむしたす。



次のように、バむナリに配線されたrpathを衚瀺できたす。
 $ otool -l main.bin | grep -A 2 -i lc_rpath
      
      





install_name_toolを䜿甚しお、rpathを削陀、倉曎、たたは远加できたす。



䟋で確認しおください
 $ ./macosx_make_good.sh Building version-0.2 Building version-0.3 Building bar Building fooapp $ ./result/main.exe Hello World! bar library uses libversion 0.2.0, number = 2 version::get_version result = 0 But I uses liversion 0.3.0 number = 3
      
      





iOSでは、すべおが同じです。



この䟋からわかるように、動的ラむブラリの点でMac OS XはLinuxCoよりも優れおいたす。



そしお最埌に、Windows


ここでもすべお順調です [6; 動的リンクずロヌド、動的リンクアプロヌチの比范] 。 ファむル名にバヌゞョンを远加するだけで、シンボリックリンクは䞍芁です ぀たり、それらはそうですが、倚くの人がそれらに぀いお文句を蚀い、NTFSでのみ動䜜したすWindows XPは間違いなくFATパヌティションにむンストヌルできたす 。 したがっお、䞋䜍互換性のためにかなりのディスク容量が必芁になる可胜性がありたす...たあ、倧䞈倫です。 



Windowsでサンプルをビルドするには、環境が既に構成されおいるVisual Studioコン゜ヌルを実行する必芁がありたす。 さらに組み立おお起動する
 > .\windows_make_good.bat // ... >.\result\main.exe Hello World! bar library uses libversion 0.2.0, number = 2 version::get_version result = 0 But I uses liversion 0.3.0 number = 3
      
      





リヌベは求められおいるだけです。 [17] 。 䟝存関係の怜玢アルゎリズムを倉曎する1぀の方法は、アプリケヌション構成ファむルずプロヌブのprivatePathプロパティを䜿甚するこずです [18] 。 ただし、この方法はWindows 7 / Server 2008 R2以降でのみ適甚できたす。



そしお、WinSxSず呌ばれるアセンブリアセンブリがありたす [19] 。 これは別の蚘事のトピックです。 ただし、この蚘事の執筆䞭に、これらのアセンブリは少なくずもSishnikiずC ++のニックネヌムの堎合のみ必芁であるずいう掞察ず理解は、すべおのアプリケヌションがcomdlg32.dllなどずリンクしおいるが、すべお異なるバヌゞョンを䜿甚しおいるこずを確認するために枛少したした。



おわりに


すべおの䞻芁なプラットフォヌムにより、通垞のコピヌでむンストヌルできるアプリケヌションを比范的簡単に䜜成できたす。 ただし、開発者は、䟝存関係の地獄、䞋䜍互換性、およびキャラクタヌマッシングの問題を自分で解決する必芁がありたす。



䞻な決定は、正しいバヌゞョン管理を遞択し、それを制埡するこずです。



奜奇心が火星の広がりをサヌフィンしおいる間、著者はここでキャラクタヌのマッシングを回避する方法を教えようずしたしたが、Habraには長い間特に反察を達成する方法を説明する蚘事がありたした habrahabr.ru/post/106107、habrahabr.ru/post/ 115558 。



远䌞 この蚘事の䜜業䞭、著者は「ストラむキ䞭」䌚議に出垭し、そこではバヌゞョン管理に関するパベルズ・K・ナザロフの報告に耳を傟けたした。 [20] 。 予期しないこずも珍しいこずもありたせんでしたが、そのような有名な䌚瀟が問題を認識し、正しい結論を䞋したず聞いおうれしかったです。 自分自身の新しい蚘事から、著者はそこからリンクを䜜成したした semver.org 。



この機䌚に、同僚のアレクサンダヌ・シドロフずアレクサンダヌ・プロコフィ゚フに建蚭的な批刀ず貎重なコメントをありがずうございたす



参照資料


  1. ^ QtMultimedia changes-5.0.1
  2. ^ http://en.wikipedia.org/wiki/Soname
  3. ^プログラムラむブラリHOWTO、 3.1.1。 共有ラむブラリ名 。
  4. ^ man ld-linux.so。
  5. ^ http://en.wikipedia.org/wiki/Rpath
  6. ^ 1 2リンカヌずロヌダヌJohn R. Levine、 http//www.iecc.com/linker/ 。
  7. ^ 1 2 Ulrich Drepperによる共有ラむブラリの曞き方、 http //www.akkadia.org/drepper/dsohowto.pdfpdf。
  8. ^ http://en.wikipedia.org/wiki/Direct_binding
  9. ^ https://bugs.gentoo.org/show_bug.cgi?id=114008
  10. ^ https://blogs.oracle.com/msw/date/20050614
  11. ^ http://cryptonector.com/2012/02/dll-hell-on-linux-but-not-solaris/
  12. ^ https://sourceware.org/binutils/docs/ld/VERSION.html
  13. ^ http://www.tux.org/pub/tux/eric/elf/docs/GNUvers.txt
  14. ^男ld。
  15. ^ 1 2 3人の嚘。
  16. ^ http://en.wikipedia.org/wiki/Mach-O#Mach-O_file_layout
  17. ^ MSDN、ダむナミックリンクラむブラリの怜玢順序、 http//msdn.microsoft.com/en-us/library/windows/desktop/ms682586%28v=vs.85%29.aspx
  18. ^ http://stackoverflow.com/a/10390305/1758733
  19. ^ http://en.wikipedia.org/wiki/WinSXS
  20. ^ Nazarov K.、バヌゞョン管理゜フトりェア補品の非垞に偏芋、 http//nastachku.ru/lectures#lecture_178
  21. Oracle、リンカヌおよびラむブラリガむド、 http//docs.oracle.com/cd/E19683-01/817-1983/index.html
  22. リンカヌの初心者向けガむド、 http//habrahabr.ru/post/150327/



All Articles