बड़े कोड आधार की (संकलन) की समस्या से कैसे निपटें?


10

हालांकि मैं कोड कर सकता हूं, मुझे अभी तक बड़ी परियोजनाओं पर काम करने का कोई अनुभव नहीं है। अब तक मैंने जो भी किया वह छोटे कार्यक्रमों को कोड करना था जो सेकंड के मामले में संकलित हो जाते हैं (विभिन्न c / c ++ अभ्यास जैसे कि एल्गोरिदम, प्रोग्रामिंग सिद्धांत, विचार, प्रतिमान, या सिर्फ एपीआई की कोशिश कर रहे हैं ...) या कुछ छोटी परियोजनाओं पर काम कर रहे हैं एक स्क्रिप्टिंग भाषा (ओं) (अजगर, php, js) में बनाया गया है जहाँ किसी संकलन की आवश्यकता नहीं है।

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

एक उदाहरण के रूप में मैं Wordpress ले जाऊंगा। यह कोशिश करना काफी आसान है और यह पता लगाना है कि इसके लिए प्लगइन कैसे बनाया जाए। पहले आप एक सरल "हैलो वर्ल्ड" प्लगइन बनाकर शुरू करते हैं, फिर आप एपीआई के साथ खुद को परिचित करने के लिए व्यवस्थापक पैनल के लिए एक सरल इंटरफ़ेस बनाते हैं, फिर आप इसे बनाते हैं और कुछ और अधिक जटिल बनाते हैं, इस बीच बदलते समय में यह कैसे दिखता है बार .. WP में बार-बार बड़ा बदलाव करने का विचार, प्रत्येक छोटे बदलाव के बाद "अगर यह काम करता है" और "यह कैसे काम करता है / महसूस करता है" तो अक्षम, धीमा और गलत लगता है।

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

मैं इस बारे में अधिक जानना चाहूंगा कि यह कैसे ठीक से किया जाता है। इससे निपटने के लिए कुछ सामान्य अभ्यास, दृष्टिकोण और परियोजना डिजाइन (पैटर्न?) क्या हैं? प्रोग्रामर्स की दुनिया में यह "मॉड्यूलरिटी" कैसे कहलाती है और मुझे इस बारे में और जानने के लिए Google को क्या करना चाहिए? क्या अक्सर ऐसा होता है कि परियोजनाएं अपने पहले सोचा अनुपात से बढ़ती हैं जो थोड़ी देर के बाद परेशानी हो जाती हैं? क्या किसी भी तरह से तैयार नहीं की गई परियोजनाओं के लंबे संकलन से बचने का कोई तरीका है ? किसी भी तरह से उन्हें संशोधित करने का एक तरीका है (शायद किसी भी अन्य विचारों को विकसित करते समय कार्यक्रम के गैर-महत्वपूर्ण भागों को छोड़कर)?

धन्यवाद।


4
ओब। XKCD और प्रासंगिक थिंकटेक टी-शर्ट * 8 ')
मार्क बूथ

1
यदि आप एक बड़े पर्याप्त बजट के साथ एक बड़े पर्याप्त प्रोजेक्ट पर काम करते हैं, तो आप अपने लिए संकलन करने के लिए सर्वर का निर्माण कर सकते हैं :)
सोयालेगर्रे

@Chad - मुझे पता है कि, लेकिन यह सिर्फ मेरे घर का ग्नू /
लिनेक्स

@ ठीक है, तो आप हमें बता रहे हैं कि हमें जावा (या किसी अन्य संकलित भाषा) से निपटने के लिए समर्पित सर्वर चाहिए ? वह कुल बकवास है
कोलोब कैनियन

1
@KolobCanyon - नहीं, मैं कह रहा हूं कि एक ऐसा पैमाना है जिस पर आप काम कर सकते हैं, जिसके लिए उन्हें आवश्यकता होगी। और अब वे काफी सस्ते हैं कि मांग पर वीएम तेजी से संकलन और परीक्षणों की प्रशंसा के लिए समर्पित है, यह काफी आसान है कि यह पैमाना इतना बड़ा नहीं है।
सोयेलेंटग्रे

