LoginSignup
2
2

More than 5 years have passed since last update.

未解決の外部シンボル(参照)を定義していない静的ライブラリのオブジェクトファイルはリンクされない

Posted at

概要

C++で書かれた、ある静的ライブラリの関数において、他のライブラリ等のどこにも定義されていない関数を呼び出していました。その静的ライブラリをリンクしている実行ファイル作成のためのビルドにおいて、リンクエラーが発生することなく成功していました。

リンクされている静的ライブラリ内で定義されていない関数を呼び出している場合、未解決の外部シンボルが残ったままとなり、リンクエラーになるのでは?と自分は思っていたのですが、間違いでした。

結論を言うと、未解決の参照を定義していない静的ライブラリのオブジェクトファイルはリンクされないということでした。

ソースコードを伴わない説明だと、分かり難いと思うので、以下に検証用の複数のケースのソースコードとその解説を載せます。検証にはClangを用いていますが、他のGCCやVC++等のコンパイラでも挙動としては変わりないと思われます。

検証

ケース1

下記の2つのC++のソースコードがあります。

main.cpp
#include <iostream>

int main()
{
    std::cout << "main()" << std::endl;

    return 0;
}
hoge.cpp
void f();

void g()
{
    f();
}

hoge.cppのf()の定義は存在していません。

未解決の外部シンボルのリンクエラーの例として、普通にビルドしてみます。g()から呼び出しているf()のシンボルが定義されておらず見つからないという、未解決の外部シンボルのリンクエラーになります。

$ clang++ -c main.cpp
$ clang++ -c hoge.cpp
$ clang++ main.o hoge.o
Undefined symbols for architecture x86_64:
  "f()", referenced from:
      g() in hoge.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

ケース2

ケース1のmain.cppとhoge.cppを再び用います。hoge.cppから作成されるhoge.oをlibhoge.aという静的ライブラリに含めるようにし、下記のようにビルドしてみると、リンクエラーが発生することなく成功します。未解決の参照を定義していないhoge.oがリンクされないからです。

$ clang++ -c main.cpp
$ clang++ -c hoge.cpp
$ ar rcs libhoge.a hoge.o
$ clang++ main.o -L. -lhoge

実行結果は下記です。

$ ./a.out
main()

ケース3

main.cppとhoge.cppのソースコードを少し修正し、main.cppのmain()から呼び出す関数h()をhoge.cppに定義します。

main.cpp
#include <iostream>

void h();

int main()
{
    std::cout << "main()" << std::endl;

    h();

    return 0;
}
hoge.cpp
#include <iostream>

void f();

void g()
{
    f();
}

void h()
{
    std::cout << "h()" << std::endl;
}

ケース2と同じようにビルドすると、未解決の外部シンボルのリンクエラーが発生します。h()という未解決の参照をhoge.oが定義しており、hoge.oがリンクされたからです。

$ clang++ -c main.cpp
$ clang++ -c hoge.cpp
$ ar rcs libhoge.a hoge.o
$ clang++ main.o -L. -lhoge
Undefined symbols for architecture x86_64:
  "f()", referenced from:
      g() in libhoge.a(hoge.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

ケース4

ケース3おいてhoge.cpp内に定義した関数h()を新しく作成するhoge2.cppに移し、libhoge.aにhoge.cppとhoge2.cppのそれぞれから作成されるhoge.oとhoge2.oを含めます。

main.cpp
#include <iostream>

void h();

int main()
{
    std::cout << "main()" << std::endl;

    h();

    return 0;
}
hoge.cpp
void f();

void g()
{
    f();
}
hoge2.cpp
#include <iostream>

void h()
{
    std::cout << "h()" << std::endl;
}

下記の手順で無事ビルドに成功しました。

$ clang++ -c main.cpp
$ clang++ -c hoge.cpp
$ clang++ -c hoge2.cpp
$ ar rcs libhoge.a hoge.o hoge2.o
$ clang++ main.o -L. -lhoge

hoge2.oは未解決の参照が定義されているためリンクされますが、hoge.oはそうではないためリンクされないからです。同じ静的ライブラリの中に含まれていても、オブジェクトファイルによってリンクされるかされないかが変わってくるということですね。

実行結果は下記です。

$ ./a.out
main()
h()

参考文献

静的ライブラリ (.a) の作成と利用

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2