Create intermediate files in build directory from makefile - makefile

I have to make a XC8 project in Ubuntu terminal with makefile.
The directory structure is like this
Project/lib/GPIO/gpio.c
Project/lib/GPIO/gpio.h
Project/main.c
Project/Makefile
Project/build/lib/GPIO
The makefile is generating intermediate files in the Project directory itself. Actually makefile will goto each location and generates intermediate files for each .c file.
Like this
Project/gpio.d
Project/gpio.p1
Project/gpio.pre
Project/<other files>
But I wanted to generate them in Project/build/lib/GPIO instead.
i.e
Project/build/lib/GPIO/gpio.d
Project/build/lib/GPIO/gpio.p1
Project/build/lib/GPIO/gpio.pre
Project/build/<other files>
Makefile:
CHIP := 18F4580
CC := xc8
INCLUDE_PATH := /opt/microchip/xc8/v2.10/include/
PROG := /usr/share/tinybldlin/tinybldlin.py
PORT := /dev/ttyUSB0
AR := libr
SRC_DIR := $(wildcard *.c)
INC_DIR := $(wildcard *.h)
LIB_DIR := \
. \
lib \
lib/GPIO
BUILD_DIR := \
build/ \
build/lib/GPIO
TARGET := pic${CHIP}
FLASH_REGION := 0-3000
ifeq (${SRCS},)
SRCS := $(foreach libdir, $(LIB_DIR), $(wildcard $(libdir)/*.c))
endif
ifeq (${INCS},)
INCS := $(foreach libdir, $(LIB_DIR), $(wildcard $(libdir)/*.h))
endif
ifeq (${OBJS},)
OBJS := $(SRCS:.c=.obj)
endif
ifeq (${P1},)
OBJS := $(SRCS:.c=.p1)
endif
MIN_CFLAGS := --chip=${CHIP} -I${INCLUDE_PATH} --ROM=${FLASH_REGION}
# The following MSG_CFLAGS controls the compiler messages
MSG_CFLAGS := -Q
# The following OPT_CFLAGS reduces the code size
OPT_CFLAGS := --opt=all
# The following OUT_CFLAGS controls the generated outputs
OUT_CFLAGS := --asmlist --summary=psect,mem -M${TARGET}.map
EXTRA_CFLAGS += ${MSG_CFLAGS} ${OPT_CFLAGS} ${OUT_CFLAGS}
CFLAGS := ${MIN_CFLAGS} ${EXTRA_CFLAGS} -DCOMPILER=${COMPILER}
ARFLAGS := r
${TARGET}.hex: ${OBJS}
${CC} ${CFLAGS} -intel $^ -o$#
${MAKE} xclean
${TARGET}.bin: ${OBJS}
${CC} ${CFLAGS} -bin $^ -o$#
${MAKE} xclean
%.p1: %.c ${INC_DIR}
${CC} ${CPPFLAGS} ${CFLAGS} --pass1 $<
%.obj: %.c ${INC_DIR}
${CC} ${CPPFLAGS} ${CFLAGS} -C $<
%.as: %.c ${INC_DIR}
${CC} ${CPPFLAGS} ${CFLAGS} -S $<
%.lib: %.obj
${AR} ${ARFLAGS} $# $<

The first thing I'll say is that this answer relies on your using GNU make. You don't say for sure that you are but since you're using pattern rules I will assume so. Note that what you want to do is not possible with standard POSIX make (unless you want to write out explicit rules for every target to be built).
You need two things:
Tell your compiler what you want to do
Tell make what you want to do
For #1, by default the compiler will generate the output which is the input file name, minus the extension (e.g. .c) plus a specific extension (e.g. .as). Since your input file is lib/GPIO/gpio.c the compiler generates gpio.as. Most compilers support a -o option which allows you to rename the output: you'll have to check your compiler's documentation if this doesn't work. So, you'd want to write your rule:
%.as: %.c ${INC_DIR}
${CC} ${CPPFLAGS} ${CFLAGS} -S -o $# $<
(etc.). Now when you compile lib/GPIO/gpio.c into lib/GPIO/gpio.as, make will set $# to lib/GPIO/gpio.as and invoke your compiler such that it creates lib/GPIO/gpio.as not gpio.as.
But you wanted to put the output files in a build subdirectory. Now that you've convinced your compiler to write files where make tells it to, you have to tell make where to put the output.
So first, when you generate the output files to be created you have to create them with the correct path:
OBJS := $(SRCS:.c=.p1)
That converts lib/GPIO/gpio.c into lib/GPIO/gpio.p1 which isn't what you want. You need this:
OBJS := $(SRCS:%.c=build/%.p1)
Now, make knows you want to build build/lib/GPIO/gpio.p1 instead. However now you'll get an error because make doesn't know how to create that file. You've told it how to build a %.p1 from %.c, but the % must be an exact text match between the target and prerequisite, and here the target % matches build/lib/GPIO/gpio but there's no build/lib/GPIO/gpio.c so the rule doesn't match. You need to rewrite the rule like this:
build/%.p1: %.c ${INC_DIR}
${CC} ${CPPFLAGS} ${CFLAGS} --pass1 -o $# $<
Now it should work. You might also want to add in a mkdir to ensure the directory exists:
build/%.p1: %.c ${INC_DIR}
#mkdir -p ${#D}
${CC} ${CPPFLAGS} ${CFLAGS} --pass1 -o $# $<

Related

How do I use automatic variables in makefile conditionals?

Summarize the problem
I would like to change the compilation for a single source file, like so:
%.exe: %.c
ifeq($#, cannon.exe)
$(CC) $(CFLAGS) -o $(patsubst %.exe,%,$#) $^ $(inc_flags) $(LDLIBS)
else
$(CC) $(CFLAGS) -o $(patsubst %.exe,%,$#) $^
endif
but it doesn't work!
Describe what you’ve tried
I have tried getting bash conditionals involved, but I couldn't figure it out and I shouldn't have to mix bash and make.
Here's the full Makefile:
CC := gcc
CFLAGS := -g -Wall -Wextra
LDLIBS := -lm
inc_dirs := math.h stdio.h
inc_flags := $(addprefix -I,$(inc_dirs))
executable:=cannon.exe
source:=$(executable:%.exe=%.cpp)
.DELETE_ON_ERROR:
all: $(executable)
%.exe: %.c
ifeq($#, cannon.exe)
$(CC) $(CFLAGS) -o $(patsubst %.exe,%,$#) $^ $(inc_flags) $(LDLIBS)
else
$(CC) $(CFLAGS) -o $(patsubst %.exe,%,$#) $^
endif
clean:
rm -f $(executable:%.exe=%)
It turns out that if you want to do a special case for a certain source file, you can just define its recipe explicitly! Make will take explicit over implicit rules. Full working code below.
CC := gcc
CFLAGS := -g -Wall -Wextra
LDLIBS := -lm
inc_dirs := math.h stdio.h
inc_flags := $(addprefix -I,$(inc_dirs))
executable:=cannon.exe
source:=$(executable:%.exe=%.cpp)
# no deps so no objs
.DELETE_ON_ERROR:
all: $(executable)
%.exe: %.c
$(CC) $(CFLAGS) -o $(patsubst %.exe,%,$#) $^
cannon.exe: cannon.c
$(CC) $(CFLAGS) -o $(patsubst %.exe,%,$#) $^ $(inc_flags) $(LDLIBS)
clean:
rm -f $(executable:%.exe=%)
A better / more make-ish solution is to use constructed variable names, like this:
CC := gcc
CFLAGS := -g -Wall -Wextra
LDLIBS := -lm
inc_dirs := math.h stdio.h
cannon_CFLAGS := $(addprefix -I,$(inc_dirs))
executable := cannon.exe
source := $(executable:%.exe=%.cpp)
# no deps so no objs
.DELETE_ON_ERROR:
all: $(executable)
%.exe: %.c
$(CC) $(CFLAGS) $($*_CFLAGS) -o $# $^
clean:
rm -f $(executable:%.exe=%)
Notes:
Your rules should always create the same name as the target in the makefile. It's not right for the target to be named foo.exe but the build command creates a file named foo. If you want to create a file named foo, then the makefile target should be named foo. Basically you should always create the file contained in the make variable $#.
Is it really the case that the directories you have are named math.h and stdio.h? That's.... bizarre. And very likely to cause serious problems. If math.h and stdio.h are files, then you should not add them with -I because -I takes directory names, in which to search file files. It doesn't take filenames.
If you really did create local files named math.h and stdio.h, that's also a very bad idea: those are standard header file names and you shouldn't redeclare them yourself unless you really know what you're doing.
If you didn't create these files and you're just trying to include the standard headers math.h and stdio.h in your file, then you definitely don't need to add any flags to your compile line. Just include them.

How can I modify my Makefile so that I build two different executables

I have a Makefile that works correctly, but now I want to modify it so that I can build two different executables (i.e. client.exe, server.exe). In my directory, I have a client.cpp and a server.cpp, each of which has a main function. I know I can't build an executable with more than one main function. Ultimately, I want to be able to build an executable (client.exe or server.exe) using 'make client', 'make server', or something to that effect.
I have seen similar questions on this website, but all of the solutions I have seen assume that the number of source files will not change. Take for example this solution: Makefile to compile multiple C programs? Or this question: How can I configure my makefile for debug and release builds?
I do not want to have to update my Makefile every time I add a new source file.
How can I modify my Makefile so that I build two different executables?
SRC_DIR := src
OBJ_DIR := obj
BIN_DIR := bin
EXE := $(BIN_DIR)/client.exe
SRC := $(wildcard $(SRC_DIR)/*.cpp)
OBJ := $(subst $(SRC_DIR),$(OBJ_DIR),$(SRC:.cpp=.o))
DEP := $(OBJ:.o=.d)
.PHONY: clean
all: $(EXE)
CXX := g++
CPPFLAGS := -I$(PWD) -MMD -MP
CXXFLAGS := -std=c++17
LDFLAGS := -L /usr/lib/x86_64-linux-gnu
CFLAGS := -Wall
$(EXE): $(OBJ) | $(BIN_DIR)
$(CXX) $(LDFLAGS) $^ -o $#
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp | $(OBJ_DIR)
$(CXX) $(CPPFLAGS) $(CFLAGS) $(CXXFLAGS) -c $< -o $#
$(BIN_DIR) $(OBJ_DIR):
mkdir -p $#
clean:
#$(RM) -rv $(BIN_DIR) $(OBJ_DIR)
-include $(DEP)
I have tried to exclude either the client.cpp or server.cpp file depending on which command I use (e.g. 'make client' or 'make server'). But I reached a dead end since I don't know how to make a rule that excludes one file.
SRC := $(filter-out $(SRC_DIR)/client.cpp, $(wildcard $(SRC_DIR)/*.cpp))
SRC := $(filter-out $(SRC_DIR)/server.cpp, $(wildcard $(SRC_DIR)/*.cpp))
Simply build two different lists of object files for your two executables:
...
EXE := $(patsubst %,$(BIN_DIR)/%.exe,client server)
...
CLIENT_OBJ := $(filter-out $(OBJ_DIR)/server.o,$(OBJ))
SERVER_OBJ := $(filter-out $(OBJ_DIR)/client.o,$(OBJ))
.PHONY: all client server
all: $(EXE)
client: $(BIN_DIR)/client.exe
server: $(BIN_DIR)/server.exe
$(BIN_DIR)/client.exe: $(CLIENT_OBJ)
$(BIN_DIR)/server.exe: $(SERVER_OBJ)
$(EXE): | $(BIN_DIR)
$(CXX) $(LDFLAGS) $^ -o $#
...

Makefile does not find rules despire of available files

Currently I am trying to get a rather big project of mine to work with a Makefile. I used Make before but in a rather crude way and not really "dynamic", this means I am pretty new to good Makefiles.
My Makefile looks like this:
INCLUDE_DIR = /inc
SOURCE_DIR = /src
BUILD_DIR = /build
BUILD_NAME = build
CC = arm-none-eabi-gcc
CFLAGS = -I$(INCLUDE_DIR)
_INCLUDES = main.h pfc.h
INCLUDES = $(patsubst %, $(INCLUDE_DIR)/%, $(_INCLUDES))
_OBJ = main.o pfc.o
OBJ = $(patsubst %, $(BUILD_DIR)/%, $(_OBJ))
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.c $(INCLUDES)
$(CC) -c -o $# $< $(CFLAGS)
$(BUILD_NAME): $(OBJ)
$(CC) -o $# $^ $(CFLAGS)
all: $(BUILD_NAME)
.PHONY: clean
clean:
rm -rf $(BUILD_DIR)/*
When I make the file I get this:
make: *** No rule to make target '/build/main.o', needed by 'build'. Stop.
I guess it is an error in this recipe:
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.c $(INCLUDES)
$(CC) -c -o $# $< $(CFLAGS)
Sadly I am not able to get this done on my own.
All files a available in the correct folders.
I really appreciate all the help!
Tristan
You have a few issues here that I can see. But first off - just check (just incase) that all your rules are only indented with tabs and not spaces..... this can be a real "silent" killer of makefiles as they give crap error messages.
Ok so - lets assume you have:
INCLUDE_DIR = inc
SOURCE_DIR = src
BUILD_DIR = build
instead of /src etc.. as mentioned in the comments.
Do you really have inc/main.h and inc/pfc.h?
I copied and pasted your makefile added your src and inc folders (but I used gcc instead of arm-none-eabi-gcc. It did the compile lines correctly, but failed at the linker stage because you are trying to build an output file called build when there is already a folder called build (not allowed in linux - maybe ok for windows but I don't recommend).
I made an answer for another question - but it might be a better start point then you have here in the case where you have nested src/inc directories and you want to be able to clean your output folders - ill put it here for convenience:
# Get your source list (use wildcard or what ever, but just for clarity you should end up with a list of files with full paths to start with):
# Output folders/targets
SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin
OUTPUT_FILE = output
# Generate list of source files - this is a linux command - but you can do this in pure make using wildcard and such).
SOURCES := $(shell find $(SOURCEDIR) -name '*.c')
# Create your objects list in the obj directory
OBJECTS = $(addprefix $(OBJ_DIR)/,$(addsuffix .o,$(basename $(SOURCES))))
# Create list of unique folders to create
DIRS = $(sort $(dir $(OBJECTS))) $(BIN_DIR)
# Create list of include paths
INCS = $(addprefix -I,$(sort $(dir $(SOURCES))))
# Main target rule
$(BIN_DIR)/$(OUTPUT_FILE): $(OBJECTS) | $(DIRS)
#echo linker: gcc $(OBJECTS) -o $#
#touch $#
# Rule to build your object file - ensure that the folders are created first (also create a dummy obj file) - note this works for parallel builds too (make -j
$(OBJ_DIR)/%.o: %.c | $(DIRS)
#echo compile: gcc $(INCS) -c $? -o $#
#touch $#
# Create your directories here
$(DIRS):
#echo Creating dir: $#
#mkdir -p $#
# Clean if needed
.PHONY: clean
clean:
rm -rf $(OBJ_DIR) $(BIN_DIR)
Note this is just a template, you still need to fill in the gcc/makefile flags - but its a decent start point...
Debugging
$(info ...) is your friend - for example you could do:
$(info OBJ = $(OBJ))
$(info objrule = $(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.c $(INCLUDES))
To print our what make has expanded these variables / lines to be - this can yield useful debug.
Here is another version of your makefile with automatic dependency generation:
INCLUDE_DIR := inc
SOURCE_DIR := src
BUILD_DIR := build
CC := arm-none-eabi-gcc
CPPFLAGS := -I$(INCLUDE_DIR)
exes := build
build.obj := main.o pfc.o
all : ${exes:%=${BUILD_DIR}/%}
.SECONDEXPANSION:
${BUILD_DIR}:
mkdir -p $#
# Rule to link all exes.
${exes:%=${BUILD_DIR}/%} : ${BUILD_DIR}/% : $$(addprefix ${BUILD_DIR}/,$${$$*.obj}) | $${#D}
${CC} -o $# ${LDFLAGS} $^ ${LDLIBS}
# Rule to compile C sources. And generate header dependencies.
${BUILD_DIR}/%.o : ${SOURCE_DIR}/%.c | $${#D}
${CC} -o $# -c ${CPPFLAGS} ${CFLAGS} -MD -MP $<
# Include automatically generated header dependencies.
ifneq ($(MAKECMDGOALS),clean)
-include $(foreach exe,${exes},$(patsubst %.o,${BUILD_DIR}/%.d,${${exe}.obj}))
endif
clean:
rm -rf $(BUILD_DIR)
.PHONY: all clean
To add another executable target do:
exes += another
another.obj := another_main.o another_pfc.o

makefile how to output to separate build directory

I have this directory structure:
makefile
src
foo.c
build
My goal is simply to build foo.c and output the build files to the build directory.
I have the following makefile:
SRCS_DIR := ./src
BUILD_DIR := ./build
SRCS := $(shell find $(SRCS_DIR) -name "*.c")
OBJS := $(subst $(SRCS_DIR),$(BUILD_DIR),$(SRCS))
OBJS := $(OBJS:.c=.o)
test.exe: $(OBJS)
gcc $(OBJS) -o $#
%.o: %.c
gcc -c $< -o $#
The problem is the pattern rule. One of the object files is build/foo.o. The problem is that %.c gets turned into build/foo.c, which doesn't exist. What I want %.c to be is src/foo.c instead, but I have no idea how to do that.
The stem of the pattern must match exactly. So if you want a pattern that will put things into a different directory, you have to modify the pattern so that the non-matching parts are not part of the stem. So you can write:
build/%.o : src/%.o
gcc -c $< -o $#
so that the % matches only the common string.

Makefile mirror build directory

I need to create Makefile that compiles .c files with a lot of subdirs (sources directory goes in around 5 level depth) and I need to place the object files in the mirrored build directory. So far, I have created this Makefile:
CC := gcc.exe
AS := as.exe
CFLAGS = -DCORE_SW_VERSION='"$(CORE_SW_VERSION)"' -Wall -mA6 -c -fmessage-length=0 -Hsdata0
CFLAGS += -fgnu89-inline -mno-volatile-cache $(INCLUDE) -Hon=each_function_in_own_section -Xcrc -std=c99 -O1
CORE_SW_VERSION:=CORE.07.01.04.01.03.01.R
HAL_SW_VERSION:=16.01.06.01.06.00
MODE_CORE := dev
MODE_HAL := dev
OBJDIR := $(shell pwd)/$(TARGET12) #TARGET12 is a make parameter
INCLUDE := $(shell cat ./$(TARGET12)_include.txt)
SOURCEDIR := ../sources
CSRC := $(shell find $(SOURCEDIR) -name '*.c')
EXCLUDES := $(shell cat ./$(TARGET12)_exclude.txt)
OBJ := $(CSRC:.c=.o)
OBJS := $(patsubst ../%.c,$(OBJDIR)/%.o,$(CSRC))
.PHONY: $(TARGET12)
$(TARGET12): $(OBJS)
$(AR) -r $(CORE_SW_VERSION).a $(OBJS)
$(OBJS): $(CSRC)
mkdir -p $(dir $#)
$(CC) $(CFLAGS) $< -o $(patsubst ../%,$(OBJDIR)/%,$#)
If I define rule for $(OBJS) this way, $< is always the first .c file in $(CSRC).
If I define $(OBJS) this way:
$(OBJS): %.o: %.c
mkdir -p $(dir $#)
$(CP) $< $#
I get error that there is no rule to make target for .c file. But I see that make is looking for .c file in build mirrored directory, and it should look at the source dir. Do you maybe know how this could be arranged?
Thanks you in advance!
The rule $(OBJS): %.o: %.c means something like this: when trying to create a .o file, use this rule if the corresponding .c file exists. For example: when make is looking for a way to create $(OBJDIR)/foo.o, it will look for $(OBJDIR)/foo.c.
In your case this file does not exists, so the rule is ignored.
What you want is rather something like this:
$(OBJS): $(OBJDIR)/%.o: $(SOURCEDIR)/%.c
mkdir -p $(dir $#)
$(CP) $< $#
The first rule for $(OBJS) you tried, states that every object file individually depends on all source files. Surely that's not correct.
Your second attempt is better, although the recipe is weird. Fix that and use VPATH to make make find the sources.

Resources