Generating a makefile target dependency from the filename in a stem - makefile

Hi I have a makefile I am creating where each .o is represented as a relative path to another directory and has a dependency on a .cpp file in the local directory. My understanding of the problem is that I can't use functions in a rule definition so the rule:
%.o: %.cpp
results in a prerequisite .cpp that is in the same directory as the .o which is not where the cpp is actually located. For example:
../../Tmp/MyClass.o: ../../Tmp/MyClass.cpp <--- WRONG, result of %.o: %.cpp
../../Tmp/MyClass.o: MyClass.cpp <--- RIGHT, how do I do this in an automatic way?
Lastly the output, which is in yet another directory, has a dependency on the .o's so they must all have full relative path information from the beginning:
OBJS := $(addprefix ../../../Tmp/XCode/${PLATFORM}/${CONFIGURATION}/, $(addsuffix .o, $(basename ${SRCS})))
${OUTPUT}: ${OBJS} ; ${AR} $# ${OBJS}
Thanks!

I think kristi's solution will work, but here's another way to do the same thing:
# Here's how you do it:
OBJS := $(addprefix ../../../Tmp/XCode/${PLATFORM}/${CONFIGURATION}/, $(addsuffix .o, $(basename ${SRCS})))
# Here's a slightly cleaner way:
BASEPATH = ../../../Tmp/XCode/$(PLATFORM)/$(CONFIGURATION)
OBJS := $(patsubst %.cc,$(BASEPATH)/%.o,$(SRCS))
# And here's the rule:
$(OBJS): $(BASEPATH)/%.o: %.cc
whatever...

This should work
../../Tmp/%.o: %.cpp
Or use a variable
builddir := ../../Tmp
$(builddir)/%.o: %.cpp

Related

Makefile - build from multiple directories

I am new to Makefile.
I have a string of multiple directories and I want to compile all the .c files in them.
The number of paths in that string can change (it is received as an argument from a script).
For example:
DIRS = path1 path2...
I will be happy to receive help with building a mechanism that can go over DIRS and compile each and every .c file in each path.
I am not sure if this is the right way, but I got this so far:
DIRS = path1 path2
define generateRules
SOURCES := $(wildcard $(path)/*.c)
%.o: $(SOURCES)
echo "path is $(path)";
$(CC) $(CFLAGS) ${INCS} ${DEFS} -c $< -o ${BUILD}/$#
endef
$(foreach path,$(DIRS),$(info $(generateRules)))
Thank you
Let's start with generating a list of the source files.
DIRS = path1 path2
SOURCES := $(wildcard $(addsuffix /*.c,$(DIRS)))
From this we can generate a list of targets:
TARGETS = $(patsubst %.c,$(BUILD)/%.o,$(notdir $(SOURCES)))
The simplest way to get the effect you want is by use of the vpath directive and a static pattern rule:
vpath %.c $(DIRS)
$(TARGETS): $(BUILD)/%.o: %.c
#echo building $# from $<
$(CC) $(CFLAGS) ${INCS} ${DEFS} -c $< -o $#
If you want to generate a rule for each source directory -- or each source file -- you can, but that requires a few more advanced techniques. I advise you to get the simple approach working first.

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: Can VPATH variable is applied to assigning Makefile variable?

i've tried to write simple makefile for practice.
I have two directories 1. srcs(.c), 2.include(.h)
and try to define SRCS variable that would contain all .c files
in current directory and srcs directory.
and below is my Makefile
CURDIR = $(shell pwd)
OBJDIR = $(CURDIR)/objdir
VPATH = $(CURDIR)/srcs
SRCS = $(wildcard *.c)
OBJS = $(patsubst %.c, %.o, $(SRCS))
all: main
main: $(OBJS)
gcc -o $# $^
$(OBJS): $(SRCS) | $(OBJDIR)
gcc -c -o $# $<
$(OBJDIR):
mkdir objdir
I designate current/src directory as a VPATH to make find
all *.c files in current directory and current/srcs but
it cannot find *.c files in /srcs directory.
May be make cannot us VPATH when it defines the variable in Makefile
right? if it's right please let me know better approach :)
Thanks.
VPATH is for directories make should search to find prerequisites.
It doesn't change where $(wildcard) searches.
VPATH lets you use foo.c (either explicitly or implicitly) in the prerequisite list of a rule and have make look in the current directory and the VPATH directories for the file for it.
If you want SRCS to contain the .c files from the srcs directory then you need to include srcs/*.c in an additional $(wildcard) call in the SRCS assignment.
SRCS = $(wildcard *.c) $(wildcard srcs/*.c)

How to have a sometimes empty dependency in makefiles?

I have the following rule:
EXECS = $(sort $(patsubst %.cpp,%$(EXESUFFIX), $(patsubst %.c,%$(EXESUFFIX), $(filter-out $(IGNORESRCS), $(EXECSRCS)))))
SRCS = $(sort $(filter-out $(EXECSRCS), $(filter-out $(IGNORESRCS), $(wildcard *.c) $(wildcard *.cpp) $(foreach DIR,$(SUBDIRS),$(wildcard $(DIR)/*.cpp) $(wildcard $(DIR)/*.c) ) )))
#OBJS = $(addprefix $(OBJDIR), $(patsubst %.cpp,%$(OBJSUFFIX), $(patsubst %.c,%$(OBJSUFFIX), $(SRCS))))
OBJS = $(patsubst %.cpp,%$(OBJSUFFIX), $(patsubst %.c,%$(OBJSUFFIX), $(SRCS)))
RESOURCE_SRCS= $(sort $(filter-out $(IGNORESRCS), $(wildcard *.rc) $(foreach DIR,$(SUBDIRS),$(wildcard $(DIR)/*.rc) ) ))
RESOURCES = $(patsubst %.rc,%$(OBJSUFFIX), $(RESOURCE_SRCS))
%$(EXESUFFIX) : %.cpp $(LIBS) $(RESOURCES)
$(CXX) $(DEFINES) $(CFLAGS) $(INCLUDES) $(LIBPATH) -o $(BINDIR)/$* $< $(RESOURCES) $(LIBINCLUDES)
The problem is that $(RESOURCES) doesnt exist for all platforms. The %$(EXESUFFIX) : %.cpp rule doesnt run, instead it tries to run g++ exec.cpp -o exec which as far as I can tell isnt a rule that I declared anywhere.
How do I get the rule to still build despite the fact that it is empty (and build the resources if it is not empty)?
If the variable is empty it has no effect on the rule. It should just work as written. What is the actual error you're seeing?
ETA:
Your question is very unclear in what, exactly, you mean by $(RESOURCES) doesn't exist. My answer was assuming you meant that the variable was empty. But given your comment below about how the makefile behaves, I now suspect what you mean is that the variable is still set to a list of files, but that those files are not present.
Because they're not there, and make doesn't know how to build them, make decides that this pattern rule cannot be used at all and it chooses a different rule.
If you want these files to only have any impact if they exist, then you can use the $(wildcard ...) function to expand only to those files that exist:
%$(EXESUFFIX) : %.cpp $(LIBS) $(wildcard $(RESOURCES))
$(CXX) ...
One critical point here: the contents of $(RESOURCES) MUST be source files. They cannot be derived files (files that are supposed to be created by make). If they are derived, the situation is far more complex.

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