C++プログラムコンパイル手順の詳細

18416 ワード

C/C++言語は多くの人がよく知っています.これは基本的に大学生一人一人が必ず学ぶプログラミング言語で、通常はプログラム設計の入門言語学として、課程の多くは大学1年生に配置されています.大学に入ったばかりで、子供たちはまだいい子で、勉強もまじめで、心を込めています.だから、C/C++言語の掌握地も悪くなくて、コンパイラは言うまでもなく、何百行ものプログラムを書くのはすべて話の下で、しかし彼らは本当にC/C++プログラムのコンパイルのステップを知っていますか?多くの人がよく知らないと思いますが、もし彼が次に「コンパイル原理」を学んだら、大まかに言えるかもしれません.VCの「快適」開発環境は多くのコンパイルの細部を遮断し、これは間違いなく初心者の入門の敷居を下げたが、彼らの「その理由を知っている」権利を「奪う」ことで、多くのものが硬背を覚えるしかなく、関連問題に遭遇すると「丈二」になる.実際、私もLinux環境でプログラミングを学ぶ過程で、C/C++ソースコードがどのようにして実行可能なファイルになったのかを徐々に明らかにしました.全体的に、C/C++ソースコードは、対応するプラットフォームの実行可能ファイルになるには、前処理、コンパイル、アセンブリ、接続の4つのステップを経なければなりません.多くの場合、プログラマは1つのコマンドで上記の4つのステップを完了することができます.例えば次のCの「Hello world!」コード:File:hw.c #include <stdio.h>

int main(int argc, char *argv[])
{
        printf("Hello World!
"
);

        return 0;
}

gccでコンパイルすると、1つのコマンドだけで実行可能ファイルhwを生成できます.
xiaosuo@gentux hw $ gcc -o hw hw.c xiaosuo@gentux hw $ ./hw Hello World!
gccが背後でどのような動作をしているのかを-vパラメータで見ることができます.Reading specs from /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/specs
Configured with: /var/tmp/portage/sys-devel/gcc-3.4.6-r2/work/gcc-3.4.6/configure--prefix=/usr --bindir=/usr/i686-pc-linux-gnu/gcc-bin/3.4.6--includedir=/usr/lib/gcc/i686-pc-linux-gnu/3.4.6/include--datadir=/usr/share/gcc-data/i686-pc-linux-gnu/3.4.6--mandir=/usr/share/gcc-data/i686-pc-linux-gnu/3.4.6/man--infodir=/usr/share/gcc-data/i686-pc-linux-gnu/3.4.6/info--with-gxx-include-dir=/usr/lib/gcc/i686-pc-linux-gnu/3.4.6/include/g++-v3--host=i686-pc-linux-gnu --build=i686-pc-linux-gnu --disable-altivec --enable-nls--without-included-gettext --with-system-zlib --disable-checking --disable-werror--enable-secureplt --disable-libunwind-exceptions --disable-multilib --disable-libgcj--enable-languages=c,c++,f77 --enable-shared --enable-threads=posix--enable-__cxa_atexit --enable-clocale=gnu
Thread model: posix
gcc version 3.4.(Gentoo 3.4.6-r2, ssp-3.4.6-1.0, pie-8.7.10)
 /usr/libexec/gcc/i686-pc-linux-gnu/3.4.6/cc1 -quiet -v hw.-quiet -dumpbase hw.c-mtune=pentiumpro -auxbase hw -version -o /tmp/ccYB6UwR.s
ignoring nonexistent directory "/usr/local/include"
ignoring nonexistent directory "/usr/lib/gcc/i686-pc-linux-gnu/3.4.6/http://www.cnblogs.com/http://www.cnblogs.com/i686-pc-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/include
 /usr/include
End of search list.
GNU C version 3.4.(Gentoo 3.4.6-r2, ssp-3.4.6-1.0, pie-8.7.10) (i686-pc-linux-gnu)
        compiled by GNU C version 3.4.(Gentoo 3.4.6-r2, ssp-3.4.6-1.0, pie-8.7.9).
GGC heuristics: --param ggc-min-expand=81 --param ggc-min-heapsize=97004
 /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/../../../../i686-pc-linux-gnu/bin/as --Qy -o /tmp/ccq8uGED.o /tmp/ccYB6UwR.s
GNU assembler version 2.17 (i686-pc-linux-gnu) using BFD version 2.17
 /usr/libexec/gcc/i686-pc-linux-gnu/3.4.6/collect2 --eh-frame-hdr -m elf_i386-dynamic-linker /lib/ld-linux.so.-o hw /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/../../../crt1.o /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/../../../crti.o /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/crtbegin.o-L/usr/lib/gcc/i686-pc-linux-gnu/3.4.-L/usr/lib/gcc/i686-pc-linux-gnu/3.4.6-L/usr/lib/gcc/i686-pc-linux-gnu/3.4.6/../../../../i686-pc-linux-gnu/lib-L/usr/lib/gcc/i686-pc-linux-gnu/3.4.6/../../.. /tmp/ccq8uGED.-lgcc --as-needed-lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/crtend.o /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/../../../crtn.o

