Paylaşılan kütüphanelerde çözülmemiş semboller için kolay kontrol?


83

Oldukça büyük bir C ++ paylaşılan nesne kitaplığı yazıyorum ve hata ayıklamayı bir acı haline getiren küçük bir sorunla karşılaştım:

Bir başlık dosyasında bir işlev / yöntem tanımlarsam ve bunun için bir saplama oluşturmayı unutursam (geliştirme sırasında), yürütülebilir bir dosya yerine paylaşılan bir nesne kitaplığı oluşturduğum için, derleme sırasında bana sahip olduğumu söyleyen hiçbir hata görünmez bu işlevi uygulamayı unuttum. Bir şeyin yanlış olduğunu bulmamın tek yolu çalışma zamanında, bu kitaplığa bağlanan bir uygulamanın sonunda bir 'tanımsız sembol' hatasıyla düştüğü zamandır.

Derleme sırasında ihtiyacım olan tüm sembollere sahip olup olmadığımı kontrol etmenin kolay bir yolunu arıyorum, belki de Makefile'ıma ekleyebileceğim bir şey.

nm -C -UBulduğum bir çözüm, tanımlanmamış tüm referansların karmaşık bir listesini elde etmek için derlenmiş kitaplığı çalıştırmaktır . Sorun, bu aynı zamanda, GLibC gibi diğer kütüphanelerde bulunan ve son uygulama bir araya getirildiğinde elbette bu kitaplıkla birlikte bağlanacak olan tüm referansların listesiyle birlikte gelir. Çıktısını kullanmak mümkün olacaktır nmiçin greptüm başlık dosyaları içinden ve herhangi birinin adını karşılık gelen olmadığını görmek .. ama bu deli görünüyor. Elbette bu nadir bir sorun değil ve bunu çözmenin daha iyi bir yolu var mı?


3
nm -C -ubeni defalarca kurtardı! ( -usistemimdeki küçük harfe dikkat edin .) Bu yorumu buraya bırakarak, bir dahaki sefere ihtiyacım olduğunda bulabilirim.
dpritch

Yanıtlar:


94

Bağlayıcı seçeneğine göz atın -z defs/ --no-undefined. Paylaşılan bir nesne oluştururken, çözülmemiş semboller varsa bağlantının başarısız olmasına neden olur.

Bağlayıcıyı çağırmak için gcc kullanıyorsanız -Wl, seçeneği bağlayıcıya geçirmek için derleyici seçeneğini kullanırsınız:

gcc -shared ... -Wl,-z,defs

Örnek olarak aşağıdaki dosyayı ele alalım:

#include <stdio.h>

void forgot_to_define(FILE *fp);

void doit(const char *filename)
{
    FILE *fp = fopen(filename, "r");
    if (fp != NULL)
    {
        forgot_to_define(fp);
        fclose(fp);
    }
}

Şimdi, bunu paylaşılan bir nesneye dönüştürürseniz, başarılı olacaktır:

> gcc -shared -fPIC -o libsilly.so silly.c && echo succeeded || echo failed
succeeded

Ancak eklerseniz -z defs, bağlantı başarısız olur ve size eksik sembolünüz hakkında bilgi verir:

> gcc -shared -fPIC -o libsilly.so silly.c -Wl,-z,defs && echo succeeded || echo failed
/tmp/cccIwwbn.o: In function `doit':
silly.c:(.text+0x2c): undefined reference to `forgot_to_define'
collect2: ld returned 1 exit status
failed

3
Bu yanıtı + 1'lemek, derleme sırasında DLL'lerin harici sembollerinin çözülmesi gereken Windows arka planından gelen kişilere yardımcı olabilir . Güzel kod parçacığını seçmenin yolu!
Shmil The Cat

