ifdef command not found (GNU make 3.81) - gnu-make

I have the following makefile for a simple helloWorld program:
helloWorld: helloWorld.cpp
echo "Argument entered is $(foo)"
ifdef foo
echo "Defined.";
else
echo "Not defined.";
endif
g++ -Wall -pedantic -g helloWorld.cpp -o h
When I invoke make from the command line like so: make foo=bar, I get the following error:
bar
"not set"
echo "Argument entered is bar"
Argument entered is bar
ifdef foo
make: ifdef: Command not found
make: *** [helloWorld] Error 127
I have gone through some of the links here on SO regarding this error but have not yet been able to solve this issue.

Your syntax is wrong. You have the make directives (ifdef, else and endif) indented like shell commands.
See Example of a Conditional in the GNU make manual for how to do exactly this sort of thing.
libs_for_gcc = -lgnu
normal_libs =
foo: $(objects)
ifeq ($(CC),gcc)
$(CC) -o foo $(objects) $(libs_for_gcc)
else
$(CC) -o foo $(objects) $(normal_libs)
endif

Related

GNU Make: always build pre-targets but don't rebuild target

Imagine my Makefile has something like:
CXXFLAGS = -O3 ${INCLUDES} --std=c++17 -g ${AUTO_ARGUMENT}
COMPILE.cc = $(CXX) $(DEPFLAGS) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
.PHONY: all directories
all: directories programs
directories: obj
obj:
mkdir obj
programs: Foo
Foo: obj/Foo.o
${CXX} obj/Foo.o ${LDFLAGS} -o Foo
obj/%.o : %.cpp
$(COMPILE.cc) $(OUTPUT_OPTION) $<
clean:
rm -rf Foo obj
I can execute make and it will create the obj subdirectory then do a nice compile and link. Works great. But if I do make clean Foo, it's going to fail. The clean removed the subdir and because I bypassed all to just make a single target, it doesn't recreate obj.
So I can do this:
Foo: directories obj/Foo.o
${CXX} obj/Foo.o ${LDFLAGS} -o Foo
But then it ALWAYS does the link:
$ make
g++ obj/Foo.o -o Foo
$ make
g++ obj/Foo.o -o Foo
But if I remove the directories part from Foo:
$ make
make: Nothing to be done for 'all'.
This is even worse:
obj/%.o : directories %.cpp
$(COMPILE.cc) $(OUTPUT_OPTION) $<
So, my question... Is there some way that I can tell an individual target to do some of the pre-setup without that target then always being rebuilt? I could probably make fake targets like this:
makeFoo: directories Foo
But that's annoying. I could also have all be:
all: setup programs
setup: directories
And then do make setup Foo. That's only moderately annoying. What I'd really like is the rule for the objects to ensure the directory exists without adding any spam or unnecessary rebuilds. I suppose I could add something to that particular rule to ensure the directory exists:
obj/Foo.o: Foo.cpp
if [ -d obj ]; then \
mkdir obj \
fi
$(COMPILE.cc) $(OUTPUT_OPTION) $<
Is there a cleaner way?
Thanks to Andreas, I made some adjustments. Here's my entire sample Makefile:
CXXFLAGS = -O3 ${INCLUDES} --std=c++17 -g ${AUTO_ARGUMENT}
COMPILE.cc = $(CXX) $(DEPFLAGS) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
.PHONY: all directories
all: directories programs
directories: | obj
obj:
mkdir obj
programs: Foo
Foo: obj/Foo.o
${CXX} obj/Foo.o ${LDFLAGS} -o Foo
obj/%.o : %.cpp | obj
$(COMPILE.cc) $(OUTPUT_OPTION) $<
clean:
rm -rf obj Foo
And here are my runs:
$ make clean Foo
rm -rf obj Foo
mkdir obj
g++ -O3 --std=c++17 -g -c -o obj/Foo.o Foo.cpp
g++ obj/Foo.o -o Foo
$ make Foo
make: 'Foo' is up to date.
The trick was order-only dependencies -- the pipe thing. See the rule for obj/%.o and directories. Note that it works the same if I do it this way or if my obj/%.o rule used directories instead.

Why is it compiling file twice

