一部のライブラリのみの静的リンク


108

GCCとリンクするときに、特定のライブラリのみをバイナリに静的にリンクするにはどうすればよいですか?

gcc ... -static ...リンクされたすべてのライブラリを静的にリンクしようとしますが、一部の静的バージョン(libX11など)がありません。


回答:


112

gcc -lsome_dynamic_lib code.c some_static_lib.a


5
オブジェクトファイルの後にライブラリをリンクします(特に静的ライブラリ)。リンク環境の古代バージョンと現代バージョン(2010年11月現在の適度に古いバージョンの現状はわかりません)では、code.cファイルの前に静的ライブラリをリストすると、そこにあるシンボルが無視されることが保証されますmain()ライブラリオブジェクトファイルのいずれかで機能。
ジョナサンレフラー

44
これがどのように機能するかについて詳しく説明してください。コードのみの回答は初心者には役立ちません。
jb。

8
@jbデフォルトでは、gccは動的にリンクします。-lsome_dynamic_libを使用すると、期待どおりに動的にリンクされます。ただし、gccに明示的に静的ライブラリを指定すると、常に静的にリンクしようとします。ただし、シンボルが解決される順序については、いくつかの注意が必要な詳細があります。それがどのように機能するのか私にはよくわかりません。疑問がある場合は、ライブラリフラグの順序を並べ替えてみてください
。-)

4
たとえばGPLライブラリを
HiB

1
@HiB GPLは、静的リンクと動的リンクに同じ方法を適用します
osvein

50

ldオプションを使用することもできます-Bdynamic

gcc <objectfiles> -static -lstatic1 -lstatic2 -Wl,-Bdynamic -ldynamic1 -ldynamic2

それ以降のすべてのライブラリ(gccによって自動的にリンクされるシステムライブラリを含む)は動的にリンクされます。


19
-Wl、-BdynamicにはGNU ldが必要なので、このソリューションはgccがシステムldを使用するシステム(Mac OS Xなど)では機能しません。
PTS

33
gcc objectfiles -o program -Wl,-Bstatic -ls1 -ls2 -Wl,-Bdynamic -ld1 -ld2

次も使用できます:-static-libgcc -static-libstdc++gccライブラリのフラグ

場合があることに注意してくださいlibs1.solibs1.aの両方が存在し、リンカが選択されますlibs1.so、それは前にかどう-Wl,-Bstaticか後-Wl,-Bdynamic。を-L/libs1-library-location/呼び出す前にパスすることを忘れないでください-ls1


1
少なくとも、このソリューションはlibgompに対する静的リンクに対して機能します。
ジェローム2014年

これは私にとってはうまくいき-staticますが、コマンドのどこかを使用すると失敗します(必要なライブラリだけではなく、より多くのものを静的にリンクしようとしていると思います)。
nh2 2016

4
NB。順序-Wl,-Bstaticとは-Wl,-Bdynamic重要です。
Pavel Vlasov 2017年

27

ld(これはgccでは機能しません)のマンページから、--staticオプションを参照してください:

このオプションは、コマンドラインで複数回使用できます。これは、それに続く-lオプションのライブラリ検索に影響します。

1つの解決策は--static、コマンドラインのオプションの前に動的依存関係を置くことです。

別の可能性は、を使用せず--staticに、静的オブジェクトファイルの完全なファイル名/パスを提供する(つまり、-lオプションを使用しない)ことで、特定のライブラリに静的にリンクすることです。例:

# echo "int main() {}" > test.cpp
# c++ test.cpp /usr/lib/libX11.a
# ldd a.out
linux-vdso.so.1 =>  (0x00007fff385cc000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007f9a5b233000)
libm.so.6 => /lib/libm.so.6 (0x00007f9a5afb0000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00007f9a5ad99000)
libc.so.6 => /lib/libc.so.6 (0x00007f9a5aa46000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9a5b53f000)

例からわかるように、libX11は静的にリンクされていたため、動的にリンクされたライブラリのリストにはありません。

