두 라이브러리가 충돌을 일으키는 동일한 이름의 함수를 제공하면 어떻게해야합니까?


94

동일한 이름의 함수를 제공하는 두 개의 라이브러리가있는 경우 어떻게해야합니까?


2
정적 라이브러리입니까 아니면 동적으로 연결됩니까?
Alnitak

더 자세한 정보가 필요합니다 ... 이름을 내보냈나요? 아니면 내부적으로 만 사용됩니까? 이름을 바꿀 수 있습니까?
Johannes Schaub-litb 2007 년

둘 다 동적으로 연결됩니다. 라이브러리를 소유하고 있지 않기 때문에 이름을 변경할 수 없습니다.
qeek

좋은 질문입니다. 물론이 모든 기호가 고유 ID로 시작한다면이 두 라이브러리에 문제가되지 않을 것 (예를 들면 vorbis_..., sf_..., sdl_...). 이것은 본질적으로 C ++가 네임 스페이스 함수의 심볼 이름에 대해 수행하는 작업입니다.
Vortico

이것은 매우 흥미로운 질문이지만 슬프게도 너무 부정확해서 너무 광범위한 답변이있는 이유입니다.
yugr

답변:


52
  • 하나 또는 둘 다를 제어하는 ​​경우 : 하나를 편집하여 이름을 변경하고 다시 컴파일하거나 소스 코드에 액세스 하지 않고도 작동하는 Benunknown 의 답변을 동등하게 볼 있습니다.
  • 둘 중 하나를 제어하지 않으면 둘 중 하나를 래핑 할 수 있습니다. 그것은 다른 ( 정적으로 링크 된 !) 라이브러리를 컴파일 하는 것입니다. 이것은 다른 이름의 래퍼를 통해 도달하는 문제가되는 것을 제외하고 원본의 모든 심볼을 다시 내보내는 것 외에는 아무것도하지 않습니다. 얼마나 번거로운가.
  • 나중에 추가 : qeek가 동적 라이브러리에 대해 이야기하고 있다고 말했기 때문에 Ferrucciomouviciel 이 제안한 솔루션 이 아마도 가장 좋습니다. (정적 연결이 기본이었던 옛날에 살고있는 것 같습니다. 그것은 제 생각을 채색합니다.)

주석에 대한 제안 : "내보내기"란 라이브러리에 연결된 모듈을 볼 수 있도록하는 것을 의미합니다 extern. 파일 범위 의 키워드 와 동일합니다 . 이것이 제어되는 방법은 OS 및 링커에 따라 다릅니다. 그리고 그것은 제가 항상 찾아봐야하는 것입니다.


그게 저의 첫 생각이기도했지만 같은 충돌 문제로 끝나지 않겠습니까? 결국 전체 프로젝트는 컴파일 / 링크 시간 또는 런타임에 링크해야하며, 이때 문제가되는 두 라이브러리가있는 그대로로드되어야합니다.
Sniggerfardimungus

@unknown : 래퍼 정적 연결로 컴파일 해야 하며 문제가되는 기호를 내 보내지 않아야합니다. 그런 다음 여전히 래퍼를 동적으로 연결할 수 있습니다. 더 명확하게 편집했습니다. 감사합니다.
dmckee --- 전 중재자 새끼 고양이

qeek의 문제가 정적 라이브러리가 아닌 ddl에있는 경우 래퍼로 새 라이브러리를 만드는 것이 어떻게 가능합니까? 그 이후로 래퍼 라이브러리는 처음부터 연결하고 싶지 않은 라이브러리의 함수를 동적으로 래핑해야합니다.
jeffD

@dmckee- "내보내기"란 무엇을 의미합니까?

4
누군가이 기술의 간단한 예를 제공 할 수 있습니까? 하나의 exe, 각각 동일한 이름을 가진 하나의 함수를 포함하는 두 개의 라이브러리.

53

다음을 사용하여 개체 파일의 기호 이름을 바꿀 수 있습니다. objcopy --redefine-sym old=new file(man objcopy 참조)를 .

그런 다음 새 이름을 사용하여 함수를 호출하고 새 개체 파일과 연결합니다.


2
좋은. Makefile에 추가하는 것은 간단합니다. 라이브러리가 업데이트되면 objcopy 주문은 다른 솔루션보다 훨씬 쉽게 업데이트 할 수 있습니다.
sigjuice

9
헤더 파일의 기호 이름도 바꾸는 것을 잊지 마십시오.
mouviciel 2009

^ SED / AWK / 펄도 헤더에 기호 이름을 변경 자동화하는 것이 유용 할 것
알렉스 잉킹

16

Windows에서는 LoadLibrary () 를 사용 하여 이러한 라이브러리 중 하나를 메모리에로드 한 다음 GetProcAddress () 를 사용 하여 함수 포인터를 통해 함수를 호출하고 호출해야하는 각 함수의 주소를 가져올 수 있습니다.

예 :

