Erlang 21 - 6. Xref - The Cross Reference Tool

6 Xref - क्रॉस संदर्भ उपकरण




erlang

6 Xref - क्रॉस संदर्भ उपकरण

Xref एक क्रॉस रेफरेंस टूल है, जिसका उपयोग फ़ंक्शन, मॉड्यूल, एप्लिकेशन और रिलीज़ के बीच निर्भरता खोजने के लिए किया जा सकता है। यह परिभाषित कार्यों और फ़ंक्शन कॉल का विश्लेषण करके ऐसा करता है।

Xref को उपयोग में आसान बनाने के लिए, पूर्वनिर्धारित विश्लेषण हैं जो कुछ सामान्य कार्य करते हैं। आमतौर पर, एक मॉड्यूल या एक रिलीज़ को अपरिभाषित कार्यों के लिए कॉल के लिए जाँच की जा सकती है। कुछ हद तक अधिक उन्नत उपयोगकर्ता के लिए एक छोटी, बल्कि लचीली भाषा है, जिसका उपयोग विश्लेषण प्रणाली के कुछ हिस्सों के चयन के लिए और चयनित कॉल पर कुछ सरल ग्राफ विश्लेषण करने के लिए किया जा सकता है।

निम्नलिखित अनुभाग Xref की कुछ विशेषताओं को दिखाते हैं, जो एक मॉड्यूल चेक और एक पूर्वनिर्धारित विश्लेषण के साथ शुरू होता है। फिर उन उदाहरणों का पालन करें जिन्हें पहले पढ़ने पर छोड़ दिया जा सकता है; उपयोग की गई सभी अवधारणाओं को समझाया नहीं गया है, और यह माना जाता है कि reference manual कम से कम स्किम्ड हो गई है।

6.1 मॉड्यूल की जाँच

मान लें कि हम निम्नलिखित मॉड्यूल की जांच करना चाहते हैं:

-module(my_module).

-export([t/1]).

t(A) ->
  my_module:t2(A).

t2(_) ->
  true.    

क्रॉस संदर्भ डेटा को BEAM फ़ाइलों से पढ़ा जाता है, इसलिए किसी संपादित मॉड्यूल की जांच करते समय पहला चरण इसे संकलित करना है:

1> c(my_module, debug_info).
./my_module.erl:10: Warning: function t2/1 is unused
{ok, my_module}    

debug_info विकल्प सुनिश्चित करता है कि BEAM फ़ाइल में डिबग जानकारी है, जो अप्रयुक्त स्थानीय कार्यों को खोजने के लिए संभव बनाता है।

मॉड्यूल को अब deprecated functions लिए कॉल, undefined functions लिए कॉल और अप्रयुक्त स्थानीय कार्यों के लिए जाँच की जा सकती है:

2> xref:m(my_module)
[{deprecated,[]},
 {undefined,[{{my_module,t,1},{my_module,t2,1}}]},
 {unused,[{my_module,t2,1}]}]    

m/1 यह जाँचने के लिए भी उपयुक्त है कि एक मॉड्यूल की BEAM फाइल जो एक रनिंग सिस्टम में लोड होने वाली है वह किसी अपरिभाषित फ़ंक्शन को कॉल नहीं करती है। या तो मामले में, कोड सर्वर का कोड पथ (मॉड्यूल code देखें) का उपयोग उन मॉड्यूल को खोजने के लिए किया जाता है, जो बाहरी रूप से निर्यात किए गए फ़ंक्शन को चेक किए गए मॉड्यूल द्वारा निर्यात नहीं किया जाता है, इसलिए library modules कहा जाता library modules

6.2 पूर्वनिर्धारित विश्लेषण

अंतिम उदाहरण में विश्लेषण करने के लिए मॉड्यूल को m/1 तर्क के रूप में दिया गया था, और कोड पथ (स्पष्ट रूप से) library path रूप में उपयोग किया गया था। इस उदाहरण में एक xref server का उपयोग किया जाएगा, जो अनुप्रयोगों और रिलीज़ का विश्लेषण करना संभव बनाता है, और लाइब्रेरी पथ को स्पष्ट रूप से चुनने के लिए भी।

प्रत्येक Xref सर्वर को एक अद्वितीय नाम से संदर्भित किया जाता है। सर्वर बनाते समय नाम दिया गया है:

1> xref:start(s).
{ok,<0.27.0>}    

