4

私は NetHack が好きで、楽しみのためにソースを少しいじりたいと思っています。それを行う前に、箱から出してコンパイルできるようにしたいと思いますが、それを実現するのに少なからず困難があります。

ここからソースコードをダウンロードし、ここの指示に従いましたが、うまくいきませんでした。

私は最終的に次のようになりました

C:\nethack-3.4.3\src>mingw32-make -f Makefile.gcc install
creating directory o
gcc -c -mms-bitfields -I../include  -g -DWIN32CON -oo/makedefs.o ../util/makedefs.c
gcc -c -mms-bitfields -I../include  -g -DWIN32CON -DDLB   -oo/monst.o  ../src/monst.c
gcc -c -mms-bitfields -I../include  -g -DWIN32CON -DDLB   -oo/objects.o      ../src/objects.c
..\util\makedefs -v
Makefile.gcc:655: recipe for target '../include/date.h' failed
mingw32-make: *** [../include/date.h] Error -1073741819

それが話している行を見ましたが、実際には何も教えてくれませんでした。インクルードディレクトリに作成されているdate.hファイルが常に空であることに気付きましたが、それもあまり役に立ちません。Install.nt README を読みましたが、その指示はかなり明確に見えました。ただし、何も変更していないため、コンパイルに失敗する理由がわかりません...

私は自分自身を有能なプログラマーだと思っていますが、makefile や C コードを実行可能なアプリケーションにコンパイルすることに関してはほとんど何も知らないので、ここでかなり迷っています。MinGW をダウンロードしてインストールしました... すべて、つまり、MinGW インストーラーを実行したときにアンインストールされたものは何も残っていません。

ここで何が間違っていますか?

編集:date.hが言及されていたように:

#
#  date.h should be remade every time any of the source or include
#  files is modified.
#

$(INCL)/date.h $(OPTIONS_FILE): $(U)makedefs.exe
    $(subst /,\,$(U)makedefs -v)

OPTIONS_FILEコメントアウトされているように見える、何らかの呼び出しを行っているように見えることに気付きました。コメントを外して、何が起こるか見てみましょう。

#$(OPTIONS_FILE): $(U)makedefs.exe
#$(subst /,\,$(U)makedefs -v)

編集2それはうまくいきませんでした。date.h ファイルを手動で作成/更新する必要がある可能性はありますか? もしそうなら、私はそれに何を入れますか?Google への質問のように聞こえます...

EDIT 3私はこれをはるかに古いバージョンで見つけて変更しようとしましたが、どちらも機能しませんでした...

EDIT 4誰かがMakedefsについて言及しましたが、これはクラッシュしているようです。問題を引き起こしていると思われる C 関数を見つけました。

void
do_date()
{
    long clocktim = 0;
    char *c, cbuf[60], buf[BUFSZ];
    const char *ul_sfx;

    filename[0]='\0';
#ifdef FILE_PREFIX
    Strcat(filename,file_prefix);
#endif
    Sprintf(eos(filename), INCLUDE_TEMPLATE, DATE_FILE);
    if (!(ofp = fopen(filename, WRTMODE))) {
        perror(filename);
        exit(EXIT_FAILURE);
    }
    Fprintf(ofp,"/*\tSCCS Id: @(#)date.h\t3.4\t2002/02/03 */\n\n");
    Fprintf(ofp,Dont_Edit_Code);

#ifdef KR1ED
    (void) time(&clocktim);
    Strcpy(cbuf, ctime(&clocktim));
#else
    (void) time((time_t *)&clocktim);
    Strcpy(cbuf, ctime((time_t *)&clocktim));
#endif
    for (c = cbuf; *c; c++) if (*c == '\n') break;
    *c = '\0';  /* strip off the '\n' */
    Fprintf(ofp,"#define BUILD_DATE \"%s\"\n", cbuf);
    Fprintf(ofp,"#define BUILD_TIME (%ldL)\n", clocktim);
    Fprintf(ofp,"\n");
#ifdef NHSTDC
    ul_sfx = "UL";
#else
    ul_sfx = "L";
#endif
    Fprintf(ofp,"#define VERSION_NUMBER 0x%08lx%s\n",
        version.incarnation, ul_sfx);
    Fprintf(ofp,"#define VERSION_FEATURES 0x%08lx%s\n",
        version.feature_set, ul_sfx);
#ifdef IGNORED_FEATURES
    Fprintf(ofp,"#define IGNORED_FEATURES 0x%08lx%s\n",
        (unsigned long) IGNORED_FEATURES, ul_sfx);
#endif
    Fprintf(ofp,"#define VERSION_SANITY1 0x%08lx%s\n",
        version.entity_count, ul_sfx);
    Fprintf(ofp,"#define VERSION_SANITY2 0x%08lx%s\n",
        version.struct_sizes, ul_sfx);
    Fprintf(ofp,"\n");
    Fprintf(ofp,"#define VERSION_STRING \"%s\"\n", version_string(buf));
    Fprintf(ofp,"#define VERSION_ID \\\n \"%s\"\n",
        version_id_string(buf, cbuf));
    Fprintf(ofp,"\n");
#ifdef AMIGA
    {
    struct tm *tm = localtime((time_t *) &clocktim);
    Fprintf(ofp,"#define AMIGA_VERSION_STRING ");
    Fprintf(ofp,"\"\\0$VER: NetHack %d.%d.%d (%d.%d.%d)\"\n",
        VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL,
        tm->tm_mday, tm->tm_mon+1, tm->tm_year+1900);
    }
#endif
    Fclose(ofp);
    return;
}

