sadece bazı kitaplıkları statik bağlama


108

GCC ile bağlantı kurarken yalnızca bazı belirli kitaplıkları ikili dosyama statik olarak nasıl bağlayabilirim?

gcc ... -static ...tüm bağlantılı kitaplıkları statik olarak bağlamayı dener , ancak bazılarının statik sürümüne sahip değilim (örneğin: libX11).


5
gcc'de

Yanıtlar:


112

gcc -lsome_dynamic_lib code.c some_static_lib.a


5
Kitaplıkları nesne dosyalarından sonra bağlayın - özellikle statik kitaplıklar. Bağlantı ortamının eski ve modern sürümlerinde (Kasım 2010 itibariyle mütevazı eski sürümler için mevcut durumdan emin değilim), statik kitaplığı code.cdosyadan önce listelemek, içindeki sembollerin yok sayılacağını garanti eder. main()kütüphane nesne dosyalarından birinde bir işlev.
Jonathan Leffler

44
Lütfen bunun nasıl çalıştığını açıklar mısınız? Yalnızca kod yanıtları, yeni başlayanlar için yararlı değildir.
jb.

8
@jb varsayılan olarak, gcc dinamik olarak bağlanır. -Lsome_dynamic_lib kullandığınızda, beklendiği gibi dinamik olarak bağlanır. Ancak, gcc'ye açıkça statik bir kitaplık verildiğinde, her zaman onu statik olarak bağlamayı deneyecektir. Bununla birlikte, sembollerin çözülme sırasına ilişkin bazı yanıltıcı ayrıntılar vardır; Bunun nasıl çalıştığından tam olarak emin değilim. Şüpheye düştüğünüzde kütüphane bayraklarının sırasını yeniden düzenlemeyi deneyin :-)
bchurchill

4
Örneğin bir GPL kitaplığı
HiB

1
@HiB GPL, statik ve dinamik bağlantı için aynı yolu uygular
osvein

50

Ayrıca ldseçeneği de kullanabilirsiniz-Bdynamic

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

Ondan sonraki tüm kitaplıklar (gcc ile otomatik olarak bağlanan sistemler dahil) dinamik olarak bağlanacaktır.


19
-Wl, -Bdynamic için GNU ld gerekir, bu nedenle bu çözüm gcc'nin sistem ld'sini kullandığı sistemlerde çalışmaz (örn. Mac OS X).
pts

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

-static-libgcc -static-libstdc++gcc kitaplıkları için bayrakları da kullanabilirsiniz

eğer akılda tutmak libs1.sove libs1.ahem mevcut, bağlayıcı bulacaktır libs1.sodaha önce eğer -Wl,-Bstaticveya sonrasında -Wl,-Bdynamic. Aramadan -L/libs1-library-location/önce geçmeyi unutmayın -ls1.


1
En azından bu çözüm libgomp'a karşı statik bağlantı kurmaya çalışıyor!
Jérôme

Bu benim için iyi çalışıyor, ancak -statickomutta bir yerlerde kullanmak başarısız oluyor (sadece istediğim kitaplıklardan daha fazla şeyi statik olarak bağlamayı denediğini varsayıyorum).
nh2

4
NB. Sırası -Wl,-Bstaticve -Wl,-Bdynamicönemlidir.
Pavel Vlasov

27

ld(Bu gcc ile çalışmaz) kılavuzundan , --staticseçeneğe atıfta bulunarak :

Bu seçeneği komut satırında birçok kez kullanabilirsiniz: onu izleyen -l seçeneklerini aramayı etkiler.

Çözümlerden biri, dinamik bağımlılıklarınızı --statickomut satırındaki seçeneğin önüne koymaktır .

Diğer bir olasılık, --staticbelirli bir kitaplığa statik olarak bağlanmak için statik nesne dosyasının tam dosya adını / yolunu (yani -l seçeneğini kullanmamak) kullanmamaktır. Misal:

# 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)