विश्लेषण की जाने वाली प्रणाली के आगे Xref सर्वर जोड़ा जाता है। यहां सिस्टम ओटीपी होगा, इसलिए लाइब्रेरी पथ की आवश्यकता नहीं होगी। अन्यथा, जब ओटीपी का उपयोग करने वाली प्रणाली का विश्लेषण करते हैं, तो ओटीपी मॉड्यूल को आमतौर पर लाइब्रेरी पथ को डिफ़ॉल्ट ओटीपी कोड पथ (या code_path , reference manual देखें) के लिए लाइब्रेरी पथ सेट करके बनाया जाता है। डिफ़ॉल्ट रूप से, विश्लेषण किए गए मॉड्यूल को जोड़ने पर BEAM फ़ाइलों और चेतावनियों के नाम आउटपुट होते हैं, लेकिन कुछ विकल्पों के डिफ़ॉल्ट मान सेट करके इन संदेशों से बचा जा सकता है:

2> xref:set_default(s, [{verbose,false}, {warnings,false}]).
ok
3> xref:add_release(s, code:lib_dir(), {name, otp}).
{ok,otp}    

add_release/3 मानता है कि पुस्तकालय निर्देशिका के सभी उपनिर्देशिका code:lib_dir() द्वारा लौटाए गए हैं code:lib_dir() में अनुप्रयोग हैं; इसका प्रभाव सभी अनुप्रयोगों की BEAM फ़ाइलों को पढ़ने में है।

अपरिभाषित कार्यों के लिए कॉल के लिए रिलीज़ की जाँच करना अब आसान है:

4> xref:analyze(s, undefined_function_calls).
{ok, [...]}    

अब हम आगे के विश्लेषण जारी रख सकते हैं, या हम Xref सर्वर को हटा सकते हैं:

5> xref:stop(s).    

अपरिभाषित कार्यों के लिए कॉल की जांच एक पूर्वनिर्धारित विश्लेषण का एक उदाहरण है, शायद सबसे उपयोगी एक। अन्य उदाहरण वे विश्लेषण हैं जो अप्रयुक्त स्थानीय कार्यों को ढूंढते हैं, या कुछ दिए गए कार्यों को कॉल करने वाले फ़ंक्शन। पूर्वनिर्धारित विश्लेषणों की पूरी सूची के लिए analyze/2,3 फ़ंक्शन देखें।

प्रत्येक पूर्वनिर्धारित विश्लेषण एक query लिए एक आशुलिपि है, एक छोटी भाषा का एक वाक्य जो predefined variables मूल्यों के रूप में क्रॉस संदर्भ डेटा प्रदान करता है। अपरिभाषित कार्यों के लिए कॉल की जांच इस प्रकार एक प्रश्न के रूप में कहा जा सकता है:

4> xref:q(s, "(XC - UC) || (XU - X - B)").
{ok,[...]}    

क्वेरी बाह्य कॉलों के लिए उन कॉलों के लिए कॉल को रोकती है, जो उन कॉलों के लिए होती हैं, जो बाहरी रूप से उपयोग किए जाते हैं, लेकिन न तो निर्यात किए जाते हैं और न ही अंतर्निहित कार्य (ऑपरेटर ऑपरेटर उपयोग किए गए कार्यों को प्रतिबंधित करता है, जबकि कॉलिंग कार्यों को प्रतिबंधित करता है)। - ऑपरेटर दो सेटों के अंतर को लौटाता है, और + ऑपरेटर को नीचे दिए गए दो सेटों के मिलन के लिए उपयोग किया जाता है।

पूर्वनिर्धारित चर XU , X , B और कुछ अन्य लोगों के बीच के संबंध विस्तृत हैं। संदर्भ मैनुअल में सभी कार्यों के सेट को व्यक्त करने के दो तरीकों का उल्लेख किया गया है, एक यह है कि वे कैसे परिभाषित किए गए हैं: इस पर ध्यान केंद्रित करते हैं: X + L + B + U , और एक है कि उनका उपयोग कैसे किया जाता है: UU + LU + XU । संदर्भ में चरों के बारे में कुछ facts का उल्लेख है:

  • F , L + X बराबर है (परिभाषित कार्य स्थानीय कार्य और बाहरी कार्य हैं);
  • U XU का एक सबसेट है (अज्ञात फ़ंक्शन बाहरी उपयोग किए गए कार्यों का एक सबसेट हैं क्योंकि कंपाइलर यह सुनिश्चित करता है कि स्थानीय रूप से उपयोग किए गए फ़ंक्शन परिभाषित हैं);
  • B XU का एक सबसेट है (कॉल-टू-इन फ़ंक्शन हमेशा बाहरी रूप से परिभाषा के होते हैं, और अप्रयुक्त अंतर्निहित कार्यों को अनदेखा किया जाता है);
  • LU F का एक उपसमूह है (स्थानीय रूप से उपयोग किए जाने वाले कार्य स्थानीय कार्य या निर्यात किए गए कार्य हैं, फिर से संकलक द्वारा सुनिश्चित किए जाते हैं);
  • UU F - (XU + LU) बराबर है F - (XU + LU) (अप्रयुक्त कार्यों को परिभाषित कार्य हैं जो न तो बाहरी और न ही स्थानीय रूप से उपयोग किए जाते हैं);
  • UU F का एक सबसेट है (विश्लेषण किए गए मॉड्यूल में अप्रयुक्त कार्यों को परिभाषित किया गया है)।

