If I erase the gcc lines from this file shouldn't it take compilation as the implicit rule? Why isn't it allowing me to run the program ./calc with that makefile configuration?
Makefile:
all: calc
clean:
rm -rf calc arit.o calc.o
calc: calc.o arit.o
#gcc -o calc calc.o arit.o
calc.o: calc.c arit.h
#gcc -c calc.c
arit.o: arit.c arit.h
#gcc -c arit.c
Because the comment is indented by a tab stop, it is treated as a command (and executed by the shell, which treats it as a comment).
If the '#' symbols were in column 1, then they would be pure (make) comments.
Further to Jonathan Leffler's answer, the following minimal GNUMakefile should do all compilation and linking through implicit rules only:
calc: calc.o arit.o
arit.o: arit.c arit.h
calc.o: calc.c arit.h
clean:
rm -rf calc arit.o calc.o
Related
I was just practising with GNU make and I was trying to write a clean target, the make file is this:
includePath := -I $(CURDIR)
outputDir = $(CURDIR)/output
COMPILER := g++
standard := -std=c++17
#sourceFiles
main.cpp := main.cpp
#output files
binaryPath = $(outputDir)
binary = main.out
#int_binaryPath = intermediate binary
int_binaryPath = $(outputDir)/int_binaries
int_binary = main.o
GPP = $(COMPILER) $(standard) $(includePath)
#print info while make is executing
# $(info $(includeDir) )
VPATH = outputDir/int_binaries $(CURDIR)/glad/src
#build=compile,link and run
$(binary): $(int_binary) glad.c -lGL -lGLU -lglfw -ldl
$(GPP) $(int_binaryPath)/main.o $(CURDIR)/glad/src/glad.c -o $(binaryPath)/$# -lGL -lGLU -lglfw -ldl
$(int_binary): $(main.cpp)
$(GPP) $(main.cpp) -c -o $(int_binaryPath)/$(int_binary)
build: $(binary)
$(binaryPath)/$(binary)
build#bg: $(binary)
$(binaryPath)/$(binary) &
rebuild: clean build
#echo "rebuild successful"
.PHONY: clean
clean:
ifeq($(wildcard $(outputDir)/$(binary)), $(outputDir)/$(binary))
rm -rf $(outputDir)/$(binary)
else ifeq($(wildcard $(outputDir)/$(int_binary)), $(outputDir)/$(int_binary))
rm -rf $(outputDir)/$(int_binary)
endif
now the part that is throwing up error is this:
.PHONY: clean
clean:
ifeq($(wildcard $(outputDir)/$(binary)), $(outputDir)/$(binary)) #this has spaces, line 47
rm -rf $(outputDir)/$(binary) #this has 2 tabs, but even 1 tab didn't work
else ifeq($(wildcard $(outputDir)/$(int_binary)), $(outputDir)/$(int_binary))
rm -rf $(outputDir)/$(int_binary)
endif
now, when I do make clean, it returns the following error:
makefile:47: *** missing separator. Stop.
What exactly am I doing wrong? Why isn't it working and what does the error mean?
You have to have a space between the ifeq and the open paren.
You have other issues; for example there's no comma between words in the wildcard function, so you're literally asking it to look for the file ./output/main.out, (including the ,) exists.
Anyway, this is not needed because rm -rf foo is simply a no-op if foo doesn't exist... you don't need all this complexity.
I have the following files in a directory:
FP01.c:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
long double ld = 0.1L; // long double constant (L or l suffix)
scanf("%Lf", &ld);
return 0;
}
makefile:
MAKEFLAGS += -rR
# the default target
.PHONY: all
all: FP01.elf
%.elf: %
cp $< $#
# prevents non-terminal match-anything rules from matching target '%.c'
# see section 10.5.5 of GNU make manual
%.c:
# a non-terminal match-anything rule
%: %.c
gcc -Wall -g $< -o $#
If FP01 does not exist, running make gives the following output:
make: *** No rule to make target 'FP01.elf', needed by 'all'. Stop.
However, if I run the following commands before make, then everything works as expected:
$ touch FP01
$ touch FP01.c
$ make
gcc -Wall -g FP01.c -o FP01
cp FP01 FP01.elf
Am I missing something or there is a bug in GNU make?
make --version gives the following output:
GNU make 4.1
Built for i686-pc-linux-gnu
Copyright (C) 1988-2014 Free Software Fundation, Inc.
License GPLv3+: ...
...
EDIT:
It seems that making match-anything rule terminal somehow fixes the problem, but I want to use built-in rule to generate FP01 if possible and unfortunately it is non-terminal.
Another thing is that I believe that non-terminal rule should work so using terminal rule doesn't actually solve the problem as I still don't know whether the bug is in make or in my "mental makefile parser".
I'm not sure if this is a bug or not, I'd have to look more deeply into it. But the simple way to fix your problem is to set the match-anything pattern rule that compiles from the .c file as terminal, which is how it should be (unless you're generating the source files from somewhere else):
%:: %.c
cp $< $#
$ make
cp FP01.c FP01
cp FP01 FP01.elf
rm FP01
I think you should use :: on the % : %.c rule because you actually want that to be a terminal match-anything rule (since you don't need the .c file to be built):
MAKEFLAGS += -rR
.PHONY: all
all: FP01.elf
%.elf: % ; cp $< $#
% :: %.c ; gcc -Wall -g $< -o $#
Note that I used the ; form for the recipes here because it's easier to copy and paste because no need to worry about tabs.
Adding FP01 as a prerequisite of .INTERMEDIATE (special built-in target) seems to make it work (no need to modify the match-anything rule). Just another workaround.
MAKEFLAGS += -rR
# the default goal
.PHONY all
all: FP01.elf
%.elf: % ; cp $< $#
# prevents non-terminal match-anything rules from matching target '%.c'
# see section 10.5.5 of GNU make manual
%.c:
# a non-terminal match-anything rule
%: %.c ; gcc -Wall -g $< -o $#
.INTERMEDIATE: FP01
I have the following simple makefile
#all: binsem.a ut.a ph
FLAGS = -Wall -L./
binsem.a:
gcc $(FLAGS) -c binsem.c
ar rcu libbinsem.a binsem.o
ranlib libbinsem.a
ut.a:
gcc $(FLAGS) -c ut.c
ar rcu libut.a ut.o
ranlib libut.a
clean:
rm -f *.o
rm -f a.out
rm -f *~
rm -f ph
rm -f *a
The problem is it only generates binsem.a and not ut.a, probably because of dependencies issues.
I tried looking at the flags but did not find the answer.
Thanks a lot.
By default, if you don't specify a target on the command line, make will build the first target it finds (and it's dependencies if it has any). Your first target is binsem.a, and you don't list any dependencies, so that's the only thing that gets built.
Try something like adding this at the top:
all: binsem.a ut.a
And mention the dependencies in your other targets:
binsem.a: binsem.c
...
ut.a: ut.c
I'm using a makefile to build my flex/bison project. I'm having problems as it is adding a call to yacc and a mv command thus overwriting one of my files.
user#dk ~/calc ±master⚡ » make clean
rm -rf lex.yy.c calc.tab.h calc.tab.c calc
user#dk ~/calc ±master » make
bison -d calc.y
flex calc.lex
g++ -o calc calc.tab.c lex.yy.c calc.c
user#dk ~/calc ±master⚡ » make clean
rm -rf lex.yy.c calc.tab.h calc.tab.c calc
user#dk ~/calc ±master » touch calc.y
user#dk ~/calc ±master » make
bison -d calc.y
flex calc.lex
yacc calc.y
mv -f y.tab.c calc.c
g++ -o calc calc.tab.c lex.yy.c calc.c
... Failure ...
I simplified the makefile to the bare minimum to reproduce this. Using bison to create two files: calc.tab.c and calc.tab.h. I do not have the .h file as a target as I'm not sure what the correct way to do that is. The call to bison will generate both of the calc.tab.* files so that is not my main concern.
What is the correct way to structure this makefile to avoid the calls to yacc and mv from being generated?
calc: calc.tab.c lex.yy.c calc.c
g++ -o calc calc.tab.c lex.yy.c calc.c
calc.tab.c: calc.y
bison -d calc.y
lex.yy.c: calc.lex calc.tab.h
flex calc.lex
clean:
rm -rf lex.yy.c calc.tab.h calc.tab.c calc
The mv comes from make's built-in rules, which contain:
%.c : %.y
$(YACC.y) $<
mv -f y.tab.c $#
It looks like make is trying to create calc.c from calc.y. Some solutions to this are to redefine that rule yourself, or rename calc.y to something that won't trigger that rule for calc.c, or disable make's built-in rules.
You can list all built-in rules with make -p.
I have the following makefile which is a slight modification on others that I have used in the past. There is an odd issue though with my variable ${CXXOPTS} not being used in the .c.o makefile rule. When I execute the makefile, this is what is executed g++ -c -o SeqPrep2.o SeqPrep2.cpp when I expect this to be executed: g++ -Iseqan-03-02-2012 -c -o SeqPrep2.o SeqPrep2.cpp. (Edit: I solved the problem but see my updated question below about why this makefile worked at all in the first place)
L=-lm -lz
SEQANINC=seqan-03-02-2012
DESTDIR=$(HOME)/
BINDIR=bin
CXXOPTS=-I${SEQANINC}
CXX=g++
A=SeqPrep2
USEROPTS=
O=$(patsubst %.cpp,%.o,$(wildcard *.cpp))
SOURCES=$(wildcard *.cpp)
all: ${A} ${O} ${SOURCES}
install: ${O} ${MYLIBS} ${SOURCES}
${CXX} ${USEROPTS} -o ${DESTDIR}${BINDIR}/${A} ${O} ${L}
${A}: ${O} ${MYLIBS} ${SOURCES}
${CXX} ${USEROPTS} -o ${A} ${O} ${L}
clean::
rm -f ${A} ${O}
.c.o:
${CXX} ${CXXOPTS} ${USEROPTS} -c $< -o $#
check-syntax:
${CXX} ${CXXOPTS} ${USEROPTS} -c -o .nul -S ${CHK_SOURCES}
UPDATE:
I changed .c.o to .cpp.o. Is this a case of gnu make guessing that when I asked for a .o file in one of my rules, that it should make it just by running g++ -c -o SeqPrep2.o SeqPrep2.cpp even though I didn't tell it to do that? I guess that is my new question, why did the above makefile work at all, and why did it have the odd behavior I observed. One thing to note is that even though it didn't come though in the formatting, there is a lot of white space between the g++ and the -c, kind of like it was trying to put in my variables, but it didn't. That is partially what originally lead me to believe that it was seeing my rule at all, even though it seems like it didn't now. Thanks for helping me understand how this stuff works.
You've got the rule .c.o but you're compiling cpp files, when I use .cpp.o: it works great! With files: me.cpp us.cpp you.cpp
I get:
Building file me.cpp
g++ -Iseqan-03-02-2012 -c me.cpp -o me.o
Building file us.cpp
g++ -Iseqan-03-02-2012 -c us.cpp -o us.o
Building file you.cpp
g++ -Iseqan-03-02-2012 -c you.cpp -o you.o
g++ -o SeqPrep2 me.o us.o you.o -lm -lz