I have a makefile
jumbo: objs/jumbo.o objs/utils.o
objs/%.o: %.C
$(CXX) $(CFLAGS) $(CPPFLAGS) -c -o $# $<
The result of the compile
g++ jumbo.C objs/jumbo.o objs/utils.o -o jumbo
objs/jumbo.o:jumbo.C:(.text+0x0): multiple definition of `main'
/tmp/ccwEFt9o.o:jumbo.C:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
make: *** [<builtin>: server] Error 1
if I replace the definition of jumbo
jumbo: jumbo.C objs/utils.o
the problem goes away but the object file is not put away in the objs directory
And I don't know whether it is recompiling jumbo or not when it should only be relinking
You haven't defined any recipe for building the target jumbo. Because of that, make looks for a built-in rule and there is one that knows how to build a file X from a file X.C. Make looks at the directory and lo and behold, there's an X.C (jumbo.C) that exists, so make chooses to use that built-in rule. The built-in rule is:
%: %.C
$(LINK.C) $^ $(LOADLIBES) $(LDLIBS) -o $#
so, since jumbo depends on objs/jumbo. and objs/utils.o directory plus the jumbo.C from the default implicit rule, you get all three on the command line.
To fix this just define your own recipe for creating jumbo:
jumbo: objs/jumbo.o objs/utils.o
$(LINK.C) $^ $(LOADLIBES) $(LDLIBS) -o $#

Using a shell variable within Makefile

I have a line line in make file for compiling a c program, which goes like this
$(CC) -c -o $# $< $(CFLAGS). I have to modify a particular line in code every time and compile again. Modification is just an argument to a function. I have the argument in one file and i use sed utility to modify my c source and then compile. I want to see which of the arguements leads to successful compilation. I tried to use this $(CC) -c -o $# $< $(CFLAGS) ; echo $? >status where I was hoping if compilation was successful status file would have an entry 0. But i see the source file name in status file. I came to know that $? is also a make automatic variable. How can i read the shell variable $? within makefile ? I have tried using $(CC) -c -o $# $< $(CFLAGS) ; echo $$? >status and $(CC) -c -o $# $< $(CFLAGS) ; echo $(shell echo $?) >status without getting correct results.
The version
echo $$? > status
definitely works for me. What OS are you using? What are the incorrect results when using $$??
If you are on Windows, there is no $?, you might want ot use %errorlevel% instead.

Makefile errors when I change a directory name

I have a Makefile that compiles, but I want to change the name of one of the directories from "release" to "objects". This is the original Makefile -
# This makefile compiles ....
INCLUDE = -I/usr/include/X11 -I/usr/local/include -I/usr/local/include/FL/images -I/usr/include/freetype2
CC=g++
CFLAGS=-w -D LINUX -O3 -fpermissive
OBJDIR=release # HERE IS THE DIRECTORY I WANT TO CHANGE
SRCDIR=src
LDFLAGS= -L/usr/X11R6/lib$(LIBSELECT) -lpthread -lfltk -lXext -lXft -lfontconfig -lXinerama -lpthread -ldl -lm -lX11
SOURCES_RAW= robot_driver_agent.cpp robot_driver_position.cpp robot_driver_priorityqueue.cpp main.cpp robot_driver_tree.cpp robot_driver_stack.cpp robot_driver_grid.cpp robot_driver_path.cpp grid_analyzer.cpp tcpserver.cpp tcpclient.cpp servercontrol.cpp clientcontrol.cpp robot.cpp udpserver.cpp udpclient.cpp owncontrol.cpp guiwindow.cpp rs232.cpp
TARGET:= go
TARGETD:= go_d
OBJECTS:=$(SOURCES_RAW:.cpp=.o)
OBJECTS:=$(patsubst %.o, $(OBJDIR)/%.o, $(OBJECTS))
SOURCES:=$(SOURCES_RAW)
SOURCES:=$(patsubst %.cpp, $(SRCDIR)/%.cpp, $(SOURCES))
all: $(TARGET)
$(TARGET): $(OBJECTS)
$(CC) -w -D LINUX $(INCLUDE) $^ -o $# $(LDFLAGS)
release/%.o: src/%.cpp
test -d $(OBJDIR) || mkdir $(OBJDIR)
$(CC) -g -c $< $(CFLAGS) -o $#
debug: $(TARGETD)
$(TARGETD): $(OBJECTS)
$(CC) -w -D LINUX $(INCLUDE) $^ -o $# $(LDFLAGS)
%.o: $(SRCDIR)/%.cpp
$(CC) -c -g $< $(CFLAGS)-o $#
.PHONY : clean
clean:
rm -f $(OBJDIR)/*.o
rm -f $(TARGET) $(TARGETD)
All I do is change the OBJDIR symbol to "objects" so it would just be -
OBJDIR=objects
But when I do that, I get the error -
make: *** No rule to make target `objects/robot_driver_agent.o', needed by `go'.
What am I missing? Is "objects" a word reserved for something in make so I can't use it for directories? Is it something in the make file that I need to change? Honestly, I don't know that much about makefiles so any help at all would be great. Thanks.
You have a rule:
release/%.o: src/%.cpp
...
So that when OBJDIR=release and Make wants to build release/robot_driver_agent.o, it knows just what to do. Then you try OBJDIR=objects, it wants to build objects/robot_driver_agent.o, and it doesn't know how because there's no rule that fits. Try changing the rule to:
$(OBJDIR)/%.o: src/%.cpp
...

How to redirect gcc errors to a file in Unix?

I tried following this but that doesn't work in Unix.
I've been running this command :
gcc temp.c -o temp.o 2> err.txt
And got the following error:
gcc: 2: No such file or directory
Any ideas what that shouldn't work? Maybe because I’m using it over a Unix server?
In tcsh you don't use 2> to redirect stderr, you use >& that will redirect both stdout and stderr. If you want to redirect them separately, have a look at this quick guide.
Redirecting stderr using 2> in tsch is not possible, but here are 2 work arounds
bash -c "gcc temp.c -o temp.o 2> err.txt" #if bash or sh is available
(gcc temp.c -o temp.o > /dev/null) > & err.txt
Yours:
gcc temp.c -o temp.o 2> err.txt
you sure mean:
gcc -o temp.o temp.c 2> err

Resources