4

I am trying to implement a makefile for my C project which has a directory structure as follows:

PROJECT_FOLDER:
    folder1
    folder2
    folder // n number of folders
    main.c

FOLDER1:
    subfolder1
    subfolder // n number of subfolders

And subfolder 1 can have further subfolders etc.. etc..

I don't intend on being stupid with my directory structure, the deepest I may go is 1-2 MAYBE 3.

Thus far I have:

# A Makefile to build our First_Game_2 project

dirs = * */parse

PROJECT =  main
HEADERS =  $(PROJECT).h
OBJ     =  $(foreach dirz, $(dirs), \
        \
        $(patsubst %.c,%.o,$(wildcard $(dirz).c)) \
        \
    )

C99     =  gcc -std=c99
CFLAGS  =  -Wall -pedantic -Werror 

$(PROJECT) : $(OBJ)
        $(C99) $(CFLAGS) -o $(PROJECT) $(OBJ)


%.o : %.c $(HEADERS)
        $(C99) $(CFLAGS) -c $<

clean:
        rm -f $(PROJECT) $(OBJ)

My problem is if parse contains a subfolder, say test to give the structure

PROJECT_FOLDER/parse/test

In such a case, nothing is returned from

$(foreach dirz, $(dirs), \
        \
        $(patsubst %.c,%.o,$(wildcard $(dirz).c)) \
        \
    )

I tested the output of the function with the following makefile

# A Makefile to build our First_Game_2 project

dirs = * */parse

PROJECT =  main
HEADERS =  $(PROJECT).h
OBJ     =  

C99     =  gcc -std=c99
CFLAGS  =  -Wall -pedantic -Werror 

$(foreach dirz, $(dirs), \
        \
        $(patsubst %.c,%.o,$(wildcard $(dirz).c)) \
        \
    )

Which, given a structure of:

dirs = * */parse */parse/test

Produces an output of:

main.o parse/parse.o

Ignoring */parse/test

Why is this the case, what can I do to fix my OBJ assignment to recognize */parse/test or otherwise?

1
  • What make is it? Incredible, but there are waaaaay more make variants out there than RMS wants to make us believe ;) Feb 22, 2013 at 20:29

1 Answer 1

5

You have the wildcard in the dirs pattern backward. You wanted:

dirs = * parse/* parse/test/*

As written, your pattern above expanded to: *.c (good), */parse.c (lucky!), and */parse/test.c, which would have confused you even more if that file existed. The only reason it looked like it worked for the first level directory is because you used the same filename, 'parse', as the directory name.

5
  • I think VPATH, assuming GNU make` might also make a difference here. But so far I always went with schemes such as $(wildcard ...) or $(shell find -...) to include the correct files. One just has to be careful if out-of-tree builds are intended. +1 Feb 22, 2013 at 20:50
  • @ckchan oh wow, that's was silly of me :S - It seems my clean function isn't being implemented now, as I was hoping to replace $(OBJ) with my ~$(foreach` logic, any ideas why clean: isn't running?
    – tsujp
    Feb 23, 2013 at 5:37
  • @tsujp: seems like that would be unrelated to clean; if it's really not running at all, make sure it isn't something obvious like a file/dir called "clean". If not, try make -d to get more detail on what make is considering.
    – ckhan
    Feb 23, 2013 at 6:12
  • It seems that having a file main.h results in object files being created in the root directory, no matter what directory they come from. E.g. main.o and parse.o are inside the same folder instead of parse.o being inside the parse folder. Conversely renaming main.h to say... includes.h results in ISO C90 warnings, even though I clearly state -std=c99. The makefile is UNCHAINED except for your answer. As for clean near this line from make -d : Successfully remade target file main'.` there is no mention of clean, neither does scrolling through the terminal. This is annoying.
    – tsujp
    Feb 23, 2013 at 6:43
  • Or you use: dirs = * */* */*/* then it is recursive, but only 3 levels deep...
    – karelv
    Sep 24, 2018 at 14:43

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .