[c++] 동적 라이브러리와 정적 라이브러리를 사용하는 경우


Answers

다른 사람들은 정적 라이브러리가 무엇인지에 대해 적절히 설명했지만 적어도 Windows에서는 정적 라이브러리를 사용할 때의 몇 가지주의 사항을 지적하고자합니다.

  • 싱글 톤 : 무언가가 전역 / 정적 및 고유 일 필요가있는 경우 정적 라이브러리에 넣는 것에 매우주의하십시오. 해당 정적 라이브러리에 대해 여러 DLL이 연결되어 있으면 각각은 자체 소유의 복사본을 갖게됩니다. 그러나 응용 프로그램이 사용자 지정 DLL이없는 단일 EXE 인 경우 문제가되지 않을 수 있습니다.

  • 참조되지 않은 코드 제거 : 정적 라이브러리에 연결할 때 DLL / EXE에서 참조하는 정적 라이브러리 부분 만 DLL / EXE에 연결됩니다.

    예를 들어 mylib.liba.objb.obj 있고 DLL / EXE가 a.obj 함수 또는 변수 만 참조하면 b.obj 전체가 링커에 의해 삭제됩니다. b.obj 에 전역 / 정적 객체가 포함되어 있으면 해당 생성자와 소멸자가 실행되지 않습니다. 이러한 생성자 / 소멸자가 부작용이있는 경우 해당 부재로 인해 실망 할 수 있습니다.

    마찬가지로 정적 라이브러리에 특수 진입 점이 포함되어있는 경우 실제로 포함되어 있는지주의해야합니다. 임베디드 프로그래밍 (예 : Windows가 아님)의 예는 특정 주소에 있다고 표시된 인터럽트 핸들러입니다. 또한 인터럽트 핸들러를 진입 점으로 표시하여 버려지지 않도록해야합니다.

    이것의 또 다른 결과는 미확인 참조로 인해 완전히 사용할 수없는 객체 파일을 정적 라이브러리에 포함 할 수 있지만 해당 객체 파일에서 함수 나 변수를 참조 할 때까지 링커 오류가 발생하지 않습니다. 라이브러리를 작성한 후 오랜 시간이 걸릴 수 있습니다.

  • 디버그 기호 : 각 정적 라이브러리에 대해 별도의 PDB가 필요하거나 디버그 기호를 DLL / EXE 용 PDB에 넣을 수 있도록 개체 파일에 배치 할 수 있습니다. Visual C ++ 문서는 필요한 옵션을 설명 합니다 .

  • RTTI : 하나의 정적 라이브러리를 여러 DLL에 연결하면 동일한 클래스에 대해 여러 개의 type_info 객체가 생길 수 있습니다. 프로그램이 type_info 가 "singleton"데이터이고 &typeid() 또는 type_info::before() 사용한다고 가정하면 바람직하지 않고 놀라운 결과를 얻을 수 있습니다.

Question

C ++에서 클래스 라이브러리를 만들 때 동적 (.dll) 라이브러리와 정적 (.lib) 라이브러리 중에서 선택할 수 있습니다. 그 (것)들 사이 다름은 무엇이고 언제 어느 것을 사용하는 것이 적당합니까?




시간, 버전, 안정성, 호환성 등의 변화에 ​​대해 신중히 생각해야합니다.

공유 코드를 사용하는 두 개의 앱이있는 경우 서로 호환되어야하는 경우를 대비하여 해당 앱을 강제로 변경 하시겠습니까? 그런 다음 dll을 사용하십시오. 모든 exe는 동일한 코드를 사용합니다.

또는 서로를 격리 시켜서 하나를 변경하고 다른 하나를 손상시키지 않았 음을 확신 할 수 있습니다. 그런 다음 정적 lib를 사용하십시오.

DLL 지옥은 당신이 아마 정적 인 lib를 사용했을 때이다. 그러나 당신은 dll을 대신 사용했고, 모든 exes가 그것으로 comaptible이 아니었다.




Ulrich Drepper의 " 공유 라이브러리 작성법"에 대한 논문은 공유 라이브러리 를 최대한 활용하는 방법이나 DSO (Dynamic Shared Objects)라고 불리는 것을 자세히 설명하는 훌륭한 자료입니다. ELF 바이너리 형식의 공유 라이브러리에 초점을 맞추었지만 일부 토론은 Windows DLL에도 적합합니다.




큰 코드베이스를 가지고 있다면 하위 라이브러리 (예 : Utils 또는 Gui 프레임 워크) 위에 빌드 된 모든 관리 가능한 라이브러리로 분할하여 정적 라이브러리로 만들 겠다는 일반적인 경험을 줄 것입니다. 다이나믹 라이브러리는 실제로 당신에게 아무 것도 사지 않으며 놀라움이 적습니다. 예를 들어 싱글 톤 인스턴스가 하나만있을 것입니다.

