Linux 上で Windows のモジュールをコンパイルする方法は Google 先生に聞くと結構出てくるけど、その逆がなかなか出てこない。

ということで Windows 上で Linux のモジュールをコンパイルする方法をメモ。

クロスコンパイラを使う方法

他のプラットフォームのモジュールを作成できるコンパイラを使う方法。もうそのまんま。

Windows 上に UNIX 環境を構築

Cygwin か MinGW/msys ということになると思う。導入に関する詳細は下記ページで。

ここでは Cygwin を使ってみる。

クロスコンパイラの作成

理屈としては、ターゲットとなる Linux の C++ 環境をターゲットとして、Cygwin で gcc をコンパイルすれば良いということになる。

と思ったけど、上手くいかないので、とりあえず以下のサイトからコンパイル済みのクロスコンパイラをいただいて使用することにする。

上記サイトの クロスコンパイラ をいただく。

クロスコンパイラを自前でつくる場合

実は、私もやろうとしたけど、挫折した。

一応、こうすればできるらしいということを、今後の為にメモしておく。

  1. まず、ターゲットとなる Linux 上で、作業用のディレクトリをつくる。
    • ここでは /tmp/linux-runtime とする。
      $ mkdir /tmp/linux-runtime
  2. C/C++ コンパイルに必要なライブラリ(依存関係も全て)をコピーする。
    • これが、どれが必要なのかよくわからないので、以下のディレクトリを全部コピー。
      $ cp -r /lib /tmp/linux-runtime
      $ cp -r /usr/lib /tmp/linux-runtime
      $ cp -r /usr/include /tmp/linux-runtime
    • 環境によっては 500MB 超える。1GB くらいになることも。
    • あからさまに C/C++ に関係ないディレクトリは削除しても良いと思う。
      python とか mozilla とか。
  3. linux-runtime を samba か scp か何かで Windows へ送る。
    • サイズが結構あるので、tar.gz とか lzma あたりで固めて移動すると良いかも。
  4. ここから Windows 側の作業。Cygwin はインストール済みという前提で。
    • Cygwin は C:\Cygwin にインストールされているとする。
  5. GNU の binutils と gcc のソースをゲットする。
  6. 上記を Cygwin で適当なところに展開。
    • ここは /home/user/work に展開したとする。
      $ tar zxvf binutils-2.19.tar.gz
      $ tar zxvf gcc-3.3.4.tar.gz
  7. インストール先ディレクトリを作成。
    • ここは /usr/local/linux とする。
      $ mkdir /usr/local/linux
  8. Linux でつくった linux-runtime 配下のファイルを /usr/local/linux に配置。
    $ mv -R (どこか)/linux-runtime /usr/local/linux
    $ ls /usr/local/linux
    lib include
  9. /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 )
  10. 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
  11. ここまでで /usr/local/linux/bin が作成されているはずなので、パスを通しておく。
    $ PATH=/usr/local/linux/bin:$PATH
  12. 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] 的なエラーが出るかも。とりあえず無視する。
  13. ここまでで、以下のフォルダが作成されているはず。
    /usr/local/linux/bin
    /usr/local/linux/include
    /usr/local/linux/lib
    /usr/local/linux/man
    /usr/local/linux/share
  14. bin の中に以下が出来上がっていればとりあえずコンパイラ完成。
    i686-linux-as
    i686-linux-gcc
    i686-linux-g++
  15. 試しに簡単なソースをコンパイルしてみる。
    $ 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 のみでコンパイルしてみる。

  1. 作業用ディレクトリを作成して移動。
    • ここでは /home/user/work/hello というディレクトリにする。
      $ mkdir /home/user/work/hello
      $ cd /home/user/work/hello
  2. ソースを書いて、hello.c という名前で保存。
    #include <stdio.h>
    
    int main(int argc, char* argv[]) {
        printf("Hello World!\n");
        return 0;
    }
  3. クロスコンパイラでコンパイルしてみる。
    $ i686-linux-gcc hello.c -o hello
    ※ gcc で起動すると Cygwin の gcc が動くので、i686-linux-gcc を指定すること。
  4. これで hello というファイルができて実行できれば OK。
    $ ls 
    hello hello.c
    $ ./hello
    Hello World!

