C言語の学習や開発を進める中で、コンパイル時に「collect2: error: ld returned 1 exit status」というエラーメッセージに遭遇し、戸惑った経験を持つ方は多いのではないでしょうか。
このエラーはC言語の初心者から中級者までが頻繁に直面するものであり、プログラムが正しく実行ファイルとして書き出せなかったことを示しています。
一見すると難解なシステムエラーのように思えますが、その原因の多くはソースコードの記述ミスやコンパイル設定の不備に集約されます。
本記事では、このエラーが発生する具体的なメカニズムを解説し、よくある原因とその解決策を詳しく紹介します。
collect2: error: ld returned 1 exit status とは何か
このエラーメッセージを理解するためには、まずC言語が実行ファイルになるまでの過程を知る必要があります。
C言語のプログラムは、プリプロセス、コンパイル、アセンブル、そしてリンクという4つの段階を経て完成します。
「collect2」はGCC(GNU Compiler Collection)の中でリンカを呼び出すためのユーティリティであり、「ld」は実際のリンク作業を行うリンカそのものを指します。
つまり、このメッセージは「プログラムの部品を一つにまとめるリンク工程で何らかの不具合が発生し、異常終了した」ということを伝えています。
重要なのは、このメッセージ自体には具体的なエラー内容が含まれていないという点です。
本当の原因は、このメッセージの数行上に表示されている別のエラーメッセージに隠されています。
原因1:main関数の記述ミス(タイポや欠如)
リンカエラーの中で最も一般的でありながら見落としがちなのが、プログラムの開始地点であるmain関数に関する問題です。
C言語の実行プログラムには、必ず一つのmain関数が存在しなければなりません。
main関数の綴り間違い
プログラミングを始めたばかりの頃に多いのが、mainをmianやMainのように書き間違えてしまうケースです。
以下のコード例を見てみましょう。
// 誤ったコード例:mainの綴りが間違っている
#include <stdio.h>
int mian(void) {
printf("Hello, World!\n");
return 0;
}
このコードをコンパイルしようとすると、リンカは「エントリーポイント(開始地点)が見つからない」と判断します。
その結果、出力されるメッセージは以下のようになります。
/usr/bin/ld: /lib/x86_64-linux-gnu/crt1.o: in function `_start':
(.text+0x24): undefined reference to `main'
collect2: error: ld returned 1 exit status
このように、undefined reference to `main’という記述がある場合は、関数名の綴りを再確認してください。
原因2:関数の宣言と定義の不一致(未定義の参照)
関数を呼び出しているにもかかわらず、その関数の実体(定義)がどこにも見当たらない場合に発生します。
これは、大規模な開発で複数のファイルを分割してコンパイルしている際や、外部ライブラリを使用している際によく発生します。
関数の実装忘れ
ヘッダーファイルで関数を宣言したものの、ソースファイル(.c)側で中身を書くのを忘れている場合にこのエラーが出ます。
#include <stdio.h>
void calculate(int a); // 宣言のみ
int main(void) {
calculate(10); // 呼び出し
return 0;
}
// ここに void calculate(int a) { ... } の定義がない
コンパイラは宣言を見て「後で関数が見つかるだろう」と判断しますが、最後のリンク工程で実体が見つからずエラーとなります。
リンクするファイルの指定漏れ
複数のソースファイルに分けて開発している場合、コンパイルコマンドにすべてのファイルを含める必要があります。
例えば、main.cとsub.cがある場合、以下のようにコマンドを打たなければなりません。
gcc main.c sub.c -o myprogram
もしgcc main.c -o myprogramとだけ入力してしまうと、sub.c内で定義した関数が読み込まれず、リンクエラーが発生します。
原因3:数学ライブラリなどのリンク指定忘れ
C言語の標準的な関数の中には、標準ライブラリ(libc)以外のライブラリを明示的に指定しなければならないものがあります。
代表的な例が、math.hに含まれる数学関数(sin, cos, pow, sqrtなど)です。
数学関数の使用例
以下のプログラムは、一見すると正しいように見えます。
#include <stdio.h>
#include <math.h>
int main(void) {
double result = sqrt(16.0);
printf("Result: %f\n", result);
return 0;
}
しかし、Linux環境などで標準的な設定のままコンパイルすると、以下のようなエラーが発生することがあります。
undefined reference to `sqrt'
collect2: error: ld returned 1 exit status
これは数学ライブラリがデフォルトでリンクされないために起こります。
解決するには、コンパイルコマンドの末尾に-lmというオプションを追加して、数学ライブラリを明示的にリンクします。
gcc main.c -o main -lm
原因4:関数の重複定義
「未定義」の逆で、同じ名前の関数やグローバル変数が複数の場所で定義されている場合もエラーになります。
これは、ヘッダーファイルに関数の実体を記述してしまい、それを複数のソースファイルでインクルードしたときによく起こります。
重複定義のエラー例
エラーメッセージにはmultiple definition of `…`という一文が含まれます。
| エラーメッセージ | 主な理由 | 対策 |
|---|---|---|
| multiple definition of `func` | 同じ名前の関数が2回以上定義されている | 不要な定義を削除するか static を検討する |
| first defined here | 最初にその名前が定義された場所を示す | 重複している箇所の特定に利用する |
ヘッダーファイルには関数の宣言のみを記述し、実体は一つのソースファイルにのみ記述するように徹底しましょう。
原因5:実行ファイルが使用中(Windows環境特有)
Windows環境で開発している場合、以前に実行したプログラムがまだ動作中(あるいはフリーズした状態)であることが原因でエラーになることがあります。
OSが実行中のファイルをロックしているため、リンカが新しい実行ファイルを上書き保存できないのです。
この場合、エラーメッセージにはpermission denied(アクセス拒否)といった言葉が含まれることが多いです。
タスクマネージャーを開き、実行中のプロセスを終了させるか、コマンドプロンプトを閉じてから再度コンパイルを試みてください。
トラブルシューティングの流れ
「collect2: error: ld returned 1 exit status」が出たときは、焦らず以下の手順で確認を行いましょう。
- ターミナルの画面を上にスクロールし、「undefined reference to…」や「multiple definition of…」という行を探す。
- エラーが指摘している関数名や変数名の綴りに間違いがないか確認する。
- 関数の定義(中身)を記述したソースファイルがコンパイル対象に含まれているか確認する。
- 外部ライブラリ(数学関数など)を使っている場合、コンパイルオプション(
-lmなど)が抜けていないか確認する。 - プログラムが二重起動していないか、パーミッションに問題がないか確認する。
まとめ
「collect2: error: ld returned 1 exit status」は、詳細なエラー情報を隠している「外袋」のようなメッセージです。
真の原因は常にその数行前に表示されている個別のメッセージにあります。
特にmain関数のミス、リンク時のファイル指定漏れ、そして数学ライブラリのリンクオプション不足は非常に遭遇率の高い原因です。
このエラーが表示されたときは、まず「どこの何が未定義だと言われているのか」を冷静に読み取ることが、解決への最短ルートとなります。
今回の内容を参考に、一つひとつの原因を丁寧に取り除き、スムーズなC言語開発を進めてください。
