How to remove extension in makefile - makefile

I have the following makefile:
CC=gcc
CFLAGS=-c ---
LDFLAGS = ---
SRCFILES := $(shell find ../ -name '*.c')
OBJFILES := $(patsubst %.c,%.o,$(SRCFILES))
TESTFILE := $(patsubst %_test.c,%,$(SRCFILES))
all: $(TESTFILE)
$(TESTFILE): $(OBJFILES)
$(CC) $(LDFLAGS) $(OBJFILES) -o $#
all: $(OBJFILES)
%.o: %.c
$(CC) $(CFLAGS) $< -o $#
For all:$(OBJFILES) and below, works perfectly fine. it creates all the object files I need however, I am having trouble creating the file test file. One of the SRC files is ABC_test.c, and the file I want to output is ABC_test (with no extension).
The ABC_test will have dependencies of all the OBJfiles. I think the way I have it set-up is correct but if it is not, please let me know. I am very new to makefiles.
I tried using substitution as you can see in the TESTFILE name. I believe my question is too specific and could not find help with a google search. Any idea what I can do?

It's important to understand that patsubst doesn't omit words from the result. If the word matches the pattern then it is substituted. If the word doesn't match the pattern then it's just emitted as-is.
So, if you have:
FOO = foo_1 foo_2 bar_1 bar_2
$(info $(patsubst foo%,FOO%,$(FOO))
then the output will be:
FOO_1 FOO_2 bar_1 bar_2
It will NOT be, as you seem to be expecting:
FOO_1 FOO_2
with the non-matching values left out. If you want to remove words from the output you need to use the filter and filter-out functions. So for example:
TESTFILE = $(patsubst %_file.c,%,$(filter %_test.c,$(SRCFILES)))

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 pattern matching not working as I expected

I'm trying to setup a simple Makefile for building a simple project that's not too hard to maintain.
I want to make use of pattern matching rules e.g. %.o : %.c ; g++ ... where I have all the object files I would want to compile deduced from wildcard matched source files.
The directory structure is
./src
./include
./build/bin
./build/objs
Right now my problem looks something like this.
INCL_DIR = ./include
SRC_DIR = ./src
BUILD_DIR = ./build
BIN_DIR = $(BUILD_DIR)/bin
OBJ_DIR = $(BUILD_DIR)/objs
SRCS = $(notdir $(wildcard $(SRC_DIR)/*.cc))
OBJS = $(addprefix $(OBJ_DIR)/, $(SRCS:%.cc=%.o))
$(BIN_DIR)/program : $(OBJS)
$(CXX) $(CXXFLAGS) -I $(INCL_DIR) $^ -o $#
$(OBJS):%.o : %.cc
$(CXX) $(CXXFLAGS) -I $(INCL_DIR) -c $< -o $#
In the line $(OBJS):%.o : %.cc an example expansion would be from target rule ./build/objs/a.o that depends on ./build/objs/a.cc but the source file is in ./src/a.cc.
So I figured I could strip away the dependency format to try and match ./src/a.cc but the utilies for text manipulations don't seem to work on the dependency side of a rule.
I tried something like
$(OBJS):%.o : $(SRC_DIR)/$(notdir %.cc)
or
$(OBJS):%.o : $(SRC_DIR)/$(*F).cc
where $(*F) would expand to a in the earlier example case but it doesn't expand to anything when listed as a dependency.
I'm not experienced with Makefiles and not sure why my attempts arent working and would very much like to hear a solution that might solve my issue.
Thanks.
The solution is already in #John's comment. I will try to explain it in bit more detail. I will use an example with hello.cc in folder src.
pattern rules hold the pattern in % symbol. If there is in the makefile a pattern rule: build/objs/%.o : src/%.cc and you request to build file build/objs/hello.o, % will carry value hello. But if your pattern rule would be $(OBJS):%.o : %.cc, the pattern % will be build/objs/hello and the dependency file build/objs/hello.cc is missing (because it is saved in src, not in build/objs).
So solution for you would be:
$(OBJS):$(OBJ_DIR)%.o : $(SRC_DIR)%.cc
$(CXX) $(CXXFLAGS) -I $(INCL_DIR) -c $< -o $#
If you want to make sure how patterns work, you can print pattern content by adding line #echo $* to recipe.

Makefile. Special chars

I have a question to this expression:
%.out: %.cpp Makefile
g++ $< -o $# -std=c++0x
What does it mean? I know, that it is defined target for *.o files but what does it mean %.cpp Makefile and $< and $#?
And:
What is differenece between:
all: $(patsubst %.cpp, %.o, $(wildcard *.cpp))
and:
all:
$(patsubst %.cpp, %.o, $(wildcard *.cpp))
The second doesn't works.
For the first part of your question:
%.out: %.cpp Makefile
g++ $< -o $# -std=c++0x
This is a pattern rule, and means: "for all files with a .cpp extension, compile (if needed) a corresponding .out file using the command g++ $< -o $# -std=c++0x
In this line, $< is the prerequisite (the .cpp file) , $# is the name of the target (the .out file). See here.
The rule also adds the makefile itself as a prerequisite, which means that all the files will be rebuild (even if they are already compiled) when you issue a make target command, if you make changes to the makefile.
For the second part of the question, your are mixing two things. A make rule is made of three parts:
target: dependencies
commands
The second one you show cannot work because there is no command. The line just produces a bunch of filenames, that your shell cannot understand.
The first one adds to the list of dependencies all the object files, whose names are deduced from all the .ccp files. But you are missing a command, so nothing should happen (unless you didn't give us the whole rule ?)
Edit: ouch, missed something, this rule actually should work fine, as make will evaluate all the prerequisite targets, thus call the pattern rule described above. I got confused by the fact that this structure is usually written like this:
targetname: $(OUTFILES)
#echo "- Done target $#"
with the variable defined above as:
OUTFILES = $(patsubst %.cpp, %.o, $(wildcard *.cpp))
or even as:
INFILES = $(wildcard *.cpp)
OUTFILES = $(patsubst %.cpp, %.o, $(INFILES))
I suggest you find a good make tutorial, or read the manual, you seem to have lots of concepts to learn...

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.

Resources