Get filename without extension within makefile - 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

Related

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.

Performing an action over each source file with make

I have created a Makefile like this
CC = sdcc
SRCS = $(PNAME).c\
../../src/gpio.c
../../src/timers.c
../../src/i2c.c
$HDRS = -I../../headers
all:
mkdir -p ./output
$(CC) $(SRCS) -lstm8 -mstm8 $(HDRS)
The problem is, sdcc can only compile one source at a time. So I need to perform something like a foreach on each source I have defined in SRCS variable. How to do this in gnu-make?
According to the docs, you must compile the files other than the one containing main() separately, to produce .rel files, then include those in the compilation command for the main file. There are several variations on how you could do that. The following avoids features specific to GNU make:
# We're assuming POSIX conformance
.POSIX:
CC = sdcc
# In case you ever want a different name for the main source file
MAINSRC = $(PMAIN).c
# These are the sources that must be compiled to .rel files:
EXTRASRCS = \
../../src/gpio.c \
../../src/timers.c \
../../src/i2c.c
# The list of .rel files can be derived from the list of their source files
RELS = $(EXTRASRCS:.c=.rel)
INCLUDES = -I../../headers
CFLAGS = -mstm8
LIBS = -lstm8
# This just provides the conventional target name "all"; it is optional
# Note: I assume you set PNAME via some means not exhibited in your original file
all: $(PNAME)
# How to build the overall program
$(PNAME): $(MAINSRC) $(RELS)
$(CC) $(INCLUDES) $(CFLAGS) $(MAINSRC) $(RELS) $(LIBS)
# How to build any .rel file from its corresponding .c file
# GNU would have you use a pattern rule for this, but that's GNU-specific
.c.rel:
$(CC) -c $(INCLUDES) $(CFLAGS) $<
# Suffixes appearing in suffix rules we care about.
# Necessary because .rel is not one of the standard suffixes.
.SUFFIXES: .c .rel
If you look carefully, by the way, you will see that the file does not explicitly perform any looping over the source files, or any such thing. It just describes how to build each target, including intermediate targets. make figures out on its own how to combine those rules to go from sources to final program (or to any other target you specify from among those you've taught it to build).
Use patsubst. Typically it is something like:
SOURCES := $(wildcard *.c)
OBJECTS := $(patsubst %.c,%.o,${SOURCES})
prog: ${OBJECTS}
cc $^ -o $#
%.o: %.c
cc $< -c -o $#

filter function in 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.

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

Simple pattern rule in make

I've written a simple make to test with pattern rule. Here it is:
default:
echo This is default target
%.o:%.c
gcc -c $< -o $#
clean:
rm -f *.o
I have a three *.c files in pwd. After make command I have:
echo This is default target
This is default target
but I expected that any *.c file in pwd will be compiled.
The first target in the makefile is the one that is built when you do not specify a specific target name.
In your makefile, default is first, so it is created.
Often, you'll create a target all as the first target, and list the programs that should be built by some more or less devious means.
.PHONY: default all clean
default:
#echo "You must specify which program you want built (or specify all)"
SRCS = $(wildcard *.c)
PROGS = ${SRCS:.c=}
all: ${PROGS}
%.o:%.c
gcc -c $< -o $#
clean:
rm -f *.o
The .PHONY target specifies that default, all and clean are not real files but phony targets.
I have a directory with many source files in it, and I have a default rule similar to the above as the first target, but I also have an all target so that make all works sensibly.
I prefer to use the ${...} notation around make variables, which make has always accepted; many people use $(...) notation the whole time.
I think default is your program target, but it did not link any objects? see my makefile:
SRCS = $(wildcard *.c)
OBJS = $(patsubst %.c, %.o, $(SRCS))
default:
#echo This is default target
Program: $(OBJS)
gcc $^ -o $#
$(OBJS): $(SRCS)
gcc -c $^
clean:
rm -f $(OBJS) $(Program)
if you type make, it just echo This is default target, if you want to make real target, you can type make Program

Resources