注意:.so完全なファイル名/パスで指定されている場合でも、ファイルは常に動的にリンクされます。


libX11.aとの出力の関係はどうなっていますldd a.outか?
Raffi Khatchadourian、2013年

1
ああ、なるほど。ldd必要な共有ライブラリを出力し、libX11はそのリストに表示されません。
Raffi Khatchadourian、2013年

これは明確ではありません。あなたは「このオプション」と「そのオプション」と言います。どのオプション?
Octopus

19

私が理解している問題は次のとおりです。いくつかのライブラリがあり、一部は静的、一部は動的、一部は静的と動的の両方です。 gccのデフォルトの動作は、「ほぼ動的」にリンクすることです。つまり、gccは可能な場合は動的ライブラリにリンクしますが、そうでない場合は静的ライブラリにフォールバックします。-staticオプションを使用してgccを実行すると、適切な動的ライブラリがある場合でも、静的ライブラリのみをリンクし、静的ライブラリが見つからない場合はエラーで終了します。

いくつかの場合にgccに期待したい別のオプションは、私が-most-staticと呼んでいるもので、基本的に-dynamic(デフォルト)の反対です。 -mostly-staticは、存在する場合、静的ライブラリに対してリンクすることを好みますが、動的ライブラリにフォールバックします。

このオプションは存在しませんが、次のアルゴリズムでエミュレートできます。

  1. -staticを含めずにリンクコマンドラインを作成します。

  2. ダイナミックリンクオプションを反復処理します。

  3. ライブラリパス、つまり-L <lib_dir>形式のオプションを変数<lib_path>に累積します。

  4. 各ダイナミックリンクオプション、つまり-l <lib_name>形式のオプションについて、コマンドgcc <lib_path> -print-file-name = lib <lib_name> .aを実行し、出力をキャプチャします。

  5. コマンドが渡したもの以外のものを出力する場合、それは静的ライブラリへのフルパスになります。ダイナミックライブラリオプションをスタティックライブラリへのフルパスに置き換えます。

リンクコマンドライン全体を処理するまで、すすぎ、繰り返します。オプションで、スクリプトはライブラリ名のリストを取得して、静的リンクから除外することもできます。

次のbashスクリプトは、トリックを行うようです:

#!/bin/bash

if [ $# -eq 0 ]; then
    echo "Usage: $0 [--exclude <lib_name>]. . . <link_command>"
fi

exclude=()
lib_path=()

while [ $# -ne 0 ]; do
    case "$1" in
        -L*)
            if [ "$1" == -L ]; then
                shift
                LPATH="-L$1"
            else
                LPATH="$1"
            fi

            lib_path+=("$LPATH")
            echo -n "\"$LPATH\" "
            ;;

        -l*)
            NAME="$(echo $1 | sed 's/-l\(.*\)/\1/')"

            if echo "${exclude[@]}" | grep " $NAME " >/dev/null; then
                echo -n "$1 "
            else
                LIB="$(gcc $lib_path -print-file-name=lib"$NAME".a)"
                if [ "$LIB" == lib"$NAME".a ]; then
                    echo -n "$1 "
                else
                    echo -n "\"$LIB\" "
                fi
            fi
            ;;

        --exclude)
            shift
            exclude+=(" $1 ")
            ;;

        *) echo -n "$1 "
    esac

    shift
done

echo

例えば:

mostlyStatic gcc -o test test.c -ldl -lpthread

私のシステムでは:

gcc -o test test.c "/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/libdl.a" "/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/libpthread.a"

または除外あり:

mostlyStatic --exclude dl gcc -o test test.c -ldl -lpthread

私はそれから得ます:

gcc -o test test.c -ldl "/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/libpthread.a"

7