Eclipse を使う

Eclipse は CDT を使うよ。

特にインストーラなどはなくて、適当なディレクトリに展開するだけ。

次に、日本語化する。英語のままでも良いならここは不要。
※ ただ、下の説明は日本語化したのを前提に書いてマス。

これも特にインストーラはなくて、展開したフォルダやファイルたちを Eclipse を展開した場所に上書きするだけ。

早速 Eclipse を使ってみる。

  1. Eclipse 起動。
  2. 「ファイル」→「新規」→「C プロジェクト」で、プロジェクト名「hello」、実行ファイル形式を選んで「完了」。
    • 「Hello World C Project」があればそっちで。
      最初からお決まりのサンプルがつく。
  3. Hello World がなかった場合はソースを作成。
    • 左ペインのプロジェクトを右クリックして「新規」→「フォルダ」で「src」フォルダ作成。
    • 「src」フォルダを右クリックして「新規」→「ソースファイル」で「hello.c」を作成。
    • 「hello.c」をダブルクリックして、以下を記述。
      #include <stdio.h>
      
      int main(int argc, char* argv[]) {
          printf("Hello World!\n");
          return 0;
      }
  4. 左ペインのプロジェクトを右クリックして「プロパティ」を開く。
  5. 「C/C++ ビルド」下にある「ツール・チェーン・エディタ」を選択。
    • 構成はどちらでも良いけど、ここは「Release」をアクティブにする。
    • 現在のツールチェーン : Cygwin GCC
    • 現在のビルダー : GNU Make ビルダー
  6. 「C/C++ ビルド」下にある「環境」を選択。
    • 「設定する環境変数」に以下を追加。
      • 名前 : PATH
      • 値 : C:\Cygwin\bin;C:\Cygwin\usr\local\linux\bin
  7. 「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 パーサー」にチェック。
      • あとは チェックをはずす。
  8. 「OK」でプロパティを閉じる。
  9. 「プロジェクト」→「すべてビルド(Ctrl + B)」でビルドしてみる。
  10. 画面下コンソールに特にエラーがなければ、Release フォルダに hello というファイルができる。
  11. その hello を Linux に持っていって実行してみる。
    $ ./hello
  12. 「Hello World!」と表示されれば、Windows 上で Linux のモジュールができたことになる!

リモートでやる方法(rsh)

といっても、telnet や rlogin でコマンド叩くのは、直接 Linux 上で作業するのと変わらないので、ここは Eclipse を使ってリモートでコンパイルする方法を書く。

rsh の設定

ここでは rsh を使うので、ホストとなる Linux 側で以下の設定をする。rsh は大抵デフォルトで入ってるけど、最近はセキュリティ性を考慮して無効になっていることが多い。

  1. rsh サーバが入っているか確認。
    $ rpm -qa rsh-server
    rsh-server-0.17-58.fc12.i686
    ※ ↑私の環境の場合の例。とにかく入っていれば何かヒットする。
  2. rsh サーバはなかった場合はインストール。(あれば、次の手順へ)
    $ su
    # yum install rsh-server
  3. rsh がインストールされると、以下のファイルが作成されるので確認。
    /etc/xinetd.d/rexec
    /etc/xinetd.d/rsh
  4. /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
    }
  5. /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
    }
  6. ファイアウォールの設定で 514 を許可する。
    • GNOME で「システム」→「管理」→「ファイアウォール」で「その他のポート」に追加しても良いし、/etc/sysconfig/iptables に追加するでも良い。
    • もしかしたら、512 番とか 513 番かもしれない。でも shell は多分 514 のはず。
  7. xinetd を再起動する。
    $ su
    # /etc/rc.d/init.d/xinetd restart
    xinetd を停止中:                         [  OK  ]
    xinetd を起動中:                         [  OK  ]
  8. ログインするユーザのホームディレクトリへ移動。
    $ cd ~
    $ pwd
    /home/(ユーザ名)
  9. .rhosts というファイルをつくって、ログインを許可するクライアントとユーザ名を書く。
    • クライアントが 192.168.1.255、 ユーザが hogehoge の場合の例。
      $ vi .rhosts
      192.168.1.255 hogehoge     # ← スペースで区切る。
  10. できたファイルのパーミッションを確認する。
    $ 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 を設定したら下記設定をしておく。

  1. 共有ディレクトリをネットワークドライブに設定しておく。
    • ここは、以下のように設定したとする。
    • Linux 側
      • 共有ディレクトリ : /var/samba/share
    • Windows 側
      • ネットワークドライブ : \\(Linux ホスト名)\share → Z:\ ドライブ
  2. Z ドライブの下に Z:\workspace\hello\src というフォルダを作成しておく。
    • Linux 側で mkdir しても良いし、Windows 側でフォルダをつくっても OK。
  3. Linux 側で ビルドするディレクトリとシェルを作成しておく。
    $ cd ~
    $ mkdir rmake
    $ cd rmake
    $ vi rmake.sh
    #!bin/bash
    cd /var/samba/workspace/hello/src
    make $1
    ※ フォルダやシェルの名前は何でも良い。
    ※ cd の先は make する場所。つまり Makefile を配置する予定地。