इन तथ्यों का उपयोग करके, नीचे दी गई तस्वीर में दो छोटे घेरे संयुक्त किए जा सकते हैं।

चित्र 6.1: परिभाषा और कार्यों का उपयोग

ऐसे घेरे में क्वेरी के चर को चिह्नित करना अक्सर स्पष्ट होता है। यह पूर्वनिर्धारित विश्लेषणों में से कुछ के लिए नीचे दी गई तस्वीर में चित्रित किया गया है। ध्यान दें कि स्थानीय फ़ंक्शन द्वारा उपयोग किए जाने वाले स्थानीय फ़ंक्शन केवल स्थानीय लोगों में चिह्नित नहीं होते हैं।

चित्र 6.2: कुछ पूर्वनिर्धारित विश्लेषण सभी कार्यों के सबसेट के रूप में होते हैं

6.3 भाव

मॉड्यूल की जांच और पूर्वनिर्धारित विश्लेषण उपयोगी हैं, लेकिन सीमित हैं। कभी-कभी अधिक लचीलेपन की आवश्यकता होती है, उदाहरण के लिए किसी को सभी कॉलों पर एक ग्राफ विश्लेषण लागू करने की आवश्यकता नहीं हो सकती है, लेकिन कुछ सबसेट समान रूप से अच्छा करेगा। वह लचीलापन एक सरल भाषा के साथ प्रदान किया जाता है। नीचे टिप्पणियों के साथ भाषा के कुछ भाव दिए गए हैं, उपयोगी उदाहरण प्रदान करने के बजाय भाषा के तत्वों पर ध्यान केंद्रित कर रहे हैं। विश्लेषण प्रणाली को ओटीपी माना जाता है, इसलिए प्रश्नों को चलाने के लिए, पहले इन कॉल का मूल्यांकन करें:

xref:start(s).
xref:add_release(s, code:root_dir()).    
xref:q(s, "(Fun) xref : Mod").
xref मॉड्यूल के सभी कार्य।
xref:q(s, "xref : Mod * X").
xref मॉड्यूल के सभी निर्यात किए गए कार्य। चौराहे ऑपरेटर * पहले ऑपरेंड को दूसरे विशेष रूप से अधिक विशेष प्रकार में बदल दिया जाता है।
xref:q(s, "(Mod) tools").
टूल एप्लिकेशन के सभी मॉड्यूल।
xref:q(s, '"xref_.*" : Mod').
xref_ शुरू होने वाले नाम के सभी मॉड्यूल।
xref:q(s, "# E | X ").
निर्यात कार्यों से कॉल की संख्या।
xref:q(s, "XC || L ").
स्थानीय कार्यों के लिए सभी बाहरी कॉल।
xref:q(s, "XC * LC").
सभी कॉल जिसमें बाहरी और स्थानीय दोनों संस्करण होते हैं।
xref:q(s, "(LLin) (LC * XC)").
वह लाइनें जहाँ अंतिम उदाहरण के स्थानीय कॉल किए जाते हैं।
xref:q(s, "(XLin) (LC * XC)").
वे पंक्तियाँ जहाँ अंतिम से पहले के उदाहरण के बाहरी कॉल किए जाते हैं।
xref:q(s, "XC * (ME - strict ME)").
कुछ मॉड्यूल के भीतर बाहरी कॉल।
xref:q(s, "E ||| kernel").
सभी कर्नेल अनुप्रयोग के भीतर कॉल करते हैं।
xref:q(s, "closure E | kernel || kernel").
कर्नेल अनुप्रयोग के भीतर सभी प्रत्यक्ष और अप्रत्यक्ष कॉल। अप्रत्यक्ष कॉल की कॉलिंग और उपयोग किए गए दोनों फ़ंक्शन कर्नेल एप्लिकेशन के मॉड्यूल में परिभाषित किए गए हैं, लेकिन यह संभव है कि कर्नेल एप्लिकेशन के बाहर कुछ फ़ंक्शन अप्रत्यक्ष कॉल द्वारा उपयोग किए जाते हैं।
xref:q(s, "{toolbar,debugger}:Mod of ME").
मॉड्यूल की एक श्रृंखला toolbar से debugger को कॉल करती है, अगर ऐसी कोई श्रृंखला है, अन्यथा false । कॉल की श्रृंखला को मॉड्यूल की एक सूची द्वारा दर्शाया गया है, toolbar पहला तत्व है और अंतिम तत्व debugger है।
xref:q(s, "closure E | toolbar:Mod || debugger:Mod").
सभी (इन) toolbar में फ़ंक्शंस से debugger में फ़ंक्शंस के लिए सीधे कॉल करता है।
xref:q(s, "(Fun) xref -> xref_base").
सभी फ़ंक्शन xref से xref_base कॉल xref_base
xref:q(s, "E * xref -> xref_base").
अंतिम अभिव्यक्ति के रूप में एक ही व्याख्या।
xref:q(s, "E || xref_base | xref").
अंतिम अभिव्यक्ति के रूप में एक ही व्याख्या।
xref:q(s, "E * [xref -> lists, xref_base -> digraph]").
सभी फ़ंक्शन xref से lists कॉल करते हैं, और सभी फ़ंक्शन xref_base से xref_base तक कॉल करते हैं।
xref:q(s, "E | [xref, xref_base] || [lists, digraph]").
सभी फ़ंक्शन xref और xref_base से lists और xref_base पर कॉल करते हैं।
xref:q(s, "components EE").
इंटर कॉल ग्राफ के सभी दृढ़ता से जुड़े घटक। प्रत्येक घटक निर्यात या अप्रयुक्त स्थानीय कार्यों का एक सेट है जो एक दूसरे को (में) सीधे कॉल करते हैं।
xref:q(s, "X * digraph * range (closure (E | digraph) | (L * digraph))").
digraph कुछ फ़ंक्शन द्वारा सीधे उपयोग किए गए (इन) digraph मॉड्यूल के सभी निर्यात किए गए कार्य।
xref:q(s, "L * yeccparser:Mod - range (closure (E |
yeccparser:Mod) | (X * yeccparser:Mod))").
व्याख्या को एक अभ्यास के रूप में छोड़ दिया जाता है।

6.4 ग्राफ विश्लेषण

representation of graphs की सूची representation of graphs उपयोग प्रत्यक्ष कॉल का विश्लेषण करने के लिए किया जाता है, जबकि digraph प्रतिनिधित्व अप्रत्यक्ष कॉल का विश्लेषण करने के लिए अनुकूल है। प्रतिबंध ऑपरेटर ( | , || और ||| ) एकमात्र ऑपरेटर हैं जो दोनों अभ्यावेदन स्वीकार करते हैं। इसका मतलब यह है कि प्रतिबंध का उपयोग करते हुए अप्रत्यक्ष कॉल का विश्लेषण करने के लिए, closure ऑपरेटर (जो ग्राफ़ के digraph प्रतिनिधित्व का निर्माण करता है) को स्पष्ट रूप से लागू किया जाना है।

अप्रत्यक्ष कॉल का विश्लेषण करने के एक उदाहरण के रूप में, निम्नलिखित एर्लैंग फ़ंक्शन प्रश्न का उत्तर देने की कोशिश करता है: यदि हम जानना चाहते हैं कि कौन से मॉड्यूल का उपयोग कुछ मॉड्यूल (एस) द्वारा अप्रत्यक्ष रूप से किया जाता है, तो क्या यह मॉड्यूल ग्राफ़ के बजाय function graph का उपयोग करते समय लायक है? याद रखें कि एक मॉड्यूल M1 को एक मॉड्यूल M2 कॉल करने के लिए कहा जाता है यदि M1 में कुछ फ़ंक्शन है जो M2 में कुछ फ़ंक्शन को कॉल करता है। यह बहुत अच्छा होगा यदि हम बहुत छोटे मॉड्यूल ग्राफ का उपयोग कर सकते हैं, क्योंकि यह Xref सर्वर के हल्के वजन modules mode में भी उपलब्ध है।