Örnekte görebileceğiniz gibi, libX11 statik olarak bağlandığı için dinamik olarak bağlı kitaplıklar listesinde değildir.

Dikkat: Bir .sodosya, tam bir dosya adı / yolu ile belirtilse bile her zaman dinamik olarak bağlanır.


LibX11.a ile çıktısı arasındaki ilişki alanı ldd a.outnedir?
Raffi Khatchadourian

1
Ah, anlıyorum. lddgerekli paylaşılan kitaplıkların çıktısını alır ve libX11 bu listede görünmez.
Raffi Khatchadourian

bu net değil. 'bu seçenek' ve 'bu seçenek' diyorsunuz. hangi seçenek?
Octopus

19

Anladığım kadarıyla sorun aşağıdaki gibidir. Bazı kitaplıklarınız var, bazıları statik, bazıları dinamik ve bazıları hem statik hem de dinamik. gcc'nin varsayılan davranışı, "çoğunlukla dinamik" olanı bağlamaktır. Yani gcc , mümkün olduğunda dinamik kitaplıklara bağlanır , ancak aksi takdirde statik kitaplıklara geri döner. Gcc için -static seçeneğini kullandığınızda , davranış sadece statik kitaplıkları bağlamak ve uygun bir dinamik kitaplık olsa bile statik kitaplık bulunamazsa bir hatayla çıkmaktır .

Ben diledi çeşitli vesilelerle var Başka bir seçenek, gcc vardı, ben dediğimiz insanın yaşadığı ülkeler -çoğunlukla-statik ve esasen tersidir -dinamik (varsayılan). -çoğunlukla statik , eğer varsa, statik kitaplıklara bağlanmayı tercih eder, ancak dinamik kitaplıklara geri döner.

Bu seçenek mevcut değildir ancak aşağıdaki algoritma ile benzetilebilir:

  1. Link komut satırını -static içermeyen oluşturma .

  2. Dinamik bağlantı seçeneklerini yineleyin.

  3. Kitaplık yollarını, yani bir <lib_path> değişkeninde -L <lib_dir> biçimindeki seçenekleri biriktirin

  4. Her dinamik bağlantı seçeneği için, yani -l <lib_name> biçimindekiler için , gcc <lib_path> -print-file-name = lib <lib_name> .a komutunu çalıştırın ve çıktıyı yakalayın.

  5. Komut, ilettiğinizden başka bir şey yazdırırsa, statik kitaplığın tam yolu olacaktır. Dinamik kitaplık seçeneğini statik kitaplığın tam yolu ile değiştirin.

Bağlantı komut satırının tamamını işleyene kadar durulayın ve tekrarlayın. İsteğe bağlı olarak komut dosyası, statik bağlamadan hariç tutmak için bir kitaplık adları listesi de alabilir.

Aşağıdaki bash betiği hile yapıyor gibi görünüyor:

#!/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

Örneğin:

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

sistemimde:

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"

veya bir istisna ile:

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

Sonra şunu alırım:

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

7

Ayrıca, -l:libstatic1.agcc'de statik kitaplığı bağlamak için kullanılabilecek (eksi l kolon) -l seçeneğinin varyantı vardır ( https://stackoverflow.com/a/20728782 sayesinde ). Belgelenmiş mi? Resmi gcc belgelerinde yoktur (paylaşılan kitaplıklar için de aynı değildir): https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html

-llibrary
-l library 

Bağlanırken kitaplık adlı kitaplıkta arama yapın. (Ayrı bir bağımsız değişken olarak kitaplığın ikinci alternatifi yalnızca POSIX uyumluluğu içindir ve önerilmez.) ... Bir -l seçeneğini kullanmakla bir dosya adı belirtmek arasındaki tek fark, -l kitaplığı 'lib' ile çevreleyen ve '.a' ve birkaç dizinde arama yapar.

