user8010471
user8010471

Reputation:

C Makefile - subdirectories for different file endings

I'm currently trying to work out a Makefile that I could use for multiple projects without the need to change it for every single project. However I recently began programming in C and making Makefiles

This is my current project structure.

project
 | src
   | gd.c, gd.h, geom.c(only file with main function)
 | obj // *.o files should be created here
 | bin // executable should be created here
 | Makefile

This is what I have build so far, but am not sure at all how to specify the subdirectories for the compiled/linked files.

 1  TARGET = projectname
 2  LIBS = -lm
 3  CC = gcc
 4  CFLAGS  = -std=c11 -Wall 
 5  LD = gcc
 6  LDFLAGS = -Wall 
 7
 8  SRCDIR = src
 9  OBJDIR = obj
10  EXEDIR = bin 
11  
12  SOURCES = 
13  HEADERS = 
14  OBJECTS = 
15 
16  $(EXEDIR)/$(TARGET): $(OBJECTS)
17      $(LD) $(OBJECTS) $(LDFLAGS) -o $@ $(LIBS)
18 
19  $(OBJECTS): $(SOURCES) $(HEADERS)
20      $(CC) $(CFLAGS) -c $< -o $@
21 
22  .PHONY: clean
23  clean:
24      rm -f *.o
25 
26  .PHONY: remove
27  remove: clean
28      rm -f $(EXEDIR)/$(TARGET)

My Question would be:

  1. How can I create these files and put them in their respective subdirectory with my layout or something similar to it?
  2. Is it possible to create the necessary folders(obj and bin) when using the make command and if so how can I do it?

Upvotes: 0

Views: 167

Answers (1)

pinam45
pinam45

Reputation: 639

If I understand well, you want to know - in your layout - how to set SOURCES, HEADERS and OBJECTS values that will make your Makefile work.

For this you can use regular expressions:

SOURCES = $(wildcard $(SRCDIR)/*.c)
OBJECTS = $(patsubst $(SRCDIR)/%.c,$(OBJDIR)/%.o,$(SOURCES))
HEADERS = $(patsubst %.c,%.h,$(SOURCES))

wildcard documentation here

patsubst documentation here

This is a simple answer, if you want to create a fully reusable Makefile you will have to deal with sources subfolders for example.

The rule to create the objects is strange (maybe it works). I think it is better if you use a rule to create one object with one source at a time, something like:

$(OBJDIR)/%.o: $(SRCDIR)/%.c
    $(CC) $(CFLAGS) -c $< -o $@

In this case the SOURCES variable become useless.

Moreover the HEADERS variable is useless I think, because in the compilation process you don't give to gcc the headers but the headers folder with gcc ... -I<headers folder>

And your clean should be rm -f $(OBJDIR)/*.o to delete the object files in the obj folder

Edit

I forgot the second question, you can use the shell commands to create the folder just before the file creation:

$(OBJDIR)/%.o: $(SRCDIR)/%.c
    @mkdir $(OBJDIR)
    $(CC) $(CFLAGS) -c $< -o $@

Upvotes: 1

Related Questions