2016-02-20 5 views
12

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

मुझे लगता है कि जेनरेट किए गए निष्पादन योग्य विभिन्न कारकों (जैसे विभिन्न टाइमस्टैम्प) के कारण समान नहीं हो सकते हैं, लेकिन सवाल यह है कि वे कार्यात्मक रूप से भिन्न हो सकते हैं।

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

मेरे प्रश्न हैं:

  1. यह सही है कि लगातार एक ही स्रोत कोड से ही बिल्ड सर्वर द्वारा किया जाता बनाता कार्यात्मक अलग हो सकता है?
  2. यदि # 1 सत्य है, तो क्या ये अंतर गलत सिंक्रनाइज़ किए गए बहु-थ्रेडेड कोड तक सीमित हैं?
  3. यदि # 2 गलत है, तो अन्य भाग क्या बदल सकते हैं?

किसी भी संबंधित सामग्री से लिंक की सराहना की जाएगी।

+1

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

+0

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

उत्तर

5

कुछ मामलों में यह निश्चित रूप से संभव है के साथ लाइन द्वारा उत्पादन लाइन की तुलना । मुझे लगता है कि आप अपने एंड्रॉइड ऐप को बनाने के लिए ग्रैडल का उपयोग कर रहे हैं।

केस 1: आप इस तरह के रूप में, कि एक संस्करण वाइल्डकार्ड के साथ शामिल किया गया है एक 3 पार्टी निर्भरता का उपयोग कर रहे हैं:

compile somelib.1+

यह जिसके कारण यह है, के लिए निर्भरता इस मामले में परिवर्तित करने के लिए संभव है स्पष्ट निर्भरता संस्करणों का उपयोग करने की अत्यधिक अनुशंसा की जाती है।

केस 2: आप Gradle's buildConfigFields का उपयोग करके अपने ऐप में पर्यावरण की जानकारी इंजेक्ट कर रहे हैं। ये मान आपके ऐप के BuildConfig कक्षा में इंजेक्शन दिए जाएंगे। आप उन मानों का उपयोग कैसे करते हैं, इस पर निर्भर करते हुए, ऐप व्यवहार लगातार निर्माण पर भिन्न हो सकता है।

केस 3: आप लगातार के बीच बनाता है अपने सीआई पर JDK अद्यतन करें। यह संभव है, हालांकि मैं अत्यधिक असंभव मानता हूं, कि यह आपके ऐप व्यवहार को संकलित करने के तरीके के आधार पर बदल सकता है। उदाहरण के लिए, आप जेडीके में एक बढ़त मामला मार रहे हैं जो बाद के संस्करण में तय हो जाता है, जिससे कोड अलग-अलग कार्य करने से पहले पहले काम करता था।

मुझे लगता है कि यह आपके पहले प्रश्न और दूसरे प्रश्न का उत्तर देता है।

संपादित करें: क्षमा करें, मुझे लगता है कि मुझे आपके ओपी से कुछ महत्वपूर्ण जानकारी याद आई है। मेरा केस 2 आपके e.g. different timestamp का उदाहरण है और केस 3 आपके configured the same way का उल्लंघन करता है। हालांकि मैं यहां जवाब छोड़ दूंगा।

4

यदि एक ही स्रोत कोड उसी मशीन/कॉन्फ़िगरेशन पर विभिन्न परिणाम उत्पन्न कर सकता है, तो प्रोग्रामिंग के रूप में हम जानते हैं कि यह संभव नहीं होगा।

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

एंड्रॉइड/ग्रेडल का उपयोग करना, एक अलग व्यवहार या सामान्य रूप से त्रुटियों का नेतृत्व करने का एक संभावित कारण लाइब्रेरी संस्करणों के लिए build.gradle फ़ाइल में + का उपयोग कर रहा है। यही कारण है कि आपको ऐसा करने से बचना चाहिए, क्योंकि लगातार निर्माण एक नया/अलग संस्करण ला सकता है, इसलिए आपके पास अलग-अलग स्रोत कोड होंगे, और इस प्रकार यह एक कार्यात्मक भिन्न निष्पादन योग्य बना सकता है।

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

[...] लगातार बनाता है, जैसा कि ऊपर वर्णित एक ही स्रोत कोड से ही बिल्ड सर्वर द्वारा किया जाता कार्यात्मक अलग हो सकता है

नहीं। आप एक ही संस्करणों का उपयोग करता है, तो, एक ही स्रोत कोड, यह वही व्यवहार पैदा करना चाहिए। जब तक आप कुछ गलत नहीं करते हैं।

[...] क्या ये मतभेद गलत सिंक्रनाइज़ किए गए बहु-थ्रेडेड कोड तक सीमित हैं?

यह आपके संकलक के साथ एक बग अर्थ होगा। हालांकि यह संभव है, यह बेहद असंभव है।

[...] अन्य भागों क्या बदल सकते हैं?

टाइमस्टैम्प और बिल्ड नंबर और कुछ नहीं इसके अलावा चाहिए परिवर्तन, एक ही स्रोत कोड और विन्यास दिया।


आपके निर्माण में इकाई (और अन्य) परीक्षणों को शामिल करना हमेशा एक अच्छा विचार है। इस तरह आप प्रत्येक निर्माण के साथ विशिष्ट व्यवहार का परीक्षण कर सकते हैं।