जवाबों:


8

जैसे यह कहा गया है कि, जब भी आप एक छोटा सा बदलाव करते हैं, तो आप कभी भी पूरे प्रोजेक्ट को दोबारा नहीं बनाते हैं। इसके बजाय आप केवल उस कोड के हिस्से को फिर से जोड़ते हैं जो बदल गया है, साथ ही इसके आधार पर सभी कोड।

C / C ++ में, संकलन बहुत सीधा है। आप प्रत्येक स्रोत फ़ाइल को मशीन कोड में संकलित करते हैं (हम उन्हें ऑब्जेक्ट फ़ाइलें * .o कहते हैं) और फिर आप अपनी सभी ऑब्जेक्ट फ़ाइलों को एक अलग निष्पादन योग्य में लिंक करते हैं।

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

ऐसे स्वचालन उपकरण हैं जो आपकी सहायता करते हैं:

  • अपने स्रोत वृक्ष के विभिन्न भागों के बीच निर्भरता निर्दिष्ट करें।
  • समय-समय पर संशोधित किए गए समयनिष्ठ, विवेकपूर्ण संकलन लॉन्च करें।

सबसे प्रसिद्ध वाले (मेक, एंट, मावेन, ...) स्वचालित रूप से यह पता लगा सकते हैं कि पिछले संकलन के बाद से कोड के किन हिस्सों को बदल दिया गया है, और वास्तव में किस ऑब्जेक्ट / बाइनरी को अपडेट करने की आवश्यकता है।

हालाँकि, यह "बिल्ड स्क्रिप्ट" लिखने की लागत (अपेक्षाकृत छोटी) आती है। यह आपके बिल्ड के बारे में सारी जानकारी रखने वाली फाइल है, जैसे टारगेट और उनकी निर्भरता को परिभाषित करना, आपको कौन सा कंपाइलर डिफाइन करना है और कौन सा ऑप्शन इस्तेमाल करना है, अपने बिल्ड एनवायरनमेंट, अपने लाइब्रेरी के रास्तों को डिफाइन करना ... आपने शायद मेकफाइल्स के बारे में सुना है (बहुत यूनिक्स दुनिया में आम), या build.xml (जावा दुनिया में बहुत लोकप्रिय)। यही है जो वे करते हैं।


2
चींटी (जावा) यह निर्धारित करने में सक्षम नहीं है कि पुनर्मूल्यांकन की आवश्यकता क्या है। यह बदले हुए स्रोत कोड को फिर से जमा करने, नौकरी के तुच्छ हिस्से को संभालता है, लेकिन कक्षा की निर्भरता को बिल्कुल नहीं समझता है। हम उसके लिए आईडीई पर निर्भर हैं, और वे गलत हो जाते हैं यदि एक विधि हस्ताक्षर को इस तरह से बदल दिया जाता है जिसमें कॉलिंग कोड में बदलाव की आवश्यकता नहीं होती है।
केविन क्लाइन

@kevincline I यह दूसरा - ANT सब कुछ संकलित करता है जब तक आप build.xmlफ़ाइल में कुछ अलग निर्दिष्ट नहीं करते हैं
Kolob Canyon

7

आप हर बार पूरे प्रोजेक्ट को दोबारा नहीं बनाते हैं। उदाहरण के लिए, यदि यह C / C ++ एप्लिकेशन है, तो संभावना है कि इसे पुस्तकालयों (Windows में DLL) में अलग किया जाएगा, प्रत्येक लाइब्रेरी को अलग से संकलित किया जा रहा है।

इस परियोजना को आम तौर पर एक समर्पित सर्वर पर दैनिक रूप से संकलित किया जाता है: वे रात में निर्मित होते हैं। इस प्रक्रिया में बड़ी मात्रा में समय लग सकता है, क्योंकि इसमें न केवल संकलन समय शामिल है, बल्कि इकाई परीक्षण, अन्य परीक्षण और अन्य प्रक्रियाओं को चलाने में लगने वाला समय भी शामिल है।


