바이너리 호환 라이브러리 작성
8657 단어 바이너리
A library is binary compatible, if a program linked dynamically to a former version of the library continues running with newer versions of the library without the need to recompile.
If a program needs to be recompiled to run with a new version of library but doesn't require any further modifications, the library is source compatible.
간단한 예를 들어 랜덤 생성 라이브러리에 두 개의 인터페이스를 제공합니다: 피드 설정 setseed 및 생성 랜덤 수 myrand.
liba.h
#ifndef _LIBA_H #define _LIBA_H struct A { int seed; }; int set_seed(struct A* a, int s); int my_rand(struct A a, int b); #endif
liba.c
#include "liba.h" int set_seed(struct A* a, int s) { a->seed = s; return 0; } int my_rand(struct A a, int b) { int r = a.seed + b; return r; }
동적 라이브러리libcutil로 컴파일합니다.so, 호출자 코드도 간단합니다.
main.c
#include "liba.h" #include <stdio.h> #include <dlfcn.h> int main() { void* handle=dlopen("libcutil.so", RTLD_LAZY); if(!handle) { fprintf(stderr, "%s
", dlerror()); return -1; } struct A a; int (*fa)(struct A*, int); fa = dlsym(handle, "set_seed"); fa(&a, 31); int (*fb)(struct A, int); fb = dlsym(handle, "my_rand"); int b = fb(a, 4); printf("%d
", b); return 0; }
이렇게 하면 정상적으로 일할 수 있다.
export LD_LIBRARY_PATH="../api_r1/:$LD_LIBRARY_PATH"; ./main 35
릴리즈 2 버전h의 struct A에는 한 명의 멤버가 추가되었습니다.
#ifndef _LIBA_H #define _LIBA_H struct A { int add; // int seed; }; int set_seed(struct A* a, int s); int my_rand(struct A a, int b); #endif
liba.c 거의 변하지 않는다.
#include "liba.h" int set_seed(struct A* a, int s) { a->add = 123; // a->seed = s; return 0; } int my_rand(struct A a, int b) { int r = a.seed + b; return r; }
컴파일 후 새 동적 라이브러리libcutil을 생성합니다.so, 사용자가 코드를 다시 컴파일하지 않고 실행:
export LD_LIBRARY_PATH="../api_r2/:$LD_LIBRARY_PATH"; ./main 4
결과 오류, 이 라이브러리libcutil.so 바이너리가 호환되지 않습니다.
이유: 라이브러리 헤더 파일liba.h에는 인터페이스뿐만 아니라 실현과 관련된 코드(struct A)도 포함되어 있다.이 라이브러리의 코드(main.c)include를 사용하면 이 헤더 파일은 struct A의 정의를 포함하고libcutil을 포함합니다.so는 struct A의 정의에 전적으로 의존합니다.고객 코드를 컴파일하지 않고 라이브러리만 교체할 때 라이브러리에 의존하는 struct A (최신 버전) 는 라이브러리를 사용하는 코드에서 struct A (오래된 버전) 와 일치하지 않습니다.
솔루션:
원리--헤드 파일에 인터페이스만 노출하고 관련 코드를 모두 넣는다.c/.cpp에서 인터페이스와 분리를 실현합니다.
실현 - 하나의 지침을 통해 인디케이션 결합을 증가시킨다.
두 가지 시나리오가 있습니다.
1. C 인터페이스는 void* 포인터를 사용하여 구체적인 struct를 가리킵니다.
#ifndef _LIBA_H #define _LIBA_H typedef void* Api; int init(Api *api, int s); // int run(Api api, int b); int release(Api api); // #endif
.c 파일에는 구현과 관련된 모든 코드가 포함되어 있습니다.
#include "liba.h" #include <stdio.h> #include <stdlib.h> struct A { int seed; }; typedef struct A* ApiII; int init(Api* api, int s) { ApiII p = (ApiII)malloc(sizeof(struct A)); if(api == NULL || p == NULL) return -1; p->seed = s; *((ApiII*)api) = p; return 0; } int run(Api api, int b) { if(api == NULL) return -1; ((ApiII)api)->seed+=b; return ((ApiII)api)->seed; } int release(Api api) { if(api != NULL) { free(api); api = NULL; } return 0; }
2.C++ 인터페이스에서 pimpl 사용
#ifndef _LIBA_H #define _LIBA_H class A { public: A(); ~A(); int init(int s); int run(int b); private: class Aimpl; // , A Aimpl* pimpl; // , }; #endif
.cpp 코드:
#include "liba.h" #include <stdio.h> class A::Aimpl { public: Aimpl(int s):seed(s){} int run(int b) { seed+=b; return seed; } private: int seed; }; A::A():pimpl(NULL) { } A::~A() { if(pimpl != NULL) { delete pimpl; pimpl=NULL; } } int A::init(int s) { if(pimpl != NULL) delete pimpl; pimpl = new A::Aimpl(s); return 0; } int A::run(int b) { if(pimpl == NULL) return -1; return pimpl->run(b); }
첨부 파일에는 관련 코드가 포함되어 있습니다.
참조 자료:
https://techbase.kde.org/Policies/Binary_Compatibility_Issues_With_C++#Definition
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
SORACOM Air의 바이너리 파서를 사용해 보았습니다.의 LTE-M 회선을 사용하여 센서에서 흡입한 데이터를 으로 보냅니다. 통신량을 줄이면 통신 요금을 저렴하게 할 수 있을 뿐만 아니라 소비 전력을 절약할 수 있습니다. 이 라이브러리를 하고 개발하고 있습니다. 콘솔에...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.