Search code examples
cmakefilenmake

Makefile cycle in dependency tree


I am trying to build my c project on windows using a makefile and nmake.

I get the following error: NMAKE : fatal error U1071: cycle in dependency tree for target 'src\source.c' Stop.

The full makefile is this

CC = cl
LINK = link
CFLAGS = /Ox \
/I ext\MulticoreBSP-for-C\ \
/I ext\unistd\include \
/I ext\pthreads-win32\sources\pthreads-w32-2-9-1-release \
/D HAVE_STRUCT_TIMESPEC

SOURCE_DIR = src
OBJECT_DIR = build

LIBS = ext\pthreads-win32\sources\pthreads-w32-2-9-1-release\pthreadVC2.lib

DLLS = bin\pthreadVC2.dll
DLLS_SRC = ext\pthreads-win32\sources\pthreads-w32-2-9-1-release\pthreadVC2.dll

BSP_SOURCES = ext\MulticoreBSP-for-C\mcbsp.c ext\MulticoreBSP-for-C\mcinternal.c ext\MulticoreBSP-for-C\mcutil.c
USER_SOURCES = source.c

SOURCES = src\$(USER_SOURCES) $(BSP_SOURCES)
OBJECTS = $(SOURCES:*.c=build\*.obj)
# OBJECTS = build\source.obj build\mcbsp.obj build\mcinternal.obj  build\mcutil.obj
EXECUTABLE = bin\BSP.exe

all: $(EXECUTABLE) $(DLLS) $(OBJECTS)

$(EXECUTABLE): $(OBJECTS)
    $(LINK) $(OBJECTS) $(LIBS) /OUT:$(EXECUTABLE)

$(DLLS): $(DLLS_SRC)
    copy $** $@

$(OBJECTS): $(SOURCES)
    $(CC) $(LDFLAGS) /c /Fo.\$(OBJECT_DIR)\ $@ $** $(CFLAGS)

clean:
    del $(OBJECT_DIR)\*.obj bin\*.dll bin\*.exe

I can see that the issue comes from defining OBJECTS in line 21 as OBJECTS = $(SOURCES:*.c=build\*.obj) and then having the rule $(OBJECTS): $(SOURCES). The fact that this is cyclic is fairly clear, and using the commented definition of OBJECTS in line 22 works fine.

How can I achieve an automatic definition of OBJECTS without the rule at line 33 causing trouble? Do I need a different rule, or something else?

(I have separate folders for the source files and the objects, and I think having that prevents me from using a simple rule like .c.obj:. At least, I haven't got it to work using something of that form).

Thanks.


Solution

  • Although the pattern matching syntax $(macroname:string1=string2)is supported by nmake, use of wildcards in this way is not. I will edit this answer if I find a way to use wildcards in nmake's version of string substitution.

    Edit:

    Its a little dodgy, but the following solves the problem

    BSP_SOURCES = mcbsp.c mcinternal.c mcutil.c
    USER_SOURCES = source.c
    
    SOURCES = src\$(USER_SOURCES) ext\MulticoreBSP-for-C\$(BSP_SOURCES: = ext\MulticoreBSP-for-C\)
    _OBJECTS = build\$(USER_SOURCES) build\$(BSP_SOURCES: = build\)
    OBJECTS = $(_OBJECTS:.c=.obj)
    

    Basically, pattern matching the spaces inbetween the elements in the list of sources, rather than using a wildcard. Note that the first prefix is added outside of the pattern match, because there is no space at the start of the list. Also note that the substitution had to be done in two steps.

    Inelegant but effective.