3
तो मुझे नहीं यह सब तो पुन: संयोजित जब मैं समय के साथ मेरे खेलने के लिए होगा ट्रेबुशेट
SoylentGray

5

मुझे लगता है कि अब तक के सभी जवाबों का भी बहुत बुरा असर रहा है, यह है कि बड़े सॉफ्टवेयर प्रोजेक्ट लगभग हमेशा छोटे टुकड़ों में टूट जाते हैं। प्रत्येक टुकड़ा सामान्य रूप से अपनी फ़ाइल में संग्रहीत किया जाता है।

इन टुकड़ों को व्यक्तिगत रूप से वस्तुओं को बनाने के लिए संकलित किया जाता है। वस्तुओं को फिर अंतिम उत्पाद बनाने के लिए एक साथ जोड़ा जाता है। [एक तरह से, यह लेगो से बाहर सामान बनाने की तरह है। आप प्लास्टिक के एक बड़े टुकड़े से अंतिम चीज़ को बाहर निकालने की कोशिश नहीं करते हैं, इसके बजाय आप इसे बनाने के लिए छोटे टुकड़ों का एक गुच्छा जोड़ते हैं।]

व्यक्तिगत रूप से संकलित टुकड़ों में परियोजना को तोड़ने से कुछ साफ-सुथरी चीजें हो सकती हैं।

वृद्धिशील भवन

सबसे पहले, जब आप एक टुकड़ा बदलते हैं, तो आपको आमतौर पर सभी टुकड़ों को फिर से इकट्ठा करने की आवश्यकता नहीं होती है। आम तौर पर बोलते हुए, जब तक आप नहीं बदलते कि आपके टुकड़े के साथ अन्य टुकड़े कैसे बातचीत करते हैं, तो दूसरों को फिर से तैयार होने की आवश्यकता नहीं है।

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

इकाई का परीक्षण

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

परीक्षण लागू करने का सीमित मामला टेस्ट ड्रिवेन डेवलपमेंट (TDD) में देखा जाता है। इस विकास मॉडल में, कोई भी कोड तब तक नहीं लिखा / संशोधित किया जाता है जब तक कि वह एक असफल परीक्षा को ठीक न करे।

इसे आसान बनाना

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

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

लेकिन फिर भी यह पता लगाना बाकी है कि चीजें एक-दूसरे से कैसे संबंधित हैं। यह बहुत काम है और जैसा कि मैंने पहले कहा था, प्रोग्रामर आलसी हैं। इसलिए वे उपकरणों के एक और वर्ग के साथ आए हैं। ये उपकरण आपके लिए निर्भरता निर्धारित करने के लिए लिखे गए हैं! अक्सर उपकरण एक्लिप्स और विज़ुअल स्टूडियो जैसे एकीकृत विकास वातावरण (IDEs) का हिस्सा होते हैं, लेकिन कुछ स्टैंडअलोन भी होते हैं जिनका उपयोग जेनेरिक और विशिष्ट अनुप्रयोगों (makedep, QMake for Qt प्रोग्राम्स) के लिए किया जाता है।

* वास्तव में, प्रोग्रामर वास्तव में आलसी नहीं होते हैं, वे बस अपना समय समस्याओं पर काम करना पसंद करते हैं, दोहराए जाने वाले कार्यों को नहीं करना जो एक प्रोग्राम द्वारा स्वचालित हो सकते हैं।


5

