1

In expansion to my previous question how to write a makefile for structured file system:

The file structure:

.
├── Headers
│   ├── function.h
│   └── test.h
├── makefile
├── README.md
└── Sources
    ├── function.c
    ├── main.c
    └── test.c

I'm trying to write a makefile that reads the #include<...> on any given source file and compile as required.

Originally I used to have a make file that looked like this:

INC_DIR = Headers
SRC_DIR = Sources
OBJ_DIR = Objects
#CXXFLAGS = -c -Wall -I. -IHeaders
CXXFLAGS = -c -Wall -I. -IHeaders
CC = gcc

SRCS = $(SRC_DIR)/*.c 
OBJS = $(OBJ_DIR)/*.o
#The wildcard and patsubt commads will come handy

DEPS = $(INC_DIR)/*.h
#need to use an automatic dependency generator

output: $(OBJ_DIR)/main.o $(OBJ_DIR)/function.o
    $(CC) $^ -o $@

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(DEPS)
    $(CC) $(CXXFLAGS) $< -o $@


run: output
    ./output

clean: 
    rm $(OBJ_DIR)/*.o 
    rm output
-@echo "Clean completed"

That meant that for every source file that output was dependent on i had to add that object to this line.

output: $(OBJ_DIR)/main.o $(OBJ_DIR)/function.o $(OBJ_DIR)/test.o
    $(CC) $^ -o $@

And is any other source file was dependent on one or more sources additional rules had to be added.

To solve this: here is what I have gathered from Auto-Dependency Generation and 4.14 Generating Prerequisites Automatically

As mentioned by the community members, I have a mixed understanding of dependency generation and how to make use of the files generated.

DEP_DIR = .d
$(shell mkdir -p $(DEP_DIR) >/dev/null)

DEPFLAGS = -MT $@ -MMD -MP -MF $(DEP_DIR)/$*.Td

INC_DIR = Headers
SRC_DIR = Sources
OBJ_DIR = Objects
$(shell mkdir -p $(OBJ_DIR) >/dev/null)
CXXFLAGS = -c -Wall -I. -IHeaders
CC = gcc

SRCS = $(SRC_DIR)/*.c 
OBJS = $(OBJ_DIR)/*.o
#The wildcard and patsubt commads will come handy

#DEPS = $(INC_DIR)/*.h

MAKEDEPEND = $(CC) $(CXXFLAGS) $< \
               | sed -n 's/^\# *[0-9][0-9]* *"\([^"]*\)".*/$*.o: \1/p' \
               | sort | uniq > $*.Td

COMPILE.c = $(CC) $(DEPFLAGS) $(CXXFLAGS)
#need to use an automatic dependency generator

#%.d: %.c
#   @set -e; rm -f $@; \
#   $(CC) -MP -MD $(CXXFLAGS) $< > $@.$$$$; \
#   sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
#   rm -f $@.$$$$

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(DEP_DIR)/%.d
    @$(MAKEDEPEND); \
    cp $*.Td $*.d; \
    sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
    -e '/^$$/ d' -e 's/$$/ :/' < $*.Td >> $*.d; \
    rm -f $*.Td
    #$(COMPILE.c) -o $@ $<  
    $(CC) $(CXXFLAGS) $(DEPFLAGS) $< -o $@

-include $(SRCS:.c=.d)

$(DEP_DIR)/%.d: ;
.PRECIOUS: $(DEP_DIR)/%.d

output: $(OBJS)
    $(CC) $^ -o $@

run: output
    ./output

clean: 
    rm -r $(OBJ_DIR) 
    rm -r $(DEP_DIR) 
    rm output
    -@echo "Clean completed"

The error when make is executed is:

$ make
gcc -c -Wall -I. -IHeaders -MT Objects/*.o -MMD -MP -MF .d/*.Td Sources/function.c -o Objects/*.o
gcc Objects/*.o -o output
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
makefile:48: recipe for target 'output' failed
make: *** [output] Error 1

So, I'm hoping to achieve the auto dependency detection and compilation. I think the error is in the way that the dependencies are detected and the way they are generated for a given source file.

Community
  • 1
  • 1
Amir
  • 101
  • 1
  • 1
  • 9
  • 2
    What is your question? – Mike Kinghan Nov 27 '16 at 10:32
  • As the title says! and the makefile that I've written doesn't work – Amir Nov 27 '16 at 12:40
  • "Doesn't work" is not a useful problem description. Also, SO is not a place where you post a bunch of code and ask for people to fix it for you. SO is a place where you come for an answer to a specific question, after you've tried to answer it yourself. In the above I'll just point out that your uncommented version of `MAKEDEPEND` is completely wrong: you are invoking the C compiler with normal flags which tell it to create an object file, not generate dependencies. You might also try reading http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/ – MadScientist Nov 27 '16 at 15:48
  • @MadScientist I have read that article and had reference to it in my post. Plus I have tried to solve my problem MYSELF first but i didn't get anywhere! Would you kindly help here? – Amir Nov 27 '16 at 16:06
  • I did help: I requested you create a question that can be answered, which means showing which part of the makefile you think is wrong, why you think it is wrong (show the command you typed and the result you got and, if it's not obvious, why you think that result is wrong). Posting a big makefile and saying "it doesn't work" without any other details is not a useful question. – MadScientist Nov 27 '16 at 19:36
  • Just FYI, `CXXFLAGS` by convention contains C++ compiler flags. If you're compiling C code you should be using `CFLAGS` instead. – MadScientist Nov 27 '16 at 19:37

1 Answers1

0

It looks to me like you're trying to combine multiple different ways of generating dependency info, and that can't work. The advanced post talks about multiple ways to solve the problem: you need to pick one not try to use them all together.

If you want to use the advanced method then use it as described in the "TL;DR" section at the top, or else in the "Combining Compilation and Dependency Generation" section at the bottom. If you're using GCC there's no need for MAKEDEPEND, sed, etc.

The advanced post says that your rule should look like this:

COMPILE.c = $(CC) $(DEPFLAGS) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
POSTCOMPILE = mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d

%.o : %.c
%.o : %.c $(DEPDIR)/%.d
        $(COMPILE.c) $(OUTPUT_OPTION) $<
        $(POSTCOMPILE)

That's it.

MadScientist
  • 92,819
  • 9
  • 109
  • 136