Eclipse の設定

Eclipse でリモートコンパイルの設定をする。

  1. Eclipse 起動。
  2. 「ファイル」→「新規」→「C プロジェクト」を選択。
  3. 下記を設定して「完了」。
    • プロジェクト名 : hello(何でも良い)
    • プロジェクトタイプ : Makefile プロジェクト → 空のプロジェクト
    • あとはデフォルトのままで。
  4. 画面左ペインのプロジェクトを右クリックして「新規」→「フォルダ」を選択して「src」という名前でフォルダ作成。
    • フォルダ名 : src
    • 「拡張」ボタンを押して、「ファイルシステム内のフォルダにリンク」にチェックを入れて、上記で作成したネットワークドライブの src フォルダを指定する。
      • Z:\workspace\hello\src
  5. 画面左ペインのプロジェクトを右クリックして「新規」→「フォルダ」を選択して「make」という名前でフォルダ作成。
  6. 「make」フォルダを右クリックして「新規」→「ファイル」で「Makefile」という名前のファイルを作成。
  7. 画面左ペインで「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"
  8. 「src」フォルダを右クリックして「新規」→「ソースファイル」で「hello.c」という名前のファイルを作成。
  9. 画面左ペインで「src」→「hello.c」をダブルクリックして下記のように記述。
    #include <stdio.h>
    
    int main(int argc, char* argv[]) {
        printf("Hello World!\n");
        return 0;
    }
  10. 「src」フォルダを右クリックして「新規」→「ファイル」で「Makefile」という名前のファイルを作成。
  11. 画面左ペインで「src」→「Makefile」をダブルクリックして下記のように記述。
    hello: hello.c
    	gcc -o hello hello.c
  12. 画面左ペインのプロジェクトを右クリックして「プロパティ」を選択。
  13. 下記を設定して「OK」。
    • 「C/C++ ビルド」の「ビルダー設定」タブで下記を設定。
      • ビルドロケーション : ${workspace_loc:/hello/make}
        ※プロジェクトの make フォルダを指定する。
    • 「C/C++ ビルド」下の「環境」で、次の環境変数を追加。
      • 名前 : PATH
      • 値 : C:\Cygwin\bin ※ Cygwin の bin にパスを通すということ。
    • 「C/C++ ビルド」下の「設定」の「バイナリパーサー」タブで下記を設定。
      • 「GNU Elf パーサー」にチェック。
      • それ以外は OFF で。
  14. 「プロジェクト」→「すべてビルド(Ctrl + B)」でビルドしてみる。
    • ちょっと時間がかかるかも。
  15. いろいろ警告が出るかもしれないけど、src フォルダに hello というファイルができていればとりあえず OK。
  16. その hello を Linux 側で実行してみる。動けば、一応成功。
    $ /var/samba/share/workspace/hello/src/hello
    Hello World!

でも、これは速度的にあんまり実用的じゃないかなぁ。

リモートデバッグ

RSE という Eclipse のプラグインを使ってデバッグしてみる。

※ ここは Eclipse CDT はインストール済みとして書く。

RSE のインストール

