Yanıtlar:
(Daha ayrıntılı metin almak için bu yanıtın geçmişine bakın, ancak şimdi okuyucunun gerçek komut satırlarını görmesinin daha kolay olduğunu düşünüyorum).
Aşağıdaki komutların tümü tarafından paylaşılan ortak dosyalar
$ cat a.cpp
extern int a;
int main() {
return a;
}
$ cat b.cpp
extern int b;
int a = b;
$ cat d.cpp
int b;
$ g++ -c b.cpp -o b.o
$ ar cr libb.a b.o
$ g++ -c d.cpp -o d.o
$ ar cr libd.a d.o
$ g++ -L. -ld -lb a.cpp # wrong order
$ g++ -L. -lb -ld a.cpp # wrong order
$ g++ a.cpp -L. -ld -lb # wrong order
$ g++ a.cpp -L. -lb -ld # right order
Bağlayıcı soldan sağa doğru arama yapar ve çözülmemiş sembolleri giderken not eder. Bir kütüphane sembolü çözerse, sembolü çözmek için o kütüphanenin nesne dosyalarını alır (bu durumda bo libb.a dışında).
Statik kitaplıkların birbirine karşı bağımlılıkları aynı şekilde çalışır - önce sembollere ihtiyaç duyan kitaplık, daha sonra sembolü çözen kitaplık olmalıdır.
Statik bir kitaplık başka bir kitaplığa bağlıysa, ancak diğer kitaplık yine eski kitaplığa bağlıysa, bir döngü vardır. Sen ederek dönüşümlü olarak bağımlı kitaplıkları içine alarak bu çözebilirsiniz -(
ve -)
gibi, -( -la -lb -)
(siz gibi parens, kaçmak gerekebilir -\(
ve -\)
). Bağlayıcı daha sonra bisiklet bağımlılıklarının çözüldüğünden emin olmak için ekteki lib'i birkaç kez arar. Her biri diğerinden önce yani Alternatif olarak, kütüphaneler birden fazla kez belirtebilirsiniz: -la -lb -la
.
$ export LD_LIBRARY_PATH=. # not needed if libs go to /usr/lib etc
$ g++ -fpic -shared d.cpp -o libd.so
$ g++ -fpic -shared b.cpp -L. -ld -o libb.so # specifies its dependency!
$ g++ -L. -lb a.cpp # wrong order (works on some distributions)
$ g++ -Wl,--as-needed -L. -lb a.cpp # wrong order
$ g++ -Wl,--as-needed a.cpp -L. -lb # right order
Burada da aynı - kütüphaneler programın nesne dosyalarını takip etmelidir. Buradaki statik kütüphanelerle karşılaştırıldığında fark, dinamik kütüphanelerin bağımlılıklarını kendilerinin ayırdığı için kütüphanelerin bağımlılıklarına önem vermemenizdir .
Son zamanlarda yapılan bazı dağıtımlar --as-needed
, programın nesne dosyalarının dinamik kitaplıklardan önce gelmesini zorunlu kılan bağlayıcı bayrağını varsayılan olarak kullanıyor . Bu bayrak iletilirse, bağlayıcı yürütülebilir dosya tarafından gerçekten ihtiyaç duyulmayan kitaplıklara bağlanmaz (ve bunu soldan sağa algılar). Son archlinux dağıtımım varsayılan olarak bu bayrağı kullanmıyor, bu nedenle doğru sırayı izlemediği için hata vermedi.
Birincisini oluştururken b.so
karşı bağımlılığı atlamak doğru değildir d.so
. a
O zaman bağlantı kurarken kütüphaneyi belirtmeniz istenir , ancak a
tamsayıya gerçekten ihtiyaç duymaz b
, bu nedenle b
kendi bağımlılıklarına dikkat edilmemelidir .
İşte için bağımlılıkları belirtmeyi kaçırırsanız bunun etkilerine bir örnek libb.so
$ export LD_LIBRARY_PATH=. # not needed if libs go to /usr/lib etc
$ g++ -fpic -shared d.cpp -o libd.so
$ g++ -fpic -shared b.cpp -o libb.so # wrong (but links)
$ g++ -L. -lb a.cpp # wrong, as above
$ g++ -Wl,--as-needed -L. -lb a.cpp # wrong, as above
$ g++ a.cpp -L. -lb # wrong, missing libd.so
$ g++ a.cpp -L. -ld -lb # wrong order (works on some distributions)
$ g++ -Wl,--as-needed a.cpp -L. -ld -lb # wrong order (like static libs)
$ g++ -Wl,--as-needed a.cpp -L. -lb -ld # "right"
Şimdi ikilinin sahip olduğu bağımlılıklara bakarsanız, ikilinin kendisinin de libd
sadece libb
olması gerektiği gibi değil de bağlı olduğuna dikkat edin . Daha libb
sonra başka bir kütüphaneye bağlıysa, bu şekilde yaparsanız ikili dosyanın yeniden bağlanması gerekir . Ve başka biri çalışma zamanında libb
kullanarak dlopen
yüklerse (eklentileri dinamik olarak yüklemeyi düşünün), çağrı da başarısız olur. Yani "right"
gerçekten de bir olmalı wrong
.
lorder
+ tsort
bunu yapar. Ancak, döngüsel referanslarınız varsa bazen düzen yoktur. Sonra her şey çözülene kadar kütüphaneler listesinde dolaşmak zorundasınız.
GNU ld bağlayıcı, akıllı bağlayıcı olarak adlandırılır. Önceki statik kitaplıkların kullandığı işlevleri takip eder ve arama tablolarından kullanılmayan işlevleri kalıcı olarak atar. Sonuç olarak, statik bir kitaplığı çok erken bağlarsanız, o kitaplıktaki işlevler artık bağlantı satırındaki statik kitaplıklar tarafından kullanılamaz.
Tipik UNIX bağlayıcısı soldan sağa doğru çalışır, bu nedenle tüm bağımlı kitaplıklarınızı solda ve bu bağımlılıkları karşılayanlar da bağlantı satırının sağında bulunur. Bazı kütüphanelerin diğerlerine, diğer kütüphanelerin de onlara bağlı olduğunu görebilirsiniz. Burası karmaşıklaşıyor. Dairesel referanslar söz konusu olduğunda, kodunuzu düzeltin!
Statik kütüphaneler söz konusu olduğunda işlerin GCC ile nasıl çalıştığını netleştirmek için bir örnek . Diyelim ki aşağıdaki senaryoya sahibiz:
myprog.o
- içeren main()
fonksiyon, bağımlılibmysqlclient
libmysqlclient
- statik, örneğin uğruna (paylaşılan kütüphaneyi, elbette, libmysqlclient
çok büyük olduğu için tercih edersiniz ); içinde /usr/local/lib
; ve gelen şeylere bağımlılibz
libz
(dinamik)Bunu nasıl bağlarız? (Not: gcc 4.3.4 kullanarak Cygwin üzerinde derleme örnekleri)
gcc -L/usr/local/lib -lmysqlclient myprog.o
# undefined reference to `_mysql_init'
# myprog depends on libmysqlclient
# so myprog has to come earlier on the command line
gcc myprog.o -L/usr/local/lib -lmysqlclient
# undefined reference to `_uncompress'
# we have to link with libz, too
gcc myprog.o -lz -L/usr/local/lib -lmysqlclient
# undefined reference to `_uncompress'
# libz is needed by libmysqlclient
# so it has to appear *after* it on the command line
gcc myprog.o -L/usr/local/lib -lmysqlclient -lz
# this works
-Wl,--start-group
Bağlayıcı bayraklarına eklerseniz , hangi sırayla olduklarını veya dairesel bağımlılıklar olup olmadığını umursamazlar.
Qt'de bu şu anlama gelir:
QMAKE_LFLAGS += -Wl,--start-group
Dağınık zaman yükler kaydeder ve çok (yavaşça derleme çok daha az zaman alır) bağlantı yavaşlatmak gibi görünmüyor.
-Xlinker seçeneğini kullanabilirsiniz.
g++ -o foobar -Xlinker -start-group -Xlinker libA.a -Xlinker libB.a -Xlinker libC.a -Xlinker -end-group
ALMOST eşittir
g++ -o foobar -Xlinker -start-group -Xlinker libC.a -Xlinker libB.a -Xlinker libA.a -Xlinker -end-group
Dikkatli ol!
Beni harekete geçiren hızlı bir ipucu: Eğer bağlayıcıyı "gcc" veya "g ++" olarak çağırıyorsanız, "--start-group" ve "--end-group" komutlarını kullanmak bu seçenekleri linker - bir hata işaretlemez. Kitaplık siparişi yanlışsa, tanımsız sembollerle bağlantı başarısız olur.
GCC'ye argümanı bağlayıcıya geçirmesini bildirmek için bunları "-Wl, - start-group" vb. Olarak yazmanız gerekir.
En azından bazı platformlarda bağlantı sırası kesinlikle önemlidir. Yanlış sırada kütüphaneler ile bağlantılı uygulamalar için çökmeler gördüm (burada yanlış anlamına gelir B önce B bağlı ama B A bağlıdır).
Bunu çok gördüm, bazı modüllerimiz kodumuzun artı kütüphanesi ve 3. parti kütüphanelerinin 100'den fazla kütüphanesine bağlanıyor.
Farklı bağlayıcılara bağlı olarak HP / Intel / GCC / SUN / SGI / IBM / vb. Çözümlenmemiş işlevler / değişkenler vb. Alabilirsiniz, bazı platformlarda kütüphaneleri iki kez listelemeniz gerekir.
Çoğunlukla kütüphanelerin, çekirdeklerin, platformun, farklı soyutlama katmanlarının yapılandırılmış hiyerarşisini kullanıyoruz, ancak bazı sistemler için hala link komutundaki sıra ile oynamak zorundasınız.
Bir çözüm belgesine dokunduğunuzda, bir sonraki geliştiricinin tekrar çalışması gerekmez.
Eski öğretim görevlim " yüksek uyum ve düşük bağlantı " derdi, bugün hala doğru.
gcc
son zamanlarda daha katı davranışlara (nispeten) dönüştü .