Makefile error trying to use a template to compile multiple programs with similar steps - makefile

I am trying to create a makefile that can compile multiple programs. It has a list of programs and will compile each one separately. Every program has pretty much exactly the same template so I tried this solution:
CFLAGS=-O3 -std=c89 -pedantic -Wall -Wextra -Werror
programs=echo cat yes true false cp
all: $(programs)
$(programs): src/$#.c
$(CC) $(CFLAGS) -o $# $^
clean:
$(RM) $(programs)
install: all
$(CP) $(programs) /usr/local/bin/
For some reason, this doesn't work. I get the error
make: *** No rule to make target 'src/.c', needed by 'echo'. Stop.
I'm trying to make this portable so no GNU extensions. POSIX Make if possible.

Here:
$(programs): src/$#.c
...
You can't use automatic variables like $# in the prerequisite list that way. The rule gets expanded before a target has been specified, so the variable contains nothing. (You can use it this way but it's a headache.)
Use a static pattern rule instead:
$(programs): %: src/%.c
$(CC) $(CFLAGS) -o $# $^

Related

BSD make & GNU make

I have Makefile. This runs on FreeBSD with gmake and make. In BSD Make command not output log same with gmake.
$ gmake
compile main.cpp
linking myout
$ make
c++ -O2 -pipe -c main.cpp -o main.o
linking myout
$ cat Makefile
TARGET = myout
default: $(TARGET)
SRCS = main.cpp
OBJS = $(SRCS:%.cpp=%.o)
default: $(BIN)
%.o: %.cpp
#echo compile $<
#$(CXX) -c $< -o $#
$(TARGET): $(OBJS)
#echo linking $#
#$(CXX) $(OBJS) -o $#
clean:
#rm -f $(OBJS) $(TARGET)
According to the FreeBSD make documentation, it doesn't support pattern rules. So your rule here:
%.o: %.cpp
#echo compile $<
#$(CXX) -c $< -o $#
in FreeBSD make is just an explicit rule telling make how to build the literal file %.o from the literal file %.cpp. Since you don't try to build a file named %.o (you're trying to build main.o), this rule is ignored / never used.
It looks like if you want something that will work the same way between both versions of make you'll have to restrict yourself to the POSIX standard suffix rules format, like this:
.SUFFIXES: .cpp .o
.cpp.o:
#echo compile $<
#$(CXX) -c $< -o $#
The default build utilities are different. FreeBSD uses a different implementation of make than GNU/Linux. The respective man pages outline differences.
https://forums.freebsd.org/threads/difference-gmake-gnu-and-freebsd-make.28784/

What are the automatic rules make is using to build objects files without being specified?

I have an old project with several C++ source and header files in a directory which are built in cygwin using GCC and a makefile. On editing the makefile to move all the temporary and output files into a sub-directory, the rules to build the object files didnt have any effect.
$(BIN): $(OBJ)
$(CXX) $(LDFLAGS) -o $(BIN) $^
%.o: %.c
$(CXX) $(INC) $(CXXFLAGS) $# -c -o $<
The following makefile still builds the output binary without having any rules to build the object files from source code.
INC=-I.
CXX=g++
CXXFLAGS=-std=c++11 -Wall -Wextra -Wconversion -pedantic -O2 -g
LDFLAGS=
CLEAN_FILES=*.o *.out *.stackdump *.exe *.gcno *.gcda
BIN=app
SRC=$(wildcard *.cpp)
OBJ=$(SRC:%.cpp=%.o)
all: $(BIN)
$(BIN): $(OBJ)
.PHONY: clean
clean:
rm -f $(CLEAN_FILES)
What is this automatic behavior called?
Two notes regarding built-in rules:
In large projects (which will have their owner rules for compiling, linking, ....), it might be easier to start with no built-in rules (make -r or make --no-builtin-rules).
Many built-in rules have hooks, via variables, that allow configuration changes. For example:
%.o: %.c:
$(COMPILE.c) $(OUTPUT_OPTION) $<
...
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
Where opssible to customize the command by modifying "CFLAGS", "CPPFLAGS", etc. Common examples will be make "CFLAGS=-O -g" to get optimized debug program, without having to redefine all the rules.
The set of rules that make knows about without you having to define them are called built-in rules. The manual lists most of them but not all of them. You can run make -p -f/dev/null to see a list of them all.

