静的ライブラリと動的ライブラリ
静的ライブラリとか動的ライブラリがよく理解できていなかったのでオライリーのC++クックブックで勉強した。その際のメモ。
論理
リンカ
- 入力 : オブジェクトファイルとライブラリのコレクション。
- それらのシンボリック参照を解決 : 実行可能ファイルまたは動的ライブラリ。「シンボリック参照を解決」とは使用されているシンボルをその定義と照合すること。
リンク、、、
- する側 : 実行可能ファイルまたは動的ライブラリ
- される側 : 実行可能ファイルや動的ライブラリをビルドするために使用されるライブラリ
実践
ディレクトリ構成
作業ディレクトリを以降では便宜的に$WORKとしています。
$ ls -R $WORK $WORK/johnpaul: john.cpp john.hpp johnpaul.cpp johnpaul.hpp paul.cpp paul.hpp $WORK/georgeringo: george.cpp george.hpp georgeringo.cpp georgeringo.hpp ringo.cpp ringo.hpp $WORK/hellobeatles: hellobeatles.cpp
ファイルの内容
$WORK/johnpaul/john.hpp
#ifndef JOHN_HPP_INCLUDED #define JOHN_HPP_INCLUDED void john(); // Prints "John, " #endif // JOHN_HPP_INCLUDED
$WORK/johnpaul/john.cpp
#include <iostream> #include "john.hpp" void john() { std::cout << "John, "; }
$WORK/johnpaul/paul.hpp
#ifndef PAUL_HPP_INCLUDED #define PAUL_HPP_INCLUDED void paul(); // Prints "Paul, " #endif // PAUL_HPP_INCLUDED
$WORK/johnpaul/paul.cpp
#include <iostream> #include "paul.hpp" void paul() { std::cout << "Paul, "; }
$WORK/johnpaul/johnpaul.hpp
#ifndef JOHNPAUL_HPP_INCLUDED #define JOHNPAUL_HPP_INCLUDED void johnpaul(); // Prints "John, Paul, " #endif // JOHNPAUL_HPP_INCLUDED
$WORK/johnpaul/johnpaul.cpp
#include "john.hpp" #include "paul.hpp" #include "johnpaul.hpp" void johnpaul() { john(); paul(); }
$WORK/georgeringo/george.hpp
#ifndef GEORGE_HPP_INCLUDED #define GEORGE_HPP_INCLUDED void george(); // Prints "George, " #endif // GEORGE_HPP_INCLUDED
$WORK/georgeringo/george.cpp
#include <iostream> #include "george.hpp" void george() { std::cout << "George, "; }
$WORK/georgeringo/ringo.hpp
#ifndef RINGO_HPP_INCLUDED #define RINGO_HPP_INCLUDED void ringo(); // Prints "and Ringo" #endif // RINGO_HPP_INCLUDED
$WORK/georgeringo/ringo.cpp
#include <iostream> #include "ringo.hpp" void ringo() { std::cout << "and Ringo\n"; }
$WORK/georgeringo/georgeringo.hpp
#ifndef GEORGERINGO_HPP_INCLUDED #define GEORGERINGO_HPP_INCLUDED // libgeorgeringo.dllをビルドするときにGEORGERINGO_DLLを定義する # if defined(_WIN32) && !defined(__GNUC__) # ifdef GEORGERINGO_DLL # define GEORGERINGO_DECL __declspec(dllexport) # else # define GEORGERINGO_DECL __declspec(dllimport) # endif # endif // WIN32 # ifndef GEORGERINGO_DECL # define GEORGERINGO_DECL # endif // Prints "George, and Ringo\n" #ifdef __MWERKS__ #pragma export on #endif GEORGERINGO_DECL void georgeringo(); #ifdef __MWERKS__ #pragma export off #endif #endif // GEORGERINGO_HPP_INCLUDED
$WORK/georgeringo/georgeringo.cpp
#include "george.hpp" #include "ringo.hpp" #include "georgeringo.hpp" void georgeringo() { george(); ringo(); }
$WORK/hellobeatles/hellobeatles.cpp
#include "johnpaul/johnpaul.hpp" #include "georgeringo/georgeringo.hpp" int main() { // Prints "John, Paul, George and Ringo\n" johnpaul(); georgeringo(); }
Macでやってみる
g++ の属性確認。Command Line Tools for Xcode に同梱されているやつです。
$ g++ -v Using built-in specs. Target: i686-apple-darwin11 Configured with: /private/var/tmp/llvmgcc42/llvmgcc42-2336.9~22/src/configure --disable-checking --enable-werror --prefix=/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2 --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-prefix=llvm- --program-transform-name=/^[cg][^.-]*$/s/$/-4.2/ --with-slibdir=/usr/lib --build=i686-apple-darwin11 --enable-llvm=/private/var/tmp/llvmgcc42/llvmgcc42-2336.9~22/dst-llvmCore/Developer/usr/local --program-prefix=i686-apple-darwin11- --host=x86_64-apple-darwin11 --target=i686-apple-darwin11 --with-gxx-include-dir=/usr/include/c++/4.2.1 Thread model: posix gcc version 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.9.00)
"johnpaul"静的ライブラリの生成
$ cd $WORK/johnpaul # オブジェクトファイルを生成。 $ g++ -c -o john.o john.cpp $ g++ -c -o paul.o paul.cpp $ g++ -c -o johnpaul.o johnpaul.cpp # アーカイブ。 $ ar ru libjohnpaul.a john.o paul.o johnpaul.o ar: creating archive libjohnpaul.a $ ranlib libjohnpaul.a
"georgeringo"動的ライブラリの生成
$ cd $WORK/georgeringo # オブジェクトファイルを生成。 $ g++ -c -o george.o george.cpp $ g++ -c -o ringo.o ringo.cpp $ g++ -c -o georgeringo.o georgeringo.cpp # 動的ライブラリ生成。 $ g++ -dynamiclib -fPIC -o libgeorgeringo.dylib george.o ringo.o georgeringo.o
"hellobeatles"実行可能ファイルの作成。
$ cd $WORK/hellobeatles # アプリケーションのcppファイルをオブジェクトファイルにコンパイル。 $ g++ -c -o hellobeatles.o hellobeatles.cpp -I ../ # リンカを使用してオブジェクトファイルとライブラリから実行可能ファイルを生成する。 $ g++ -o hellobeatles1 hellobeatles.o -L ../johnpaul -L ../georgeringo -ljohnpaul -lgeorgeringo # 実行してみるもエラー。 $ ./hellobeatles1 dyld: Library not loaded: libgeorgeringo.dylib Referenced from: $WORK/hellobeatles/./hellobeatles1 Reason: image not found Trace/BPT trap: 5 # 別の方法でリンカを使用してオブジェクトファイルとライブラリから実行可能ファイルを生成する。 $ g++ -o hellobeatles2 hellobeatles.o ../johnpaul/libjohnpaul.a ../georgeringo/libgeorgeringo.dylib # 実行してみるもやっぱりエラー。 $ ./hellobeatles2 dyld: Library not loaded: libgeorgeringo.dylib Referenced from: $WORK/hellobeatles/./hellobeatles2 Reason: image not found Trace/BPT trap: 5 # DYLD_LIBRARY_PATH を指定してやるとOK。 $ env DYLD_LIBRARY_PATH=$WORK/georgeringo ./hellobeatles1 John, Paul, George, and Ringo $ env DYLD_LIBRARY_PATH=$WORK/georgeringo ./hellobeatles2 John, Paul, George, and Ringo # リンクを確認。相対パスになってる。 $ otool -L hellobeatles1 hellobeatles1: libgeorgeringo.dylib (compatibility version 0.0.0, current version 0.0.0) /usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 52.0.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0) $ otool -L hellobeatles2 hellobeatles2: libgeorgeringo.dylib (compatibility version 0.0.0, current version 0.0.0) /usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 52.0.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0) # 実行可能ファイルをパスの通りそうなところにコピーしてみる。 $ cp -iv hellobeatles1 ../georgeringo/ hellobeatles1 -> ../georgeringo/hellobeatles1 $ cp -iv hellobeatles2 ../georgeringo/ hellobeatles2 -> ../georgeringo/hellobeatles2 $ cd $WORK/georgeringo/ # コピーしたものを実行するとOK。 $ ./hellobeatles1 John, Paul, George, and Ringo $ ./hellobeatles2 John, Paul, George, and Ringo
Ubuntuでやってみる
g++ の属性確認
$ g++ -v 組み込み spec を使用しています。 COLLECT_GCC=g++ COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-linux-gnu/4.6/lto-wrapper ターゲット: i686-linux-gnu configure 設定: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.6.3-1ubuntu5' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --enable-targets=all --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=i686-linux-gnu --host=i686-linux-gnu --target=i686-linux-gnu スレッドモデル: posix gcc バージョン 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
"johnpaul"静的ライブラリの生成
$ cd $WORK/johnpaul $ g++ -c -o john.o john.cpp $ g++ -c -o paul.o paul.cpp $ g++ -c -o johnpaul.o johnpaul.cpp $ ar ru libjohnpaul.a john.o paul.o johnpaul.o ar: creating libjohnpaul.a $ ranlib libjohnpaul.a
"georgeringo"動的ライブラリの生成
$ cd $WORK/georgeringo $ g++ -c -o george.o george.cpp $ g++ -c -o ringo.o ringo.cpp $ g++ -c -o georgeringo.o georgeringo.cpp $ g++ -shared -fPIC -o libgeorgeringo.so george.o ringo.o georgeringo.o
"hellobeatles"実行可能ファイルの作成
$ cd $WORK/hellobeatles # アプリケーションのcppファイルをオブジェクトファイルにコンパイル。 $ g++ -c -o hellobeatles.o hellobeatles.cpp -I ../ # リンカを使用してオブジェクトファイルとライブラリから実行可能ファイルを生成する。 $ g++ -o hellobeatles1 hellobeatles.o -L ../johnpaul -L ../georgeringo -ljohnpaul -lgeorgeringo # 実行してみるもエラー $ ./hellobeatles1 ./hellobeatles1: error while loading shared libraries: libgeorgeringo.so: cannot open shared object file: No such file or directory # リンクを確認。見つからないと言われる。 $ ldd hellobeatles1 linux-gate.so.1 => (0xb777b000) libgeorgeringo.so => not found libstdc++.so.6 => /usr/lib/i386-linux-gnu/libstdc++.so.6 (0xb7689000) libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb74e3000) libm.so.6 => /lib/i386-linux-gnu/libm.so.6 (0xb74b7000) /lib/ld-linux.so.2 (0xb777c000) libgcc_s.so.1 => /lib/i386-linux-gnu/libgcc_s.so.1 (0xb7499000) # リンカを使用してオブジェクトファイルとライブラリから実行可能ファイルを生成する。 $ g++ -o hellobeatles2 hellobeatles.o ../johnpaul/libjohnpaul.a ../georgeringo/libgeorgeringo.so # 実行してみるとOK。 $ ./hellobeatles2 John, Paul, George, and Ringo # リンクを確認。ちゃんと認識されている。 $ ldd hellobeatles2 linux-gate.so.1 => (0xb77a9000) ../georgeringo/libgeorgeringo.so (0xb77a4000) libstdc++.so.6 => /usr/lib/i386-linux-gnu/libstdc++.so.6 (0xb76b4000) libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb750e000) libm.so.6 => /lib/i386-linux-gnu/libm.so.6 (0xb74e2000) /lib/ld-linux.so.2 (0xb77aa000) libgcc_s.so.1 => /lib/i386-linux-gnu/libgcc_s.so.1 (0xb74c4000)