Yanıtlar:
gcc -lsome_dynamic_lib code.c some_static_lib.a
code.cdosyadan önce listelemek, içindeki sembollerin yok sayılacağını garanti eder. main()kütüphane nesne dosyalarından birinde bir işlev.
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.
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.
-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).
-Wl,-Bstaticve -Wl,-Bdynamicönemlidir.
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.
ldd a.outnedir?
lddgerekli paylaşılan kitaplıkların çıktısını alır ve libX11 bu listede görünmez.
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:
Link komut satırını -static içermeyen oluşturma .
Dinamik bağlantı seçeneklerini yineleyin.
Kitaplık yollarını, yani bir <lib_path> değişkeninde -L <lib_dir> biçimindeki seçenekleri biriktirin
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.
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"
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 libraryBağ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ğernamespecformun olduğu:filename, ld adlı bir dosyayı kütüphane yolunu arayacaktırfilenameaksi 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, arananlibnamespec.sobirini aramadan önce çağrılan bir kitaplık için bir dizin arayacaktırlibnamespec.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ınfilename.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
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.