Làm thế nào để gcc tìm thấy tập tin tiêu đề sau đây?


10

Tôi đã đưa sys/ptrace.hvào chương trình C của mình.

Đầu ra của /usr/lib/gcc/x86_64-linux-gnu/4.8/cc1 -vcung cấp các đường dẫn sau trong đó gcc tìm tệp tiêu đề

#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-linux-gnu/4.8/include
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/4.8/include-fixed
 /usr/include
End of search list.

đầu ra gcc -Mcho chương trình của tôi cung cấp cho các vị trí tệp tiêu đề sau

    pt.o: pt.c /usr/include/stdc-predef.h /usr/include/stdio.h \
 /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \
 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
 /usr/lib/gcc/x86_64-linux-gnu/4.8/include/stddef.h \
 /usr/include/x86_64-linux-gnu/bits/types.h \
 /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/libio.h \
 /usr/include/_G_config.h /usr/include/wchar.h \
 /usr/lib/gcc/x86_64-linux-gnu/4.8/include/stdarg.h \
 /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
 /usr/include/x86_64-linux-gnu/bits/sys_errlist.h \
 /usr/include/x86_64-linux-gnu/sys/ptrace.h

/usr/include/x86_64-linux-gnu/không được chứa trong đầu ra đầu tiên, gcc tìm thấy sys/ptrace.hnhư thế nào?

BIÊN TẬP:

Đầu ra của echo '#include <sys/ptrace.h>' | gcc -fsyntax-only -xc -v -H -kết quả trong

Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.8.4-2ubuntu1~14.04' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libmudflap --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04) 

Đó là đệ quy nhìn vào /usr/include.. Bạn đang cố gắng giải quyết vấn đề gì?
Ramhound

Nó không giống như nó đệ quy nhìn qua. Nếu có, sẽ không cần bao gồm tiền tố / tiền tố. Bao gồm chỉ ptrace.h, ví dụ, không hoạt động.
dùng912083132

Tôi không nghĩ bạn bao gồm /sys/ptrace.hnhưng sys/ptrace.h, phải không?
dùng253751

Đây gần như chắc chắn là một lỗi trong các bản vá "multiarch" đối với GCC. Thư mục /usr/include/x86_64-linux-gnu đang được coi là một hệ thống bao gồm thư mục và nên được bao gồm trong danh sách đường dẫn tìm kiếm được in bởi gcc -v. Tôi không chắc làm thế nào ai đó quản lý để đạt được lỗi đó; Nếu tôi nhớ chính xác, cách rõ ràng nhất để thêm hệ thống bao gồm các thư mục sẽ thêm chúng vào những gì được in bởi -v. (Tôi đã viết ~ 50% bộ tiền xử lý của GCC, nhưng đó là 15 năm trước, vì vậy tôi có thể đang đánh giá sai một cái gì đó.)
zwol

@Ramhound Nó chắc chắn không tìm kiếm đệ quy dưới đây /usr/include. Điều đó sẽ phá vỡ mọi thư viện C trên thế giới.
zwol

Câu trả lời:


12

Câu trả lời ngắn hơn.

Câu hỏi của bạn là về đầu ra của cc1 -v, nhưng đó không phải là yếu tố trong CPP (Bộ tiền xử lý C) và nó bao gồm cả được trộn vào toàn bộ chuỗi biên dịch. Nếu bạn chạy cpp -vtrên hệ thống của mình, bạn sẽ thấy, một hỗn hợp bao gồm trông giống với đầu ra của cc1 -vnhưng ít nhất là /usr/include/x86_64-linux-gnuđường dẫn được thêm vào trong đó.

Câu trả lời dài hơn.

/usr/include/x86_64-linux-gnu/không được chứa trong đầu ra đầu tiên, gcc tìm thấy sys/ptrace.hnhư thế nào?

Về mặt kỹ thuật, /usr/include/x86_64-linux-gnu/không được đặt rõ ràng ở đầu ra đầu tiên, nhưng /usr/include/chắc chắn là như vậy. Và đó là đường dẫn tìm kiếm mặc định như được giải thích trong tài liệu chính thức của GNU GCC :

GCC tìm kiếm ở một số nơi khác nhau cho các tiêu đề. Trên một hệ thống Unix bình thường, nếu bạn không hướng dẫn cách khác, nó sẽ tìm các tiêu đề được yêu cầu #include <file>trong:

  • / usr / địa phương / bao gồm
  • libdir / gcc / đích / phiên bản / bao gồm
  • / usr / mục tiêu / bao gồm
  • / usr / bao gồm

Và giải thích thêm ở đây:

GCC tìm kiếm các tiêu đề được yêu cầu #include "file"đầu tiên trong thư mục chứa tệp hiện tại, sau đó trong các thư mục như được chỉ định bởi -iquotecác tùy chọn, sau đó ở cùng một vị trí, nó sẽ tìm kiếm một tiêu đề được yêu cầu với dấu ngoặc nhọn. Ví dụ: nếu /usr/include/sys/stat.hchứa # include "types.h", GCC tìm kiếm types.hđầu tiên /usr/include/sys, sau đó trong đường dẫn tìm kiếm thông thường của nó.

