Search code examples
cmakefiledirectory-structure

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


I have a C project that combines multiple .c and .h files. Previously I just had all of these files in the top level directory, along with the following 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

This works fine as far as I can tell.

I then reorganized things, putting the .c files in a src folder and the .h files in a lib folder. I changed the Makefile to the following:

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

Now, when I compile for Linux (make), it works OK. When I cross-compile for windows (make win), I get the following error:

`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 includes all the libraries via:

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

and is located in the src folder

If I return the folder structure to what it was before and use the old Makefile, it works and tests fine, so I think the issue lies in the Makefile rather than the code itself. Can anyone point me in the right direction? If any information is missing, please let me know so I can fix it.


Solution

  • The reason in file io.h. When you moved io.h to subdirectory, dirent.h wants to include your file instead of system one.

    #include <io.h>
    

    To resolve this situation, just rename your io.h.