2009-09-21 12 views
5

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

फर्मवेयर के रूपों को बनाए रखने के लिए कई विकल्प देख सकते हैं, लेकिन कोई भी मुझे बहुत पसंद नहीं करता है। अपने काम के लिए आवेदन करने वाले सर्वोत्तम अभ्यास क्या हैं?

वैकल्पिक मैं के बारे में सोच सकते हैं:

  • को परिभाषित करता है। पूर्व प्रसंस्करण। पेशेवर: सब कुछ हमेशा स्रोत कोड में मौजूद होता है, उत्पादों में से किसी एक के अपडेट को याद करना मुश्किल होता है। विपक्ष: पढ़ने के लिए कठिन। यह ठीक हो सकता है जबकि हमारे पास केवल दो प्रकार हैं, जब यह चार या अधिक हो जाता है तो यह दर्द होगा। इसके अलावा, यह DRY सिद्धांत लागू करने के लिए कठिन लगता है (स्वयं को दोहराएं)।

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

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

  • प्रति मॉड्यूल पर एक भंडार बनाएँ। उदाहरण के लिए एक डिस्प्ले ड्राइवर के लिए एक भंडार, पावर प्रबंधन हार्डवेयर के लिए दूसरा, उपयोगकर्ता इनपुट इंटरफ़ेस के लिए दूसरा, ... पेशेवर: अच्छी मॉड्यूलरिटी। पनडुब्बियों के रूप में आपको आवश्यक मॉड्यूल चुनकर एक नया उत्पाद बनाएं! सभी submodules शाखाएं हो सकती है, उदाहरण के लिए एक संस्करण हार्डवेयर का एक अलग तरीके से उपयोग करता है। विपक्ष: बहुत सारे और मॉड्यूल के बहुत सारे, प्रत्येक फाइल को दो फाइलों का ट्रैक रखते हैं (एक फ़ाइल और एक स्रोत फ़ाइल शामिल)। एक परेशानी। कोई मॉड्यूल में कोई महत्वपूर्ण अपडेट करता है? यदि किसी को उचित हो तो इस मॉड्यूल की अन्य शाखाओं में परिवर्तन को शामिल करने की आवश्यकता है। फिर किसी को भी प्रत्येक उत्पाद भंडार में सबमिशन अपडेट करना होगा। काफी कुछ काम करते हैं, और हम गिट के स्नैपशॉट पक्ष को खो देते हैं।

आप यह कैसे करते हैं, और यह कैसे काम कर रहा है? या आप यह कैसे करेंगे?

मुझे एहसास है कि मुझे चेरी पिकिंग के साथ अनुभव होना चाहिए।

+0

एक उत्पाद प्रति उत्पाद समाधान के साथ आप हमेशा एक अलग शाखा (ईएस) पर विकास कर सकते हैं, और फिर इस शाखा को वेरिएंट (प्रति उत्पाद) शाखाओं में विलय कर सकते हैं। –

उत्तर

5

मैं जितना संभव हो #define एस के लिए जाने की कोशिश करता हूं। एक उचित कोड के साथ आप पठनीयता और पुनरावृत्ति पर प्रभाव को कम कर सकते हैं।

लेकिन साथ ही #define दृष्टिकोण सुरक्षित रूप से विभाजन और शाखाकरण के साथ जोड़ा जा सकता है, जिसका आवेदन कोडबेस की प्रकृति पर निर्भर करता है।

+0

परिभाषा सबसे खराब संभव समाधान है। वे उस स्रोत कोड को बनाते हैं जिसे आप संपादक में देखते हैं, जिसे संकलक देखता है उससे भिन्न होता है। – xpmatteo

+2

और 'अगर आप स्रोत में जो स्रोत कोड देखते हैं उसे निष्पादित किया गया है। उस पूरी चीज को प्रोग्रामिंग कहा जाता है। –

+0

उच्च स्तरीय भाषाओं का पूरा बिंदु मनुष्यों के लिए प्रोग्रामिंग को आसान बनाना है। संकलन समय पर आपके दिमाग में व्याख्या करने के लिए और रनटाइम पर IFs इसे और अधिक कठिन बनाता है और प्रोग्राम यह समझने के लिए त्रुटि उत्पन्न करता है कि प्रोग्राम क्या करता है। – xpmatteo

5

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

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

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

+0

ओओ अच्छा होगा, लेकिन यह असेंबलर में एम्बेडेड कोड है, यहां तक ​​कि एक सी संकलक भी उपलब्ध नहीं है। मैं समझता हूं कि ओओ की अवधारणाओं को वैसे भी लागू किया जा सकता है। केवल आवश्यक फाइलों को इकट्ठा करना और लिंक करना एक विकल्प है, लेकिन मेरा मानना ​​है कि ऐसी दो फाइलें (एक प्रति संस्करण) बहुत समान होगी, इस प्रकार एक-दूसरे को दोहराया जाएगा। – Gauthier

+0

