GCCのオプション

はじめに

用語の定義

最初にこの記事で扱う言葉を定義しておく。

登場するファイル

/* hello.c */
#include<stdio.h>

int main(){
	printf("Hello World!\n");
	return 0;
}

全体的なオプション

-c

ソースファイルをアセンブルまでする(リンクはしない)。
(例)

$ ls
hello.c
$ gcc -c hello.c 
$ ls
hello.c  hello.o

-o ファイル名

出力先を「ファイル名」に指定する。
(例)

$ ls
hello.c
$ gcc -c -o hello_world.o hello.c 
$ ls
hello.c  hello_world.o


言語オプション

-fno-builtin

ビルトイン関数を利用しない。ビルドイン関数というのは、コンパイラに予め組み込まれている関数(printfとか)。
(例)
自分でprintfという名前の関数を定義してみる(#include も消去)。

/* hello.c */
void printf(){
	int i=3;
}

int main(){
	printf();
	return 0;
}

これでコンパイルすると

$ gcc -c hello.c 
hello.c:2:6: warning: conflicting types for built-in function ‘printf’
 void printf(){
      ^

「(コンパイラ側でも予め定義されてて、)printf関数が複数存在している」という警告が出てしまう。自分のprintfが使いたいので-fno-builtinオプションをつけてコンパイルすると、

$ gcc -c -fno-builtin hello.c 
$ 

警告なしでコンパイルできることから、ビルトイン関数を利用していないことが確認できた。


プリプロセッサのオプション

-E

プリプロセスのみを行い、標準出力または指定された出力ファイルに 対して出力する。
(例)

$ ls
hello.c
$ gcc -E -o hello.i hello.c 
$ ls
hello.c  hello.i

hello.iの中身を見てみると、

# 1 "hello.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "hello.c"
# 1 "/usr/include/stdio.h" 1 3 4
(省略)
extern int ftrylockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
# 942 "/usr/include/stdio.h" 3 4
# 3 "hello.c" 2

# 4 "hello.c"
int main(){
 printf("Hello World!\n");
 return 0;
}

マクロ(#include )が展開されていることが確認できる。

-nostdinc

ヘッダファイルのための標準のシステムディレクトリを検索しない。
(例)

$ ls
hello.c
$ gcc -E -nostdinc -o hello.i hello.c 
hello.c:2:18: error: no include path in which to search for stdio.h 

-nostdincオプションがなかったときは、stdio.hを求めて自動的に/usr/include/を検索してくれていた。しかし、今回は「明示的にstdio.hのパスを示せ」というエラーが出ており、ヘッダファイルの自動検索をしていないことが確認できた。

-Dマクロ

指定したマクロに対して整数1を定義として与える。
(例)
以下のように、hello.cを少し改造する

/* hello.c */
#include <stdio.h>

int main(){
	printf("%d\n",EXAMPLE);
	return 0;
}

これでコンパイルすると、「EXAMPLEが定義されていない」とエラーが出る。そこでDオプションでEXAMPLEに対し整数1を定義として与える。

$ gcc -DEXAMPLE -o hello hello.c 
$ ./hello 
1

整数1が出力された。つまりプリプロセッサにより、"#define EXAMPLE 1"という命令がソースファイルに加えられたことが確認できた。


リンカのオプション

-Lディレクトリ名

(標準システムディレクトリに加えて、)ライブラリを検索するディレクトリを追加する。

-nostdlib

リンク時に、標準のシステムライブラリとスタートアップファイルを使用しない。指定したファイルのみがリンカに渡される。

-static

(動的リンクではなく、)静的リンクを行う。

-T

リンカスクリプトを指定する。


ディレクトリオプション

-Wall

警告をすべて表示する。
(例)
以下のようにhello.cに1行追加する。

/* hello.c */
#include<stdio.h>

int main(){
	printf("Hello World!\n");
	int i=10;
	return 0;
}

これを-Wallオプションなしでコンパイルすると、

$ gcc -c hello.c 
$ 

警告が出ることはない。しかし-Wallオプションありでコンパイルすると

$ gcc -c -Wall hello.c
hello.c: In function ‘main’:
hello.c:6:6: warning: unused variable ‘i’ [-Wunused-variable]
  int i=10;
      ^

上記の警告が出る。

-Iディレクトリ名

ヘッダファイルを検索するディレクトリを示す。
(例)
先ほどの-nostdincオプションの例を再掲すると

$ ls
hello.c
$ gcc -E -nostdinc -o hello.i hello.c 
hello.c:2:18: error: no include path in which to search for stdio.h 

という、エラーが出ていた。そこでstdio.hを作成し、その-Iオプションでパスを示してみる(Iの後のドットはカレントディレクトリを表す)。

$ ls
hello.c
$ touch stdio.h
$ gcc -E -nostdinc -I. -o hello.i hello.c
$ ls
hello.c  hello.i  stdio.h

エラーなしで、hello.iが生成できた。中身を見てみると、

# 1 "hello.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "hello.c"
# 1 "./stdio.h" 1
# 3 "hello.c" 2

int main(){
 printf("Hello World!\n");
 return 0;
}

自身で用意したstdio.hが展開されていることが確認できた(もちろん、実際にprintfで文字列を出力することはできない)。


最適化オプション

-Os

サイズ優先で最適化?(詳しいことはわからない)


h8300-elf-gccのオプション

-mh

300H CPUのコードを生成する