HMODULE lib = LoadLibrary("foo.dll");
void *p = GetProcAddress(lib, "bar");
// cast p to the approriate function pointer type (fp) and call it
(*fp)(arg1, arg2...);
FreeLibrary(lib);

foo.dll에서 bar라는 함수의 주소를 가져 와서 호출합니다.

나는 유닉스 시스템이 유사한 기능을 지원한다는 것을 알고 있지만 그 이름은 생각할 수 없습니다.


dlopen dlsym, 및 dlclose. 그러나 Unix에서의 캡슐화는 Windows만큼 효과적이지 않을 수 있습니다.
user877329


8

여기에 생각이 있습니다. 16 진 편집기에서 문제가되는 라이브러리 중 하나를 열고 문제가되는 모든 문자열을 다른 것으로 변경하십시오. 그러면 이후의 모든 호출에서 새 이름을 사용할 수 있습니다.

업데이트 : 나는 방금 이것을 끝냈고 작동하는 것 같습니다. 물론 나는 이것을 철저히 테스트하지 않았습니다. hexedit 산탄 총으로 다리를 날려 버리는 좋은 방법에 지나지 않을 것입니다.


실제로 끔찍한 해결책은 아닙니다. 약간 끔찍하지만 기호 테이블의 문자열을 변경하는 것뿐입니다. 거기에는 실질적인 기능적 해가 없습니다.
Evan Teran

다른 누군가가 와서 다시로드하지 않도록 라이브러리의 이름을 바꾸고 싶을 것입니다. 당신은 하나의 갈등에서 수십 또는 수백으로 갈 것입니다. =] 나는 stackoverflow에 대해 이것을 좋아합니다 : 우리는 질문에 대한 테스트 된 답변을 가지고 있고 3 개의 투표를 가지고 있습니다. 첫 번째 (불완전한) 답변 : 17. =]
Sniggerfardimungus

1
이름을 짧게 만 만들 수 있으므로 이름 변경 기회가 제한됩니다 . 또한 Linux에서는 ELF 해시 테이블을 업데이트하는 데 어려움이 있습니다.
yugr

7

Linux를 사용한다고 가정하면 먼저 추가해야합니다.

#include <dlfcn.h>

예를 들어, 적절한 컨텍스트에서 함수 포인터 변수를 선언하십시오.

int (*alternative_server_init)(int, char **, char **);

https://stackoverflow.com/a/678453/1635364에 명시된 Ferruccio와 같이 , 실행하여 사용하려는 라이브러리를 명시 적으로로드합니다 (좋아하는 플래그 선택).

void* dlhandle;
void* sym;

dlhandle = dlopen("/home/jdoe/src/libwhatnot.so.10", RTLD_NOW|RTLD_LOCAL);

나중에 호출하려는 함수의 주소를 읽으십시오.

sym = dlsym(dlhandle, "conflicting_server_init");

다음과 같이 할당 및 캐스팅

alternative_server_init = (int (*)(int, char**, char**))sym;

원본과 비슷한 방식으로 전화하십시오. 마지막으로 다음을 실행하여 언로드합니다.

dlclose(dlhandle);


6

함께 사용하지 마십시오. 내가 올바르게 기억하면 링커는 그러한 경우 오류를 발행합니다.

나는 시도하지 못했지만, 해결책이있을 수 있습니다 dlopen(), dlsym()그리고 dlclose()어떤 프로그래밍 동적 라이브러리를 처리 할 수 있습니다. 두 함수가 동시에 필요하지 않은 경우 두 번째 라이브러리 / 함수를 사용하기 전에 첫 번째 라이브러리를 열고 첫 번째 함수를 사용하고 첫 번째 라이브러리를 닫을 수 있습니다.


감사. 이것에 대해 생각하지 않았습니다. 하지만 동시에 두 가지를 갖고 싶습니다.
qeek

두 가지를 동시에 사용하려면 어떻게해야합니까?
QZHua

@QZHua : 다른 응답자 (예 : 기호 이름 변경 관련)가 문제를 해결해야합니다.
mouviciel

6

.o 파일이있는 경우 여기에 좋은 대답이 있습니다. https://stackoverflow.com/a/6940389/4705766

요약:

  1. objcopy --prefix-symbols=pre_string test.o .o 파일의 기호 이름을 바꾸려면

또는

  1. objcopy --redefine-sym old_str=new_str test.o .o 파일에서 특정 기호의 이름을 바꿉니다.

4

이 문제는 C ++에 네임 스페이스가있는 이유입니다. 동일한 이름을 가진 2 개의 타사 라이브러리에 대한 c에는 실제로 훌륭한 솔루션이 없습니다.

동적 객체 인 경우 공유 객체 (LoadLibrary / dlopen / etc)를 명시 적으로로드하고 해당 방식으로 호출 할 수 있습니다. 또는 동일한 코드에서 동시에 두 개의 lib가 필요하지 않은 경우 정적 링크로 작업을 수행 할 수 있습니다 (.lib / .a 파일이있는 경우).

