gccコマンドの裏側を知りたいときのヒント集メモ。
使用環境:
CentOS 5.x gcc-4.1.2-48.el5 libgcc-4.1.2-48.el5 cpp-4.1.2-48.el5 binutils-2.17.50.0.6-6.el5 binutils-devel-2.17.50.0.6-14.el5
本サイト内の関連URL:
参考書籍:
gccコマンドが隠蔽しているビルド過程を確認し、手動でGNUツールチェインを実行する際のヒント集。
gccコマンドを"-v"オプション付きで実行すると、普段は隠されているビルド過程を出力させることが出来る。
$ gcc -v -o foo foo.c Using built-in specs. Target: i386-redhat-linux コンフィグオプション: ../configure --prefix=/usr (...省略...) /usr/libexec/gcc/i386-redhat-linux/4.1.2/cc1 \ -quiet -v foo.c -quiet -dumpbase foo.c \ -mtune=generic -auxbase foo -version \ -o /tmp/ccHJGC4y.s 存在しないディレクトリ "/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../i386-redhat-linux/include" を無視します #include "..." の探索はここから始まります: #include <...> の探索はここから始まります: /usr/local/include /usr/lib/gcc/i386-redhat-linux/4.1.2/include /usr/include 探索リストの終わり GNU C version 4.1.2 20080704 (Red Hat 4.1.2-48) (i386-redhat-linux) compiled by GNU C version 4.1.2 20080704 (Red Hat 4.1.2-48). GGC heuristics: --param ggc-min-expand=64 --param ggc-min-heapsize=64436 Compiler executable checksum: 625231d1211c3689652276225f4f5c88 as -V -Qy -o /tmp/ccup2RC0.o /tmp/ccHJGC4y.s GNU assembler version 2.17.50.0.6-6.el5 (i386-redhat-linux) using BFD version 2.17.50.0.6-6.el5 20061020 /usr/libexec/gcc/i386-redhat-linux/4.1.2/collect2 \ --eh-frame-hdr -m elf_i386 \ --hash-style=gnu \ -dynamic-linker /lib/ld-linux.so.2 \ -o foo \ /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crt1.o \ /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crti.o \ /usr/lib/gcc/i386-redhat-linux/4.1.2/crtbegin.o \ -L/usr/lib/gcc/i386-redhat-linux/4.1.2 \ -L/usr/lib/gcc/i386-redhat-linux/4.1.2 \ -L/usr/lib/gcc/i386-redhat-linux/4.1.2/../../.. \ /tmp/ccup2RC0.o \ -lgcc \ --as-needed \ -lgcc_s \ --no-as-needed \ -lc -lgcc \ --as-needed \ -lgcc_s \ --no-as-needed \ /usr/lib/gcc/i386-redhat-linux/4.1.2/crtend.o \ /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crtn.o
プリプロセスだけを行う"-E"オプションと併用すると効果的。
$ gcc -H -E -o foo.i foo.c . /usr/include/stdio.h .. /usr/include/features.h ... /usr/include/sys/cdefs.h .... /usr/include/bits/wordsize.h ... /usr/include/gnu/stubs.h .... /usr/include/bits/wordsize.h .... /usr/include/gnu/stubs-32.h .. /usr/lib/gcc/i386-redhat-linux/4.1.2/include/stddef.h .. /usr/include/bits/types.h ... /usr/include/bits/wordsize.h ... /usr/lib/gcc/i386-redhat-linux/4.1.2/include/stddef.h ... /usr/include/bits/typesizes.h .. /usr/include/libio.h ... /usr/include/_G_config.h .... /usr/lib/gcc/i386-redhat-linux/4.1.2/include/stddef.h .... /usr/include/wchar.h ..... /usr/lib/gcc/i386-redhat-linux/4.1.2/include/stddef.h ..... /usr/include/bits/wchar.h .... /usr/include/gconv.h ..... /usr/include/wchar.h ...... /usr/lib/gcc/i386-redhat-linux/4.1.2/include/stddef.h ..... /usr/lib/gcc/i386-redhat-linux/4.1.2/include/stddef.h ... /usr/lib/gcc/i386-redhat-linux/4.1.2/include/stdarg.h .. /usr/include/bits/stdio_lim.h .. /usr/include/bits/sys_errlist.h
複数のインクルードPATHを調整する場面で役立つだろう。
$ gcc -print-search-dirs インストール: /usr/lib/gcc/i386-redhat-linux/4.1.2/ プログラム: =(省略) ライブラリ: =(省略)
cppコマンドがインストールされている場合は、
$ cpp -print-search-dirs
でも同じ結果になる。
実行時に確認したい場合は、"-v"オプションを使うとよいだろう。
$ gcc -v -E -o foo.i foo.c (省略) #include "..." の探索はここから始まります: #include <...> の探索はここから始まります: /usr/local/include /usr/lib/gcc/i386-redhat-linux/4.1.2/include /usr/include 探索リストの終わり
"-I"オプションを指定して、"#include <...>"の検索PATHを追加してみる:
$ gcc -v -I/tmp -E -o foo.i foo.c (省略) #include "..." の探索はここから始まります: #include <...> の探索はここから始まります: /tmp /usr/local/include /usr/lib/gcc/i386-redhat-linux/4.1.2/include /usr/include 探索リストの終わり
"-I-"オプションを活用し、"/tmp"を"#include """ にのみ追加し、"/home"を"#include <>"に追加してみる:
$ gcc -v -I/tmp -I- -I/home -E -o foo.i foo.c (省略) #include "..." の探索はここから始まります: /tmp #include <...> の探索はここから始まります: /home /usr/local/include /usr/lib/gcc/i386-redhat-linux/4.1.2/include /usr/include 探索リストの終わり
上記オプションは"cpp"コマンドでも同様に利用可能。
"cc1", "collect2"など、gccが舞台裏で起動しているgccツールのフルパスを取得する:
$ gcc -print-prog-name=cc1 /usr/libexec/gcc/i386-redhat-linux/4.1.2/cc1 $ gcc -print-prog-name=collect2 /usr/libexec/gcc/i386-redhat-linux/4.1.2/collect2
gccのランタイムライブラリファイルのフルパスを取得する:
$ gcc -print-libgcc-file-name | /usr/lib/gcc/i386-redhat-linux/4.1.2/libgcc.a |
$ gcc -print-file-name=crti.o | /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crti.o |
$ gcc -print-file-name=crt1.o | /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crt1.o |
$ gcc -print-file-name=crtbegin.o | /usr/lib/gcc/i386-redhat-linux/4.1.2/crtbegin.o |
$ gcc -print-file-name=crtend.o | /usr/lib/gcc/i386-redhat-linux/4.1.2/crtend.o |
$ gcc -print-file-name=crtn.o | /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crtn.o |
binutilsのlinkerであるldコマンドの"-t"オプションを使う。
-t : trace link files
$ gcc -c -o foo.o foo.i $ gcc -o foo -Wl,-t foo.o /usr/bin/ld: mode elf_i386 /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crt1.o /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crti.o /usr/lib/gcc/i386-redhat-linux/4.1.2/crtbegin.o foo.o -lgcc_s (/usr/lib/gcc/i386-redhat-linux/4.1.2/libgcc_s.so) /lib/libc.so.6 (/usr/lib/libc_nonshared.a)elf-init.oS /lib/ld-linux.so.2 -lgcc_s (/usr/lib/gcc/i386-redhat-linux/4.1.2/libgcc_s.so) /usr/lib/gcc/i386-redhat-linux/4.1.2/crtend.o /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crtn.o
ld --verbose
でリンカスクリプト表示、SEARCH_DIR()を確認する。
$ ld --verbose GNU ld version 2.17.50.0.6-6.el5 20061020 Supported emulations: elf_i386 i386linux using internal linker script: ================================================== /* Script for -z combreloc: combine and sort reloc sections */ OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) ENTRY(_start) SEARCH_DIR("/usr/i386-redhat-linux/lib"); \ SEARCH_DIR("/usr/local/lib"); \ SEARCH_DIR("/lib"); \ SEARCH_DIR("/usr/lib"); SECTIONS { ...
静的リンクを行うにはgccの "-static" オプションを使う。
舞台裏を見てみると、"collect2"に"-static"オプションがわたっている。
$ gcc -c -o foo.o foo.c $ gcc -v -static -o foo foo.o (...) /usr/libexec/gcc/i386-redhat-linux/4.1.2/collect2 \ -m elf_i386 \ --hash-style=gnu \ -static \ -o foo \ /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crt1.o \ /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crti.o \ /usr/lib/gcc/i386-redhat-linux/4.1.2/crtbeginT.o \ -L/usr/lib/gcc/i386-redhat-linux/4.1.2 \ -L/usr/lib/gcc/i386-redhat-linux/4.1.2 \ -L/usr/lib/gcc/i386-redhat-linux/4.1.2/../../.. \ foo.o \ --start-group \ -lgcc \ -lgcc_eh \ -lc \ --end-group \ /usr/lib/gcc/i386-redhat-linux/4.1.2/crtend.o \ /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crtn.o
"--start-group", "--end-group"については"info ld"参照。
"-t"でトレースしてみる。表示量が大きいので、ファイルに落とす。
$ gcc -Wl,-t -static -o foo foo.o > list.txt
list.txt:
/usr/bin/ld: mode elf_i386 /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crt1.o /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crti.o /usr/lib/gcc/i386-redhat-linux/4.1.2/crtbeginT.o foo.o (/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../libc.a)libc-start.o (/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../libc.a)check_fds.o ... (/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../libc.a)dl-sym.o (/usr/lib/gcc/i386-redhat-linux/4.1.2/libgcc_eh.a)unwind-dw2.o (/usr/lib/gcc/i386-redhat-linux/4.1.2/libgcc_eh.a)unwind-dw2-fde-glibc.o (/usr/lib/gcc/i386-redhat-linux/4.1.2/libgcc_eh.a)unwind-c.o (/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../libc.a)stack_chk_fail_local.o (/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../libc.a)dl-iteratephdr.o (/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../libc.a)stack_chk_fail.o /usr/lib/gcc/i386-redhat-linux/4.1.2/crtend.o /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crtn.o
libgcc_eh.aなど、gcc側のビルトインライブラリからもリンクされていることが分かる。
"-static"オプションを指定しなければ、デフォルトの動的リンクとなる。
"-dynamic-linker"オプションで実行時リンカを指定している。
$ gcc -v -o foo foo.o (...) /usr/libexec/gcc/i386-redhat-linux/4.1.2/collect2 \ --eh-frame-hdr \ -m elf_i386 \ --hash-style=gnu \ -dynamic-linker /lib/ld-linux.so.2 \ -o foo \ /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crt1.o \ /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crti.o \ /usr/lib/gcc/i386-redhat-linux/4.1.2/crtbegin.o \ -L/usr/lib/gcc/i386-redhat-linux/4.1.2 \ -L/usr/lib/gcc/i386-redhat-linux/4.1.2 \ -L/usr/lib/gcc/i386-redhat-linux/4.1.2/../../.. \ foo.o \ -lgcc \ --as-needed \ -lgcc_s \ --no-as-needed \ -lc \ -lgcc \ --as-needed \ -lgcc_s \ --no-as-needed \ /usr/lib/gcc/i386-redhat-linux/4.1.2/crtend.o \ /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crtn.o
"--as-needed", "--no-as-needed"については"info ld"参照。
"-t"でトレースしてみる。
$ gcc -Wl,-t -o foo foo.o /usr/bin/ld: mode elf_i386 /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crt1.o /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crti.o /usr/lib/gcc/i386-redhat-linux/4.1.2/crtbegin.o foo.o -lgcc_s (/usr/lib/gcc/i386-redhat-linux/4.1.2/libgcc_s.so) /lib/libc.so.6 (/usr/lib/libc_nonshared.a)elf-init.oS /lib/ld-linux.so.2 -lgcc_s (/usr/lib/gcc/i386-redhat-linux/4.1.2/libgcc_s.so) /usr/lib/gcc/i386-redhat-linux/4.1.2/crtend.o /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crtn.o