यहाँ सामान की मेरी सूची है जिसे आप C / C ++ बिल्ड करने की कोशिश कर सकते हैं:

  • क्या आपने केवल वही बनाया है जो बदल गया है? अधिकांश वातावरण डिफ़ॉल्ट रूप से ऐसा करते हैं। अगर यह या हेडर में से कोई भी बदल गया है तो किसी फ़ाइल को फिर से जोड़ने की कोई आवश्यकता नहीं है। इसी तरह, dll / exe के पुनर्निर्माण का कोई कारण नहीं है यदि सभी लिंक objs / lib में परिवर्तित नहीं हुए हैं।
  • 3 पार्टी सामान रखें जो कभी नहीं बदलता है और कुछ हेडर केवल कोड लाइब्रेरी क्षेत्र में पढ़ते हैं। आपको केवल हेडर और संबंधित बायनेरिज़ की आवश्यकता है। आपको इसे एक बार के अलावा किसी अन्य स्रोत से पुनर्निर्माण की आवश्यकता नहीं होनी चाहिए ।
  • जब सब कुछ पुनर्निर्माण किया जाता है, तो मेरे अनुभव में दो सीमित कारक कोर और डिस्क गति की संख्या रहे हैं । एक बहुत अच्छा hdd के साथ एक मांसल क्वाड कोर, हाइपरथ्रेडेड मशीन प्राप्त करें और आपके प्रदर्शन में सुधार होगा। एक ठोस राज्य ड्राइव पर विचार करें - ध्यान रखें कि सस्ते वाले अच्छे एचडीडी से भी बदतर हो सकते हैं। अपने hdd को बढ़ाने के लिए छापे का उपयोग करने पर विचार करें
  • Incredibuild जैसे एक वितरित बिल्ड सिस्टम का उपयोग करें जो आपके नेटवर्क पर अन्य कार्य स्टेशनों में संकलन को विभाजित करेगा। (सुनिश्चित करें कि आपके पास एक ठोस नेटवर्क है)।
  • लगातार हेडर फ़ाइलों को फिर से लोड करने से बचाने के लिए एक एकता बिल्ड सेटअप करें।

यदि आपके प्रोजेक्ट "बहुत छोटे" से परे हो जाता है, तो मेरे अनुभव में (ज्यादा नहीं, लेकिन अच्छी तरह से) डिस्क की गति अप्रासंगिक होने लगती है। बस अपने अगले बुलेट पॉइंट में आप जो कहते हैं उसके बारे में सोचें: आप नेटवर्क का उपयोग संकलन में तेजी लाने के लिए कर रहे हैं। यदि डिस्क एक बड़ी अड़चन थी, तो नेटवर्क का सहारा लेना बहुत अच्छा कदम नहीं है।
आर। मार्टिनो फर्नांडिस

एक और सस्ता समाधान एक tmpfs में संकलित करना है। यदि संकलन प्रक्रिया IO- बद्ध है, तो प्रदर्शन को बढ़ा सकता है।
अर्टिफैक्ट 2

4

"यदि यह काम करता है" और "यह कैसे काम करता है" और "यह कैसे काम करता है / महसूस करता है" तो यह अक्षम, धीमा और गलत लगता है।

व्याख्या की गई किसी चीज को निष्पादित करना भी बहुत अक्षम और धीमा है, और (यकीनन) गलत है। आप देव के पीसी पर समय की आवश्यकताओं के बारे में शिकायत कर रहे हैं, लेकिन उपयोगकर्ता के पीसी पर समय की आवश्यकताओं का संकलन नहीं करना , जो यकीनन बहुत बुरा है।

इससे भी महत्वपूर्ण बात यह है कि आधुनिक सिस्टम काफी उन्नत वृद्धिशील पुनर्निर्माण कर सकते हैं और मामूली बदलावों के लिए पूरी बात को फिर से जोड़ना आम नहीं है- संकलित प्रणालियों में स्क्रिप्ट घटक शामिल हो सकते हैं, विशेष रूप से यूआई जैसी चीजों के लिए।


1
मेरा मानना ​​है कि मेरे प्रश्न का अर्थ व्याख्यात्मक दृष्टिकोण की बहस बनाम व्याख्या करना नहीं था। इसके बजाय मैंने सिर्फ सलाह दी कि एक बड़े (संकलित) प्रोजेक्ट का विकास कैसे ठीक से किया जाए। वृद्धिशील विचार के लिए धन्यवाद हालांकि।
pootzko

@ पूटज़को: खैर, जब आप इंटरप्रेटिंग के डाउनसाइड्स के बारे में भी बात नहीं कर रहे हैं, तो संकलन के डाउनसाइड्स पर चर्चा करना काफी अनुचित है।
15-16 बजे डेडएमजी सेप

