VS2008でTclVFSをtcl.8.5.15に対応させる方法 (VS2012、tcl 8.6.8 追記)

不具合現象

Tcl 8.5 系の現在の最新版である Tcl 8.5.15 と TclVFS 20080503 を VS2008 Express Edition 32bitモードでビルドしようとしたところ、下記エラーが出てしまいました。

<Tcl 8.5.15 + TclVFS 20080503 32bit モードでのビルドエラー内容>
===============================================================================
*** Compiler has 'Optimizations'
*** Compiler does not have 'Pentium 0x0f fix'
*** Linker has 'Win98 alignment problem'
*** Intermediate directory will be '.\Release_VC9\vfs_ThreadedDynamic'
*** Output directory will be '.\Release_VC9'
*** Suffix for binaries will be ''
*** Optional defines are '-DTCL_CFGVAL_ENCODING=\"cp1252\" -DSTDC_HEADERS -DTCL_THREADS=1 -DTCL_CFG_OPTIMIZED'
*** Compiler version 9. Target machine is IX86
*** Compiler options '-W3 -Ot -Oi -fp:strict -Gs -GS -GL -RTC1 -W3'
*** Link options '-ltcg'
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\wtime.inl(37) : warning C4133: '関数' : 'const time_t *' と 'const __time32_t *' の間で型に互換性がありません。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\wtime.inl(43) : warning C4133: '関数' : 'const time_t *' と 'const __time32_t *' の間で型に互換性がありません。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\time.inl(32) : warning C4244: '関数' : 'time_t' から '__time32_t' への変換です。データが失われる可能性があります。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\time.inl(32) : warning C4244: '関数' : 'time_t' から '__time32_t' への変換です。データが失われる可能性があります。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\time.inl(38) : warning C4133: '関数' : 'const time_t *' と 'const __time32_t *' の間で型に互換性がありません。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\time.inl(44) : warning C4133: '関数' : 'const time_t *' と 'const __time32_t *' の間で型に互換性がありません。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\time.inl(51) : warning C4133: '関数' : 'const time_t *' と 'const __time32_t *' の間で型に互換性がありません。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\time.inl(57) : warning C4133: '関数' : 'const time_t *' と 'const __time32_t *' の間で型に互換性がありません。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\time.inl(64) : warning C4133: '関数' : 'const time_t *' と 'const __time32_t *' の間で型に互換性がありません。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\time.inl(69) : warning C4133: '関数' : 'const time_t *' と 'const __time32_t *' の間で型に互換性がありません。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\time.inl(81) : warning C4133: '関数' : 'time_t *' と '__time32_t *' の間で型に互換性がありません。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\sys/stat.inl(44) : error C2466: サイズが 0 の配列を割り当てまたは宣言しようとしました。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\sys/stat.inl(49) : error C2466: サイズが 0 の配列を割り当てまたは宣言しようとしました。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\sys/timeb.inl(46) : error C2466: サイズが 0 の配列を割り当てまたは宣言しようとしました。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\sys/utime.inl(39) : error C2466: サイズが 0 の配列を割り当てまたは宣言しようとしました。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\sys/utime.inl(44) : error C2466: サイズが 0 の配列を割り当てまたは宣言しようとしました。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\sys/utime.inl(49) : error C2466: サイズが 0 の配列を割り当てまたは宣言しようとしました。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\sys/utime.inl(78) : error C2466: サイズが 0 の配列を割り当てまたは宣言しようとしました。

また、多少エラー内容は違いますが、同じような現象が、Windows SDK .Net 3.5 SP1 (VC9 相当) の 64bitモードで Tcl 8.5.11 と TclVFS 20080503 を ビルドしても発生しました。

