How to write a template rule to separate where the object and source files are?

Suppose I have a directory structure such as:

./Header
./Srcs
./makefile

The contents of the folder ./Header/are two header files:

header1.h

#ifndef HEADER1_H
#define HEADER1_H
#include <stdio.h>

void func1();

#endif

header2.h

#ifndef HEADER2_H
#define HEADER2_H
#include <stdio.h>

void func2();

#endif

In ./Srcs/I have the following srcs:

src1.c

#include <header1.h>

void func1() {
   printf("func1()\n");
}

src2.c

#include <header2.h>

void func2() {
   printf("func2()\n");
}

main.c

#include <header1.h>
#include <header2.h>

int main(int argc, char** argv) {
   func1();
   func2();
   return 0;
}

Finally, the makefile looks like this:

CC=gcc
INCLUDE=-I./Header/
SRC_DIR=./Srcs/
SRC_LIST=$(addprefix $(SRC_DIR), main.c src1.c src2.c)
OBJ_LIST=$(addsuffix .o, $(basename $(SRC_LIST)))
OUTPUT=test

%.o : %.c
    $(CC) -c $< -o $@ $(INCLUDE)

all : $(OBJ_LIST)
    $(CC) -o $(OUTPUT) $(OBJ_LIST)

clean : $(OUTPUT) $(OBJ_LIST)
    rm -r $(OUTPUT) $(OBJ_LIST)

Executing the make file:

gcc -c Srcs/main.c -o Srcs/main.o -I./Header/
gcc -c Srcs/src1.c -o Srcs/src1.o -I./Header/
gcc -c Srcs/src2.c -o Srcs/src2.o -I./Header/
gcc -o test ./Srcs/main.o ./Srcs/src1.o ./Srcs/src2.o

In particular, due to the template rule that I used, all the object files are generated in the folder ./Srcs/, what I would like to do is put all the object files in the directory where the final output will be, in my specific example the final output will be in the same directory where the makefile is located.

How can I write my makefile to achieve this?

+4
2

, , :

#PROJDIR is the folder where your Makefile is
PROJDIR := $(realpath $(CURDIR)/..)

#SOURCEDIR is the root folder where your sources sub-folder ares
SOURCEDIR := $(PROJDIR)/Sources

#BUILDDIR is the root folder where your objects will be
BUILDDIR := $(PROJDIR)/Build

#DIRS are the sub-folder, e.g. Sources/Folder1 and Build/Folder1
DIRS = Folder0 Folder1 Folder2

#Here we create a list of source and builder folders with full path
SOURCEDIRS = $(foreach dir, $(DIRS), $(addprefix $(SOURCEDIR)/, $(dir)))
TARGETDIRS = $(foreach dir, $(DIRS), $(addprefix $(BUILDDIR)/, $(dir)))

#We allow GNU make to search for the sources in all the sources folders
VPATH = $(SOURCEDIRS)

#We define a function to generate a Build/Folder1/%.o: %.c rule for each sub-folder
define generateRules
$(1)/%.o: %.c
    @echo Building $$@
    $(CC) -c  -o $$@ $$< 
endef

#Finally we generate the rule for each build folder
$(foreach targetdir, $(TARGETDIRS), $(eval $(call generateRules, $(targetdir))))

:

#PROJDIR is the folder where your Makefile is
PROJDIR := $(realpath $(CURDIR)/..)

#SOURCEDIR is the root folder where your sources sub-folder ares
SOURCEDIR := $(PROJDIR)/Sources

#BUILDDIR is the root folder where your objects will be
BUILDDIR := $(PROJDIR)/Build

#DIRS are the sub-folder, e.g. Sources/Folder1 and Build/Folder1
DIRS = Folder0 Folder1 Folder2

#Here we create a list of source with full path
SOURCEDIRS = $(foreach dir, $(DIRS), $(addprefix $(SOURCEDIR)/, $(dir)))

#We allow GNU make to search for the sources in all the sources folders
VPATH = $(SOURCEDIRS)

$(BUILDDIR)/%.o: %.c
    $(CC) -o $@ $<
0

, , - , , , makefile.

, make, GNU make, : . , , :

SRC_DIR = ./Srcs
OUTPUT_DIR = .
OBJ_LIST = $(addprefix $(OUTPUT_DIR)/, main.o src1.o src2.o)
OUTPUT = $(OUTPUT_DIR)/test

all : $(OUTPUT)

$(OUTPUT) : $(OBJ_LIST)
    $(CC) -o $@ $(OBJ_LIST)

# Here the key:
$(OUTPUT_DIR)/%.o : $(SRC_DIR)/%.c
    $(CC) -c $< -o $@ $(INCLUDE)

clean :
    rm -rf $(OUTPUT) $(OBJ_LIST)

.PHONY: all clean

:

  • , . , , all.

  • , , . all ; .

  • clean ( ) , , ! , .

  • GNU make, , , , PHONY, .

  • GNU make .o .c , :

    $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
  • GNU make .o , :
    $(CC) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@
  • , , $(OUTPUT_DIR).
0

Source: https://habr.com/ru/post/1652470/


All Articles