लिनक्स साझा लाइब्रेरी न्यूनतम रन करने योग्य एपीआई बनाम एबीआई उदाहरण
यह उत्तर मेरे अन्य उत्तर से निकाला गया है: एक एप्लीकेशन बाइनरी इंटरफ़ेस (ABI) क्या है? लेकिन मुझे लगा कि यह सीधे तौर पर इसका उत्तर देता है, और यह कि प्रश्न डुप्लिकेट नहीं हैं।
साझा पुस्तकालयों के संदर्भ में, "एक स्थिर एबीआई होने" का सबसे महत्वपूर्ण निहितार्थ यह है कि आपको पुस्तकालय परिवर्तन के बाद अपने कार्यक्रमों को फिर से स्थापित करने की आवश्यकता नहीं है।
जैसा कि हम नीचे दिए गए उदाहरण में देखेंगे, एबीआई, ब्रेकिंग प्रोग्राम को संशोधित करना संभव है, भले ही एपीआई अपरिवर्तित हो।
main.c
#include <assert.h>
#include <stdlib.h>
#include "mylib.h"
int main(void) {
mylib_mystrict *myobject = mylib_init(1);
assert(myobject->old_field == 1);
free(myobject);
return EXIT_SUCCESS;
}
mylib.c
#include <stdlib.h>
#include "mylib.h"
mylib_mystruct* mylib_init(int old_field) {
mylib_mystruct *myobject;
myobject = malloc(sizeof(mylib_mystruct));
myobject->old_field = old_field;
return myobject;
}
mylib.h
#ifndef MYLIB_H
#define MYLIB_H
typedef struct {
int old_field;
} mylib_mystruct;
mylib_mystruct* mylib_init(int old_field);
#endif
संकलन और उसके साथ ठीक चलता है:
cc='gcc -pedantic-errors -std=c89 -Wall -Wextra'
$cc -fPIC -c -o mylib.o mylib.c
$cc -L . -shared -o libmylib.so mylib.o
$cc -L . -o main.out main.c -lmylib
LD_LIBRARY_PATH=. ./main.out
अब, मान लीजिए कि पुस्तकालय के वी 2 के लिए, हम करने के लिए एक नए क्षेत्र में जोड़ना चाहते हैं mylib_mystrict
कहा जाता है new_field
।
यदि हमने फ़ील्ड को पहले की old_field
तरह जोड़ा है:
typedef struct {
int new_field;
int old_field;
} mylib_mystruct;
और पुस्तकालय का पुनर्निर्माण किया, लेकिन नहीं main.out
, तो मुखर विफल रहता है!
इसका कारण यह है लाइन:
myobject->old_field == 1
असेंबली जनरेट किया था int
जो संरचना के पहले तक पहुंचने की कोशिश कर रहा है , जो अब new_field
अपेक्षित के बजाय है old_field
।
इसलिए इस बदलाव ने एबीआई को तोड़ दिया।
यदि, हालांकि, हम इसके new_field
बाद जोड़ते हैं old_field
:
typedef struct {
int old_field;
int new_field;
} mylib_mystruct;
तब पुरानी जनरेट असेंबली अभी भी int
संरचना के पहले तक पहुंचती है, और कार्यक्रम अभी भी काम करता है, क्योंकि हमने एबीआई को स्थिर रखा है।
यहाँ GitHub पर इस उदाहरण का पूरी तरह से स्वचालित संस्करण है ।
इस ABI को स्थिर रखने का एक और तरीका यह होगा कि इसे mylib_mystruct
एक अपारदर्शी संरचना के रूप में माना जाता है , और केवल विधि सहायकों के माध्यम से अपने क्षेत्रों तक पहुंच बनाई जाती है। इससे एबीआई को स्थिर रखना आसान हो जाता है, लेकिन एक प्रदर्शन ओवरहेड को उकसाएगा क्योंकि हम अधिक फ़ंक्शन कॉल करेंगे।
एपीआई बनाम एबीआई
पिछले उदाहरण में, यह ध्यान रखना दिलचस्प है कि new_field
पहले जोड़ने से old_field
, केवल एबीआई को तोड़ दिया गया, लेकिन एपीआई को नहीं।
इसका मतलब यह है, अगर हमने main.c
पुस्तकालय के खिलाफ अपने कार्यक्रम को फिर से तैयार किया है, तो यह परवाह किए बिना काम करेगा।
अगर हमने उदाहरण के लिए फ़ंक्शन सिग्नेचर को बदल दिया होता तो हम एपीआई भी तोड़ देते:
mylib_mystruct* mylib_init(int old_field, int new_field);
उस मामले में, main.c
पूरी तरह से संकलन बंद हो जाएगा।
प्रोग्रामिंग एपीआई बनाम एबीआई
हम एपीआई परिवर्तनों को एक तीसरे प्रकार में वर्गीकृत कर सकते हैं: शब्दार्थ परिवर्तन।
उदाहरण के लिए, यदि हमने संशोधित किया था
myobject->old_field = old_field;
सेवा:
myobject->old_field = old_field + 1;
तब यह न तो एपीआई और न ही एबीआई main.c
को तोड़ देता , लेकिन फिर भी टूट जाता!
ऐसा इसलिए है क्योंकि हमने प्रोग्राम के ध्यान देने योग्य पहलू के बजाय फ़ंक्शन के "मानव विवरण" को बदल दिया है।
मेरे पास बस दार्शनिक अंतर्दृष्टि थी जो एक अर्थ में सॉफ्टवेयर का औपचारिक सत्यापन "अर्थमेटिक एपीआई" से अधिक "प्रोग्रामेटिक रूप से सत्यापन योग्य एपीआई" में ले जाता है।
सिमेंटिक एपीआई बनाम प्रोग्रामिंग एपीआई
हम एपीआई परिवर्तनों को एक तीसरे प्रकार में वर्गीकृत कर सकते हैं: शब्दार्थ परिवर्तन।
सिमेंटिक एपीआई, आमतौर पर एक प्राकृतिक भाषा का वर्णन है कि एपीआई क्या करना चाहिए, आमतौर पर एपीआई प्रलेखन में शामिल होता है।
इसलिए कार्यक्रम का निर्माण किए बिना शब्दार्थ एपीआई को तोड़ना संभव है।
उदाहरण के लिए, यदि हमने संशोधित किया था
myobject->old_field = old_field;
सेवा:
myobject->old_field = old_field + 1;
तब यह न तो प्रोग्रामिंग एपीआई और न ही एबीआई main.c
को तोड़ता था , लेकिन सिमेंटिक एपीआई टूट जाएगा।
प्रोग्राम को अनुबंध एपीआई की जाँच करने के दो तरीके हैं:
- कोने के मामलों का एक गुच्छा परीक्षण करें। करने में आसान है, लेकिन आप हमेशा एक को याद कर सकते हैं।
- औपचारिक सत्यापन । करने के लिए कठिन है, लेकिन एक "मानव" / मशीन सत्यापन योग्य तरीके से प्रलेखन और परीक्षणों को अनिवार्य रूप से एकजुट करने, शुद्धता के गणितीय प्रमाण का उत्पादन करता है! जब तक पाठ्यक्रम के अपने औपचारिक विवरण में एक बग नहीं है ;-)
उबंटू 18.10, जीसीसी 8.2.0 में परीक्षण किया गया।