공유 객체 (.so), 정적 라이브러리 (.a) 및 DLL (.so)의 차이점은 무엇입니까?


272

나는 리눅스 라이브러리와 관련하여 토론에 참여했으며, 몇 가지 사항을 확인하고 싶습니다.

응용 프로그램을 작성할 때 라이브러리를 사용하는 두 가지 방법이 있다는 것이 내 이해 (잘못되면 수정하고 나중에 게시물을 편집 할 것입니다)입니다.

  1. 정적 라이브러리 (.a 파일) : 링크 타임에 전체 라이브러리의 복사본이 최종 응용 프로그램에 저장되므로 라이브러리 내의 함수를 항상 호출 응용 프로그램에서 사용할 수 있습니다
  2. 공유 객체 (.so 파일) : 링크 타임에 해당 헤더 (.h) 파일을 통해 API에 대해 객체를 확인합니다. 라이브러리는 실제로 필요할 때까지 런타임까지 사용되지 않습니다.

정적 라이브러리의 명백한 장점은 전체 응용 프로그램을 자체적으로 포함 할 수 있고 동적 라이브러리의 이점은 ".so"파일을 대체 할 수 있다는 것입니다 (예 : 보안으로 인해 업데이트해야하는 경우) 기본 응용 프로그램을 다시 컴파일하지 않아도됩니다.

공유 객체와 DLL (동적 연결 라이브러리)이 ".so"파일 인 경우에도 일부 사람들이 구별한다고 들었습니다. Linux 또는 다른 POSIX 호환 OS (예 : MINIX, UNIX, QNX 등)에서 C / C ++ 개발에있어 공유 객체와 DLL 사이에 차이점이 있습니까? 지금까지 한 가지 중요한 차이점은 공유 객체가 런타임에 방금 사용되는 반면 DLL은 응용 프로그램 내에서 dlopen () 호출을 사용하여 먼저 열어야한다는 것입니다.

마지막으로, 일부 개발자는 "공유 아카이브"를 언급하는 것을 들었습니다.이 라이브러리는 이해하기에는 정적 라이브러리이지만 응용 프로그램에서 직접 사용하지는 않습니다. 대신, 다른 정적 라이브러리는 "공유 아카이브"에 링크되어 공유 아카이브에서 일부 (전부는 아님) 기능 / 자원을 빌드중인 정적 라이브러리로 가져옵니다.

도움을 주셔서 감사합니다.

최신 정보


이 용어가 제게 제공된 상황에서, Linux를 배워야하는 Windows 개발자 팀이 사용하는 용어는 사실상 잘못된 용어였습니다. 나는 그들을 고치려고했지만 (잘못된) 언어 규범이 고착되었습니다.

  1. 공유 객체 : 프로그램이 시작될 때 프로그램에 자동으로 연결되고 독립형 파일로 존재하는 라이브러리입니다. 라이브러리는 컴파일 타임에 링크 목록에 포함됩니다 (예 : LDOPTS+=-lmylib라는 라이브러리 파일의 경우 mylib.so). 라이브러리는 컴파일 타임과 응용 프로그램이 시작될 때 있어야합니다.
  2. 정적 라이브러리 : 응용 프로그램 코드와 프로그램을 빌드 할 때 프로그램에 자동으로 링크되는 라이브러리 코드 및 둘 다를 포함하는 최종 바이너리를 포함하는 단일 (큰) 응용 프로그램의 빌드 시간에 실제 프로그램 자체에 병합되는 라이브러리 기본 프로그램과 라이브러리 자체는 단일 독립 실행 형 이진 파일로 존재합니다. 라이브러리는 컴파일 타임에 링크 목록에 포함됩니다 (예 : LDOPTS+=-lmylibmylib.a라는 라이브러리 파일의 경우). 라이브러리는 컴파일 타임에 존재해야합니다.
  3. DLL : 기본적으로 공유 객체와 동일하지만 컴파일 타임에 링크 목록에 포함되지 않고 라이브러리는 dlopen()/ dlsym()명령을 통해로드 되므로 프로그램을 컴파일하기 위해 빌드시 라이브러리가 없어도됩니다. 또한 라이브러리는 응용 프로그램을 시작하거나 컴파일 할 때 (필요하게) 존재할 필요가 없습니다 . 왜냐하면 dlopen/ dlsym호출이 수행 되는 순간에만 필요하기 때문입니다 .
  4. 공유 아카이브 : 기본적으로 정적 라이브러리와 동일하지만 "내보내기 공유"및 "-fPIC"플래그로 컴파일됩니다. 라이브러리는 컴파일 타임에 링크 목록에 포함됩니다 (예 : LDOPTS+=-lmylibS라는 라이브러리 파일의 경우 mylibS.a). 둘 사이의 차이점은 공유 객체 또는 DLL이 공유 아카이브를 자체 코드에 정적으로 링크하고 공유 객체의 기능을 다른 프로그램에서 사용할 수있게하려면이 추가 플래그가 필요하다는 것입니다. DLL 내부. 이것은 누군가가 정적 라이브러리를 제공하고이를 SO로 다시 패키지하려는 경우에 유용합니다. 라이브러리는 컴파일 타임에 존재해야합니다.

