साझा पुस्तकालयों में अनसुलझे प्रतीकों की आसान जाँच?


83

मैं एक काफी बड़ा C ++ साझा-ऑब्जेक्ट लायब्रेरी लिख रहा हूं, और एक छोटी सी समस्या में चला गया है जो दर्द को कम करती है:

यदि मैं एक हेडर फ़ाइल में फ़ंक्शन / विधि को परिभाषित करता हूं, और इसके लिए एक स्टब बनाने के लिए भूल जाता हूं (विकास के दौरान), चूंकि मैं एक निष्पादन योग्य के बजाय एक साझा ऑब्जेक्ट लाइब्रेरी के रूप में निर्माण कर रहा हूं, कोई त्रुटि नहीं संकलन-समय पर मुझे बता रहा है। उस फंक्शन को लागू करना भूल गए। एकमात्र तरीका जो मुझे पता है कि कुछ गलत है, रनटाइम पर है, जब अंततः इस पुस्तकालय के खिलाफ एक आवेदन लिंक एक 'अपरिभाषित प्रतीक' त्रुटि के साथ खत्म हो जाता है।

मुझे यह जांचने का एक आसान तरीका मिल रहा है कि क्या मेरे पास सभी प्रतीक हैं जो मुझे संकलन के समय चाहिए, शायद कुछ मैं अपने मेकफिल में जोड़ सकता हूं।

एक समाधान जो मैंने किया था, वह है nm -C -Uकि सभी अपरिभाषित संदर्भों की एक लुप्तप्राय सूची प्राप्त करने के लिए संकलित पुस्तकालय को चलाना । समस्या यह है कि यह सभी संदर्भों की सूची के साथ भी आता है, जो अन्य पुस्तकालयों में हैं, जैसे जीएलआईबीसी, जो कि अंतिम आवेदन के साथ डालने पर इस पुस्तकालय के साथ निश्चित रूप से जुड़ा होगा। यह के उत्पादन में उपयोग करने के लिए संभव हो जाएगा nmकरने के लिए grepअपने सभी हेडर फाइल के माध्यम से और अगर नामों में से कोई भी संबंधित को देखने के .. लेकिन यह पागल लगता है। निश्चित रूप से यह कोई असामान्य मुद्दा नहीं है और इसे हल करने का एक बेहतर तरीका है?


3
nm -C -uमुझे कई बार बचाया है! ( -uमेरे सिस्टम पर लोअरकेस नोट करें ।) इस टिप्पणी को यहां छोड़ दें ताकि मैं अगली बार यह पा सकूं कि मुझे इसकी आवश्यकता है।
dpritch

जवाबों:


94

लिंकर विकल्प -z defs/ देखें --no-undefined। एक साझा ऑब्जेक्ट बनाते समय, यह लिंक का कारण बन जाएगा यदि अनसुलझे प्रतीक हैं तो विफल हो जाएंगे।

यदि आप लिंकर को लागू करने के लिए gcc का उपयोग कर रहे हैं, तो आप लिंकर के -Wlविकल्प को पास करने के लिए कंपाइलर विकल्प का उपयोग करेंगे :

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

एक उदाहरण के रूप में, निम्न फ़ाइल पर विचार करें:

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

अब, यदि आप एक साझा ऑब्जेक्ट में निर्माण करते हैं, तो यह सफल होगा:

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

लेकिन अगर आप जोड़ते हैं -z defs, तो लिंक विफल हो जाएगा और आपको अपने लापता प्रतीक के बारे में बताएगा:

> 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
+1 यह उत्तर उन लोगों की सहायता कर सकता है जो विंडोज पृष्ठभूमि से आते हैं जिसमें संकलन समय के दौरान DLL के बाहरी प्रतीकों को हल किया जाना चाहिए। अच्छा कोड स्निपेट के लिए जाने का रास्ता!
शमिल द कैट

@ शमिल TheCat: नमस्ते, मैंने डालने की कोशिश की है -Wl, -z, मेरी मेक फाइल में डिफ, फिर भी मुझे दौड़ने के दौरान अपरिभाषित प्रतीक त्रुटि मिल रही है लेकिन संकलन के दौरान नहीं। मैं क्या कर सकता हूँ?। मेरे परिदृश्य में, मेरे पास एक के अंदर दो फ़ोल्डर हैं (जैसे, A / B, i, e B A के अंदर है), और मैं "libA.so" में कुछ प्रतीक या B देख सकता हूं। मुझे यकीन नहीं है कि बी में हर प्रतीक "libA.so" में उपलब्ध है। मैं यह कैसे सुनिश्चित करूँ?
विनय

@ShmilTheCat विंडोज डीएलएल जैसी चीजों को और भी अधिक बनाने के लिए, आप -Bsymbolicलिंकर कमांड लाइन में जोड़ सकते हैं । यहां तक ​​कि अगर forgot_to_defineअब -zचेक के लिए पुस्तकालय में मौजूद है , तो निष्पादन योग्य अभी भी अपनी परिभाषा के साथ इसे ओवरराइड कर सकता है और लाइब्रेरी की अपनी परिभाषाएं उस ओवरराइड पर जाएगी; -Bsymbolicचीजों को बल देता है ताकि पुस्तकालय की अपनी परिभाषाएं अपने कार्यों पर जाएं।
कज़

