前回は完膚なきまでに事実を誤認していた。llvm-arはbitcodeとnative codeを同時に含む。llvm-arのマニュアルに曰く、
- t[v]
- Print the table of contents. Without any modifiers, this operation just prints the names of the members to the standard output. With the v modifier, llvm-ar also prints out the file type (B=bitcode, Z=compressed, S=symbol table, blank=regular file), the permission mode, the owner and group, the size, and the date. If any files are specified, the listing is only for those files. If no files are specified, the table of contents for the whole archive is printed.
t命令にvモディファイヤを付けると、たとえばこんな出力が得られる。
rw-r--r-- 501/ 20 636 Oct 14 10:46:35 2008 bar0.o
rw-r--r-- 501/ 20 544 Oct 14 10:46:35 2008 bar1.o
brw-r--r-- 501/ 20 544 Oct 14 10:46:35 2008 foo0.o
brw-r--r-- 501/ 20 540 Oct 14 10:46:35 2008 foo1.o
foo0.oとfoo1.oがbitcodeのオブジェクトファイルで、bar0.oとbar1.oがnative codeのオブジェクトファイルだ。x命令を使うと、アーカイブファイルからオブジェクトファイルを抽出できる。
- x[oP]
- Extract archive members back to files. The o modifier applies to this operation. This operation retrieves the indicated files from the archive and writes them back to the operating system's file system. If no files are specified, the entire archive is extract.
だけど、llvm-ldは、bitcodeとnative codeの両方を含むアーカイブファイルを良きにはからってくれない(tools/llvm-ld/llvm-ld.cppを読むとItems
とNativeLinkItems
に二分しちゃってる)。だったら、x命令を使用してオブジェクトファイルを抽出して、bitcodeだけからなるアーカイブファイルとnative codeだけからなるアーカイブファイルを作成しよう。下記はコンセプトを実証するためのもので、オブジェクトファイルがディレクトリ階層を持っている場合に破綻する(かもしれない)。
#! /bin/sh
set -e
file="$1"
shift
b_objs=`llvm-ar tv "$file" | awk '/^b/ { printf " %s", $9}'`
n_objs=`llvm-ar tv "$file" | awk '/^ / { printf " %s", $9}'`
d=`dirname "$file"`
s=`printf '%s' "$file" | sed -e 's/.*\(\..*\)$/\1/'`
n=`basename "$file" "$s"`
cd "$d"
mkdir "-p" "$n-o"
cd "$n-o"
llvm-ar "xo" "../$n$s"
llvm-ar "rc" "$n-b$s" $b_objs
ar "rc" "$n-n$s" $n_objs
mv "$n-b$s" "$n-n$s" ".."
cd ..
rm "-fr" "$n-o"
話はほとんど、これでおしまい。ただし、native codeがbitcodeのシンボルを参照する場合(多くの場合参照する、そもそも、参照しなかったらそのコードに意味がない)、できあがったアーカイブファイルをリンクする際に-disble-internalize
の付与を検討するべきだ。すべてのbitcodeが先にリンクされ(願わくば最適化され)、その後native codeがリンクされる。最適化はnative codeが参照しているシンボルをどっかにやっちゃうかもしれない(native codeからしか参照されていなかったら、たぶんどっかにやっちゃう)。