추가 업데이트

" DLL"와 " shared library" 의 구분은 위에서 언급 한 설명을 준수하면서 당시 내가 일했던 회사 (Windows 개발자는 Linux 개발로 옮겨 가야하고 용어는 멈춤)에서 (게으르고, 부정확 한) 구어체 일뿐입니다.

또한 S"공유 아카이브"의 경우 라이브러리 이름 다음에 나오는 " "리터럴은 해당 업계에서 일반적으로 사용되는 것이 아니라 해당 회사에서 사용 된 규칙 일뿐입니다.


14
를 들어 .a파일의는 "a"는 실제로 "archove"을 의미하고, 단순히 오브젝트 파일의 아카이브입니다. 최신 링커는 while 라이브러리를 포함 할 필요가없고 아카이브에 필요한 객체 파일 만 포함 할뿐만 아니라 참조되는 객체 파일의 코드 / 데이터 섹션 만 사용할 수도 있습니다.
일부 프로그래머 친구 16:13에

4
DLL은 Windows 용어 일뿐입니다. 유니스에는 사용되지 않습니다.
R .. GitHub 중지 도움 얼음



2
물론 @DevNull "arch i ve". :)
일부 프로그래머 친구

답변:


93

나는 항상 DLL과 공유 객체가 같은 것에 대해 다른 용어라고 생각했습니다 .Windows는 DLL을 호출하고 UNIX 시스템에서는 공유 객체이며 일반적인 용어는 동적으로 연결된 라이브러리- UNIX에서 .so를 열면 dlopen()'동적 라이브러리'다음 에 호출됩니다 ).

그것들은 실제로 응용 프로그램 시작시에만 연결되지만 헤더 파일에 대한 검증 개념은 올바르지 않습니다. 헤더 파일은 라이브러리를 사용하는 코드를 컴파일하는 데 필요한 프로토 타입을 정의하지만 링크 타임에 링커는 라이브러리 자체를 조사하여 필요한 기능이 실제로 있는지 확인합니다. 링커는 링크 타임에 함수 본문을 찾아야합니다. 그렇지 않으면 오류가 발생합니다. 라이브러리가 자체적으로 프로그램이 컴파일 된 이후 변경되었을 수 있음을 지적 했으므로 런타임에도 마찬가지입니다. 이것이 플랫폼 라이브러리에서 ABI 안정성이 중요한 이유입니다. ABI 변경으로 인해 기존 프로그램이 이전 버전에 대해 컴파일 된 것이기 때문입니다.

정적 라이브러리는 프로젝트 컴파일의 일부로 자신을 빌드하는 것과 마찬가지로 컴파일러에서 직접 객체 파일 묶음이므로 정확히 같은 방식으로 링커로 가져와 공급되며 사용되지 않는 비트는 정확히 같은 방식으로 떨어졌습니다.


1
Linux에서 볼 수있는 일부 프로젝트가 ".so"파일 내의 함수에 액세스하기 위해 dlopen () 호출을 사용해야하는 이유는 무엇입니까? 그건 그렇고, 감사합니다!
Cloud

9
그렇게하지 않는 사람들은 프로세스 로더, 즉 리눅스의 엘프 로더에 의해 함수를 전달합니다. 응용 프로그램이 컴파일 할 때 존재하지 않는 .so 또는 .dll을 열고 사용하려는 경우 dlopen이 존재하거나 플러그인과 같은 추가 기능을 추가합니다.
rapadura

그러나 빌드 타임에 .so가 없으면 응용 프로그램이 전혀 컴파일되지 않습니까? 링커가 .so가 없어도 최종 프로그램을 빌드하도록 강제 할 수 있습니까? 감사합니다.
Cloud