t(S) ->
  {ok, _} = xref:q(S, "Eplus := closure E"),
  {ok, Ms} = xref:q(S, "AM"),
  Fun = fun(M, N) -> 
      Q = io_lib:format("# (Mod) (Eplus | ~p : Mod)", [M]),
      {ok, N0} = xref:q(S, lists:flatten(Q)),
      N + N0
    end,
  Sum = lists:foldl(Fun, 0, Ms),
  ok = xref:forget(S, 'Eplus'),
  {ok, Tot} = xref:q(S, "# (closure ME | AM)"),
  100 * ((Tot - Sum) / Tot).    

कोड पर टिप्पणियाँ:

  • हम मॉड्यूल के लिए फ़ंक्शन ग्राफ़ के समापन को कम करना चाहते हैं। ऐसा करने के लिए प्रत्यक्ष अभिव्यक्ति (Mod) (closure E | AM) , लेकिन फिर हमें स्मृति में ई के सभी सकर्मक समापन का प्रतिनिधित्व करना होगा। इसके बजाय प्रत्येक विश्लेषण किए गए मॉड्यूल के लिए अप्रत्यक्ष रूप से उपयोग किए जाने वाले मॉड्यूल की संख्या पाई जाती है, और सभी मॉड्यूल पर योग की गणना की जाती है।
  • कई प्रश्नों में उपयोग के लिए फ़ंक्शन ग्राफ के digraph प्रतिनिधित्व को रखने के लिए एक उपयोगकर्ता चर को नियोजित किया गया है। कारण दक्षता है। जैसा कि = ऑपरेटर के विपरीत है := ऑपरेटर बाद के विश्लेषणों के लिए एक मूल्य बचाता है। यहां यह नोट करने की जगह हो सकती है कि किसी क्वेरी के भीतर समान सबएक्सप्रेस का मूल्यांकन केवल एक बार किया जाता है; = चीजों को गति देने के लिए उपयोग नहीं किया जा सकता।
  • Eplus | ~p : Mod Eplus | ~p : Mod | ऑपरेटर दूसरे ऑपरेंड को पहले ऑपरेंड के प्रकार में परिवर्तित करता है। इस मामले में मॉड्यूल मॉड्यूल के सभी कार्यों में परिवर्तित हो जाता है। मॉड्यूल को एक प्रकार निर्दिष्ट करना आवश्यक है : Mod ( : Mod ), अन्यथा kernel जैसे मॉड्यूल को एक ही नाम के साथ एप्लिकेशन के सभी कार्यों में परिवर्तित किया जाएगा; अस्पष्टता के मामलों में सबसे सामान्य स्थिरांक का उपयोग किया जाता है।
  • चूँकि हम केवल एक अनुपात में रुचि रखते हैं, एकरी ऑपरेटर # जो ऑपरेंड के तत्वों को गिना जाता है। इसे ग्राफ़ के digraph प्रतिनिधित्व पर लागू नहीं किया जा सकता है।
  • हम फंक्शन ग्राफ के लिए उपयोग किए जाने वाले लूप के साथ मॉड्यूल ग्राफ को बंद करने के आकार का पता लगा सकते हैं, लेकिन चूंकि मॉड्यूल ग्राफ इतना छोटा है, इसलिए एक अधिक प्रत्यक्ष विधि संभव है।

जब Erlang फ़ंक्शन t/1 को OTP के वर्तमान संस्करण के साथ लोड किए गए Xref सर्वर पर लागू किया गया था, तो लौटाया गया मान 84 (प्रतिशत) के करीब था। इसका मतलब है कि मॉड्यूल ग्राफ का उपयोग करते समय अप्रत्यक्ष रूप से उपयोग किए जाने वाले मॉड्यूल की संख्या लगभग छह गुना अधिक है। तो उपर्युक्त प्रश्न का उत्तर यह है कि इस विशेष विश्लेषण के लिए फ़ंक्शन ग्राफ का उपयोग करते समय यह निश्चित रूप से लायक है। अंत में, ध्यान दें कि अनसुलझे कॉल की उपस्थिति में, ग्राफ़ अधूरा हो सकता है, जिसका अर्थ है कि अप्रत्यक्ष रूप से उपयोग किए जाने वाले मॉड्यूल हो सकते हैं जो दिखाई नहीं देते हैं।