@ShmilTheCat: Merhaba, make dosyama -Wl, -z, defs koymayı denedim, yine de çalışırken tanımsız sembol hatası alıyorum ama derleme sırasında değil. Ne yapabilirim?. Benim senaryomda, iç içe iki klasörüm var (örneğin, A / B, i, e B A'nın içindedir) ve "libA.so" da birkaç sembol veya B görüyorum. B'deki her sembolün "libA.so" da mevcut olup olmadığından emin değilim. Bundan nasıl emin olabilirim?
Vinay

@ShmilTheCat İşleri daha da bir Windows DLL gibi -Bsymbolicyapmak için linker komut satırına ekleyebilirsiniz . Kontrol forgot_to_definesayesinde artık kütüphanede mevcut olsa bile -z, çalıştırılabilir kendi tanımıyla onu geçersiz kılabilir ve kütüphanenin kendi tanımları bu geçersiz kılmaya gidecektir; -Bsymbolicşeyleri, kütüphanenin kendi işlevlerine ilişkin tanımlarının işlevlerine gitmesi için zorlar.
Kaz

Yalnızca gerçekten kullanılan işlevler için çalışır. Ben yaparsanız // forgot_to_define(fp);o mu değil bir hata bildirir
Ajan Smith

19

Linux'ta (kullanıyor göründüğünüz) ldd -r a.outsize tam olarak aradığınız cevabı vermelidir.

GÜNCELLEME: a.outkontrol etmek için oluşturmanın önemsiz bir yolu :

 echo "int main() { return 0; }" | g++ -xc++ - ./libMySharedLib.so
 ldd -r ./a.out

4
Bu, orijinal gönderide önerdiğim nm -C -U ile neredeyse aynı şeyi yapıyor. Sorun şu ki, bahsedilecek bir 'a.out' uygulaması yok, bu paylaşılan bir kitaplık, yani ldd -r mylibrary. Diğer çeşitli dinamik kitaplıklardan semboller kullandığı için tam bir çıktı yığını veriyor .. Özellikle ilgileniyorum söz konusu eksik semboller tanımlanan benim ziyade dış kütüphaneleri daha başlık dosyaları.
David Claridge

2
bu kabul edilmelidir, soru tanımlanmamış sembolleri kontrol etmenin kolay yolu nedir, tanımlanmamış sembollerden nasıl kaçınılacağı değil
http8086

9

Ya bir test takımı? İhtiyacınız olan sembollere bağlanan taklit çalıştırılabilir dosyalar oluşturursunuz. Bağlama başarısız olursa, kütüphane arayüzünüz eksik demektir.


4

Aynı sorunu bir kez yaşadım. C ++ 'da bir bileşen modeli geliştiriyordum ve tabii ki bileşenler çalışma zamanında dinamik olarak yüklenmelidir. Aklıma üç çözüm geliyor, uyguladıklarım bunlar:

  1. Statik olarak derlenebilen bir yapı sistemi tanımlamak için biraz zaman ayırın. Mühendislik için biraz zaman kaybedeceksiniz, ancak bu can sıkıcı çalışma zamanı hatalarını yakalamakta size çok zaman kazandıracak.
  2. İşlevlerinizi iyi bilinen ve iyi anlaşılan bölümlerde gruplayın, böylece her bir karşılık gelen işlevin kendi saplamasına sahip olduğundan emin olmak için işlevleri / saplamaları gruplayabilirsiniz. İyi bir şekilde belgelemeye zaman ayırırsanız, belki tanımları (örneğin doxygen yorumları aracılığıyla) kontrol eden bir komut dosyası yazabilir ve bunun için ilgili .cpp dosyasını kontrol edebilirsiniz.
  3. Aynı kitaplık kümesini yükleyen ve dlopen olarak RTLD_NOW bayrağını belirten birkaç test yürütülebilir dosyası yapın (* NIX altındaysanız). Eksik sembolleri işaret edecekler.

Umarım yardımcı olur.


RTLD_NOW satırlarında, anında (tembel olmayan) bağlanmaya zorlamak için bir env var var mı?
Stefano Borini

1
Evet. burada LD_BIND_NOW (libc5; glibc, 2.1.1'den beri) Boş olmayan dizge olarak ayarlanmışsa, dinamik bağlayıcının işlev çağrısı çözümlemesini ilk kez başvurulduğu noktaya ertelemek yerine program başlangıcında tüm simgeleri çözümlemesine neden olur. Bu, bir hata ayıklayıcı kullanırken kullanışlıdır.
Stefano Borini

Bu, OP: LD_WARN (yalnızca ELF) (2.1.3'ten beri glibc) için de yararlı olabilir. Boş olmayan dizgeye ayarlanmışsa, çözümlenmemiş semboller hakkında uyarın.
Stefano Borini

Stefano: Evet, bu doğru. Bu değişkenler var. Ancak, dinamik yüklemeyi daha sonraya erteliyorsanız (örneğin, kullanıcı bir modülü yüklediğinde), bu değişkenler, amaçlanan (gelecekteki) kitaplıkları yükleyen test programını gerçekten yazmadığınız sürece yararlı değildir.
Diego Sevilla
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.