Linux 上で Windows のモジュールをコンパイルする方法は Google 先生に聞くと結構出てくるけど、その逆がなかなか出てこない。
ということで Windows 上で Linux のモジュールをコンパイルする方法をメモ。
クロスコンパイラを使う方法 †
他のプラットフォームのモジュールを作成できるコンパイラを使う方法。もうそのまんま。
Windows 上に UNIX 環境を構築 †
Cygwin か MinGW/msys ということになると思う。導入に関する詳細は下記ページで。
ここでは Cygwin を使ってみる。
クロスコンパイラの作成 †
理屈としては、ターゲットとなる Linux の C++ 環境をターゲットとして、Cygwin で gcc をコンパイルすれば良いということになる。
と思ったけど、上手くいかないので、とりあえず以下のサイトからコンパイル済みのクロスコンパイラをいただいて使用することにする。
上記サイトの クロスコンパイラ をいただく。
クロスコンパイラを自前でつくる場合 †
実は、私もやろうとしたけど、挫折した。
一応、こうすればできるらしいということを、今後の為にメモしておく。
- まず、ターゲットとなる Linux 上で、作業用のディレクトリをつくる。
- C/C++ コンパイルに必要なライブラリ(依存関係も全て)をコピーする。
- linux-runtime を samba か scp か何かで Windows へ送る。
- サイズが結構あるので、tar.gz とか lzma あたりで固めて移動すると良いかも。
- ここから Windows 側の作業。Cygwin はインストール済みという前提で。
- Cygwin は C:\Cygwin にインストールされているとする。
- GNU の binutils と gcc のソースをゲットする。
- 上記を Cygwin で適当なところに展開。
- インストール先ディレクトリを作成。
- ここは /usr/local/linux とする。
$ mkdir /usr/local/linux
- Linux でつくった linux-runtime 配下のファイルを /usr/local/linux に配置。
$ mv -R (どこか)/linux-runtime /usr/local/linux
$ ls /usr/local/linux
lib include
- /usr/local/linux/lib にある libc.so のパスを修正。
/* GNU ld script
Use the shared library, but some functions are only in
the static library, so try that secondarily. */
GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a )
↓
/* GNU ld script
Use the shared library, but some functions are only in
the static library, so try that secondarily. */
GROUP ( /usr/local/linux/lib/libc.so.6 /usr/local/linux/lib/libc_nonshared.a )
- binutils をコンパイル、インストール。
$ cd /home/user/work/binutils-2.19
$ mkdir build
$ cd build
$ ../configure --prefix=/usr/local/linux \
--target=i686-linux \
--host=i686-pc-cygwin \
--build=i686-pc-cygwin
(略)
$ make
$ make install
- ここまでで /usr/local/linux/bin が作成されているはずなので、パスを通しておく。
$ PATH=/usr/local/linux/bin:$PATH
- gcc をコンパイル、インストール。
$ cd /home/user/work/binutils-2.19
$ mkdir build
$ cd build
$ ../configure --prefix=/usr/local/linux \
--target=i686-linux \
--host=i686-pc-cygwin \
--build=i686-pc-cygwin \
--enable-languages=c,c++ \
--enable-shared \
--enable-threads \
--includedir=/usr/local/linux/include
(略)
$ make
$ make install
※ オプション不要なものや足りないものがあるかもしれない。
※ make で [configure-target-libiberty] 的なエラーが出るかも。とりあえず無視する。
- ここまでで、以下のフォルダが作成されているはず。
/usr/local/linux/bin
/usr/local/linux/include
/usr/local/linux/lib
/usr/local/linux/man
/usr/local/linux/share
- bin の中に以下が出来上がっていればとりあえずコンパイラ完成。
i686-linux-as
i686-linux-gcc
i686-linux-g++
- 試しに簡単なソースをコンパイルしてみる。
$ i686-linux-gcc hello.c -o hello
これで hello が出力される。が、Windows 上では実行できない。
Linux に hello を持っていって実行できれば、成功!
となるはずが、私は上手くいかない。何か手順が足りないんだと思うけど。。
Cygwin で動作確認 †
Cygwin 環境で、以下の構成になっているとする。
- C:/Cygwin
- /bin/make
- /usr/local/linux/bin/i686-linux-as
- /usr/local/linux/bin/i686-linux-gcc
- /usr/local/linux/bin/i686-linux-g++
試しに Cygwin のみでコンパイルしてみる。
- 作業用ディレクトリを作成して移動。
- ソースを書いて、hello.c という名前で保存。
#include <stdio.h>
int main(int argc, char* argv[]) {
printf("Hello World!\n");
return 0;
}
- クロスコンパイラでコンパイルしてみる。
$ i686-linux-gcc hello.c -o hello
※ gcc で起動すると Cygwin の gcc が動くので、i686-linux-gcc を指定すること。
- これで hello というファイルができて実行できれば OK。
$ ls
hello hello.c
$ ./hello
Hello World!
Eclipse を使う †
Eclipse は CDT を使うよ。
特にインストーラなどはなくて、適当なディレクトリに展開するだけ。
次に、日本語化する。英語のままでも良いならここは不要。
※ ただ、下の説明は日本語化したのを前提に書いてマス。
これも特にインストーラはなくて、展開したフォルダやファイルたちを Eclipse を展開した場所に上書きするだけ。
早速 Eclipse を使ってみる。
- Eclipse 起動。
- 「ファイル」→「新規」→「C プロジェクト」で、プロジェクト名「hello」、実行ファイル形式を選んで「完了」。
- 「Hello World C Project」があればそっちで。
最初からお決まりのサンプルがつく。
- Hello World がなかった場合はソースを作成。
- 左ペインのプロジェクトを右クリックして「プロパティ」を開く。
- 「C/C++ ビルド」下にある「ツール・チェーン・エディタ」を選択。
- 構成はどちらでも良いけど、ここは「Release」をアクティブにする。
- 現在のツールチェーン : Cygwin GCC
- 現在のビルダー : GNU Make ビルダー
- 「C/C++ ビルド」下にある「環境」を選択。
- 「設定する環境変数」に以下を追加。
- 名前 : PATH
- 値 : C:\Cygwin\bin;C:\Cygwin\usr\local\linux\bin
- 「C/C++ ビルド」下にある「設定」を選択。
- 「ツール設定」に以下を設定。
- GCC Assembler コマンド : i686-linux-as
- Cygwin C++ Compiler コマンド : i686-linux-g++
- Cygwin C Compiler コマンド : i686-linux-gcc
- Cygwin C++ Linker コマンド : i686-linux-g++
- 「成果物」に以下を設定。
- 成果物タイプ : 実行可能
- 成果物の名前 : hello
- あとは空白。
- 「バイナリパーサー」に以下を設定。
- 「Cygwin PE パーサー」と「Elf パーサー」にチェック。
- あとは チェックをはずす。
- 「OK」でプロパティを閉じる。
- 「プロジェクト」→「すべてビルド(Ctrl + B)」でビルドしてみる。
- 画面下コンソールに特にエラーがなければ、Release フォルダに hello というファイルができる。
- その hello を Linux に持っていって実行してみる。
$ ./hello
- 「Hello World!」と表示されれば、Windows 上で Linux のモジュールができたことになる!
リモートでやる方法(rsh) †
といっても、telnet や rlogin でコマンド叩くのは、直接 Linux 上で作業するのと変わらないので、ここは Eclipse を使ってリモートでコンパイルする方法を書く。
rsh の設定 †
ここでは rsh を使うので、ホストとなる Linux 側で以下の設定をする。rsh は大抵デフォルトで入ってるけど、最近はセキュリティ性を考慮して無効になっていることが多い。
- rsh サーバが入っているか確認。
$ rpm -qa rsh-server
rsh-server-0.17-58.fc12.i686
※ ↑私の環境の場合の例。とにかく入っていれば何かヒットする。
- rsh サーバはなかった場合はインストール。(あれば、次の手順へ)
$ su
# yum install rsh-server
- rsh がインストールされると、以下のファイルが作成されるので確認。
/etc/xinetd.d/rexec
/etc/xinetd.d/rsh
- /etc/xinetd.d/rexec を開いて disable = no に変更する。
service exec
{
disable = no # ← ここ。他はいじらない。
socket_type = stream
wait = no
user = root
log_on_success += USERID
log_on_failure += USERID
server = /usr/sbin/in.rexecd
}
- /etc/xinetd.d/rsh を開いて disable = no に変更する。
service shell
{
disable = no # ← ここ。他はいじらない。
socket_type = stream
wait = no
user = root
log_on_success += USERID
log_on_failure += USERID
server = /usr/sbin/in.rshd
}
- ファイアウォールの設定で 514 を許可する。
- GNOME で「システム」→「管理」→「ファイアウォール」で「その他のポート」に追加しても良いし、/etc/sysconfig/iptables に追加するでも良い。
- もしかしたら、512 番とか 513 番かもしれない。でも shell は多分 514 のはず。
- xinetd を再起動する。
$ su
# /etc/rc.d/init.d/xinetd restart
xinetd を停止中: [ OK ]
xinetd を起動中: [ OK ]
- ログインするユーザのホームディレクトリへ移動。
$ cd ~
$ pwd
/home/(ユーザ名)
- .rhosts というファイルをつくって、ログインを許可するクライアントとユーザ名を書く。
- できたファイルのパーミッションを確認する。
$ ls -l -a | grep .rhosts
-rw-rw-r--. 1 hogehoge group1 28 2010-05-20 16:02 .rhosts
多分、グループに書き込み許可がついてる。不思議なことに、所有者以外に書き込み許可があると、rsh でパーミッションエラーが出る。ので、自分だけ書き込み許可をする。
$ chmod 644 .rhosts
$ ls -l -a | grep .rhosts
-rw-r--r--. 1 hogehoge group1 28 2010-05-20 16:02 .rhosts
-rw-r--r-- になっていれば OK。
ここまでで、rsh の設定は終わり。
Windows 側に戻って Cygwin の rsh で繋いでみる。
ちなみに、最近の Cygwin は rsh がデフォルトで入ってこないので、入れてない場合はまずインストールしておく。Setup.exe からいつもの感じで入れればいい。「Net」カテゴリの下あたりにあるはず。
ということで、つないでみる。
接続先 Linux マシンが 192.168.1.1、ユーザ名 hogehoge とすると、
$ rsh -l hogehoge 192.168.1.1 "hostname"
これで Linux マシンのホスト名が返ってくれば設定は OK。
samba の設定 †
samba も使うので、その設定。下記を参考にどうぞ。
samba を設定したら下記設定をしておく。
- 共有ディレクトリをネットワークドライブに設定しておく。
- ここは、以下のように設定したとする。
- Linux 側
- 共有ディレクトリ : /var/samba/share
- Windows 側
- ネットワークドライブ : \\(Linux ホスト名)\share → Z:\ ドライブ
- Z ドライブの下に Z:\workspace\hello\src というフォルダを作成しておく。
- Linux 側で mkdir しても良いし、Windows 側でフォルダをつくっても OK。
- Linux 側で ビルドするディレクトリとシェルを作成しておく。
$ cd ~
$ mkdir rmake
$ cd rmake
$ vi rmake.sh
#!bin/bash
cd /var/samba/workspace/hello/src
make $1
※ フォルダやシェルの名前は何でも良い。
※ cd の先は make する場所。つまり Makefile を配置する予定地。
Eclipse の設定 †
Eclipse でリモートコンパイルの設定をする。
- Eclipse 起動。
- 「ファイル」→「新規」→「C プロジェクト」を選択。
- 下記を設定して「完了」。
- プロジェクト名 : hello(何でも良い)
- プロジェクトタイプ : Makefile プロジェクト → 空のプロジェクト
- あとはデフォルトのままで。
- 画面左ペインのプロジェクトを右クリックして「新規」→「フォルダ」を選択して「src」という名前でフォルダ作成。
- フォルダ名 : src
- 「拡張」ボタンを押して、「ファイルシステム内のフォルダにリンク」にチェックを入れて、上記で作成したネットワークドライブの src フォルダを指定する。
- 画面左ペインのプロジェクトを右クリックして「新規」→「フォルダ」を選択して「make」という名前でフォルダ作成。
- 「make」フォルダを右クリックして「新規」→「ファイル」で「Makefile」という名前のファイルを作成。
- 画面左ペインで「make」→「Makefile」をダブルクリックして下記のように記述。
all :
rsh 192.168.1.1 -l hogehoge -n "~/rmake/rmake.sh"
.PHONY : clean
clean :
rsh 192.168.1.1 -l hogehoge -n "~/rmake/rmake.sh"
- 「src」フォルダを右クリックして「新規」→「ソースファイル」で「hello.c」という名前のファイルを作成。
- 画面左ペインで「src」→「hello.c」をダブルクリックして下記のように記述。
#include <stdio.h>
int main(int argc, char* argv[]) {
printf("Hello World!\n");
return 0;
}
- 「src」フォルダを右クリックして「新規」→「ファイル」で「Makefile」という名前のファイルを作成。
- 画面左ペインで「src」→「Makefile」をダブルクリックして下記のように記述。
hello: hello.c
gcc -o hello hello.c
- 画面左ペインのプロジェクトを右クリックして「プロパティ」を選択。
- 下記を設定して「OK」。
- 「C/C++ ビルド」の「ビルダー設定」タブで下記を設定。
- ビルドロケーション : ${workspace_loc:/hello/make}
※プロジェクトの make フォルダを指定する。
- 「C/C++ ビルド」下の「環境」で、次の環境変数を追加。
- 名前 : PATH
- 値 : C:\Cygwin\bin
※ Cygwin の bin にパスを通すということ。
- 「C/C++ ビルド」下の「設定」の「バイナリパーサー」タブで下記を設定。
- 「GNU Elf パーサー」にチェック。
- それ以外は OFF で。
- 「プロジェクト」→「すべてビルド(Ctrl + B)」でビルドしてみる。
- いろいろ警告が出るかもしれないけど、src フォルダに hello というファイルができていればとりあえず OK。
- その hello を Linux 側で実行してみる。動けば、一応成功。
$ /var/samba/share/workspace/hello/src/hello
Hello World!
でも、これは速度的にあんまり実用的じゃないかなぁ。
リモートデバッグ †
RSE という Eclipse のプラグインを使ってデバッグしてみる。
※ ここは Eclipse CDT はインストール済みとして書く。
RSE のインストール †
まず Linux 側に RSE DStore Server をインストール。
- RSE DStore Server を取得。
- TM Release Build: 3.0.3
- ↑ここから rseserver-3.0.3-linux.tar をダウンロード。
※今後、このバージョンが残ってるかわからないけど。。
※しかも、現在 drops なのが気になるけど、まあ気にしない。(2010/05/20)
※ない場合は、以下、その時点のファイル名に読み替える。
- RSE DStore Server をインストールするディレクトリを作成。
- インストールディレクトリに rseserver-3.0.3-linux.tar を移動。
# mv (ダウンロードしたところ)/rseserver-3.0.3-linux.tar /opt/rseserver
- そして展開。
# cd /opt/rseserver
# tar xvf rseserver-3.0.3-linux.tar
- ファイアウォールの設定で、4075 番を許可する。
- GNOME でやる場合は「システム」→「管理」→「ファイアウォール」で許可するポートを追加する。
- iptables を直接編集しても OK。
- 要は 4075 番が開けば良い。
- 同様に、ファイアウォールの設定で、60000、60001 を許可する。
- DStore Server は接続ユーザごとにポートを割り振るので、その割り振り先のポートも開けておく。
- ここは 2人 で接続する想定で、60000番 と 60001番にそれぞれ振られるようにする。
- DStore Server を起動。
# perl ./daemon.pl 4075 60000-60001
※ ポート 4075 で待ち受けて、接続ユーザを 60000 から 60001 の範囲で振ってね、という意味。
Daemon running on: (ホスト名), port: 4075
と表示されれば OK。
※ 起動後はプロンプトに戻ってこないので、停止させるときは Ctrl + C で。
Windows 側の Eclipse には RSE プラグインをインストール。
- RSE を取得。
- 展開して出てきた eclipse フォルダを インストールされている Eclipse フォルダに上書き。
- 日本語化パッケージを取得。
- 展開して出てきた eclipse フォルダを インストールされている Eclipse フォルダに上書き。
gdbserver のインストール †
ターゲットとなる Linux に gdbserver をインストール。gdbserver というのは、gdb という gcc でコンパイルされたプログラムのデバッガをリモートで使えるようにするもの。
- gdbserver がインストールされているかどうか確認。
# rpm -qa | grep gdb-gdbserver
gdb-gdbserver-x.x.x-xx.fc12.i686
というように表示されればインストール済み。表示がなければ未インストール。
- gdbserver がない場合はインストール。
# yum install gdb-gdbserver
- コマンドが通るか確認。
# gdbserver --version
バージョン情報が表示されれば OK。
Cygwin 上から使ってみる。
- 簡単なソース hello.c を書く。
#include <stdio.h>
int main(int argv, char* argc[]) {
printf("Hello World!\n");
return 0;
}
- クロスコンパイラでデバッグオプション(-g)を指定して hello.c をコンパイル。
$ i686-linux-gcc -g hello.c -o hello
- 出力された hello を Linux マシンへコピーする。
- Linux 側で、コピーされた hello を gdbserver で起動する。
- Windows(Cygwin)で、gdb で hello を起動。
$ gdb hello
(だーっと表示される)
(gdb) ← このプロンプトが表示される。
- Windows(Cygwin)で、接続先を指定する。
- Linux 側に以下が表示されれば、接続は成功。
Remote debugging from host 192.168.1.3
- Windows(Cygwin) 側で quit で終了。
(gdb) quit
※ gdbserver も同時に終了する。
Eclipse の設定 †
(ごめんなさい。まだ書いてません。)
Linux メモ