Yanıtlar:
gcc -lsome_dynamic_lib code.c some_static_lib.a
code.c
dosyadan önce listelemek, içindeki sembollerin yok sayılacağını garanti eder. main()
kütüphane nesne dosyalarından birinde bir işlev.
Ayrıca ld
seç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.so
ve libs1.a
hem mevcut, bağlayıcı bulacaktır libs1.so
daha önce eğer -Wl,-Bstatic
veya sonrasında -Wl,-Bdynamic
. Aramadan -L/libs1-library-location/
önce geçmeyi unutmayın -ls1
.
-static
komutta 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,-Bstatic
ve -Wl,-Bdynamic
önemlidir.
ld
(Bu gcc ile çalışmaz) kılavuzundan , --static
seç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ı --static
komut satırındaki seçeneğin önüne koymaktır .
Diğer bir olasılık, --static
belirli 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 .so
dosya, tam bir dosya adı / yolu ile belirtilse bile her zaman dinamik olarak bağlanır.
ldd a.out
nedir?
ldd
gerekli 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.a
gcc'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. -lname
Seçenek için arama yapacak libname.so
daha sonra libname.a
lib öneki eklenmesi ve .so
(şu anda etkinse) ya da .a
sonek. Ancak -l:name
seç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ı
namespec
bağlantı kurulacak dosyalar listesine ekleyin . Bu seçenek herhangi bir sayıda kullanılabilir. Eğernamespec
formun olduğu:filename
, ld adlı bir dosyayı kütüphane yolunu arayacaktırfilename
aksi 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.so
birini aramadan önce çağrılan bir kitaplık için bir dizin arayacaktırlibnamespec.a
. (Kural olarak, bir.so
uzantı paylaşılan bir kitaplığı belirtir.) Bu davranışın,:filename
her 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.