1
나는 그것이 당신이 .so의 기능을 어떻게 사용하는지에 달려 있다고 생각하지만, 여기에 대한 나의 지식은 멈 춥니 다 : / 좋은 질문.
rapadura

1
dlopen () 및 해당 함수 계열과 관련하여 이것은 프로그래밍 방식으로 dll을 프로그래밍 방식으로 열고 닫는 데 사용되므로 응용 프로그램 전체에서 메모리에로드 할 필요가 없다는 것을 이해합니다. 그렇지 않으면, 링커에게 명령 줄 인수 (일명 makefile)로 라이브러리를로드 할 것을 지시해야합니다. 런타임에로드되고 응용 프로그램이 종료 될 때까지 메모리에로드 된 상태로 유지됩니다. OS 수준에서 발생할 수있는 일이 더 있지만, 대략 응용 프로그램과 관련하여 발생합니다.
Taylor Price

197

정적 라이브러리 (.A)는 링커에 의해 생성 된 최종 실행에 직접 연결할 수있는 도서관, 그것은 그 안에 포함되고 실행 파일이 배포 될 시스템에 라이브러리가 할 필요가 없습니다.

공유 라이브러리 (.so를) 실행 파일이 실행되고 필요는 실행 파일이 배포 된 시스템에 존재하는 경우에 너무로드됩니다 연결된하지만 최종 실행 파일에 포함되지 않은 라이브러리입니다.

windows (.dll)동적 링크 라이브러리 는 Linux의 공유 라이브러리 (.so)와 비슷하지만 OS (Windows와 Linux)와 관련된 두 구현 사이에는 약간의 차이가 있습니다.

DLL은 두 가지 종류의 함수를 정의 할 수 있습니다 : 수출 및 내부. 내 보낸 함수는 정의 된 DLL 내 에서뿐만 아니라 다른 모듈에서도 호출하도록되어 있습니다. 내부 함수는 일반적으로 정의 된 DLL 내에서만 호출하도록되어 있습니다.

Linux 의 SO 라이브러리는 모든 심볼을 심문 프로세스에 사용할 수 있으므로 내보낼 수있는 심볼을 나타 내기 위해 특별한 내보내기 명령문이 필요하지 않습니다.


1
간단한 설명 +1 DLL에서 함수가 "내부"로 선언 되면 라이브러리 외부에서 호출 할 수 없습니까?
Mike

23
모든 기호가 SO 라이브러리에서 사용 가능한 것은 아닙니다. 라이브러리 사용자가 모든 기호를 볼 이유가 없기 때문에 숨겨진 기호가 가능하고 권장됩니다.
Zan Lynx

3
참고 : g ++에는 __attribute__선택적으로 '내보내기'기호에 대한 구문 이 있습니다.#define DLLEXPORT __attribute__ ((visibility("default"))) #define DLLLOCAL __attribute__ ((visibility("hidden")))
Brian Haak

33

Windows의 DLL 세부 정보를 자세히 설명하여 * NIX-land에서 내 친구들에게 그 신비를 명확히 할 수 있습니다.

DLL은 공유 객체 파일과 같습니다. 둘 다 이미지이며, 해당 OS의 프로그램 로더가 메모리에로드 할 수 있습니다. 이미지에는 링커와 로더가 필요한 연결을 만들고 코드 라이브러리를 사용하는 데 도움이되는 다양한 메타 데이터가 함께 제공됩니다.

Windows DLL에는 내보내기 테이블이 있습니다. 내보내기는 이름 또는 테이블 위치 (숫자)별로 수행 될 수 있습니다. 후자의 방법은 "오래된 학교"로 간주되며 훨씬 더 취약합니다. DLL을 다시 작성하고 테이블에서 함수의 위치를 ​​변경하면 재앙으로 끝날 것입니다. 반면 진입 점 연결이 이름으로되어 있으면 실제 문제는 없습니다. 따라서 문제로 잊어 버리십시오. 그러나 타사 공급 업체 라이브러리와 같은 "공룡"코드로 작업하는 경우 문제가 있다는 점에 유의하십시오.

