2008-02-19

Visual Studio 2008 Express Editions

ンターネットである情報を探していたら、ひょんなことから Visual Studio 2008 Express Editions のサイトにたどり着き、これは使えそうだと思い、早速オンライン・インストールをしました。

ずっと昔、Visual C++ 6 までは購入して使っていましたが、コンパイラの用途が購入価格に見合わず、結局 Cygwin/MinGW の GCC を利用するようになってしまいました。

Visual Studio 2008 Express Editions の「よくある質問」によると、30日以上使い続けるにはユーザー登録をしなければならないものの、Visual Studio Express Edition を使用して作成したアプリケーションについては、ライセンスの制限がないということです。また、Visual C++ 2008 Express Edition には、MFCATL が含まれていないが、基本的な Optimizing Compiler が含まれているとのことなので、Tcl/Tk などのコンパイルには使えそうです。


そこで、Tcl/Tk 8.5.1 をコンパイルしてみました。
まず、SourceForge.net のサイトから Tcl/Tk8.5.1 のソース(tcl8.5.1-src.tar.gz と tk8.5.1-src.tar.gz、あるいは zip ファイル)をダウンロードしてきて圧縮ファイルを解凍(展開)しておきます。ここでは、E:\mingw\src\ 以下にソースを展開しています。

次に、スタートメニューから、Visual Studio 2008 コマンドプロンプトを起動します。

最初に、Tcl からコンパイルします。インストール先のトップディレクトリを、環境変数 INSTALLDIR にセットしてからビルドします。

Setting environment for using Microsoft Visual Studio 2008 x86 tools.

C:\Program Files\Microsoft Visual Studio 9.0\VC>e:

E:\>cd mingw\src

E:\mingw\src>set INSTALLDIR=e:\mingw\build\Tcl

E:\mingw\src>cd tcl8.5.1\win

E:\mingw\src\tcl8.5.1\win>nmake -fmakefile.vc

Microsoft(R) Program Maintenance Utility Version 9.00.21022.08
Copyright (C) Microsoft Corporation. All rights reserved.

===============================================================================
*** Compiler has 'Optimizations'
*** Compiler does not have 'Pentium 0x0f fix'
:
:
:
LINK : warning LNK4224: /OPT:NOWIN98 はサポートされていません。無視されます。
ライブラリ .\Release_VC9\tcldde13.lib とオブジェクト .\Release_VC9\tcldde13.e
xp を作成中
コード生成しています。
コード生成が終了しました。
if exist .\Release_VC9\tcldde13.dll.manifest mt -nologo -manifest .\Rele
ase_VC9\tcldde13.dll.manifest -outputresource:.\Release_VC9\tcldde13.dll;2

E:\mingw\src\tcl8.5.1\win>nmake -fmakefile.vc install

Microsoft(R) Program Maintenance Utility Version 9.00.21022.08
Copyright (C) Microsoft Corporation. All rights reserved.

===============================================================================
*** Compiler has 'Optimizations'
*** Compiler does not have 'Pentium 0x0f fix'
:
:
:
Installing package platform::shell 1.1.3 as a Tcl Module
Installing tcldde13.dll
Installing tclreg12.dll
Installing encodings

E:\mingw\src\tcl8.5.1\win>

次に、Tk をビルドします。ビルドの前に、環境変数 TCLDIR へ tcl8.5.1 のソースのトップディレクトリをセットします。インストール先は、この場合は Tcl と同じにしました。つまり、環境変数 INSTALLDIR の値はそのままです。

E:\mingw\src\tcl8.5.1\win>cd ..\..\tk8.5.1\win

E:\mingw\src\tk8.5.1\win>set TCLDIR=e:\mingw\src\tcl8.5.1

E:\mingw\src\tk8.5.1\win>nmake -fmakefile.vc

E:\mingw\src\tk8.5.1\win>nmake -fmakefile.vc install

以上が Tcl/Tk の基本的なビルド手順です。ちなみに、nmake /fnmake -f の両方の形式が可能です。つい癖で -f と入力してしまうのですが、エラーが出なかったので気が付きました。

生成したバイナリについての詳細な評価はまだしていませんが、とりあえず、MinGW クロスコンパイラでビルドした Tcl/Tk のバイナリと、ファイルサイズを比較してみました。

Visual C++ でビルドしたバイナリ



MinGW クロスコンパイラ でビルドしたバイナリ


明らかに、Visual C++ でビルドしたバイナリのサイズの方が小さいことが判ります。詳細なベンチマークを今後やってみたいと考えています。
昔、VC6 と MinGW の gcc で比較したときには、VC6 でコンパイラでビルドしたバイナリの方が、バイナリサイズが小さく、かつ実行速度も速いという結果が出たと記憶していますが、最新の gcc との比較で、どの程度の差が出るか興味があります。

10 件のコメント:

匿名 さんのコメント...

こんにちは。 MinGW Cross Compiler Projectに感謝しております。 時間ができたので、最近Fedora8にクロスコンパイル環境をつくってサンプルプログラムをコンパイルし、Windows box上での動作確認もできたのですが、なんとDOS窓も表示されてしまいます。 これを出さなくするにはどうしたら良いのか教えていただければと、こうして書いています。 CからTcl/Tkコマンドを呼び出しているプログラムです。 考えた末、この質問はやはり、ここしかないかなと思いました。

