如何在Windows 7中编译NetHack?

时间:2014-08-04 20:40:41

标签: c windows-7 compiler-errors mingw nethack

我喜欢NetHack,我希望能够对源有所了解。 在我这样做之前,我希望能够开箱即用,但是我可以轻松地实现这一目标。

我从here下载了源代码,然后按照here的说明操作,但它没有用。

我最终得到以下

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

我看着它正在谈论的那条线,但它并没有真正告诉我任何事情。我注意到在include目录中创建的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文件?如果是这样,我该怎么做?听起来像谷歌的问题......

编辑3 我找到了this版本较旧的版本,并尝试对其进行更改,但它也没有...

编辑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;
}

另外我应该提一下,当它在编译过程中达到这一点时,立即出现这个图像: enter image description here

所以我们已经把问题(我认为?)缩小到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)。     $(CFLAGSBASE)指向-c $(cflags) -I$(INCL) $(WINPINC) $(cdebug)         $(cflags)指向-mms-bitfields         $(WINPINC)指向-I$(WIN32)             $(WIN32)指向../win/win32         $(cdebug)指向-g      $(WINPFLAG)指向-DTILES -DMSWIN_GRAPHICS -D_WIN32_IE=0x0400。 。 。 它就是。我认为我需要修改以使其与RossRidge -D_USE_32BIT_TIME_T提到的内容一起工作。

然而,既然我已经到了那么远,我想知道这些东西是什么意思。 查看第一行时,我看到$(U)makedefs.exe :。对我来说,似乎是编译输出文件的目标声明?那是对的吗?此外,@之前和$(link) $(LFLAGSU)之后-o$的含义是什么? $之后-o的含义是什么?

无论如何,我想尝试我想出来的东西,看看它是否有效。 ...将-D_USE_32BIT_TIME_T添加到WINPFLAG的Aaaand无法正常工作。

FINAL(ish)编辑:结果显示RossRidge在使用-D_USE_32BIT_TIME_T标志的建议中是正确的。我的错误是把它放在了错误的地方。如果您查看框中的Makefile.gcc,请查看第165行(在IF语句中)。你希望在结尾处追上-D_USE_32BIT_TIME_T。但是你也想在第176行的末尾添加它,该行位于IF语句的ELSE末尾。所以整个块看起来都是这样的(不是一个巨大的变化,但仍然足够重要,如果你不做它并且你在我的情况下运行就会崩溃):

################################################
#                                              #
# 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

1 个答案:

答案 0 :(得分:4)

(我不知道我是否应该得到答案,因为如果没有Harry Johnston和indiv的评论,我不会意识到问题是什么,但我会尝试将评论扩展为完整的答案。)

正如indiv所解释的那样,makedefs.exe崩溃的原因是因为ctime返回NULL。通常你不希望ctime这样做,所以我们需要查看文档,找出它会在什么情况下返回错误。由于MinGW用于编译,我们需要查看Microsoft的Visual C ++文档。这是因为MinGW没有它自己的C运行时,它只使用了Microsoft的。

查看ctime的Visual Studio C运行时库参考条目,我们发现:

  

返回值

     

指向字符串结果的指针。如果符合以下条件,我们将退回NULL

     
      
  • 时间表示1970年1月1日午夜UTC之前的日期。
  •   
  • 如果您使用_ctime32_wctime32,则时间代表2038年1月19日03:14:07之后的日期。
  •   
  • 如果您使用_ctime64_wctime64,则时间代表3000年12月31日23:59:59之后的日期。
  •   

现在可以非常安全地假设原始海报没有将系统时钟设置为远未来或过去的时间。那么为什么ctime会使用错误的时间呢? Harry Johnston指出代码使用long代替time_t来存储时间值。这并不太令人惊讶。 Nethack实际上是旧代码,最初Unix将其时间存储在long值中,后来使用time_t时间值。 Nethack将不得不处理那些没有time_t的旧系统,以便在其活跃的开发阶段进行大量工作。

这解释了为什么Nethack源使用了错误的类型,但它并没有完全解释为什么它将错误的值传递给ctime。我们没有看到ctime本身的返回值的描述,只有_ctime32_ctime64这一事实为我们提供了线索。如果time_t是64位类型,则使用long代替将是一个问题。在Windows long上只有32位,因此它意味着ctime传递的是一个部分时间值的数字,一部分是随机位。阅读文档证实了这种情况,并为我们提供了一个可能的解决方案:

  

ctime是一个内联函数,其计算结果为_ctime64,而time_t相当于   __time64_t。如果您需要强制编译器将time_t解释为旧的32位   time_t,您可以定义_USE_32BIT_TIME_T。执行此操作将导致ctime进行评估   到_ctime32。建议不要这样做,因为您的应用程序可能在1月后失败   18,2038,并且不允许在64位平台上使用

现在,由于定义_USE_32BIT_TIME_T仅影响C头的编译方式,并且由于MinGW提供了自己的C头,因此MinGW可能不支持这一点。快速检查MinGW的time.h会发现它确实存在,因此使用-D_USE_32BIT_TIME_T编译器选项来定义此宏的简单解决方案。