まず Linux 側に RSE DStore Server をインストール。

  1. RSE DStore Server を取得。
    • TM Release Build: 3.0.3
    • ↑ここから rseserver-3.0.3-linux.tar をダウンロード。
      ※今後、このバージョンが残ってるかわからないけど。。
      ※しかも、現在 drops なのが気になるけど、まあ気にしない。(2010/05/20)
      ※ない場合は、以下、その時点のファイル名に読み替える。
  2. RSE DStore Server をインストールするディレクトリを作成。
    • ここは /opt/rseserver とする。
      $ su     ← root でやる。
      # mkdir /opt/rseserver
  3. インストールディレクトリに rseserver-3.0.3-linux.tar を移動。
    # mv (ダウンロードしたところ)/rseserver-3.0.3-linux.tar /opt/rseserver
  4. そして展開。
    # cd /opt/rseserver
    # tar xvf rseserver-3.0.3-linux.tar
  5. ファイアウォールの設定で、4075 番を許可する。
    • GNOME でやる場合は「システム」→「管理」→「ファイアウォール」で許可するポートを追加する。
    • iptables を直接編集しても OK。
    • 要は 4075 番が開けば良い。
  6. 同様に、ファイアウォールの設定で、60000、60001 を許可する。
    • DStore Server は接続ユーザごとにポートを割り振るので、その割り振り先のポートも開けておく。
    • ここは 2人 で接続する想定で、60000番 と 60001番にそれぞれ振られるようにする。
  7. DStore Server を起動。
    # perl ./daemon.pl 4075 60000-60001
    ※ ポート 4075 で待ち受けて、接続ユーザを 60000 から 60001 の範囲で振ってね、という意味。
    Daemon running on: (ホスト名), port: 4075
    と表示されれば OK。
    ※ 起動後はプロンプトに戻ってこないので、停止させるときは Ctrl + C で。

Windows 側の Eclipse には RSE プラグインをインストール。

  1. RSE を取得。
    • RSE Download
    • ここは RSE-runtime-x.x.x.zip というファイルをダウンロード。
  2. 展開して出てきた eclipse フォルダを インストールされている Eclipse フォルダに上書き。
  3. 日本語化パッケージを取得。
  4. 展開して出てきた eclipse フォルダを インストールされている Eclipse フォルダに上書き。

gdbserver のインストール

ターゲットとなる Linux に gdbserver をインストール。gdbserver というのは、gdb という gcc でコンパイルされたプログラムのデバッガをリモートで使えるようにするもの。

  1. gdbserver がインストールされているかどうか確認。
    # rpm -qa | grep gdb-gdbserver
    gdb-gdbserver-x.x.x-xx.fc12.i686
    というように表示されればインストール済み。表示がなければ未インストール。
  2. gdbserver がない場合はインストール。
    # yum install gdb-gdbserver
  3. コマンドが通るか確認。
    # gdbserver --version
    バージョン情報が表示されれば OK。

Cygwin 上から使ってみる。

  1. 簡単なソース hello.c を書く。
    #include <stdio.h>
    
    int main(int argv, char* argc[]) {
        printf("Hello World!\n");
        return 0;
    }
  2. クロスコンパイラでデバッグオプション(-g)を指定して hello.c をコンパイル。
    $ i686-linux-gcc -g hello.c -o hello
  3. 出力された hello を Linux マシンへコピーする。
  4. Linux 側で、コピーされた hello を gdbserver で起動する。
    • Windows(Cygwin)側の IP を 192.168.1.3 、待受けポートを 2345 の場合はこんな感じ。
      $ gdbserver 192.168.1.3:2345 (コピーした場所)/hello
  5. Windows(Cygwin)で、gdb で hello を起動。
    $ gdb hello
    (だーっと表示される)
    (gdb)   ← このプロンプトが表示される。
  6. Windows(Cygwin)で、接続先を指定する。
    • gdbserver を起動した Linux の IP が 192.168.1.2 、待受けポート 2345 の場合はこう。
      (gdb) target remote 192.168.1.2:2345
  7. Linux 側に以下が表示されれば、接続は成功。
    Remote debugging from host 192.168.1.3
  8. Windows(Cygwin) 側で quit で終了。
    (gdb) quit
    ※ gdbserver も同時に終了する。

Eclipse の設定

(ごめんなさい。まだ書いてません。)


Linux メモ


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2010-05-25 (火) 17:10:18 (5250d)