Why doesn't this make file work?

CC=g++
CFLAGS=-Wall -ggdb
OBJDIR=Objects
SRCDIR=Source
HDIR=Headers
OBJ=$(patsubst %,$(OBJDIR)/%,main.o vector.o obstacle.o \
person.o simulation.o map.o wall.o room.o )
all: CrowdSim
CrowdSim: $(OBJ)
$(CC) $(CFLAGS) -o $# $^
$(OBJDIR)/%.o: $(SRCDIR)/%.cc $(HDIR)/%.h
$(CC) $(CFLAGS) -c -o $# $<
clean:
rm -rf Objects/*.o Source/*.o
When attempting to make, I receive the error: "No rule to make target 'Objects/main.o' needed by 'CrowdSim'. Note: this is my first attempt at a makefile, and I'm following the example here.
Additional information: All my .cc files are stored in Source, all my .h files are in Headers, and I want to put all my .o files in Objects.
A rule like this:
$(OBJDIR)/%.o: $(SRCDIR)/%.cc $(HDIR)/%.h
requires both the prerequisites to exist. If either one does not exist, then the rule doesn't match and make will ignore it and look for another rule. In this case there is no other rule, so make fails.
If you don't always have both a .cc and .h file for every .o file, then you cannot write your rule like this.
Instead, you'll have to write the pattern rule like this:
$(OBJDIR)/%.o: $(SRCDIR)/%.cc
$(CC) $(CFLAGS) -c -o $# $<
Then you'll have to declare the header files separately, like this:
$(OBJDIR)/vector.o: $(HDIR)/vector.h
etc. for any headers. You might consider implementing a method to automatically manage dependencies, such as this one.
By the way, CC and CFLAGS are for C compilers. You have C++ code here. By convention in makefiles you should use CXX and CXXFLAGS for C++ compilers.

GNU make Pattern Rule Fails with 'Main.cpp"

I've got a general-purpose makefile that I've successfully used for small (personal) projects before, as below:
#Makefile to compile a folder's contents into a program.
PROGNAME := MyProgram
LIBRARIES :=
CXX := g++ --std=c++11
INCLUDES := -Isrc -Ihdr
VPATH := src:hdr
CPP_FILES := $(wildcard src/*.cpp)
OBJ_FILES := $(patsubst src/%.cpp,obj/%.o,$(CPP_FILES))
$(PROGNAME): $(OBJ_FILES)
$(CXX) $(INCLUDES) $(LIBRARIES) $^ -o $# $(ROOTFLAGS)
#Automatically generate dependencies (-MM), change the target to be the
# object file (-MT) and output it to the dependency file (-MF).
%.d: src/%.cpp
$(CXX) $(INCLUDES) -MM -MT '$(patsubst src/%.cpp,obj/%.o,$<)' $< -MF $#
obj/%.o: src/%.cpp %.d hdr/%.h
echo $#
$(CXX) $(INCLUDES) -o $# -c $< $(ROOTFLAGS)
.PHONY: clean
clean:
rm obj/*.o $(PROGNAME)
This is designed for the following directory structure:
ParentFolder/
Makefile
hdr/
file1.h
...
src/
file1.cpp
...
obj/
I gave the makefile to a colleague and they found it didn't work - after some investigation, the cause of the problem seems to be that they had a source file called main.cpp in src/, which when running make would give the following error:
make: *** No rule to make target `obj/main.o', needed by `MyProgram'. Stop.
If I rename main.cpp to something else (e.g. test.cpp) then the makefile works as expected.
What is the cause of this behaviour? I've looked through the GNU Make Manual but did not find anything regarding special treatment of files called main.* (in fact, some of the examples use it).
While trying to fix the problem, I found that defining an explicit rule for main.o meant that it would be found - therefore, I presume it's an interaction with the main name and pattern-based rules, but I have not been able to find what that may be.
The trouble is that this rule:
obj/%.o: src/%.cpp %.d hdr/%.h
echo $#
$(CXX) $(INCLUDES) -o $# -c $< $(ROOTFLAGS)
requires a corresponding header file. I suspect that there is no hdr/main.h, and Make has no way to build one, so when it is searching for a way to build obj/main.o it considers this rule, rejects it, and finds no other.
I suggest you add another pattern rule (after this one) to handle source files without matching header files:
obj/%.o: src/%.cpp %.d
echo $#
$(CXX) $(INCLUDES) -o $# -c $< $(ROOTFLAGS)
(P.S. Your dependency handling is a little odd and appears to be vestigial -- you generate dependency files and never use them. We can help you with that, once you're building main.o correctly.)

Makefile runs over C file twice

I have two files: assign1.c and ports.h.
FYI: I am using avr-gcc.
I built the following makefile, which I also use for another project (and other TARGET) where it works fine.
TARGET = assign2
LIB=
INCLUDE=ports.h
CFLAGS =-mmcu=atmega32 -Wall
CC = avr-gcc
SRC= $(TARGET).c
OBJ= $(SRC:.c=.o)
OBJCOPY = avr-objcopy
FORMAT = ihex
MSG_COMPILING = Compiling:
MSG_LINKING = Linking:
MSG_FLASH = Creating load file for flash:
all:elf hex
elf: $(TARGET).elf
hex: $(TARGET).hex
%.hex: %.elf
#echo $(MSG_FLASH) $#
#echo
$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $#
$(RM) *.elf $(TARGET)
#echo
%.elf: $(OBJ) $(LIB)
#echo $(MSG_LINKING) $#
#echo
$(CC) $(CFLAGS) $^ -o $#
#echo
%.o: $(SRC) $(INCLUDE)
#echo $(MSG_COMPILING) $<
#echo
$(CC) $(CFLAGS) -c $<
#echo
.PHONY : clean
clean:
$(RM) *.o *.hex *.elf $(TARGET)
The terminal prints the following output.
C:\Project>make
Compiling: assign2.c
avr-gcc -mmcu=atmega32 -Wall -c assign2.c
In file included from assign2.c:8:
c:/winavr-20100110/lib/gcc/../../avr/include/util/delay.h:90:3: warning: #warnin
g "Compiler optimizations disabled; functions from <util/delay.h> won't work as
designed"
Linking: assign2.elf
avr-gcc -mmcu=atmega32 -Wall assign2.o -o assign2.elf
Compiling: assign2.c
avr-gcc -mmcu=atmega32 -Wall -c assign2.c
In file included from assign.c:8:
c:/winavr-20100110/lib/gcc/../../avr/include/util/delay.h:90:3: warning: #warnin
g "Compiler optimizations disabled; functions from <util/delay.h> won't work as
designed"
avr-gcc elf.o assign2.elf -o elf
avr-gcc: elf.o: No such file or directory
make: *** [elf] Error 1
rm assign2.o
C:\Project>
For some reason it seems to compile the first file, a second time and doing so crashes.
Can anyone correct me on my errors?
The problem is your pattern rules. You are writing pattern rules like this (after make expands the variables):
%.o: assign2.c ports.h
What this rule tells make is that ANY target it wants to build that matches the %.o pattern, can be built by compiling assign2.c. That's obviously not true: this rule build exactly one target: assign2.o.
So make reads your makefile and wants to build a file named elf. It sees that elf depends on $(TARGET).elf, so it builds that (that's the first compile and link, that works). Then make wants to build elf itself. You haven't declared it to be .PHONY, so make assumes it might be a real target.
Make looks through its built-in rules to find one that will let it build elf, and it finds a built-in rule: % : %.o which it can use to compile a program from a .o file with the same prefix. So now for target elf make wants to try to build a file elf.o. Oho! It sees there's a pattern rule that lets it build any .o file based on the assign2.c source file, so it runs that rule (that's the second compile) expecting it to build elf.o... which it doesn't, obviously.
Then make runs the built-in link recipe, using elf.o which doesn't exist, and fails.
The solution to your problem is two things:
First, you should always declare all your makefile targets that you don't actually want to build as .PHONY so make won't try to build them:
.PHONY: all elf hex
Second, you should never use pattern rules where the prerequisite is not also a pattern (this can be useful in certain very specific situations, but not in general). You should either change those pattern rules to explicit rules:
assign2.elf: $(OBJ) $(LIB)
...
$(OBJ): $(SRC) $(INCLUDE)
...
Or make them into full pattern rules by using the pattern in the prerequisites list as well:
%.elf : %.obj $(LIB)
...
%.o: %.c $(INCLUDE)
...

Resources