1
नहीं यह नहीं। यह एक और बहस है और मेरा सवाल से कोई लेना-देना नहीं है। मैं यह नहीं कह रहा हूं कि यह ऐसी चीज है जिस पर चर्चा नहीं की जानी चाहिए। यह होना चाहिए, लेकिन यहाँ नहीं।
पूतज़्को

@pootzko: तब आप अपने प्रश्न के बहुमत को यह मानने के लिए समर्पित नहीं करना चाहिए कि आप संकलन के बारे में क्या पसंद करते हैं। आपको कुछ बहुत कम और अधिक रसीला लिखना चाहिए, जैसे, "बड़ी परियोजनाओं के संकलन समय को कैसे कम किया जा सकता है?"
डेडएमजी सेप

मुझे नहीं पता था कि मुझे किसी से पूछना था कि मैं "अपना प्रश्न" कैसे पूछूं ..? : OI ने इसे लिखा क्योंकि मैंने अपनी बात को बेहतर तरीके से समझाया ताकि दूसरे इसे बेहतर तरीके से समझ सकें और मुझे समझा सकें कि संकलित भाषाओं के साथ समान / समान चीज कैसे प्राप्त करें। मैंने फिर से - नहीं किया - किसी को भी मुझे यह बताने के लिए कहें कि क्या व्याख्या की गई भाषाएं उपयोगकर्ता के पीसी पर खराब समय की आवश्यकताओं का कारण बनती हैं। मुझे पता है कि, और इसका मेरे सवाल से कोई लेना-देना नहीं है - "यह संकलित भाषाओं के साथ कैसे किया जाता है", क्षमा करें। अन्य लोगों को लगता है कि मैंने जो भी पूछा था, वह समझ गया था, इसलिए मुझे नहीं लगता कि मेरा प्रश्न पर्याप्त नहीं है ..
pootzko

4
  • आंशिक पुनर्निर्माण

यदि परियोजना उचित संकलन निर्भरता डीएजी को लागू करती है तो आप केवल उन ऑब्जेक्ट फ़ाइलों को पुनः प्राप्त कर सकते हैं जो आपके परिवर्तन को प्रभावित करती हैं।

  • एकाधिक संकलन प्रक्रिया

इसके अलावा एक उचित संकलन निर्भरता DAG मानकर, आप कई प्रक्रियाओं का उपयोग करके संकलन कर सकते हैं। कोर / सीपीयू प्रति एक काम आदर्श है।

  • निष्पादन योग्य परीक्षण

आप परीक्षण के लिए कई निष्पादनयोग्य बना सकते हैं जो केवल विशेष ऑब्जेक्ट फ़ाइलों को लिंक करते हैं।


2

मेनमा के जवाब के अलावा, हमने उन मशीनों को भी अपग्रेड किया है, जिन पर हम काम करते हैं। आपके द्वारा की गई सबसे अच्छी खरीदारी में से एक SSD थी जब आप मदद नहीं कर सकते लेकिन पूरी परियोजना को फिर से शुरू करने के लिए।

एक और सुझाव एक अलग संकलक की कोशिश करना होगा। दिन में वापस, हम जावा के कंपाइलर से बाइक पर स्विच करते हैं और अब हम ग्रहण के साथ बंडल किए गए कंपाइलर का उपयोग करने के लिए आगे बढ़े हैं (पता नहीं कि क्या इसका कोई नाम है) जो मल्टीकोर प्रोसेसर का बेहतर लाभ उठाता है।

हमारे 37,000 फ़ाइल प्रोजेक्ट को इन परिवर्तनों को करने से पहले खरोंच से संकलित करने में लगभग 15 मिनट लग गए। परिवर्तनों के बाद इसे 2-3 मिनट तक काट दिया गया था।

बेशक, इसके लायक है मेनमा की बात फिर से। हर बार जब आप कोई बदलाव देखना चाहते हैं, तो पूरे प्रोजेक्ट को दोबारा न करें।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.