また、コンパイルプロセスのこの時点に到達すると、すぐに次の画像が表示されます。 ここに画像の説明を入力

それで、問題を (私が思うに?) 問題を壊している makedefs ヘルパー プログラムに絞り込んだので、次のステップはその理由を見つけることだと思いますか?

編集 5 : Makedefs.c をコンパイルするときに特別なパラメーターを使用する必要があることが提案されています。Makefile を調べて、コンパイルが行われる場所を見つけました。コンパイルが行われている場所を見つけたと思いますが、ここで何が起こっているのかはよくわかりません。

$(U)makedefs.exe: $(MAKEOBJS)
    @$(link) $(LFLAGSU) -o$@ $(MAKEOBJS)

$(O)makedefs.o: $(CONFIG_H) $(INCL)/monattk.h $(INCL)/monflag.h \
     $(INCL)/objclass.h $(INCL)/monsym.h $(INCL)/qtext.h \
     $(INCL)/patchlevel.h $(U)makedefs.c $(O)obj.tag
    $(cc) $(CFLAGSU) -o$@ $(U)makedefs.c

私はそれ$(*)が変数または変数に相当する Makefile であることを知っています。

$(U)を指し$(UTIL)/、 を$(UTIL)指し../utilます。 $(MAKEOBJS)を指し$(O)makedefs.o $(O)monst.o $(O)objects.oます。 準成功した実行で観察した動作を考慮すると、これは理にかなっています (大きなフリーズ前にいくつかのファイルがコンパイルされます) $(O)$(OBJ)/o$(O)makedefs.oo/makedefs.o

とにかく、$(link)を指しgccます。 $(LFLAGSU)を指す を$(LFLAGSBASEC)指す を指す を指すを$(linkdebug)指す-g

$(CONFIG_H)多数のヘッダー ファイルを指します。

CONFIG_H = $(INCL)/config.h $(INCL)/config1.h $(INCL)/tradstdc.h \
           $(INCL)/global.h $(INCL)/coord.h $(INCL)/vmsconf.h \
           $(INCL)/system.h $(INCL)/unixconf.h $(INCL)/os2conf.h \
           $(INCL)/micro.h $(INCL)/pcconf.h $(INCL)/tosconf.h \
           $(INCL)/amiconf.h $(INCL)/macconf.h $(INCL)/beconf.h \
           $(INCL)/ntconf.h $(INCL)/nhlan.h

$(INCL)を指し../includeます。 $(CFLAGSU)を指し$(CFLAGSBASE) $(WINPFLAG)ます。 $(WIN32) を指す を$(CFLAGSBASE)指す-c $(cflags) -I$(INCL) $(WINPINC) $(cdebug) $(cflags)-mms-bitfields $(WINPINC)指すを指す を指すを指す を指す . . そして、そこにあります。RossRidge -D_USE_32BIT_TIME_T.-I$(WIN32)../win/win32 $(cdebug)-g $(WINPFLAG)-DTILES -DMSWIN_GRAPHICS -D_WIN32_IE=0x0400

しかし、私はここまで来たので、このようなもののいくつかが何を意味するのかを知りたいと思っています. 最初の行を見ると、$(U)makedefs.exe :. 私には、コンパイルされた出力ファイルのターゲットの宣言のように見えますか? あれは正しいですか?@また、 の前後の$(link) $(LFLAGSU)意味は何-o$ですか? $とはどういう意味-oですか?

とにかく、私が考え出したことを試して、それがまったく機能するかどうかを確認したいと思います. ...ああ、追加-D_USE_32BIT_TIME_TしてもうまくいきWINPFLAGませんでした。

最終(ish)編集: RossRidgeが-D_USE_32BIT_TIME_Tフラグを使用するという彼の提案で正しかったことがわかりました。私の間違いは、間違った場所に置いていました。同梱されている Makefile.gcc を見ると、165 行目 (IF ステートメント内) に注目してください。あなた-D_USE_32BIT_TIME_Tはその最後にタックしたい. しかし、その IF ステートメントの ELSE の最後にある 176 行目の最後にも追加する必要があります。そのため、代わりにブロック全体が次のようになります (大きな変更ではありませんが、変更を行わずに私の状況で実行している場合はクラッシュするほど重要です):

