c - 如何在Windows 7中编译NetHack?

标签 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自述文件,指示似乎很明确。但是,由于我没有进行任何更改,所以我不知道为什么它无法编译...

我认为自己是一个能干的程序员,但是我几乎不了解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的问题...

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

我还要提到在编译过程中达到这一点时,立即出现以下图像:

因此,我们已经将问题(我认为是)缩小到了可以解决问题的makedefs helper程序中,所以现在我想下一步应该是找出原因?

编辑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)
$(INCL)指向大量头文件:
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
../include指向$(CFLAGSU)$(CFLAGSBASE) $(WINPFLAG)指向$(CFLAGSBASE)
-c $(cflags) -I$(INCL) $(WINPINC) $(cdebug)指向$(cflags) -mms-bitfields指向$(WINPINC) -I$(WIN32)指向../win/win32 $(WIN32)指向$(cdebug) -g指向$(WINPFLAG) -DTILES -DMSWIN_GRAPHICS -D_WIN32_IE=0x0400指向$(U)makedefs.exe :。 。 。
在那里。我认为这是我需要修改以使其与RossRidge -D_USE_32BIT_TIME_T提到的内容一起使用的功能。

但是,既然我走了那么远,我确实想弄清楚这些东西的含义。
当看第一行时,我看到@。对我来说,这似乎是已编译输出文件的目标的声明?那是对的吗?另外,在$(link) $(LFLAGSU)之前和之后-o$的含义是什么? $之后的-o是什么意思?

无论如何,我想尝试一下我想出的方法,看看它是否可以工作。
... Aaaand将-D_USE_32BIT_TIME_T添加到WINPFLAG不起作用。

最终编辑:原来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

最佳答案

(我不知道我的答案是否值得,因为没有哈里·约翰斯顿(Harry Johnston)和个人的评论,我不会知道问题出在哪里,但我会尝试将评论扩展成一个完整的答案。)

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

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

Return Value

A pointer to the character string result. NULL will be returned if:

  • time represents a date before midnight, January 1, 1970, UTC.
  • If you use _ctime32 or _wctime32 and time represents a date after 03:14:07 January 19, 2038.
  • If you use _ctime64 or _wctime64 and time represents a date after 23:59:59, December 31, 3000, UTC.


现在可以很安全地假设原始发布者尚未将他的系统时钟设置为遥远的将来或过去的很长时间。那么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 is an inline function which evaluates to _ctime64 and time_t is equivalent to __time64_t. If you need to force the compiler to interpret time_t as the old 32-bit time_t, you can define _USE_32BIT_TIME_T. Doing this will cause ctime to evaluate to _ctime32. This is not recommended because your application may fail after January 18, 2038, and it is not allowed on 64-bit platforms



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

关于c - 如何在Windows 7中编译NetHack?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25127159/

相关文章:

visual-c++ - 代码可以在一个Visual Studio C++项目中运行,而在另一个项目中则不能

java - setDisplayHomeAsUpEnabled()错误: non-static method cannot be referenced from a static context

c - 互斥文件读取同步

python - python 多处理函数返回多个输出

windows-7 - Windows 7 EXE 文件名以 "Patch"开头,无法运行

windows-7 - Windows 7 中缺少 makecert.exe,如何获取和使用它

c - 当我向它添加 0.1 时, float 不会改变

我可以在没有 sudo 的情况下运行包含 setuid() 的 C 程序吗?

c - 如果字符指针指向的只读存储器不是连续的,那么它们如何工作?

kotlin getparameters函数不起作用