I'm updating the title and content here to make it clear that this particular question was asking something that I didn't see answered plainly elsewhere. The key notion is understanding that something that looks like a single target doing multiple things in a Makefile is actually multiple targets doing one thing each.
I will also remove some extraneous material since that ended up not being relevant.
Original Content
My problem is that I have a Makefile that is (apparently) not calling one of my sub-directory Makefiles correctly. I have a project structure like this:
quendor
src
cheap
cheap_init.c
Makefile
zmachine
main.c
Makefile
Makefile
The Makefile in the project root will refer to the Makefiles in the individual directories. Here is that core Makefile:
CC ?= gcc
CFLAGS += -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L
CFLAGS += -O2 -fomit-frame-pointer
RANLIB ?= $(shell which ranlib)
AR ?= $(shell which ar)
export CC
export AR
export CFLAGS
export RANLIB
SRC_DIR = src
ZMACHINE_DIR = $(SRC_DIR)/zmachine
ZMACHINE_LIB = $(ZMACHINE_DIR)/quendor_zmachine.a
CHEAP_DIR = $(SRC_DIR)/cheap
CHEAP_LIB = $(CHEAP_DIR)/quendor_cheap.a
SUB_DIRS = $(ZMACHINE_DIR) $(CHEAP_DIR)
SUB_CLEAN = $(SUB_DIRS:%=%-clean)
$(SUB_DIRS):
#echo $(SUB_DIRS) # src/zmachine src/cheap
#echo "DIR:"
#echo $# # src/zmachine
$(MAKE) -C $#
$(SUB_CLEAN):
-$(MAKE) -C $(#:%-clean=%) clean
clean: $(SUB_CLEAN)
help:
#echo "Quendor"
.PHONY: $(SUB_DIRS) $(SUB_CLEAN) clean help
A key problem for me is this bit from the above:
$(SUB_DIRS):
#echo $(SUB_DIRS) # src/zmachine src/cheap
#echo "DIR:"
#echo $# # src/zmachine
$(MAKE) -C $#
I put the echo statements in just to show what's happening. Notice the $SUB_DIRS is correctly showing both directories, but when the Makefile runs it only shows src/zmachine. (The comments there indicate what I see during runtime.) The Makefile (apparently) doesn't process src/cheap.
The full output of the Makefile running is this (the first three lines there being my echo statements):
src/zmachine src/cheap
DIR:
src/zmachine
/Applications/Xcode.app/Contents/Developer/usr/bin/make -C src/zmachine
cc -Wall -std=c99 -D_POSIX_C_SOURCE=200809L -O2 -fomit-frame-pointer -fPIC -fpic -o main.o -c main.c
ar rc quendor_zmachine.a main.o
/usr/bin/ranlib quendor_zmachine.a
** Done with Quendor Z-Machine.
The only thing I could think of initially was that perhaps after running the sub-makefile in src/zmachine, the Make process was either erroring out or thinking it was done. But the $(SUB_DIRS) part should have iterated through both directories, I would have thought.
So I'm a bit stuck as to how to proceed.
Extra Note: The "I would have thought" part of what I said was where I was incorrect. $(SUB_DIRS) was not being executed as I thought it was; the accepted answer has clarified this.
The way make works is, if you don't provide an argument, it will start by scanning the Makefile looking for the "default goal". The default goal is simply the first target it encounters (notice it's the first target, not targets).
In your case, the rule:
$(SUB_DIRS):
$(MAKE) -C $#
Is equivalent to:
src/zmachine src/cheap:
$(MAKE) -C $#
Which is equivalent to:
src/zmachine:
$(MAKE) -C $#
src/cheap:
$(MAKE) -C $#
So the first target make encounters is src/zmachine, and that's its default goal and the one that gets processed. The way to fix this is, as user657267 said in the comments, to add one target that you know will be processed first that would have the other targets (that you really want to build) as its prerequisites.
Related
I'm trying to create a makefile titled 'p1' for a project.
When I try the command make p1 it returns with make: nothing to be done for p1
Also, when I try the command make p1 clean it returns no rule to make p1 'clean.' Stop
Here is my makefile:
a.out: main.o P1LinkedList.o const_iterator.o iterator.o Node.o
g++ -std=c++11 main.o const_iterator.o iterator.o Node.o
main.o:
g++ -std=c++11 -c main.cpp
P1LinkedList.o:
g++ -std=c++11 -c P1LinkedList.cpp
iterator.o:
g++ -std=c++11 -c iterator.cpp
const_iterator.o:
g++ -std=c++11 -c const_iterator.cpp
Node.o:
g++ -std=c++11 -c Node.cpp
depend:
g++ -MM main.cpp > p1.dep
clean:
rm -f a.out *.o
What do I need to fix to have the makefile compile .o files from my .cpp files and how do I fix the issue with the clean command?
Edit:
Here are the commands I've used to compile manually:
Helens-Air:p1a helenade$ g++ -std=c++11 *.cpp
Helens-Air:p1a helenade$ ./a.out
^^ and this just continues with the program execution from there
We may have to take this in stages.
First, you seem to misunderstand the difference between a makefile name and a target name. This appears to have been a miscommunication between you and your teacher, but it's easy to clear up.
Suppose you have a makefile named "Makefile", containing the following:
foo:
#echo running the foo rule
bar:
#echo running the bar rule
If you make foo, you will get:
running the foo rule
The argument (foo) tells Make which target to attempt to build. And how did Make know which makefile to use? (After all, you could have a dozen makefiles in the working directory.) You can specify which makefile to use, but if you don't then by default Make will look for a makefile named Makefile (or makefile or GNUmakefile, don't worry about this for now). To specify a makefile with another name, like "Buildfile", you can use the -f flag:
make -f Buildfile
So "p1" ought to have been the name of a target, not a makefile. Within the makefile, rename your a.out rule to p1. Then rename the whole makefile to Makefile. Then
make p1
should work (or at least run).
Edit:
I'll go out on a limb. In the a.out rule (which should now be called the p1 rule), I notice that you have left P1LinkedList.o out of the list of object files to be linked. So try changing it:
p1: main.o P1LinkedList.o const_iterator.o iterator.o Node.o
g++ -std=c++11 main.o P1LinkedList.o const_iterator.o iterator.o Node.o
If that works, you can simplify it with an automatic variable:
p1: main.o P1LinkedList.o const_iterator.o iterator.o Node.o
g++ -std=c++11 $^
And there will be other small improvements you can make.
If it doesn't work, try ls *.cpp and see if you've overlooked some other source file.
I am trying to compile a code -
this code uses a few libraries and for starters I am trying to create a makefile to get one library
I am having difficulties.
this is the makefile
HOME = $(shell pwd)
LIBNA = libbv.a
LIBZP = $(HOME)/$(LIBNA)
# FFLAGC = -Mextend -Msave -g -C -Mchkfpstk -Mchkptr -fpic -Ktrap=fp
FC = gfortran
ifeq ($(OSTYPE),linux)
FC = pgf95 -Msave -fpic
endif
# per il gfortran
FFLAGC = -g -Wall-ffixed-line-length-0 -Mextend -Msave -g -C -Mchkfpstk -Mchkptr -fpic -Ktrap=fp
# FC = gfortran
#
SOURCE = \
filename1.f\
filename2.f\
...
filenamen.f
.SUFFIXES: .f
OBJ = $(SRCS:.f=.o)
.f.o:
$(FC) $(FFLAG) -c $< $#
$(LIBZP): $(LIBZP)($(OBJ))
ar -r $(LIBZP) $?
rm -f $?
this is the makefile I am using.
I get the error
make: *** No rule to make target absolutepath/libbv.a()', needed by
absolute_path/libbv.a'. Stop.
I was wondering if any of you can help
Well, your error message shows this:
absolutepath/libbv.a()
with nothing inside the parentheses. But your makefile has this:
$(LIBZP): $(LIBZP)($(OBJ))
with $(OBJ) in the parentheses. So clearly, $(OBJ) is expanding to the empty string. Why is that?
Well, OBJ is set here:
OBJ = $(SRCS:.f=.o)
based on SRCS. Well, what does that variable contain?
Aha. Nothing, because it's never set. You set this though:
SOURCE = \
...
SOURCE != SRCS, so you're modifying an empty variable and OBJ is the empty string.
I'm not sure why you're prefixing the target with the current directory... that's where it will go by default if you don't specify any directory. In any event, you can use $(CURDIR) rather than running $(shell pwd).
If you're going to use GNU make anyway, I recommend you use pattern rules rather than suffix rules: they're much simpler to read/understand:
%.o : %.f
$(FC) $(FFLAG) -c $< $#
Also don't you need a -o here before $#? I don't use Fortran compilers but I would imagine they work more or less the same as C/C++ compilers.
today I'm requesting your help about a Makefile that's driving me crazy. There it is:
# Executable name
NAME = libft.a
# Compiler and archive linker settings
CC = gcc
AR = ar
CFLAGS = -Wall -Wextra -Werror -O3 -g3
ARFLAGS = -rsc
IFLAGS = -I./includes/
# Project layout
SRC_DIR = ./src/
INC_DIR = ./inc/
OBJ_DIR = ./obj/
OBJ = $(shell grep -r .o ./obj | awk '{print $$3}' | tr '\n' ' ')
.PHONY: all clean fclean re
#------------------------------------------------------------------------------#
all: $(OBJ_DIR) $(NAME)
$(OBJ_DIR):
mkdir -p $(OBJ_DIR)
$(NAME): compile $(OBJ) $(INC_DIR)libft.h
#echo "Linking library $(NAME).\n"
#$(AR) $(ARFLAGS) $(NAME) $(OBJ)
#echo " ✧ $(AR) $(ARFLAGS) $(NAME) object files: OK! √\n"
compile:
make -C src/io
make -C src/lists
make -C src/memory
make -C src/strings
make -C src/tests
I've tried multiple combination of dependencies, rules, etc but I just don't get it. Sometimes I got it to stop relinking but in thoses cases it wouldn't re-compile object files because $(OBJ) was empty and wasn't updated after I ran compile.
This version is close to be good, but everytime I run make it executes the recipe $(NAME) and does the ar -rsc %(OBJ) .. How can I put them in dependencies to $(NAME) ?
Well, basically your entire approach here cannot succeed. Just for one example: you are trying to find the object files using grep (honestly I don't understand that shell command at all; what does printing the $3 word from the output of grep -r do??? Don't you just mean find $(OBJ_DIR) -name \*.o here?) This will expand to all the object files found in your subdirectories. But, that shell command runs when your top-level makefile is parsed, and that parsing happens before make runs any rules... so, no object files have been built yet! So, this target doesn't depend on anything. Even after some object files have been built, it only depends on object files that already exist, not on object files that are created during the build.
Really if I were you I'd do this completely differently. However, the simplest way to make your makefile work properly as written is to build $(NAME) using a recursive make as well; change your makefile like this:
all: compile
$(NAME): $(OBJ) $(INC_DIR)libft.h
#echo "Linking library $(NAME).\n"
#$(AR) $(ARFLAGS) $# $^
#echo " ✧ $(AR) $(ARFLAGS) $# object files: OK! √\n"
compile:
mkdir -p $(OBJ_DIR)
$(MAKE) -C src/io
$(MAKE) -C src/lists
$(MAKE) -C src/memory
$(MAKE) -C src/strings
$(MAKE) -C src/tests
$(MAKE) $(NAME)
Here all doesn't depend on $(NAME); instead, the compile step first builds everything then at the end it recursively invokes itself to build $(NAME); at this point we know everything is up to date and we can depend on the object files existing.
Other things: note I used the automatic variable $^ here not $(OBJ); that variable is a simple variable that runs a shell script: it's expensive! Every time you expand the $(OBJ) variable you pay that cost, so you only ever want to do it one time. Alternatively, you can use := to set OBJS instead so it's only invoked once per make instance. That's still one more time than you need but avoiding this will be painful.
I also moved the mkdir into the compile rule. It's cleaner there than as a prerequisite of all.
Finally, you should never invoke sub-makes using the make command directly. Always use the $(MAKE) variable, or various things will not work correctly.
The question was obvioulsy solved by the previous post.
You need to use the $(MAKE) variable to call recursively your make file with the $(NAME) rule instead of putting $(NAME) as a all dependency, after subsequent calls to your underlying Makefiles using the $(MAKE) variable again.
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.
I've searched around for this issue, but nobody but me seems to have it, which is why I'll now ask.
If have this basic makefile:
CCPP = arm-none-linux-gnueabi-g++
CFLAGS = "-WALL -DPLATFORM_TARGET -DPRINT_MESSAGE"
LIB = lib/libarm.a
LDFLAGS = -lpthread
OBJECTS = $(wildcard ./*/*.o)
PROG = /exports/appl
MODULES = lib src
all: $(PROG)
$(CCPP) $(LDFLAGS) $(OBJECTS) $(LIB) -o $(PROG)
$(PROG): $(MODULES)
#for i in $(MODULES); do (cd $$i && $(MAKE) \
CCPP=$(CCPP) LDPP=$(CCPP) CFLAGS=$(CFLAGS) LDFLAGS=$(LDFLAGS)) || exit 1 ;\
done
clean:
#for i in $(MODULES); do (cd $$i && $(MAKE) clean) || exit 1 ; done
rm $(PROG)
lib:
ar cr ../lib/$(LIB) $(OBJECTS)
This works. It takes whatever source file is within lib and src and compiles and links it nicely together. (By using local makefiles found in these folders which I can post too if need be)
Anyway, what I WANT now, is add more -D directives conditionally.
I've tried:
ifdef ALLOW_BACKTRACE
CFLAGS += -DALLOW_BACKTRACE
LDFLAGS += -rdynamic
endif
and also:
ifdef ALLOW_BACKTRACE
CFLAGS := $(CFLAGS) -DALLOW_BACKTRACE
#endif
or by putting the whole thing in quotes etc...but each time I try, it brings up the help page of make, telling me that it can't 'recognize' the new define.
Any idea what I'm doing wrong?
Any help is much appreciated.
Okay, this should be a more correct version of your makefile, I can not test it though because I don't have your sources:
export CCPP := arm-none-linux-gnueabi-g++
# Note that -pthread is required for both compiling and linking.
export CFLAGS := -pthread -WALL -DPLATFORM_TARGET -DPRINT_MESSAGE
export LDFLAGS := -pthread
LIB := lib/libarm.a
PROG := /exports/appl
MODULES := lib src
all: $(PROG)
$(PROG): $(MODULES)
$(CCPP) -o $# $(LDFLAGS) ./*/*.o $(LIB)
$(MODULES) : % :
$(MAKE) -C $#
touch $#
clean-module.%:
$(MAKE) -C $* clean
clean : $(MODULE:%=clean-module.%)
rm -f $(PROG)
.PHONY: all clean clean-module.%
What I changed:
LDFLAGS = -lpthread: when building multi-threaded applications you need both an extra compiler and linker flag, which is what -pthread/-pthreads gcc options is.
Contents of OBJECTS = $(wildcard ./*/*.o) are only correct when $(MODULES) built correctly. Removed it.
$(PROG) commands actually build $(PROG) target as it should.
$(MODULES) commands build the modules by invoking make in the corresponding directory. And then they update the timestamp of the directory to force rebuild of $(PROG). Since it is a recursive make it can't know whether anything have actually been updated in the module, hence it need to trigger the rebuild of anything that depends on the modules.
I still have a feeling that this won't work for you because your original makefile is missing dependencies.
Try doing this -->
ifeq ($(ALLOW_BACKTRACE),1)
CFLAGS += -DALLOW_BACKTRACE
endif
You've got to be KIDDING me!
Ahem. I seem to have found the solution to my own problem. I don't quite get it, but whatever works, right?
Anyway, here's what I did:
CFLAGS += -Wall -DPLATFORM_TARGET -DPRINT_MESSAGE
ifdef ALLOW_BACKTRACE
CFLAGS += -DALLOW_BACKTRACE
LDFLAGS += -rdynamic
endif
LDFLAGS += -lpthread
$(PROG): $(MODULES)
#for i in $(MODULES); do (cd $$i && $(MAKE) \
CCPP=$(CCPP) LDPP=$(CCPP) CFLAGS="$(CFLAGS)" LDFLAGS=$(LDFLAGS)) || exit 1 ;\
done
First thing: -rdynamic needs to be the first flag in the linker, otherwise it refuses to work. (Don't ask me why, if anyone could enlighten me, be my guest.
Second: I had to put quotes around the expanded $(CFLAGS) in my actual build step. As soon as I did that, it worked like a charm...probably because it had a problem with the spaces.
Thanks to everyone, who went to the trouble of trying to help me.