물론 이러한 솔루션은 모든 프로젝트에 적용되지 않습니다.


1
어 그래. 이 일반적인 질문에 대해 이것은 좋은 대답처럼 보입니다. 그러나 동일한 컴파일러에서 모든 것을 함께 컴파일하면 네임 스페이스가 멋집니다. 만세, 이름 충돌은 없습니다. 그러나 바이너리 형식의 라이브러리를 가져 와서 다른 컴파일러와 통합하려면 행운을 빕니다. 개체 파일의 이름 변경 규칙은 첫 번째 장애물 일뿐입니다 (외부 "C"가 도움이 될 수 있으며 네임 스페이스의 효과를 취소합니다).
Tomasz Gandor 2014-07-31

3

저주? 내가 아는 한, 동일한 이름의 링크 포인트를 노출하는 두 개의 라이브러리가 있고 둘 모두에 대해 링크해야하는 경우 할 수있는 일이별로 없습니다.


12
맹세는 확실히 첫 번째 단계입니다. 그것에 대해 의심의 여지가 없습니다.
dmckee --- 전 중재자 새끼 고양이

1
"할 수있는 일이 많지 않습니다."-여전히 관련이 있습니까? 다른 답변은 다양한 솔루션을 제공 합니다.
yugr

2

그들 중 하나에 래퍼 라이브러리를 작성해야합니다. 래퍼 라이브러리는 고유 한 이름의 기호를 노출해야하며 고유하지 않은 이름의 기호는 노출하지 않아야합니다.

다른 옵션은 헤더 파일에서 함수 이름을 바꾸고 라이브러리 오브젝트 아카이브에서 심볼의 이름을 바꾸는 것입니다.

어느 쪽이든, 둘 다 사용하려면 해킹 작업이 될 것입니다.



1

질문은 10 년이 다가오고 있지만 항상 새로운 검색이 있습니다.

이미 답변했듯이 --redefine-sym 플래그가있는 objcopy는 Linux에서 좋은 선택입니다. 예를 들어 https://linux.die.net/man/1/objcopy를 참조하십시오. 전체 문서는 를 . 변경하는 동안 기본적으로 전체 라이브러리를 복사하고 모든 업데이트를 수행하려면이 작업을 반복해야하기 때문에 약간 복잡합니다. 그러나 적어도 작동해야합니다.

Windows의 경우 라이브러리를 동적으로로드하는 것이 해결책이며 Linux의 dlopen 대안과 같은 영구적 인 것입니다. 그러나 dlopen () 및 LoadLibrary () 모두 유일한 문제가 중복 이름 인 경우 피할 수있는 추가 코드를 추가합니다. 여기서 Windows 솔루션은 objcopy 접근 방식보다 더 우아합니다. 링커에게 라이브러리의 심볼이 다른 이름으로 알려져 있다고 말하고 해당 이름을 사용하십시오. 그것을하기위한 몇 가지 단계가 있습니다. def 파일을 만들고 EXPORTS 섹션에 이름 번역을 제공해야합니다. 참조 https://msdn.microsoft.com/en-us/library/hyx1zcd3.aspx를 (VS2015, 그것은 결국 새로운 버전으로 교체 얻을 것이다) 또는 http://www.digitalmars.com/ctg/ctgDefFiles.html(아마 더 영구적 인) def 파일의 전체 구문 세부 정보를 보려면. 프로세스는 라이브러리 중 하나에 대한 def 파일을 만든 다음이 def 파일을 사용하여 lib 파일을 빌드 한 다음 해당 lib 파일과 링크하는 것입니다. (Windows DLL의 경우 lib 파일은 코드 실행이 아닌 링크에만 사용됩니다.) .dll 파일과 헤더 파일이있을 때 .lib 파일을 만드는 방법을 참조하십시오. 을 빌드하는 프로세스에 대해서는 . 여기서 유일한 차이점은 별칭을 추가하는 것입니다.

Linux 및 Windows의 경우 이름이 별칭이 지정되는 라이브러리 헤더의 함수 이름을 바꿉니다. 작동해야 할 또 다른 옵션은 새 이름을 참조하는 파일에서 #define old_name new_name, 내보내기가 별칭이 지정된 라이브러리의 헤더를 #include 한 다음 호출자에 #undef old_name을 포함하는 것입니다. 라이브러리를 사용하는 파일이 많은 경우 더 쉬운 대안은 정의, 포함 및 정의 해제를 래핑하는 헤더를 만든 다음 해당 헤더를 사용하는 것입니다.

이 정보가 도움이 되었기를 바랍니다.


0

dlsym, dlopen, dlerror, dlclose, dlvsym 등을 사용한 적이 없지만 man 페이지에서 libm.so를 열고 cos 함수를 추출하는 예제를 제공합니다. dlopen은 충돌을 찾는 과정을 거치나요? 그렇지 않은 경우 OP는 두 라이브러리를 수동으로로드하고 라이브러리가 제공하는 모든 기능에 새 이름을 할당 할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.