web-dev-qa-db-ja.com

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

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

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

97
peoro

gcc -lsome_dynamic_lib code.c some_static_lib.a

103
Let_Me_Be

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

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

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

48
Dmitry Yudakov
gcc objectfiles -o program -Wl,-Bstatic -ls1 -ls2 -Wl,-Bdynamic -ld1 -ld2

以下を使用することもできます:gccライブラリの-static-libgcc -static-libstdc++フラグ

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

28
wgodoy

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ファイルは、完全なファイル名/パスで指定されている場合でも、常に動的にリンクされます。

27
ypnos

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

gccが望んでいた別のオプションは、-mostly-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"
18
jcoffland

静的ライブラリをリンクするために使用できるgccの-lオプションの-l:libstatic1.a(マイナス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のドキュメントで説明されています。 -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

7
osgx

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

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

4

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

gcc -lssl main.o -lFooLib -o main

そうしないと、機能しません。それを理解するのに時間がかかります。

2
Vincent