makefile과 함께 제공되지 않는 한 샘플 C 코드를 실행하는 것은 어렵습니다.
나는 종종 정말 멋진 일을 한다고 말해지는 코드가 포함된 C 파일을 발견하지만 gcc main.c
첫 번째 기본 컴파일 시도에서 실패합니다.
main.c:(.text+0x1f): undefined reference to `XListInputDevices'
clang-3.7: error: linker command failed with exit code 1 (use -v to see invocation)
- 또는 유사합니다.
-lX11
이는 올바른 링커 플래그(예 : -lXext
또는 ) 가 누락되었음을 의미합니다 -lpthread
.
하지만 어느 것?
제가 현재 이 문제를 처리하는 방식은 다음과 같습니다.함수가 포함된 라이브러리 헤더 찾기, Github의 검색을 사용하여 동일한 헤더를 가져온 다른 프로그램을 찾고, makefile을 열고, 링커 플래그를 찾고, 이를 내 컴파일 명령에 복사한 다음, 여전히 컴파일되는 가장 작은 세트를 찾을 때까지 플래그를 계속 제거했습니다.
비효율적이고 지루하며 더 나은 방법이 있을 거라고 생각하게 만듭니다.
답변1
문제는 소스 파일을 검사하여 사용할 링커 플래그를 결정하는 방법입니다. 아래 예제는 데비안용입니다. 여기서 주목해야 할 관련 항목은 헤더 파일이다.
따라서 헤더 파일을 포함하는 C 소스 파일이 있다고 가정합니다.
#include <X11/extensions/XInput.h>.
XInput.h
예 를 apt-file
들어 이 헤더 파일이 설치된 패키지에 포함되어 있다는 것을 알고 있으면 검색할 수도 있습니다 . 예를 들어dpkg -S
dlocate
apt-file search XInput.h
libxi-dev: /usr/include/X11/extensions/XInput.h
이는 헤더 파일이 libxi의 개발 패키지(C 라이브러리의 경우 개발 패키지(일반적으로 libname-dev
또는 형식 libname-devel
)에 헤더 파일이 포함되어 있음) 에 속하므로 -lxi
링커 플래그를 사용해야 함을 알려줍니다.
비슷한 접근 방식이 패키지 관리 시스템을 사용하는 모든 배포에 적용됩니다.
답변2
문제의 핵심: 헤더 파일과 라이브러리 이름
문제의 핵심이 게시되었습니다.질문 자체 아래에 있는 댓글:
XListInputDevices의 경우 적절한 포함 라인은 입니다
#include <X11/extensions/XInput.h>
. 나는 생각 중입니다-lSomething 플래그를 기반으로 필요한 것이 무엇인지 어떻게 알 수 있습니까?
-lXi
이 질문에 올바르게 대답하려면 libXi.so
와 의 차이점을 이해해야 합니다 XInput.h
. 이것은XInput.h
헤드 파일그리고 -l
대상 파일을 찾으세요. gcc 사용법에 관한 Red Hat 문서에 따르면,섹션 16.1,
라이브러리는 특별한 파일 이름 규칙을 사용합니다. foo라는 라이브러리는 libfoo.so 또는 libfoo.a 파일로 존재해야 합니다. GCC의 링크 입력 옵션은 자동으로 이 규칙을 이해하지만 출력 옵션은 그렇지 않습니다.
헤더와 라이브러리는 모두 필수이며 관련되어 있지만 동일하지는 않습니다(인용하다):
...헤더를 #include하면 컴파일러는 호출한 함수에 대한 코드를 program.o에 삽입하지 않습니다. 단지 그에 대한 참조를 삽입할 뿐입니다.
앞에서 언급했듯이 헤더와 링커는 헤더가 함수 및 기타 항목에 대한 선언(또는 일반 용어로 설명)을 저장하는 반면, 라이브러리는 실제 객체(인용하다) 또는 이러한 함수의 컴파일된 버전입니다.이 답변에서 알 수 있듯이:
- 제목은 전화할 수 있는 전화번호이고...
- ...도서관은 여러분이 다가갈 수 있는 실제 사람입니다!
헤더와 라이브러리는 어떻게 함께 작동합니까? 이는 모두 애플리케이션을 구축하는 데 필요한 단계입니다. 먼저 기능과 인터페이스에 대한 설명을 수집합니다(일명.컴파일된) 그런 다음 작성하는 코드는 다음과 같습니다.연결됨실제 인터페이스와 기능을 구현하는 라이브러리.
도서관 자체~해야 한다포함된 헤더로 컴파일(인용하다) 도서관으로. 실제로 예를 보면 알 수 있습니다.간단한 정적 라이브러리를 만드는 방법.
따라서 귀하의 질문에 대한 답변은 다음과 같습니다.헤더와 라이브러리 이름 사이에는 보장된 관계가 없습니다.(아니면 적어도 지금까지는 찾지 못했습니다. 또한 참조하세요.이 참조). 그리고 그것들을 어떻게 일치시킬 것인지를 알아내는 것은 패키지나 소스 코드에 무엇이 있는지 이해하는 문제입니다.
실제로 다음을 수행하여 이를 증명할 수 있습니다.
$ echo '#include<errno.h> int main(){return 0;}' | gcc -S -lc
이는 libc에 대해 컴파일하고 있지만 libc의 일부인 헤더 이름이 다르다는 것을 나타냅니다.
이를 보여주는 또 다른 예는 #include <math.h>
의 일부이지만 libc
실제 구현은 에 있으므로 libm.so.6
컴파일된 코드를 볼 수 있다는 것입니다 gcc -lm
.
$ apt-file find /lib/x86_64-linux-gnu/libm.so.6
libc6: /lib/x86_64-linux-gnu/libm.so.6
관련 .so 또는 .a 라이브러리 파일 찾기
많은 미스터리는 문서를 통해 해결될 수 있습니다. 한 번 보자gcc
링크 옵션에 대한 문서(참고로 굵은 글씨는 제가 강조한 것입니다):
-도서관
-l 라이브러리
링크할 때 library라는 이름의 라이브러리를 검색하세요. (라이브러리를 별도의 매개변수로 사용하는 두 번째 옵션은 POSIX 호환만을 위한 것이므로 권장되지 않습니다.)
-l 옵션은GCC에 의해 링커에 직접 전달됨. 정확한 세부사항은 링커 문서를 참조하세요. 다음의 일반적인 설명은 GNU 링커에 적용됩니다.
좋습니다. gcc
실제로는 라이브러리 자체를 찾는 것이 아닙니다. 이것이 링커의 역할입니다. 하지만 계속 읽어보자.
링커 검색표준 디렉토리 목록도서관용. 검색된 디렉토리에는 여러 표준 시스템 디렉토리와 -L로 지정한 디렉토리가 포함됩니다.
따라서 표준 디렉토리 목록이 있습니다. 그렇군요, 범위가 좁아졌습니다. 이 목록은 어떻게 얻나요?일방 통행 그 중 하나가 바로 사용법인데, ldconfig -v
유저분이 친절하게 설명해주셔서트로토리움
그러나 gcc
문서에서는 다음과 같이 더 자세히 설명합니다.
정적 라이브러리는 liblibrary.a와 유사한 파일 이름을 가진 개체 파일의 아카이브입니다. 일부 대상은 일반적으로 liblibrary.so와 유사한 이름을 가진 공유 라이브러리도 지원합니다. 정적 라이브러리와 공유 라이브러리가 모두 발견되면 -static 옵션을 사용하지 않는 한 링커는 공유 라이브러리를 먼저 연결합니다.
명령에서 이 옵션을 작성하는 위치는 다양합니다. 링커는 지정된 순서대로 라이브러리와 개체 파일을 검색하고 처리합니다. 따라서 "foo.o -lz bar.o"는 foo.o 파일 뒤, bar.o 앞에서 라이브러리 "z"를 검색합니다. bar.o가 "z"의 함수를 참조하는 경우 해당 함수는 로드되지 않을 수 있습니다.
즉, 실제로 지시 gcc
하고 이어서 ld
수행하는 작업은 파일을 찾는 것입니다 libxi.so
(따라서공유 객체 확장) 또는 libxi.a
표준 경로 목록에 있습니다. 우리가 무언가를 저장했는데 /opt
링커 ld
가 그것에 대해 모른다면 무엇이든 전달하면 -l
작동하지 않습니다.
libwhatever.so
허용되는 대답은 해당 라이브러리 의 가장 데비안 패키지 이름에 해당하는 라이브러리의 가장 데비안 패키지 이름을 가짐으로써 이를 암시하는 것 같습니다 . 하지만 나는 이런 작은 세부 사항 없이도 나의 보잘것없는 요구에 맞는 데비안 패키징에 대해 충분히 알고 있기 때문에 이를 확인하거나 거부할 수 없습니다. 내가 아는 전부는ld
apt가 캐시 재구축을 유발할 수 있음.
ld
이제 실제로 이러한 모든 디렉터리가 캐시에 있다는 사실을 인식하는 것도 중요합니다 /etc/ld.so.cache
. 따라서 디렉터리가 캐시에서 제거되면 링커는 라이브러리가 존재하는지 알 수 없습니다.
물론, 위의 모든 이론을 예제를 기반으로 테스트하고 싶다면 libxi-devel
다음과 같이 할 수 있습니다.
$ dpkg-query -L libxi-dev | grep -i '.so'
/usr/share/man/man3/XIDefineCursor.3.gz
/usr/lib/x86_64-linux-gnu/libXi.so
/usr/share/man/man3/XIUndefineCursor.3.gz
그런 다음 검색 디렉토리 목록에 ldconfig
있는지 확인 하십시오 /usr/lib/x86_64-linux-gnu
. 그것은 다음과 같습니다.
$ ldconfig -p | grep libXi.so
libXi.so.6 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libXi.so.6
libXi.so.6 (libc6) => /usr/lib/i386-linux-gnu/libXi.so.6
libXi.so (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libXi.so
.h
이제 이 파일도 쓸모가 없는 걸까요? 라는 질문이 제기됩니다. 아니요, gcc
분명히 컴파일 타임에 존재해야 합니다( gcc
포함 경로가 실제로 확인되고일부 라이브러리는 헤더 파일만 될 수 있습니다.)
$ mv /usr/include/X11/extensions/XInput.h /tmp
$ echo '#include <X11/extensions/XInput.h> void main(){return 0;}' | gcc -lXi -E -
# 1 "<stdin>"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "<stdin>"
<stdin>:1:36: warning: extra tokens at end of #include directive
<stdin>:1:10: fatal error: X11/extensions/XInput.h: No such file or directory
compilation terminated.
답변3
이것은 다른 배포판에 상응하는 도구를 수집하는 데 사용되는 커뮤니티 위키입니다.파힘의 방법. 자유롭게 편집할 수 있지만 검색이 가능하도록 알파벳순으로 정렬해 두시기 바랍니다.
아치
pkgfile
저장소에서 사용되며 extra
헤더 파일 이름을 인수로 전달합니다.
예:
$ pkgfile XInput.h
extra/libxi
extra/nx-headers
더반
(그리고데비안 기반의 모든 것사용 dpkg
)
apt-file search
헤더 파일 이름은덮은 대로.
루트 다이어그램
warl0ck의 다른 질문에서 언급했듯이pfl
, 패키지를 사용하는 프로그램 e-file
, 또는포티지 파일 목록의 웹 기반 검색.