Vì vậy, điều này ngụ ý rằng x86_64-linux-gnu/đường dẫn được chèn vào /usr/include/*/sys/như thế này:

/usr/include/x86_64-linux-gnu/sys/ptrace.h

Ít nhất đó là những gì tôi nghĩ ban đầu trong một phiên bản trước của câu hỏi này . Nhưng sau khi kiểm tra trang web này , lời giải thích về những gì đang xảy ra chi tiết hơn một chút và phản hồi trực tiếp từ trang web đó với nội dung tương đương với những gì tôi đã đăng ở trên được đăng lại dưới đây; nhấn mạnh đậm là của tôi:

nhưng đó là một câu trả lời mơ hồ (và cũng không đầy đủ). Chắc chắn phải có một cách để GCC cho bạn biết chính xác nơi mà nó sẽ tìm kiếm các tệp tiêu đề của nó? Chà, mặc dù thật tiện lợi khi nghĩ GCC là một ứng dụng nguyên khối duy nhất lấy các tệp mã nguồn và tạo ra các chương trình làm việc, về mặt kỹ thuật, đó là một tập hợp các chương trình khác kết hợp với nhau để tạo ra tệp đối tượng được biên dịch cuối cùng. Đầu tiên trong số này là CPP, viết tắt của C Pre-Processor , công việc của họ là tìm kiếm các chỉ thị của trình biên dịch như #includevà sửa đổi mã nguồn theo quy định của chúng; trong trường hợp bao gồm, bằng cách sao chép nội dung của tệp khác vào tệp hiện tại. Bạn có thể thấy nơi nó tìm các tệp này bằng cách chuyển cờ -v:

Hãy biết rằng CPP (Bộ xử lý trước C) là bước đầu tiên trong quy trình của trình biên dịch, chúng ta hãy xem kết quả đầu ra bao gồm các ứng dụng cpp -vtrên hệ thống thử nghiệm Ubuntu 12.04.5 của tôi:

#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-linux-gnu/4.6/include
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/4.6/include-fixed
 /usr/include/x86_64-linux-gnu
 /usr/include

Trong đó bạn có thể thấy rõ /usr/include/x86_64-linux-gnu. Và để so sánh, đây là đầu ra tương tự của bộ điều khiển /usr/lib/gcc/x86_64-linux-gnu/4.6/cc1 -vtrên nền tảng trên cùng một hệ thống thử nghiệm Ubuntu 12.04.5:

#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-linux-gnu/4.6/include
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/4.6/include-fixed
 /usr/include

Lưu ý cách /usr/include/x86_64-linux-gnuđược chèn rõ ràng vào hỗn hợp bằng hành động CPP (C Pre-Processor) ban đầu. Và bài đăng trên trang web đó tiếp tục giải thích những con đường đó đến từ đâu; một lần nữa nhấn mạnh đậm là của tôi:

đường dẫn này thực sự được tích hợp vào CPP (là một phần của GCC) tại thời điểm biên dịch; nếu vì bất kỳ lý do gì bạn kết thúc việc xóa một trong những thư mục đó, nó vẫn sẽ được kiểm tra trên mỗi lần biên dịch. Mỗi thư mục được tìm kiếm theo thứ tự được liệt kê ở đây; nếu một tập tin được tìm thấy /usr/local/include, ba thư mục tiếp theo sẽ không được kiểm tra.

Vì vậy, tất cả sôi sục xuống CPP (Bộ tiền xử lý C) được gọi là phần đầu tiên của chuỗi biên dịch C.


Tại sao x86_64-linux-gnu / bị đẩy vào giữa?
dùng912083132

@ user912083132: Đó là $TARGETphần tôi đã đề cập trong câu trả lời và nhận xét của mình. Đó là đầu ra của config.guesskhi GCC được biên dịch, hoặc được trao cho configuretập lệnh của nó với --targetcờ. Câu hỏi thực sự là, làm thế nào để con đường đó được lắp ráp? Có phải nó chỉ quay trở lại qua cùng một danh sách, nối thêm $TARGETvào từng danh sách , sau khi không tìm thấy tiêu đề lần đầu tiên thông qua?
Warren Young

@ user912083132 Cập nhật câu trả lời của tôi với một số thông tin mới lượm lặt được. Hãy đọc lại nó; câu trả lời giải thích nó đến từ CPP (C Pre-Processor).
JakeGould

2

Nói ngắn gọn về mã nguồn GCC, tôi không thể cho bạn biết "tại sao", nhưng tôi có thể nói với bạn rằng phiên bản GCC mà tôi có ở đây rơi vào /usr/include/$TARGETsau khi cạn kiệt các lựa chọn mà bạn và JakeGould đã tìm thấy . Bạn có thể thấy nó như vậy:

$ strace -f -e open gcc -c foo.c -o foo.o 2>&1 | grep ptrace.h

nơi foo.cchứa a #include <sys/ptrace.h>.

Bạn cần -flập luận ở đây vì gccsinh ra trẻ em để thực hiện công việc biên dịch thực tế. Bạn cần 2>&1bởi vì straceđang viết kết quả của nó vào thiết bị lỗi chuẩn chứ không phải thiết bị xuất chuẩn.

Lưu ý rằng bạn nhận được ENOENTlỗi cho tất cả các thư mục tài liệu trước khi cuối cùng nó thử một thư mục thành công.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.