windows用プログラム実行時にDOS窓が表示されてしまう以外に、wine環境ができていない(wine上でwindows版プログラムが起動できないなど)ので、Fedora8上でテストできないので不便でしかたがないのですが、注意点がありましたらこれも教えていただければと、、、。 

cソースとメイクファイルもここに示します。メイクにあるようにTcl/Tkは8.4.18を使用しています。 これはエラーなしでそれぞれのOS用にコンパイルしたプログラムがFedora8、Windows上できちんと動くからです。 
(サンプルはUranoさんの http://www.geocities.co.jp/SiliconValley/4137/dir4/tapi23.html などを参考にしています。)
本当は、C言語部分とTcl部分を分けたファイルにし、メイクファイルにそのように記述してコンパイルしたい、、、どうしたらよいのか、、、サンプルはありませんか?
アドバイスをいただけると助かります。(米国中部時間のため応答に時差があります、、、)

/* cソース, use " instead of < */
#include "stdio.h" /* changed " to < */

#include "tcl.h"
#include "tk.h"

int main(int argc, char* argv[]){

Tcl_Interp* interp;

interp = Tcl_CreateInterp();

Tcl_FindExecutable(argv[0]);

if(Tcl_Init(interp) != TCL_OK){
fprintf(stderr, "FATAL: Tcl initialization error: %s\n",
Tcl_GetStringResult(interp)); return 1;
}
if(Tk_Init(interp) != TCL_OK){
fprintf(stderr, "FATAL: Tk initialization error: %s\n",
Tcl_GetStringResult(interp)); return 1;
}

{
char command[] =
"\n\
label .1lbl -text { Enter your name (and click OK):} \n\
entry .2ent \n\
button .3cmd -text OK -command ok_clicked \n\
button .4cmd -text {Exit this program} -command exit \n\
pack .1lbl -anc w \n\
pack .2ent -fill x \n\
pack .3cmd -fill x \n\
pack .4cmd -fill x \n\
proc ok_clicked {} { \n\
tk_messageBox -message \"[.2ent get], you are here!\" \n\
} \n\
";

Tcl_DString ds;

char* command_utf = Tcl_ExternalToUtfDString(NULL, command, -1, & ds);

if(Tcl_Eval(interp, command_utf) != TCL_OK){
fprintf(stderr, "Error: %s\n",
Tcl_GetStringResult(interp)); return 1;
}

Tcl_DStringFree(& ds);
}

Tk_MainLoop();

return 0;
}
/* end of file */

/////////////////////////////////////////////////////

# Makefile.win
# compile: make -f Makefile.win
# cross-compile on linux
# Fedora8 + mingw + Tcl/Tk8.4(ActiveTcl8.4.18 windows version)
# 2008-02-15: compile ok
# 2008-02-15: run ok(on windows)
# 2008-02-15: run ng(wine on fedora)

INC_STD = /usr/local/i386-mingw32/include # stdio.h, windows.h
LIB_STD = /usr/local/i386-mingw32/lib #

INC_TCL = /home/kn/tcls/tcl8418w/include # tcl.h
LIB_TCL = /home/kn/tcls/tcl8418w/lib # tcl84.lib

INC_TK = /home/kn/tcls/tcl8418w/include # tk.h
LIB_TK = /home/kn/tcls/tcl8418w/lib # tk84.lib

CC = i386-mingw32-gcc

CFLAGS = -g -Wall \
-I$(INC_STD) -L$(LIB_STD) \
-I$(INC_TCL) -L$(LIB_TCL) \
-I$(INC_TK) -L$(LIB_TK)

LIBS = \
-L$(LIB_STD) -lm \
-L$(LIB_TCL) -ltcl84 -lm \
-L$(LIB_TK) -ltk84 -lm

.c.o:
$(CC) -c $(CFLAGS) $*.c

sampleCTKwf.exe: sampleCTK.o
$(CC) -o $@ sampleCTK.o $(LIBS)

clean: sampleCTK.o
rm -f $?

/////////////////////////////////////////////////////

# Makefile.linux
# compile: make -f Makefile.linux
# fedora8 + gcc(4.1.2) + Tcl/Tk8.4(ActiveTcl8.4.18, linux version)
# 2008-02-15: compile ok
# 2008-02-15: run ok

INC_STD = /usr/include # stdio.h, stdlib.h
LIB_STD = /usr/lib # lib..., libX...

INC_X11 = /usr/include/X11 # X.h, Xlib.h
LIB_X11 = /usr/lib # libX11...so

INC_TCL = /opt/tcl8418u/include # tcl.h
LIB_TCL = /opt/tcl8418u/lib # libtcl8.4.so

INC_TK = /opt/tcl8418u/include # tk.h
LIB_TK = /opt/tcl8418u/lib # libtk8.4.so

CC = gcc

# -02 for optimization flag
CFLAGS = -O2 -I$(INC_STD) -I$(INC_X11) -I$(INC_TCL) -I$(INC_TK)

LIBS = \
-L$(LIB_STD) -ldl -lm \
-L$(LIB_X11) -lX11 -ldl -lm \
-L$(LIB_TCL) -ltcl8.4 -ldl -lm \
-L$(LIB_TK) -ltk8.4 -ldl -lm

.c.o:
$(CC) -c $(CFLAGS) $*.c

sampleCTKuf: sampleCTK.o
$(CC) -o $@ sampleCTK.o $(LIBS)

clean: sampleCTK.o
rm -f $?

bitWalk さんのコメント...

kojiさん、こんにちは。
DOS窓を表示しないようにするためのマクロがあるのですが、package requre でロードする拡張パッケージばかり作っているので、忘れてしまいました。ちょっと調べてみます。しばらくお待ちください。

bitWalk さんのコメント...

判りました。
リンク時に -mwindows を加えてみてください。

bitWalk さんのコメント...

> 本当は、C言語部分とTcl部分を分け
> たファイルにし、メイクファイルに
> そのように記述してコンパイルした
> い、、、どうしたらよいのか、、、
> サンプルはありませんか?

分けることは可能です。また、分けるとしても、いくつか異なるアプローチもあります。
示していただいたサンプルをベースにして、ブログの本記事で解説してもよろしいでしょうか?

匿名 さんのコメント...

いつも、ありがとうございます。

>示していただいたサンプルをベースに
>して、ブログの本記事で解説しても
>よろしいでしょうか?
もちろんです。 今回投稿したのも他の人に参考になるかな?という意図もありました(メイクを冗長に書いているのそのためですが、これも苦手でして、、、。もっと良いわかりやすいサンプルがあれば多くの人に参考になるかと)。

また、ふろしきをひろげるつもりはありませんが将来MacのクロスコンパイルもLinux上で行ないたいとひそかに考えています。(同じアプリ)

Tcl/Tkで100%書くのが一番OS間での互換性が高いのでしょうが、CからTcl/Tkを呼ぶプログラムも同様にできて欲しいという希望が捨てきれないのです。「API(GUI)をTcl/Tkで書くC言語ソフト」が自由に書けるようになりたいのです。 

ブログで具体的な質問するのは?と長いこと躊躇していましたが、どこにも行き所がないこの情報の少なさ。いまだに変わっていません。  

これからもよろしくお願いします。

bitWalk さんのコメント...

> もちろんです。 今回投稿したのも
> 他の人に参考になるかな?という意
> 図もありました

わかりました。週末にかけて、自分でテストして、掲載する内容を準備します。

匿名 さんのコメント...

さきほどは書き損じてしまいました。

>リンク時に -mwindows を加えてみてください。
はい。DOS窓なしで動くことを確認しました。
リンク時のスイッチでしたか。不勉強でした。
おお、動きが、、、らしくなってきた。(とてもうれしいの意)
これで真のクロスコンパイルの完成となった気がする!

>週末にかけて、自分でテストして、
>掲載する内容を準備します。
感謝です。

匿名 さんのコメント...

一番肝心なことを見落としていました。

目標は、c言語部分(計算)とTcl部分(GUI)を別ファイルに分け、これをメイクしたいことです。 ですが、投稿したサンプルが適当なサンプルでないことに今更ながら気がつきました。 コンパイル環境をつくるのとその確認に囚われすぎていた、、、(サンプルは確かにC言語からTclコマンドを呼出していますが、Tclのproc を使っていては意味がない、、、)

本当にしたいこと、知りたいサンプルプログラムは(例えば手順として)
1)(myApp.tcl に記述した)ウィンドウAA上のボタンBBを押す
2)(myApp.c に記述した)関数CCで計算した計算結果DDを得る
3)(myApp.tcl に記述した)ウィンドウAA上のラベルEEに計算結果DDを表示する

のようなプログラムです。ここでのc言語とTcl間の値の受け渡しもわかりません。(我ながらあきれた)、、、引き続き自分でもこれから悩んでみます、、、

良いサンプルが示されることを期待しつつ。

bitWalk さんのコメント...

> 目標は、c言語部分(計算)とTcl部分
> (GUI)を別ファイルに分け、これをメ
> イクしたいことです。
(snip)
> ここでのc言語とTcl間の値の受け渡
> しもわかりません。(我ながらあきれ
> た)、、、引き続き自分でもこれから
> 悩んでみます、、、

いろいろとお悩みのようですね。少しずつ用意して紹介していきます。

ただ、Tcl はコマンド言語ですので、今回 koji さんが示されたような、C ソースに Tcl のスクリプトを埋め込む拡張よりも、Tcl のコマンドを C で拡張して、スクリプトと C でやり取りする方が、Tcl らしい拡張だと思います。もちろん、どれが正しい拡張っていうものではありませんけれども…。

匿名 さんのコメント...

>Tcl のコマンドを C で拡張して、
>スクリプトと C でやり取りする方が、
>Tcl らしい拡張だと思います。
基本に戻っていろいろやりながら考えてみます。ありがとうございました。