################################################
#                                              #
# Nothing below here should have to be changed.#
#                                              #
################################################

ifeq  "$(GRAPHICAL)" "Y"
WINPORT  = $(O)tile.o $(O)mhaskyn.o $(O)mhdlg.o \
    $(O)mhfont.o $(O)mhinput.o $(O)mhmain.o $(O)mhmap.o \
    $(O)mhmenu.o $(O)mhmsgwnd.o $(O)mhrip.o $(O)mhsplash.o \
    $(O)mhstatus.o $(O)mhtext.o $(O)mswproc.o $(O)winhack.o
WINPFLAG   = -DTILES -DMSWIN_GRAPHICS -D_WIN32_IE=0x0400 -D_USE_32BIT_TIME_T
NHRES   = $(O)winres.o
WINPINC = -I$(WIN32)
WINPHDR = $(WIN32)/mhaskyn.h $(WIN32)/mhdlg.h $(WIN32)/mhfont.h \
    $(WIN32)/mhinput.h $(WIN32)/mhmain.h $(WIN32)/mhmap.h \
    $(WIN32)/mhmenu.h $(WIN32)/mhmsg.h $(WIN32)/mhmsgwnd.h \
    $(WIN32)/mhrip.h $(WIN32)/mhstatus.h \
    $(WIN32)/mhtext.h $(WIN32)/resource.h $(WIN32)/winMS.h
WINPLIBS =  -lcomctl32 -lwinmm
else
WINPORT = $(O)nttty.o
WINPFLAG= -DWIN32CON -D_USE_32BIT_TIME_T
WINPHDR =
NHRES   = $(O)console.o
WINPINC =
WINPLIBS = -lwinmm
endif
4

1 に答える 1

4

(ハリー・ジョンストンと個人のコメントがなければ問題が何であるかを認識できなかったので、回答の功績に値するかどうかはわかりませんが、コメントを完全な回答に拡大しようとします。)

indiv説明したように、クラッシュする理由はmakedefs.exeNULL をctime返すためです。通常、これを行うことは想定ctimeしていないため、ドキュメントを確認して、どのような状況でエラーが返されるかを確認する必要があります。コンパイルには MinGW が使用されているため、Microsoft の Visual C++ のドキュメントを参照する必要があります。これは、MinGW には独自の C ランタイムがなく、Microsoft のランタイムを使用しているためです。

Visual Studio C ランタイム ライブラリ リファレンスのエントリを見ると、次のctimeことがわかります。

戻り値

文字列結果へのポインター。NULL次の場合に返されます。

  • time は、1970 年 1 月 1 日の午前 0 時 (UTC) より前の日付を表します。
  • _ctime32またはを使用_wctime32し、time が 2038 年 1 月 19 日 03:14:07 より後の日付を表す場合。
  • _ctime64またはを使用_wctime64し、time が UTC 3000 年 12 月 31 日 23:59:59 より後の日付を表す場合。

これで、元の投稿者がシステム クロックを遠い未来または過去の時刻に設定していないと想定するのはかなり安全です。では、なぜctime間違った時間を使用するのでしょうか? longHarry Johnston さんは、コードが時間の値を格納する代わりにを使用していることを指摘しtime_tました。これはそれほど驚くべきことではありません。Nethack は非常に古いコードであり、元来 Unix はその時間をlong値に格納し、time_t時間の値を後で使用していました。time_tNethackは、活発な開発期間のかなりの期間を持たなかった古いシステムを扱わなければならなかったでしょう。

これは、Nethack ソースが間違った型を使用している理由を説明していますが、間違った値を に渡している理由を完全には説明していませんctimectimeそれ自体の戻り値の説明が表示されないという事実は、手がかり_ctime32を与えてくれます。が 64 ビット型の場合、代わりに使用_ctime64すると問題が発生します。Windows では32 ビットしかないため、1 つの部分が時間値で、もう 1 つの部分がランダム ビットである数値が渡されることを意味します。ドキュメントを読むと、これが事実であることが確認され、可能な解決策が得られます。time_tlonglongctime

ctime_ctime64に評価され、time_tと同等 のインライン関数__time64_tです。コンパイラに強制的time_tに古い 32 ビット として解釈さ せる必要がある場合time_tは、 を定義できます_USE_32BIT_TIME_T。これを行うと、 がctimeに評価され_ctime32ます。アプリケーションが 2038 年 1 月 18 日以降に失敗する可能性があり、64 ビット プラットフォームでは許可されないため、これはお勧めできません。

定義_USE_32BIT_TIME_Tは C ヘッダーのコンパイル方法にのみ影響し、MinGW は独自の C ヘッダーを提供するため、MinGW がこれをサポートしていない可能性があります。MinGW を簡単にチェックするとtime.h、そうであることがわかります。そのため、-D_USE_32BIT_TIME_Tコンパイラ オプションを使用してこのマクロを定義するという簡単な解決策があります。

于 2014-08-06T00:51:24.567 に答える