filter function in Makefile - makefile

Is there a way to pick up the target name using automatic variable.
SOURCES = $(wildcard *.c)
dummytgt: $(OBJ)/tier.o
$(GCC) $(CFLAGS) -c $(filter $#,$(SOURCES)).c -o $#
I do not want to mention the filename as input but would want to use the filter function to get the .c file which is same as target name. make throws an error no input files

It's helpful to have a look at how make parses this:
SOURCES = $(wildcard *.c)
dummytgt: $(OBJ)/tier.o
$(GCC) $(CFLAGS) -c $(filter $#,$(SOURCES)).c -o $#
First off,
it will read the makefile, defining and expanding macros as it goes.
SOURCES = $(wildcard *.c) means that ${SOURCES} is a lazy variable with definition $(wildcard *.c).
Lazy? Yes, these recursive variables (as the make manual has it) only expand their right-hand side when they are themselves expanded.
Make needs the dependencies as it reads the file, so $(OBJ) is expanded.
Let's assume that the expansion of ${OBJ} is objs (say).
The shell command block remains as a single lazy variable.
It's important to note that these are not expanded until make decides that it wants to build dmmytgt.
You could have written this to exactly the same effect:
dummytgt: objs/tier.o
$(GCC) $(CFLAGS) -c $(filter $#,$(wildcard *.c)).c -o $#
For this fragment to work,
the file objs/tier.o must already exist.
Let's assume it does.
Make now has all it needs to build dummytgt (according to your makefile),
so now it expands the command block.
$(wildcard *.c) expands to 1.c 2.c (say).
$# is dummytgt
$(filter dummytgt,1.c 2.c) is of course empty (and always will be!)
${GCC} is gcc (say)
${CFLAGS} is empty (say)
Thus the shell gets
gcc -c .c -o dummytgt
Presumably gcc complains that there is no file called .c.
The resulting error stops make's execution.
A few thing not to like here:
$(wildcard ) is only for hacky one-liner makefiles IMHO.
dummytgt requires objs/tier.o, but its build instructions never reference it.
Your $(filter ) always expands to nothing.

$(filter $#.c,$(SOURCES))
But I don't see why you don't use
$#.c
Or better still, make it a prerequisite.

Related

Why is makefile exhibiting non-deterministic behaviour?

I have a makefile that is trying to do the following: identify all files under the current directory (all sub-directories included) with .c and .s extensions, for each one compile a non-linked object file and put it into a directory. All C files end up in objects/c, all assembly files end up in objects/ass.
The makefile always works as expected on the first execution (all commands are called in the right order) and no errors are produced.
However if I call make again, half of the time i get "nothing to be done for 'all'.". Which is what you would expect, since no files have been modified. But the other half of the time, make is selecting a random assembly file and compiling that file. That is to say,if I keep doing "make" I sometimes compile file1.s sometimes file2.s. and it keeps randomly swapping between the assembly files add infinitum (it never reaches a "nothing to be done") state.
How is make exhibitting non deterministic behaviour?
This is the smallest makefile I could make that reproduces the error:
SRC_C = $(wildcard *.c) $(wildcard **/*.c)
SRC_ASS = $(wildcard *.s) $(wildcard **/*.s)
OBJECTS_C = $(addprefix $(OBJECT_DIR)c/, $(notdir $(SRC_C:.c=.o)))
OBJECTS_ASS = $(addprefix $(OBJECT_DIR)ass/, $(notdir $(SRC_ASS:.s=.o)))
OBJECTS = $(OBJECTS_C) $(OBJECTS_ASS)
OBJECT_DIR = objects/
all: $(OBJECTS)
%/:
mkdir $#
$(OBJECTS_C): $(OBJECT_DIR) $(OBJECT_DIR)c/
arm-none-eabi-gcc -O0 -march=armv8-a $(wildcard */$(#F:.o=.c)) -nostartfiles -c -o $#
$(OBJECTS_ASS): $(OBJECT_DIR) $(OBJECT_DIR)ass/
arm-none-eabi-as -march=armv8-a $(wildcard */$(#F:.o=.s)) -c -o $#
.PHONY: clean
clean:
rm -rf $(OBJECT_DIR)
You have many errors here.
The biggest is a conceptual one: By flattening all your object files into one directory, there's no way to express proper dependencies using pattern rules, so your object files do not really depend on their respective source files. I'd say: just don't do that! Having object directories is fine, but they should mirror the directory structure of the source tree.
Further errors:
directly depending on directories. This will not work as expected, directories should always be order-only dependencies, as already stated in the comments
Make doesn't support recursive wildcards -- if you really need that, you could write your own function or, assuming you're always building on *nix, just call find instead
Pattern rules for creating directories are not the best idea either -- I'd suggest to collect all needed directories in a variable and loop over that.
Stylistic improvements:
Assign variables that don't need deferred evaluation with :=
Assign variables influencing the build process with ?=, so the user can override them at the command line
Use "standard" variables like CC, AS, CROSS_COMPILE
declare all phony targets in .PHONY.
Your Makefile with these changes applied would look like this:
OBJECT_DIR ?= objects
C_OBJECT_DIR ?= $(OBJECT_DIR)/c
AS_OBJECT_DIR ?= $(OBJECT_DIR)/ass
SRC_C:= $(shell find -name \*.c)
SRC_ASS:= $(shell find -name \*.s)
OBJECTS_C:= $(addprefix $(C_OBJECT_DIR)/, $(SRC_C:.c=.o))
OBJECTS_ASS:= $(addprefix $(AS_OBJECT_DIR)/, $(SRC_ASS:.s=.o))
OBJECTS:= $(OBJECTS_C) $(OBJECTS_ASS)
OUTDIRS:= $(sort $(dir $(OBJECTS)))
CROSS_COMPILE ?= arm-none-eabi-
CC ?= gcc
AS ?= as
CFLAGS ?= -O0 -march=armv8-a -nostartfiles
ASFLAGS ?= -march=armv8-a
all: $(OBJECTS)
$(OUTDIRS):
$(foreach _dir,$#,mkdir -p $(_dir);)
$(C_OBJECT_DIR)/%.o: %.c | $(OUTDIRS)
$(CROSS_COMPILE)$(CC) -c -o $# $(CFLAGS) $<
$(AS_OBJECT_DIR)/%.o: %.s | $(OUTDIRS)
$(CROSS_COMPILE)$(AS) -c -o $# $(ASFLAGS) $<
clean:
rm -rf $(OBJECT_DIR)
.PHONY: all clean
Note there is one important thing missing: automatic dependencies. With this Makefile, each object file depends on its respective source file, but completely misses any headers included. For anything other than a simple toy, you should add that, google for "gnu make gcc automatic dependencies" or something similar (not the scope of this question).

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...

Different dependency locations in Makefile based on target

I'm trying to set up a Makefile to handle two different targets from one set of sources, and I'm a little out of my element. The vast majority of it works fine, but my dependency structure is hosed and thus I'm forced to do a full recompile each time. A pared down sample is as follows:
first: OBJDIR = obj
second: OBJDIR = obj-2
SRCS = $(wildcard src/*.cc)
OBJECTS = $(patsubst %.cc,$(OBJDIR)/%.o,$(SRCS))
first: CFLAGS = -g -Wall -Wextra -std=c++11 -MMD
second: CFLAGS = -g -Wall -Wextra -std=c++11 -MMD -DCOMPILE_FLAG
$(OBJDIR)/%.o: %.cc
#mkdir -p $(OBJDIR)/src
clang++ -c $(CFLAGS) -o $(OBJDIR)$# $<
#DEPENDENCIES AREN'T WORKING PROPERLY
-include $(OBJECTS:.o=.d)
first: $(OBJECTS)
clang++ -o gen/first $(OBJECTS)
second: $(OBJECTS)
clang++ -o gen/second $(OBJECTS)
If I #echo $(OBJECTS:.o=.d) under my first: executable generation (or as it's used in the compilation step), it properly expands to /obj/src/filename.d. However, when it's in the include line, it shows up simply as /src/filename.d. Obviously the .d files don't exist in that location, so it doesn't find them and does a full recompile.
Makefiles are not something I'm heavily experienced with, so if there are better ways to do anything up above, I'm all ears. The key point, though, is being able to have two sets of object files and two sets of dependencies from the same sources.
--
To clarify on the eventual goals, what I have is a set of source files that are used to build two separate executables, with the differences handled via #ifdefs.
What I want to get out of the makefile structure is a single makefile with two targets. Each target generates its own .o/.d files, so that when a change is made to the source, I can run make first and make second to generate the two new executables without having to recompile everything from scratch. I've handled this previously by having two separate makefiles, but that just seems wrong.
You've missed a critical sentence in the GNU make manual related to target-specific variables:
As with automatic variables, these values are only available within the context of a target's recipe
This means that you can't use target-specific variables in either the target or prerequisite lists: any variables used there will ALWAYS have the global value and never the target-specific value. Similarly, include lines are parsed as the makefile is read in: there's no target context at all here either so the global value is used.
Further, any time you see ANY rule in a makefile that is creating a file which is not exactly $# but is instead some modification of it, that's a red flag and you know you have a problem: -o $(OBJDIR)$# is wrong.
In general, there's a lot wrong with this makefile and it's not entirely clear exactly what you're trying to do here. Maybe if you stepped back and described the goal you want to achieve we can give you some pointers.
I believe the answer is simply to rethink the way I was doing it. I've rewritten the makefile to be as follows (trimming out anything unrelated), after reading a lot of Makefile documentation and taking into consideration some comments from MadScientist:
CC = clang++
SRCS = $(wildcard src/*.cc)
OBJECTS = $(patsubst %.cc,$(OBJDIR)/%.o,$(SRCS))
CFLAGS = -g -Wall -Wextra -std=c++11 -MMD
.PHONY: all clean run
all: $(EXECUTABLE)
-include $(OBJECTS:.o=.d)
$(EXECUTABLE): $(OBJECTS)
#mkdir -p gen
$(CC) -o gen/$(EXECUTABLE) $(OBJECTS)
$(OBJDIR)/%.o: %.cc
#mkdir -p $(#D)
$(CC) -c $(CFLAGS) $(CMDFLAGS) -o $# $<
clean:
rm -rf obj obj-2 gen
run:
cd gen && ./$(EXECUTABLE)
From there, I made a couple aliases in my .bash_profile:
alias mfirst="make OBJDIR=obj EXECUTABLE=first"
alias msecond="make OBJDIR=obj-2 CMDFLAGS=-DCOMPILE_FLAG EXECUTABLE=second"
Because the variables are now set outside of any target specification, everything plays nicely. It keeps the object files and the dependencies separate, and the aliases still allow quick usage (including mfirst run, for example).
Feel free to point out any flaws here, but I'm fairly happy with the result.

Get filename without extension within makefile

My makefile looks like this:
SRCS = $(wildcard *.asm)
OBJS = ${SRCS:.asm=.o}
# define a suffix rule for .asm -> .o
.asm.o : $(SRCS)
nasm -f elf $<
all: $(OBJS)
gcc -o ?? $<
^need the name of the target without file extension here ($* is blank)
However, $* is working within .asm.o but is blank within all.
How would I go about setting the gcc output filename to the filename of the object file without any extension?
For example, I want it to execute the following (after the .o file is generated by nasm)
gcc filename filename.o
I think you are looking for
.PHONY: all
all: $(patsubst %.o,%,$(OBJS))
%: %.o
gcc -o $# $<
Your attempt would define a target all which depended on all the object files as if it contained them all; I presume you really want each object file to be independent, and for the all target to depend on them all being made.
(Technically you could now use $* because it is identical to $# in this case, but that's just obscure.)
This is by and large isomorphic to your existing nasm rule, except when there is no suffix, you cannot use the suffix syntax. In other words, your rule is equivalent to
OBJS = $(patsubst %.asm,%.o,$(SRCS))
%.o: %.asm
nasm -f elf $<
The only remaining difference is the .PHONY declaration which just documents that all isn't a file name.
Use VAR = $(basename your_file.ext) <=> $(VAR) = your_file
Let's say that you want to remove .o from test.o
VAR = $(basename test.o)
resulting in $VAR containing "test"
See More Functions Here

Makefile. How to exclude one particular file from compilation?

I am trying to exclude main.cpp file from the list of files to be compiled defined by the rule below:
$(TMPDIRPATH)%.o: %.cpp
#echo compile $<
ifneq ($(notdir $<), main.cpp)
#$(COMPILE.cpp) $(OUTPUT_OPTION) $<
endif
This 'ifneq' condition always evaluates to true, which is bizarre. What am I doing wrong? Is there a better way to exlude one file from an explicit rule?
Why don't you try using the filter-out text function if you're using GNU Make.
Returns all whitespace-separated words in text that do not match any of the pattern words, removing the words that do match one or more. This is the exact opposite of the filter function.
For example, given:
objects=main1.o foo.o main2.o bar.o
mains=main1.o main2.o
the following generates a list which contains all the object files not in ‘mains’:
$(filter-out $(mains),$(objects))
That isn't the best way to do it, but if you do it along these lines, write it as a shell condition, not using GNU make conditionals:
$(TMPDIRPATH)%.o: %.cpp
#echo compile $<
#if [ $(notdir $<) != main.cpp ]; \
then $(COMPILE.cpp) $(OUTPUT_OPTION) $<; \
fi
The continuation markers (backslashes) are needed. So are the semicolons. The values prefixed with $ will be expanded by make before the shell is invoked to interpret them. You probably don't want the echo where it is, either. You probably need:
$(TMPDIRPATH)%.o: %.cpp
#if [ $(notdir $<) != main.cpp ]; \
then echo compile $<; \
$(COMPILE.cpp) $(OUTPUT_OPTION) $<; \
fi
The way I would expect to do it is with a list of the files to be compiled. Using any wild card mechanism leads to problems when extra files are added - other tests, or stray files that aren't really part of the system.
The comment says "But the GNU Make Manual says ifneq should work".
The ifneq would work if it were positioned correctly, which means 'not indented as part of the commands associated with a rule'. You could, therefore, write something like (an appallingly bad example, but my brain's on the fritz):
ifneq (${CFLAGS}, -Wall)
CFLAGS += -Wall
endif
file1.o: file1.c
${CC} ${CFLAGS} -c $<
But when the ifneq is indented as in the question, it is just a command that actually isn't found on the system when the make runs the shell to process the command.
The ifneq line is evaluated only once, when make starts up and parses the makefile. In that context, $< is empty.
To get different behavior for each of the targets matched by your pattern rule, you could do something like
$(TMPDIRPATH)%.o: %.cpp
#echo compile $<
#$(if $(filter main.cpp,$<),$(COMPILE.cpp) $(OUTPUT_OPTION) $<)
It might help you to think of the difference between ifneq and $(if) in a makefile as like the difference between #if and if() in C code.
Taking a step back, though: If you don't want main.cpp to be compiled by this rule, then you probably want to provide an explicit rule with $(TMPDIRPATH)main.o as its target, which will be preferred to the pattern rule always. Or, if you don't want$(TMPDIRPATH)main.o to get made at all, you should be looking for rules that have it on the right sight of the :, and removing it from there.
Make doesn't really have a good way to handle conditionals within a rule. You could put the conditional in the command, but in this case there's a much cleaner way:
$(TMPDIRPATH)main.o:
#echo compile $< (but not really)
$(TMPDIRPATH)%.o: %.cpp
#echo compile $<
#$(COMPILE.cpp) $(OUTPUT_OPTION) $<
EDIT:
I didn't realize you didn't have a main.cpp. The solution is simple: remove main.cpp as the prerequisite of the main.o rule (I've removed it above). Now the makefile doesn't need it, and won't try to build it.
But you're still running the rule, which means that something is still trying to build main.o, as either an explicit target or a prerequisite of something else. That is a symptom of confusion, which this change to the makefile will not fix. If you tell us more about the situation, maybe we can propose a better solution. What calls for main.o? Do you have a main.o? What target do you specify when you call Make?

Resources