Binutils ld dokümanı bunu açıklıyor. -lnameSeçenek için arama yapacak libname.sodaha sonra libname.alib öneki eklenmesi ve .so(şu anda etkinse) ya da .asonek. Ancak -l:nameseçenek yalnızca tam olarak belirtilen adı arayacaktır: https://sourceware.org/binutils/docs/ld/Options.html

-l namespec
--library=namespec

İle belirtilen arşiv veya nesne dosyasını namespecbağlantı kurulacak dosyalar listesine ekleyin . Bu seçenek herhangi bir sayıda kullanılabilir. Eğer namespecformun olduğu :filename, ld adlı bir dosyayı kütüphane yolunu arayacaktır filenameaksi takdirde adlı bir dosyayı kütüphane yolunu arayacaktır, libnamespec.a.

Paylaşılan kitaplıkları destekleyen sistemlerde, ld, dışındaki dosyaları da arayabilir libnamespec.a. Özellikle, ELF ve SunOS sistemlerinde, ld, aranan libnamespec.sobirini aramadan önce çağrılan bir kitaplık için bir dizin arayacaktır libnamespec.a. (Kural olarak, bir .souzantı paylaşılan bir kitaplığı belirtir.) Bu davranışın, :filenameher zaman çağrılan bir dosyayı belirten için geçerli olmadığını unutmayın filename.

Bağlayıcı, arşivi komut satırında belirtildiği yerde yalnızca bir kez arayacaktır. Arşiv, komut satırında arşivden önce görünen bazı nesnelerde tanımlanmamış bir sembolü tanımlıyorsa, bağlayıcı arşivden uygun dosya (lar) ı içerecektir. Ancak, daha sonra komut satırında görünen bir nesnede tanımlanmamış bir sembol, bağlayıcının arşivi yeniden aramasına neden olmaz.

-(Bağlayıcıyı arşivleri birden çok kez aramaya zorlamanın bir yolu için seçeneğe bakın .

Aynı arşivi komut satırında birden çok kez listeleyebilirsiniz.

Bu tür arşiv araması, Unix bağlayıcılar için standarttır. Ancak, AIX üzerinde ld kullanıyorsanız, bunun AIX bağlayıcısının davranışından farklı olduğunu unutmayın.

Varyant -l:namespec, binutils'in (2007) 2.18 sürümünden beri belgelenmektedir: https://sourceware.org/binutils/docs-2.18/ld/Options.html


Bu seçenek, her şeyin başarısız olduğu yerde çalışıyor gibi görünüyor. Libjsoncpp.a'yı statik bağlamamız gereken bir durumla karşılaştık, çünkü inşa makinelerimiz libjsocpp.so.0'a bağlı ikili dosyalar üretirken, hedef işletim sistemi yalnızca libjsoncpp.so.1'i sağlar. Bu farkı ortadan kaldırana kadar, bizim durumumuzda uygun sonuçlar veren tek çözüm buydu.
Tomasz W

4

Bazı yükleyiciler (bağlayıcılar), dinamik yüklemeyi açıp kapatmak için anahtarlar sağlar. GCC böyle bir sistemde (Solaris - ve muhtemelen diğerleri) çalışıyorsa, ilgili seçeneği kullanabilirsiniz.

Hangi kitaplıkları statik olarak bağlamak istediğinizi biliyorsanız, statik kitaplık dosyasını bağlantı satırında tam yolla belirtebilirsiniz.


6
Bu cevap kabul edilmiş olsa da soruna tam olarak değinmemektedir. @Peoro'nun çözmeye çalıştığı sorunu açıkladığı gibi, tüm kitaplıkların statik sürümlerine sahip olmaması, mümkün olduğu kadar çok kitaplığı statik olarak bağlamak istediğini ima ediyor. Cevabımı gör.
jcoffland

2

dinamik ve statik kitaplığı bir satıra bağlamak için, dinamik kitaplıklardan ve nesne dosyalarından sonra statik kitaplıklar koymalısınız , örneğin:

gcc -lssl main.o -lFooLib -o main

aksi takdirde çalışmaz. Bunu anlamam bazen beni alıyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.