为什么在 Windows 上使用 dirent.h 时会出现不完整的类型错误?

Why am I getting an incomplete type error when using dirent.h on Windows?

我有一个结合了多个 .c 和 .h 文件的 C 项目。以前我只是将所有这些文件以及以下 Makefile 放在顶级目录中:

O = o
E =
CC = gcc
OUT = cusum$E
CFLAGS = -D_GNU_SOURCE -O3 -Wall -Wextra --static
DEPS = bessel.h detector.h io.h stepfit.h lmmin_int64.h utils.h
ODIR = obj
_OBJ = main.$O bessel.$O detector.$O io.$O lmmin_int64.$O stepfit.$O utils.$O
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
LIBS = -lm

$(ODIR)/%.$O: %.c $(DEPS)
    $(CC) -c -o $@ $< $(CFLAGS) $(LIBS)

$(OUT): $(OBJ)
    $(CC) -o $@ $^ $(CFLAGS) $(LIBS)

.PHONY: clean win

clean:
    rm -f $(OUT) $(ODIR)/*.$O *~ core $(INCDIR)/*~
    rm -f $(OUT).exe w$(ODIR)/*.obj *~ core $(INCDIR)/*~

win:
    $(MAKE) CC=x86_64-w64-mingw32-gcc E=.exe O=obj ODIR=wobj

据我所知,这工作正常。

然后我重新组织了一些东西,将 .c 文件放在 src 文件夹中,将 .h 文件放在 lib 文件夹中。我将 Makefile 更改为以下内容:

O = o
E =
CC = gcc
OUT = dist/cusum$E
CFLAGS = -D_GNU_SOURCE -O3 -Wall -Wextra --static
INCDIR = lib/
DEPS = lib/*.h
ODIR = build/obj
_OBJ = main.$O bessel.$O detector.$O io.$O lmmin_int64.$O stepfit.$O utils.$O
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
LIBS = -lm

$(ODIR)/%.$O: src/%.c $(DEPS)
    $(CC) -c -o $@ $< $(CFLAGS) -I$(INCDIR) $(LIBS)

$(OUT): $(OBJ)
    $(CC) -o $@ $^ $(CFLAGS) -I$(INCDIR) $(LIBS)

.PHONY: clean win cleanwin

clean:
    rm -f $(OUT) $(ODIR)/*.$(O) *~ core $(INCDIR)/*~

win:
    $(MAKE) CC=x86_64-w64-mingw32-gcc E=.exe O=obj ODIR=build/wobj
    
cleanwin:
    $(MAKE) clean CC=x86_64-w64-mingw32-gcc E=.exe O=obj ODIR=build/wobj

现在,当我为 Linux (make) 编译时,它工作正常。当我为 windows (make win) 交叉编译时,出现以下错误:

`make[1]: Entering directory '[...]'

x86_64-w64-mingw32-gcc -c -o build/wobj/main.obj src/main.c -D_GNU_SOURCE -O3 -Wall -Wextra --static -Ilib/ -lm

In file included from lib/io.h:31:0,
                 from src/main.c:21:

/usr/share/mingw-w64/include/dirent.h:41:21: error: field ‘dd_dta’ has incomplete type
  struct _finddata_t dd_dta;
                     ^~~~~~

/usr/share/mingw-w64/include/dirent.h:88:22: error: field ‘dd_dta’ has incomplete type
  struct _wfinddata_t dd_dta;

`

main.c 通过以下方式包含所有库:

#include"lib1.h"
#include"lib2.h"
....

并且位于 src 文件夹中

如果我 return 将文件夹结构恢复到原来的样子并使用旧的 Makefile,它可以正常工作并测试,所以我认为问题出在 Makefile 而不是代码本身。谁能指出我正确的方向?如果缺少任何信息,请告诉我,以便我进行修复。

所以 windows 版本的 MinGW 似乎有一些定义问题。添加到我的 include/dirent.h 编译器版本中的以下代码为我解决了这个问题。编辑库函数一般来说可能不是一个好主意,所以只有当你喜欢冒险时才使用它......我没有声称这不会破坏其他地方的所有东西。

#ifndef _FSIZE_T_DEFINED
typedef unsigned long   _fsize_t;
#define _FSIZE_T_DEFINED
#endif

struct _finddata_t
{
    unsigned    attrib;     /* Attributes, see constants above. */
    time_t      time_create;
    time_t      time_access;    /* always midnight local time */
    time_t      time_write;
    _fsize_t    size;
    char        name[FILENAME_MAX]; /* may include spaces. */
};

struct _wfinddata_t
{
    unsigned    attrib;     /* Attributes, see constants above. */
    time_t      time_create;
    time_t      time_access;    /* always midnight local time */
    time_t      time_write;
    size_t  size;
    wchar_t     name[FILENAME_MAX]; /* may include spaces. */
};

文件 io.h 中的原因。当您将 io.h 移动到子目录时,dirent.h 想要包含您的文件而不是系统文件。

#include <io.h>

要解决这种情况,只需重命名您的 io.h。