केवल वास्तव में उपयोग किए जाने वाले कार्यों के लिए काम करता है। अगर मैं // forgot_to_define(fp);इसे एक त्रुटि की रिपोर्ट नहीं करता हूं
एजेंट

19

लिनक्स पर (जो आप उपयोग करते हुए दिखाई देते हैं) ldd -r a.out आपको वही उत्तर देना चाहिए जिसकी आप तलाश कर रहे हैं।

अद्यतन: एक तुच्छ तरीका है a.outजिसके खिलाफ जाँच करें:

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

4
यह लगभग nm -C -U जैसी ही बात करता है, जो मैंने मूल पोस्ट में सुझाई थी। समस्या यह है कि कोई 'a.out' एप्लिकेशन नहीं है, यह एक साझा पुस्तकालय है, इसलिए ldd -r mylibrary.so आउटपुट का एक पूरा ढेर देता है, क्योंकि यह विभिन्न अन्य गतिशील पुस्तकालयों से प्रतीकों का उपयोग करता है .. मुझे विशेष रूप से दिलचस्पी है बाहरी पुस्तकालयों के बजाय मेरे हेडर फ़ाइलों में परिभाषित किए गए प्रतीकों को गायब करना।
डेविड क्लेरिज

2
इसे स्वीकार किया जाना चाहिए, सवाल यह है कि अपरिभाषित प्रतीकों की जांच करने का आसान तरीका क्या है, अपरिभाषित प्रतीकों से कैसे बचें
http8086

9

क्या एक परीक्षण के बारे में? आप नकली निष्पादन योग्य बनाते हैं जो आपके लिए आवश्यक प्रतीकों से जुड़ते हैं। यदि लिंकिंग विफल हो जाती है, तो इसका मतलब है कि आपका लाइब्रेरी इंटरफ़ेस अधूरा है।


4

एक बार मुझे भी यही समस्या हुई। मैं C ++ में एक घटक मॉडल विकसित कर रहा था, और निश्चित रूप से, घटकों को गतिशील रूप से रनटाइम पर लोड करना चाहिए। तीन समाधान दिमाग में आते हैं, जो मैंने लागू किए थे:

  1. एक निर्माण प्रणाली को परिभाषित करने के लिए कुछ समय लें जो सांख्यिकीय रूप से संकलित करने में सक्षम है। आप कुछ समय इंजीनियरिंग में इसे खो देंगे, लेकिन यह आपको इन कष्टप्रद रनटाइम त्रुटियों को पकड़ने में बहुत समय बचाएगा।
  2. अपने कार्यों को अच्छी तरह से ज्ञात और अच्छी तरह से समझे जाने वाले वर्गों में समूहित करें, ताकि आप कार्यों के समूह / स्टब्स को सुनिश्चित कर सकें कि प्रत्येक संगत फ़ंक्शन का स्टब है। यदि आप इसे अच्छी तरह से प्रलेखित करने के लिए समय लेते हैं, तो आप शायद एक स्क्रिप्ट लिख सकते हैं जो परिभाषाओं की जांच करता है (उदाहरण के लिए, इसकी डॉक्सीजन टिप्पणियाँ) और इसके लिए इसी .cpp फ़ाइल की जाँच करें।
  3. कई परीक्षण निष्पादन योग्य कार्य करें जो पुस्तकालयों के एक ही सेट को लोड करते हैं और RTL_NOW ध्वज को dlopen में निर्दिष्ट करते हैं (यदि आप * NIX के अंतर्गत हैं)। वे लापता प्रतीकों का संकेत देंगे।

उम्मीद है की वो मदद करदे।


RTLD_NOW की तर्ज पर, क्या env var तत्काल (गैर आलसी) बाइंडिंग के लिए बाध्य है?
स्टेफानो बोरीनी

1
हाँ। यहाँ यह LD_BIND_NOW है (libc5; 2.1.1 के बाद से glibc) यदि गैर-रिक्त स्ट्रिंग पर सेट किया जाता है, तो डायनेमिक लिंकर का कारण प्रोग्राम स्टार्टअप पर सभी प्रतीकों को हल करने के बजाय फ़ंक्शन कॉल रिओवल से उस बिंदु पर होता है जब वे पहली बार सजा लेते हैं। डिबगर का उपयोग करते समय यह उपयोगी है।
स्टेफानो बोरीनी

यह ओपी के उद्देश्य के लिए भी उपयोगी हो सकता है: LD_WARN (केवल ELF) (2.1.3 के बाद से चमक) यदि गैर-खाली स्ट्रिंग पर सेट किया गया है, तो अनसुलझे प्रतीकों के बारे में चेतावनी दें।
स्टेफानो बोरीनी

स्टेफानो: हाँ, यह सही है। वे चर मौजूद हैं। हालाँकि, यदि आप बाद में गतिशील लोडिंग को समाप्त कर रहे हैं (जब उपयोगकर्ता किसी मॉड्यूल को लोड करता है) तो ये चर तब तक उपयोगी नहीं होते हैं जब तक आप वास्तव में परीक्षण कार्यक्रम नहीं लिखते हैं जो इच्छित (भविष्य) पुस्तकालयों को लोड करता है।
डिएगो सेविला
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.