Windows DLL은 EXE (실행 가능 응용 프로그램)와 마찬가지로 컴파일 및 연결로 작성되지만 동적로드 또는 응용 프로그램에서 SO를 사용하는 것처럼 DLL은 단독으로 사용되지 않아야합니다. 링크 타임 바인딩 (SO에 대한 참조는 응용 프로그램 바이너리의 메타 데이터에 포함되어 있으며 OS 프로그램 로더는 참조 된 SO를 자동로드합니다). SO가 다른 SO를 참조 할 수있는 것처럼 DLL은 다른 DLL을 참조 할 수 있습니다.

Windows에서 DLL은 특정 진입 점 만 사용할 수있게합니다. 이것을 "수출"이라고합니다. 개발자는 특수 컴파일러 키워드를 사용하여 심볼을 외부에서 볼 수 있도록 (다른 링커 및 동적 로더에 표시) 만들거나 DLL 자체가있을 때 링크 타임에 사용되는 모듈 정의 파일에 내보내기를 나열 할 수 있습니다. 작성 중입니다. 현대적인 방법은 키워드로 함수 정의를 장식하여 심볼 이름을 내보내는 것입니다. 키워드를 사용하여 현재 컴파일 단위 외부의 DLL에서 가져올 기호로 선언하는 헤더 파일을 만들 수도 있습니다. 자세한 내용은 키워드 __declspec (dllexport) 및 __declspec (dllimport)을 찾으십시오.

DLL의 흥미로운 기능 중 하나는 표준 "로드시 / 언로드"핸들러 함수를 선언 할 수 있다는 것입니다. DLL이로드되거나 언로드 될 때마다 DLL은 경우에 따라 초기화 또는 정리를 수행 할 수 있습니다. 이것은 DLL을 장치 드라이버 또는 공유 객체 인터페이스와 같은 객체 지향 리소스 관리자로 사용하는 데 적합합니다.

개발자가 이미 구축 된 DLL을 사용하려면 DLL을 만들 때 DLL 개발자가 만든 "내보내기 라이브러리"(* .LIB)를 참조하거나 런타임에 DLL을 명시 적으로로드하고 요청해야합니다. LoadLibrary () 및 GetProcAddress () 메커니즘을 통한 이름 별 진입 점 주소 대부분의 경우 DLL이 내 보낸 진입 점에 대한 링커 메타 데이터를 포함하는 LIB 파일에 대한 링크는 DLL이 사용되는 방식입니다. 동적 로딩은 일반적으로 프로그램 동작 (추가 기능 또는 나중에 정의 된 기능, 즉 "플러그인"에 액세스)에서 "다형성"또는 "런타임 구성"을 구현하기 위해 예약되어 있습니다.

Windows 작업 방식은 때때로 혼란을 야기 할 수 있습니다. 시스템은 .LIB 확장자를 사용하여 일반 정적 라이브러리 (POSIX * .a 파일과 같은 아카이브)와 링크시 DLL에 응용 프로그램을 바인드하는 데 필요한 "내보내기 스텁"라이브러리를 모두 참조합니다. 따라서 * .LIB 파일에 같은 이름의 * .DLL 파일이 있는지 항상 확인해야합니다. 그렇지 않으면 * .LIB 파일이 정적 라이브러리 아카이브이고 DLL의 바인딩 메타 데이터를 내 보내지 않을 가능성이 높습니다.


4

정적 파일은 링크 타임에 응용 프로그램에 복사되고 공유 파일은 링크 타임에 확인되고 런타임에로드됩니다.

dlopen 호출은 응용 프로그램이 대신 런타임에 수행하려는 경우 공유 오브젝트만을위한 것이 아니라, 그렇지 않으면 응용 프로그램이 시작될 때 공유 오브젝트가 자동으로로드됩니다. DLLS와 .so는 동일합니다. dlopen은 프로세스에보다 세분화 된 동적 로딩 기능을 추가하기 위해 존재합니다. DLL을 열거 나 사용하기 위해 dlopen을 직접 사용할 필요는 없으며 응용 프로그램 시작시에도 발생합니다.


더 많은 로딩 제어를 위해 dlopen ()을 사용하는 예는 무엇입니까? 시작할 때 SO / DLL이 자동으로로드되면 dlopen ()이 다른 권한이나 제한 사항으로 닫히고 다시 열립니까? 감사합니다.
Cloud

1
dlopen은 플러그인 또는 유사한 기능을위한 것이라고 생각합니다. 권한 / 제한은 자동로드와 동일해야하며 dlopen은 종속 라이브러리를 재귀 적으로로드합니다.
rapadura

DLL하고 .so있습니다 정확히 같은 일. 이 답변
Basile Starynkevitch
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.