少し整理して、冗長情報をいくつか削除した後、以下のようにします:

cc1 hw.-o /tmp/ccYB6UwR.s
as -o /tmp/ccq8uGED.o /tmp/ccYB6UwR.s
ld -o hw /tmp/ccq8uGED.o
の3つのコマンドは、コンパイルステップの +コンパイル、アセンブリ、 にそれぞれ します. とコンパイルは1つのコマンド(cc 1)で い、

に び することができます.cpp -o hw.i hw.c
cc1 hw.-o /tmp/ccYB6UwR.s

のhwをコンパイルできる されたものである.cファイルのMakefileは の りです..PHONY: clean

all: hw

hw: hw.o
        ld -dynamic-linker /lib/ld-linux.so.-o hw /usr/lib/crt1.o \
                /usr/lib/crti.o \
                /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/crtbegin.o \
                hw.-lc \
                /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/crtend.o \
                /usr/lib/crtn.o

hw.o: hw.s
        as -o hw.o hw.s

hw.s: hw.i
        /usr/libexec/gcc/i686-pc-linux-gnu/3.4.6/cc1 -o hw.s hw.c

hw.i: hw.c
        cpp -o hw.i hw.c

clean:
        rm -rf hw.i hw.s hw.o

もちろん、 のMakefileのいくつかのパスは のシステムの な で、あなたは とは うかもしれません. に、コンパイラの ステップが をしているかをコンパイル に てみましょう.まず、 、 のファイルhwである.i: # 1 "hw.c"
# 1 "<built-in>"
# 1 "<command line>"

...
__extension__ typedef __quad_t __off64_t;
__extension__ typedef int __pid_t;
__extension__ typedef struct { int __val[2]; } __fsid_t;

...
extern int remove (__const char *__filename) __attribute__ ((__nothrow__));

extern int rename (__const char *__old, __const char *__new) __attribute__((__nothrow__));

...

int main(int argc, char *argv[])
{
 printf("Hello World!
"
);

 return 0;
}

:ファイルが きいため、 な はほんの しか っていません.プリプロセッサは、 のCソースファイルに まれるすべてのファイル( に まれるファイルを む)の を し、 ファイルに するほか、すべてのマクロ を しているので、プリプロセッサの ファイルにはマクロが つかりません.これにより、マクロ を する な も されます. 2 「コンパイル」は、C/C++コードをアセンブリコードに「 」することです..file "hw.c"
        .section .rodata
.LC0:
        .string "Hello World!
"

        .text
.globl main
        .type main, @function
main:
        pushl %ebp
        movl %esp, %ebp
        subl $8, %esp
        andl $-16, %esp
        movl $0, %eax
        addl $15, %eax
        addl $15, %eax
        shrl $4, %eax
        sall $4, %eax
        subl %eax, %esp
        subl $12, %esp
        pushl $.LC0
        call printf
        addl $16, %esp
        movl $0, %eax
        leave
        ret
        .size main, .-main
        .section .note.GNU-stack,"",@progbits
        .ident "GCC: (GNU) 3.4.6 (Gentoo 3.4.6-r2, ssp-3.4.6-1.0, pie-8.7.10)"

このアセンブリファイルは のC/C++ファイルよりずっと さく、 していないタイプ や など、 なものがたくさん されています. 3ステップ「アセンブリ」は、 2ステップで されるアセンブリコードを のフォーマットに したマシンコードに し、Linux では にELFターゲットファイルとして される.xiaosuo@gentux hw $ file hw.o
hw.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped

のステップ「 」は、 のステップで したターゲットファイルとシステムライブラリのターゲットファイルとライブラリファイルを し、 に のプラットフォームで な ファイルを します.なぜシステムライブラリのターゲットファイル(crt 1.o,crti.oなど)に するのですか?これらのターゲットファイルは、スタックメモリ り てコンテキスト の など、Cランタイム を または するために され、 にはcrtもC RunTimeの である.これはもう つの を している:プログラムはmain から されるのではなく、crtの のあるエントリから され、Linux のこのエントリは_start. のMakefileは、 に された ファイルを します. に された ファイルを するには、Makefileの なセグメントを する があります.hw: hw.o
    ld -m elf_i386 -static -o hw /usr/lib/crt1.o \
        /usr/lib/crti.o \
        /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/crtbeginT.o \
        -L/usr/lib/gcc/i686-pc-linux-gnu/3.4.6 \
        -L/usr/i686-pc-linux-gnu/lib \
        -L/usr/lib/ \
        hw.--start-group -lgcc -lgcc_eh -lc --end-group \
        /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/crtend.o \
        /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/../../../crtn.o

これで、 ファイルが に されます. のプロジェクトではコンパイルプロセスをこのように かく ける はありません. の3つのステップは に されています.Makefileでは のように されています.hw.o: hw.c
    gcc -o hw.-c hw.c

、hw.cがどのような を ったのか、 の3つのステップはほとんど けられない.だから らを に くのも くありません. に--pipeパラメータでコンパイラに ファイルの わりにパイプを うことを えて、コンパイルの を めることができます.
 
 
:ソースhttp://www.xxlinux.com/linux/article/development/soft/20070424/8267.html