'compat' फ़ाइलों को रखने के बाद, यह एक या एक अद्वितीय मंच है, क्या मुझे लगता है कि एक अच्छा विचार है। –

+0

जावा के लिए वर्कअराउंड अतिरिक्त प्लगइन का उपयोग करना है जैसे ग्रहण के लिए एंटीना। सही नहीं है, लेकिन काफी मददगार है। – David

2

मुझे लगता है कि उचित उत्तर इस बात पर निर्भर करता है कि वेरिएंट कितने अलग हैं।

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

आपको जरूरी शाखाओं पर भिन्न रूपों की आवश्यकता नहीं है; वास्तव में, आपको आवश्यक होने पर केवल शाखाओं का उपयोग करना चाहिए (लेकिन जब आवश्यक हो तो उनका उपयोग करें!)। आप चार फाइलें कह सकते हैं, सभी एक आम शाखा पर, हमेशा दिखाई देते हैं। आप सही संस्करण को लेने के लिए संकलन की व्यवस्था कर सकते हैं।

#include "config.h" 
#if defined(USE_VARIANT_A) 
#include "variant_a.c" 
#elif defined(USE_VARIANT_B) 
#include "variant_b.c" 
#else 
#include "basecase.c" 
#endif 
+0

मैं मेकफ़ाइल में ऐसा करने के बजाय बहुत कुछ करता हूं, मैं # फाइलों के साथ सी फाइलों को नापसंद करता हूं: वे मेरे मेकफ़ाइल में दिखाई नहीं देंगे। मैं मानता हूं कि कोई चांदी की बुलेट नहीं है, समाधान वेरिएंट के भिन्नता पर निर्भर करता है :) मुझे डर है कि #defines से शुरू करना है और उत्पाद परिवार को 10 प्रकारों में बढ़ाना है। – Gauthier

+0

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

+0

अब तक मेरा मतलब 10 में से 1 विकल्प है। भगवान का शुक्र है :) मुझे समझ में नहीं आ रहा है कि संस्करण नियंत्रित मेकफ़ाइल (एक प्रति संस्करण) क्यों इस विधि को अमान्य कर देगा? – Gauthier

6

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

इसका लाभ यह है कि किसी विशेष संस्करण पर काम करते समय, आप चीजों को भ्रमित करने के लिए वहां अन्य सभी प्रकार के कोड के बिना अपने सभी कोड एक साथ देखते हैं। पठनीयता, यह भी #ifdef, #elif, #endif साथ स्रोत कचरा तुलना में काफी बेहतर है आदि

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

यदि आप उपर्युक्त दृष्टिकोण का उपयोग करते हैं, तो आपको अपने कोड के संगठन का समर्थन करने के लिए अपने संस्करण नियंत्रण में ऐसी चाल का उपयोग करने की आवश्यकता नहीं है।

+0

+1 केवल शाखा में जाने के बारे में सलाह के लिए +1 (यदि अपवाद हैं)। कोड का समर्थन करने के लिए वीसीएस चाल का उपयोग करने के जोखिम के लिए भी। ऐसी कस्टम कोड फ़ाइलों के साथ DRY के बारे में PhiLho पर मेरी टिप्पणी देखें। – Gauthier

+0

जब मैं किसी विशेष संस्करण पर काम कर रहा हूं, तो मैं अक्सर अन्य प्रकार के कोड देखना चाहता हूं। कोड फोल्डिंग के लिए यह एक अच्छा उपयोग है .. –

1

आप चोट की दुनिया में हैं!

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

आदर्श रूप से आप विभिन्न लक्ष्यों को लोड करने और कुछ धूम्रपान परीक्षण चलाने में सक्षम होंगे।

#else 
    #error You MUST specify a variant! 
#endif 

यह सुनिश्चित करें कि सभी फाइलों को निर्माण प्रक्रिया के दौरान एक ही संस्करण के लिए निर्माण कर रहे हैं कर देगा:

आप #define तरीका अपनाते हैं, तो मैं निम्नलिखित किसी ऐसे स्थान पर जहां संस्करण को चेक किया गया जाते थे।

+0

निश्चित रूप से, #error। और यहां तक ​​कि, यदि कई प्रकार परिभाषित परिभाषित किए गए हैं, तो सभी को अपरिभाषित किया गया है (या एक और # आतंक भेजें)। – Gauthier

0

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

जाहिर है, अगर मैं आवश्यकता हो तो मैं स्थिति संकलन का उपयोग करूंगा, ताकि संस्करण नियंत्रण के तहत केवल एक स्रोत फ़ाइल हो, लेकिन अन्य सामान फ़ाइलों के लिए जो केवल एक होस्ट/लक्ष्य शाखा में दिखाई देनी चाहिए, या जहां सामग्री पूरी तरह से अलग होगी, एक अलग तंत्र की आवश्यकता है। यदि आप ओओ तकनीकों का उपयोग उस समस्या को हल करने के लिए कर सकते हैं जो भी desirabl होगा ई।

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

संबंधित मुद्दे