<Tcl 8.5.11 + TclVFS 20080503 64bit モードでのビルドエラー内容>
===============================================================================
*** Compiler has 'Optimizations'
*** Intermediate directory will be '.\Release_AMD64_VC9\vfs_ThreadedDynamic'
*** Output directory will be '.\Release_AMD64_VC9'
*** Suffix for binaries will be ''
*** Optional defines are '-DTCL_CFGVAL_ENCODING=\"cp1252\" -DSTDC_HEADERS -DTCL_THREADS=1 -DTCL_CFG_OPTIMIZED -DTCL_CFG_DO64BIT'
*** Compiler version 9. Target machine is AMD64
*** Compiler options '-W3 -Ot -Oi -fp:strict -Gs -GS -GL -RTC1 -W3'
*** Link options '-ltcg'
cl -DPACKAGE_NAME="\"vfs\"" -DPACKAGE_VERSION="\"1.3\"" -DBUILD_vfs -nologo -c -W3 -W3 -D _CRT_SECURE_NO_DEPRECATE -D _CRT_NONSTDC_NO_DEPRECATE -Fp.\Release_AMD64_VC9\vfs_ThreadedDynamic\ -DUSE_TCL_STUBS -Ot -Oi -fp:strict -Gs -GS -GL -MD -I"..\..\tcl8.5.15\generic" -I"..\..\tcl8.5.15\win" -I"..\win" -I"..\generic" -DTCL_CFGVAL_ENCODING=\"cp1252\" -DSTDC_HEADERS -DTCL_THREADS=1 -DTCL_CFG_OPTIMIZED -DTCL_CFG_DO64BIT -DBUILD_vfs -Fo.\Release_AMD64_VC9\vfs_ThreadedDynamic\ @C:\Users\keita\AppData\Local\Temp\nm6691.tmp
vfs.c
..\generic\vfs.c(1108) : error C2037: left of 'st_mode' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1122) : error C2037: left of 'st_dev' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1129) : error C2037: left of 'st_ino' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1136) : error C2037: left of 'st_mode' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1143) : error C2037: left of 'st_nlink' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1150) : error C2037: left of 'st_uid' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1157) : error C2037: left of 'st_gid' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1164) : error C2037: left of 'st_size' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1171) : error C2037: left of 'st_atime' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1178) : error C2037: left of 'st_mtime' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1185) : error C2037: left of 'st_ctime' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1190) : error C2037: left of 'st_mode' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1192) : error C2037: left of 'st_mode' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1195) : error C2037: left of 'st_mode' specifies undefined struct/union '__stat64'

どうやら、 __stat64 をうまく認識できていないようです。

__stat64 は、 #include <sys/types.h> や #include <sys/stat.h> を C ソースに記述することで
使うことができるようになります。
Tcl では、#include "tclPort.h" の中で、 __stat64 を Tcl_StatBuf に typedef しています。

TclVFSのソース vfs.c を見てみると、先頭に
vfs.c ソースの先頭部分>
#include <tcl.h>
/* Required to access the 'stat' structure fields, and TclInExit() */
#include "tclInt.h"
#include "tclPort.h"

と書いてありますので、 Tcl_StatBuf (=__stat64) の定義をしようとはしているようです。

原因

わかりません...

対策

色々試してみたところ、 #include <tcl.h> よりも先に #include "tclPort.h" を記述することで
ビルドが通るようになりました。
つまり、 vfs.c の上記箇所を、下記のように変更すればOKです。

vfs.c ソース修正例>
#include "tclPort.h" /* ← tcl.h の前に移動してきた */
#include <tcl.h>
/* Required to access the 'stat' structure fields, and TclInExit() */
#include "tclInt.h"

<VS2012、Tcl 8.6.8では下記手順も追加>
1661行目 (VfsFileAttrStrings 関数定義の戻り値の型)を
static CONST char **

static CONST char * CONST86 *
と書き換え

この変更により、下記組み合わせのビルドがそれぞれ通るようになったことを確認済です。
  • Tcl 8.5.11 + TclVFS 20080503 64bit モード (Windows SDK .Net 3.5 SP1)
  • Tcl 8.5.15 + TclVFS 20080503 32bit モード (Visual Studio 2008 Express Edition)
  • Tcl 8.5.15 + TclVFS 20080503 64bit モード (Windows SDK .Net 3.5 SP1)
  • Tcl 8.6.8 + TclVFS 20080503 64bit モード (Visual Studio 2012 Express Edition)