-l:libstatic1.a静的ライブラリをリンクするために使用できるgccの-lオプションの(マイナスlコロン)バリアントもあります(https://stackoverflow.com/a/20728782に感謝)。文書化されていますか?gccの公式ドキュメントにはありません(これは共有ライブラリにも当てはまりません):https : //gcc.gnu.org/onlinedocs/gcc/Link-Options.html

-llibrary
-l library 

リンク時にlibraryという名前のライブラリを検索します。(ライブラリを個別の引数として使用する2番目の選択肢はPOSIX準拠のためだけであり、推奨されません。)... -lオプションを使用することとファイル名を指定することの間の唯一の違いは、-lが 'lib'でライブラリを囲み、 '.a'といくつかのディレクトリを検索します。

binutils ld docで説明しています。-lnameオプションでは、検索を行いますlibname.soため、その後libname.aのlib接頭辞を追加し、.so(現時点では有効になっている場合)または.a接尾辞。ただし、-l:nameオプションは指定された名前を正確に検索するだけです:https : //sourceware.org/binutils/docs/ld/Options.html

-l namespec
--library=namespec

によって指定されたアーカイブまたはオブジェクトファイルnamespecをリンクするファイルのリストに追加します。このオプションは何度でも使用できます。namespecの形式の場合 :filename、ldはライブラリパスでというファイルfilenameを検索しますlibnamespec.a。それ以外の場合は、ライブラリパスでというファイルを検索します。

共有ライブラリをサポートするシステムでは、ldは以外のファイルも検索する場合がありますlibnamespec.a。具体的には、ELFおよびSunOSシステムでは、ldはと呼ばれるライブラリを検索するlibnamespec.so前に、呼び出されるライブラリをディレクトリで 検索しlibnamespec.aます。(慣例により、.so拡張子は共有ライブラリを示します。)この動作は:filename、常にと呼ばれるファイルを指定するには適用されないことに注意してくださいfilename

リンカは、コマンドラインで指定された場所で、アーカイブを1回だけ検索します。アーカイブが、コマンドラインでアーカイブの前に表示された一部のオブジェクトで未定義のシンボルを定義している場合、リンカーはアーカイブから適切なファイルを含めます。ただし、後でコマンドラインに表示されるオブジェクトに未定義のシンボルがあっても、リンカーはアーカイブを再度検索しません。

-(リンカーにアーカイブを複数回検索させる方法については、オプションを参照してください。

コマンドラインで同じアーカイブを複数回リストすることができます。

このタイプのアーカイブ検索は、Unixリンカーの標準です。ただし、AIXでldを使用している場合は、AIXリンカーの動作とは異なることに注意してください。

バリアント-l:namespecは、binutils(2007)の2.18バージョン以降でドキュメント化されていますhttps : //sourceware.org/binutils/docs-2.18/ld/Options.html


このオプションは、他のすべてが失敗した場合に機能するようです。ビルドマシンはlibjsocpp.so.0にリンクされたバイナリを生成するのに対し、ターゲットOSはlibjsoncpp.so.1のみを提供するため、libjsoncpp.aを静的リンクする必要がある場合に遭遇しました。この違いを明らかにするまでは、これが私たちのケースで適切な結果をもたらした唯一のソリューションでした。
Tomasz W

4

一部のローダー(リンカー)は、動的ロードをオンまたはオフにするスイッチを提供します。GCCがそのようなシステム(Solaris-および場合によっては他のシステム)で実行されている場合は、関連するオプションを使用できます。

静的にリンクするライブラリがわかっている場合は、リンク行に静的ライブラリファイルをフルパスで指定するだけです。


6
この回答は受け入れられましたが、問題を完全には解決していません。@peoroが解決しようとしている問題を説明したように、彼はすべてのライブラリの静的バージョンがないため、できるだけ多くのライブラリを静的にリンクしたいと考えています。私の答えを見てください。
jcoffland

2

動的ライブラリと静的ライブラリを1行でリンクするには、次のように、動的ライブラリとオブジェクトファイルのに静的ライブラリを配置する必要があります。

gcc -lssl main.o -lFooLib -o main

それ以外の場合は機能しません。それを理解するのに時間がかかります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.