나머지 코드베이스 (예 : 써드 파티 라이브러리)와 완전히 다른 라이브러리를 가지고 있다면 dll로 만드십시오. 라이브러리가 LGPL 인 경우 라이선스 조건으로 인해 dll을 사용해야 할 수도 있습니다.




정말 큰 프로젝트에서 초기로드 시간에 라이브러리를 만들거나, 라이브러리를 한 번에 또는 다른 링크로 만들 것인지 결정해야합니다. 컴파일러가 필요로하는만큼 링크를 오래 걸릴 것인지 결정해야합니다. 글 머리 기호를 물고 앞에 붙이거나 동적 링커가 로딩 할 때 할 수 있습니까?




정적 라이브러리가 클라이언트로 컴파일됩니다. .lib는 컴파일 할 때 사용되며 라이브러리의 내용은 소비 가능한 실행 파일의 일부가됩니다.

동적 라이브러리는 런타임에로드되고 클라이언트 실행 파일로 컴파일되지 않습니다. 동적 라이브러리는 다중 클라이언트 실행 파일이 DLL을로드하고 해당 기능을 활용할 수 있으므로보다 융통성이 있습니다. 또한 클라이언트 코드의 전체 크기와 유지 관리 가능성을 최소한으로 유지합니다.




임베디드 프로젝트 또는 특수 플랫폼 정적 라이브러리에 대한 작업 만 수행하는 유일한 방법 인 경우에도 응용 프로그램으로 컴파일하는 번거 로움이 적습니다. 또한 모든 것을 포함하는 프로젝트와 메이크 파일을 가지고 있으면 더 행복하게 살 수 있습니다.




라이브러리를 여러 실행 파일에서 공유하려는 경우 실행 파일의 크기를 줄이기 위해 동적으로 만드는 것이 좋습니다. 그렇지 않으면 확실히 정적으로 만드십시오.

dll을 사용할 때 몇 가지 단점이 있습니다. 로드 및 언로드에 대한 추가 오버 헤드가 있습니다. 추가 종속성도 있습니다. executalbes와 호환되지 않도록 dll을 변경하면 작업이 중단됩니다. 반면에 정적 라이브러리를 변경하면 이전 버전을 사용하는 컴파일 된 실행 파일이 영향을받지 않습니다.




정적 라이브러리 만들기

$$:~/static [32]> cat foo.c
#include<stdio.h>
void foo()
{
printf("\nhello world\n");
}
$$:~/static [33]> cat foo.h
#ifndef _H_FOO_H
#define _H_FOO_H

void foo();

#endif
$$:~/static [34]> cat foo2.c
#include<stdio.h>
void foo2()
{
printf("\nworld\n");
}
$$:~/static [35]> cat foo2.h
#ifndef _H_FOO2_H
#define _H_FOO2_H

void foo2();

#endif
$$:~/static [36]> cat hello.c
#include<foo.h>
#include<foo2.h>
void main()
{
foo();
foo2();
}
$$:~/static [37]> cat makefile
hello: hello.o libtest.a
        cc -o hello hello.o -L. -ltest
hello.o: hello.c
        cc -c hello.c -I`pwd`
libtest.a:foo.o foo2.o
        ar cr libtest.a foo.o foo2.o
foo.o:foo.c
        cc -c foo.c
foo2.o:foo.c
        cc -c foo2.c
clean:
        rm -f foo.o foo2.o libtest.a hello.o

$$:~/static [38]>

동적 라이브러리 만들기

$$:~/dynamic [44]> cat foo.c
#include<stdio.h>
void foo()
{
printf("\nhello world\n");
}
$$:~/dynamic [45]> cat foo.h
#ifndef _H_FOO_H
#define _H_FOO_H

void foo();

#endif
$$:~/dynamic [46]> cat foo2.c
#include<stdio.h>
void foo2()
{
printf("\nworld\n");
}
$$:~/dynamic [47]> cat foo2.h
#ifndef _H_FOO2_H
#define _H_FOO2_H

void foo2();

#endif
$$:~/dynamic [48]> cat hello.c
#include<foo.h>
#include<foo2.h>
void main()
{
foo();
foo2();
}
$$:~/dynamic [49]> cat makefile
hello:hello.o libtest.sl
        cc -o hello hello.o -L`pwd` -ltest
hello.o:
        cc -c -b hello.c -I`pwd`
libtest.sl:foo.o foo2.o
        cc -G -b -o libtest.sl foo.o foo2.o
foo.o:foo.c
        cc -c -b foo.c
foo2.o:foo.c
        cc -c -b foo2.c
clean:
        rm -f libtest.sl foo.o foo

2.o hello.o
$$:~/dynamic [50]>



Related