+2

"टाइमस्टैम्प और बिल्ड नंबर के अलावा कुछ और नहीं बदला जाना चाहिए" -> मुझे नहीं पता कि यह आपके द्वारा उपयोग किए जा रहे कंपाइलरों पर लागू होता है, लेकिन अन्य कंपाइलरों के लिए, यह निश्चित रूप से लागू नहीं होता है। उदाहरण के लिए, डिजाइन द्वारा सी # कंपाइलर में उन्हें अलग करने के लिए हर नई बाइनरी में एक GUID शामिल है; और जीसीसी अलग-अलग रनों में (यादृच्छिक रूप से) विभिन्न अनुकूलन चुन सकते हैं (सकता है?)। Https://superuser.com/questions/639351/does-recompiling-a-program-produce-a-bit-for-bit-identical-binary – hmijail

+0

@hmijail यह प्रश्न जावा और एंड्रॉइड के बारे में है, हालांकि देखें। शायद कुछ हैं, मैं किसी के बारे में नहीं जानता। साथ ही मुझे लगता है कि यह मानना ​​उचित है कि GUID और बिल्ड नंबर काफी समान हैं क्योंकि प्रत्येक बिल्ड –

1

वे समान होना चाहिए, सिवाय: निर्माण प्रणाली में

  • वहाँ सूत्रण है/अनुकूलन मुद्दों।

  • निर्माण पर्यावरण पर हार्डवेयर विफलताओं सीपीयू/राम/HDD मुद्दों

  • समय/मंच से संबंधित निर्माण सिस्टम स्वयं या निर्माण स्क्रिप्ट

तो तुम सही पर ठीक उसी कोड का निर्माण कर रहे है, तो में कोड एक ही HW निर्माण प्रणाली, एक ही OS संस्करण एवं आपके कोड के ठीक उसी संस्करण का उपयोग विशेष रूप से निर्माण समय परिणाम से नहीं निर्भर करती ही होना चाहिए। उनके पास सटीक चेक रकम और आकार भी होना चाहिए।

इसके अलावा परिणाम एक ही है केवल यदि आपका कोड बाहरी मॉड्यूल जो Gradle/Maven तरह का निर्माण समय में इंटरनेट से डाउनलोड किया गया है पर निर्भर नहीं है - तो आप इस एक ही पुस्तकालयों जागीरदार नहीं कर सकते हैं की वजह से वे संस्करण में नहीं हैं नियंत्रण। इसके अलावा वहाँ निर्भरता जहां मॉड्यूल संस्करण निर्दिष्ट वास्तव में नहीं किया जा सकता है, इसलिए यदि मेंटेनर इस मॉड्यूल अद्यतन अपने निर्माण प्रणाली एक अद्यतन का उपयोग करेगा (जैसे 2.0 +।) -> तो मूल रूप से अपने विभिन्न स्रोत कोड से उत्पन्न बनाता है।

किसी के रूप में निर्माण सर्वर पर ईकाई परीक्षण का उपयोग कर उल्लेख यकीन है कि अपने निर्माण स्थिर है बनाने के लिए और स्पष्ट कीड़े शामिल नहीं है अच्छी आदत है।

5

मुझे लगता है कि अलग अलग कार्यक्षमता केवल वातावरण में विसंगतियों या हो सकता है आप कुछ 3 पार्टी पुस्तकालय के स्नैपशॉट संस्करण उपयोग कर रहे की वजह से हो सकता है, और इस तरह यह कुछ समय के बाद अद्यतन किया गया था।

कुछ सलाह: अगर यह संभव है कि यह फिर से बनाने, निर्माण उपकरण के वर्बोज़ मोड का उपयोग करें (उदाहरण के लिए Maven में -X) और कुछ diff कार्यक्रम

-1

यह निश्चित रूप से संभव है। आप एक उदाहरण प्रोग्राम बना सकते हैं जो हर बार जब आप इसे शुरू करते हैं तो कार्यक्षमता में भिन्न व्यवहार करेंगे।

एक रणनीति डिजाइन पैटर्न की कल्पना करें जो आपको रनटाइम के दौरान एल्गोरिदम के बीच चयन करने देता है और आप आरएनजी के आधार पर एक एल्गोरिदम लोड करते हैं।

+0

दोनों के साथ परिवर्तन अलग-अलग कोड बनाने से अलग नहीं है। आपके उदाहरण में कोड निर्माण के बावजूद किसी भी समय इसे शुरू करने के लिए अलग-अलग तरीके से व्यवहार करने के लिए है। –

0

हालांकि यह प्रश्न जावा/एंड्रॉइड को संबोधित करता है, लेकिन जॉन स्कीट ने लगभग different C# parsers treating some Unicode characters differently ब्लॉग किया, ज्यादातर यूनिकोड चरित्र डेटाबेस में परिवर्तनों के कारण।

अपने उदाहरणों में, मंगोलियाई स्वर सेपरेटर (यू + 180 ई) या तो एक सफेद जगह या पहचानकर्ता के भीतर अनुमति देने वाला एक चरित्र माना जाता है, जो परिवर्तनीय असाइनमेंट में विभिन्न परिणाम प्रदान करता है।

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