Issue with Makefile in top level directory, sources in subdirectories - makefile

I have a directory called project.
It contains two sub-directories called client and server, and a makefile called Makefile.
client and server have got source files called client.c and server.c, respectively.
I don't have any separate makefiles in the subdirectories for sources belonging to that directory. All builds are done by the single makefile. The Makefile code is
FLAGS = -W -Wall -g -pthread
SERV =./server/server.c #My server code
CLI =./client/client.c #My client code
build:svr cnt
svr: $(SERV)
cc $(FLAGS) $(SERV) -o ./server/server.out
cnt: $(CLI)
cc $(FLAGS) $(CLI) -o ./client/client.out
Now I ran make cnt and it replied
cc -W -Wall -g -pthread ./client/client.c -o ./client/client.out
The problem is all the subsequent make cnt commands end up compiling it again and outputting the above text even though I'm not changing ./client/client.c
I'm stuck here. Don't know what to do.
What I want to do is:
With make cnt, compile client/client.c and output its executable in the client/ directory
With make svr, compile server/server.c and output its executable in server/ directory.
And with make, compile bothserver/server.candclient/client.c` and output their executables in their respective directories
But since I don't have any executables called svr and `cnt the problem I am having isn't solved.
If I change the target to ./client/client.out instead of cnt and then call make client/client.out then it would be fine, exactly what I need but I don't want to enter long command make client/client.out in my terminal
The workaround I have got is as follows
cnt: $(CLI)
cc $(FLAGS) $(CLI) -o cnt
cp cnt ./client/client.out
But not quite satisfied with it. I'm sure what I want to do is really simple and there should be some convenient way around doing it. So how can I do that?

Let's formulate what you want. You want target named `cnt' not to be rebuilt. The makefile you've written knows nothing about client.out file, because it only appears in shell commands within a rule. Make program doesn't read information from shell commands, it only does substitutions there and executes them.
When makefile chooses the targets it will rebuild (`cnt' is one of these targets), it compares update time of a target file with update time of its prerequsites. Since at the time you run ``make cnt'' the file named cnt is absent, the target named so is considered as requiring update. So commands are run and yield no file named cnt, so next make run will consider it for updating as well.
There are two possible solutions. The first one is to give targets same names as of the file, that the rule commands will generate. So, you might end up like this:
client/client.out: $(CLI)
cc $(FLAGS) $(CLI) -o ./client/client.out
Your questioin has nothing to do with directories, by the way. You should also read about .PHONY directive, use $(CC) instead of cc and read gnu make manual, which might be very helpful.

Try this:
SERVO =./server/server.out
CLIO =./client/client.out
.PHONY: srv cnt build
build: svr cnt
svr: $(SERVO)
cnt: $(CLIO)
$(SERVO) $(CLIO): %.out : %.c
cc $(FLAGS) $^ -o $#
Now you can make srv, make cnt, or just make.
There are slightly more sophisticated things you can do, but this should be enough for now.

Related

Makefile and subdirectories

I'm struggling with the correct syntax of a makefile.
This is my folder structure:
project
│ Makefile
│ HERE SHOULD BE THE OUT FILE AFTER make command
│
└───include
│ header.h
│
│
└───src
function1.c
function2.c
How must the makefile look to ensure correct results?
This is my current makefile:
SOURCES = src/function.c src/function.c src/function.c
OBJECTS = $(SOURCES:.c=.o)
CC = cc
RM = rm -f
CFLAGS = -Wall -Wextra -Werror
NAME = output.a
all: $(NAME)
$(NAME):
$(CC) $(CFLAGS) -c $(SOURCES)
ar rcs $(NAME) $(OBJECTS)
clean:
$(RM) $(OBJECTS)
fclean: clean
$(RM) $(NAME)
re: fclean $(NAME)
my current output if i run make all:
cc -Wall -Wextra -Werror -c src/function1.c src/function2.c
ar rcs output.a src/function1.o src/function2.o src/function1.o
ar: src/function1.o: No such file or directory
make: *** [Makefile:15: output.a] Error 1
if i run make flcean the output looks the following:
rm -f src/function1.o src/function2.o
rm -f output.a
So it doesn´t remove anything because the .o files are stored in the root, not the /src subdirectory
I'm struggling with the correct syntax of a makefile.
Your makefile syntax is fine. In fact, your makefile is syntactically valid and reasonably well structured. It looks a lot better than many of the ones we see around here.
I guess what you're actually struggling with is that it doesn't work, even after you fix the weird disagreement between the source file list in the makefile itself and the actual source files on disk. But "doesn't work" is a pretty vague, though lamentably common, description. You would get better help, faster, by saying something along the lines of "the .o files are created in the top-level directory instead of in the src/ directory." (Which is exactly what I expect to happen, and as a result, the ar command will fail, and the clean target will not clean the .o files.)
You need to understand that make itself doesn't know much about building software. What it knows is how to match rules to patterns so as to execute associated recipes of shell commands. The particular kinds of patterns it matches and the built-in rules that come with it are oriented toward building software, but you can't expect it to go very far with anticipating what you mean. It, like any other computer program, will happily do what you say, instead, when that differs. In this case, it just runs the cc command with the arguments you specify, and cc will choose under those circumstances to put the .o files in the working directory.
From a stylistic and best-practices standpoint, it's best to write rules that build only their target file, unlike your rule for $(NAME) that attempts to build not just $(NAME) but also all the component object files. The object files would be better built according to their own rule or rules. Making the object files prerequisites of the rule for $(NAME) will ensure that they get built when needed. That will also allow for them to not be built when that is not needed. That variation on your rule would look like this:
$(NAME): $(OBJECTS)
ar rcs $# $^
Note also that in the recipe, I have substituted automatic variable $# for a repetition of the rule target name. That's good form, but not obligatory. I have also substituted automatic variable $^ for a repetition of the prerequisite list. That's less clear-cut, in part because $^ is specific to GNU make, but if you're ok with that dependency then it's a great way to avoid repeating yourself.
Now, about building the object files: you could write a pattern rule (GNU make only) or a suffix rule that builds an object file from a corresponding C source file, or you could even write a separate rule for each object file. But you don't actually need to do that. make comes with a built in rule that will serve your needs in that area just fine, so your best bet may be to not attempt to provide your own rule for that at all. That is: modifying the rule for $(NAME) as suggested above should be sufficient for successful building, supposing, again, that the contents of your SOURCES variable accurately reflect the source files you want to build.

Defining path variable for a make file

In my assignment instructions, I was told to make a
Makefile without absolute directory names or derived binary files. Execution of make with no parameters should build the target program "wordpairs". Assume that the environment variable GET_WORD is defined as the pathname of a directory which contains directories "include" and "lib" containing getWord.h and libget.a
My directory for my code contains: pic
And my Makefile is:
#DIR := ${GET_WORD}
DIR := ${CURDIR}
Main : getWord.o crc64.o sTools.o hashingTools.o Main.c libget.a
gcc -g -o wordpairs Main.c getWord.o crc64.o sTools.o hashingTools.o $(DIR)/lib/libget.a
getWord.o : getWord.c getWord.h
cc -c $(DIR)/include/getWord.c $(DIR)/include/getWord.h
# cc -c getWord.c getWord.h
crc64.o : crc64.c crc64.h
cc -c crc64.c crc64.h
sTools.o : sTools.c sTools.h
cc -c sTools.c sTools.h
hashingTools.o : hashingTools.c hashingTools.h
cc -c hashingTools.c hashingTools.h
clean :
rm $(DIR)/include/*.h.gch
But when I run make, I get
make: *** No rule to make target 'getWord.c', needed by 'getWord.o'. Stop.
The files are in the folders include/lib.
I only understand the basic of make files, so can someone help me out how to achieve what I was assigned to do? What's causing this error?
(updated makefile code)
So apparently I just need to define GET_WORD variable where the grade can change it to a specific location. The thing is that apparently you cant call variables in the requirement file line (see how I didnt specific anything for getWord.o)
GET_WORD = /home/tam#change this!
wordpairs : Main.c crc64.o hashingTools.o sTools.o getWord.o
gcc -o wordpairs $^ -I ${GET_WORD}/include ${GET_WORD}/lib/libget.a
getWord.o :
cc -c ${GET_WORD}/include/getWord.c ${GET_WORD}/include/getWord.h
crc64.o : crc64.c crc64.h
cc -c $^
hashingTools.o : hashingTools.c hashingTools.h
cc -c $^
sTools.o : sTools.c sTools.h
cc -c $^
clean :
rm wordpairs crc64.o hashingTools.o sTools.o *.h.gch
#echo $(GET_WORD) ${GET_WORD}
getWord.o : getWord.c getWord.h looks for these files in the current directory.
You should apparently use GET_WORD to define a couple of additional variables, not redefine it to something else than what's given explicitly in the assignment.
If you figure out how to set INC to the include/ directory, your rule for these files should look something like
getWord.o : $(INC)/getWord.c $(INC)/getWord.h
cc -c $^
Notice how a dependency on a file in another directory must include the directory name; and how make won't actually look at how to make a new thing until the dependency resolution forces it to (and even then it doesn't know that a string in the command it runs is equal to one of the dependencies just because the strings are identical, let alone then when they are different, as in your attempt).
Notice also the use of $^ to say "the things in the dependencies". Generally, you want to avoid repeating information - if you change something, you don't want to change it in many places because it's easy to forget (see also DRY principle.)
... I don't think the professor wants the .c file in the include directory, actually, though; just the .h file would be my guess.
As a further aside, to have just make without arguments create a particular target, put it as the first target in your Makefile.
I hope this is sufficient to help you see how to solve your assigment!

GNU make in newly created subdirectory

First - I know there are a lot of discussions similar to this, but I've spent hours without them working for me.
My makefile first creates a directory named by the current date and time. I then have the makefile append to a header file a line which creates a string with this directory name. For this reason, I first need to copy all the source files (including the header) into the newly created subdirectory, so that I can preserve the original header and only modify the header (in the subdirectory) which will be used for compilation. I would then like to build in that new directory.
My trouble is getting make to properly build the .o files in the new subdirectory. The solution I've found is to have
$(NOW)%.o: $(NOW)%.cpp
$(CC) -c $(FLAGS) $<
where $(NOW)$ is the subdirectory name. The issue is that my $(FLAGS) seem to be ignored: the output is, roughly
g++ -c -o <.o file> <.cpp file>
(Yes, there is actually extra introduced space between g++ and -c.) Whereas building in the top level directory a la
%.o: %.cpp
$(CC) -c $(FLAGS) $<
correctly outputs
g++ -c <my flags> -o <.o file> <.cpp file>
To summarize, I am unable to compile normally by transferring the source files to a newly-created subdirectory and building the .o files in that directory. TYIA.
Ad John points out, there's no way to definitively diagnose your problem with the tiny bit of makefile you provided, because the error is not in the code you provided, it's in some other part of your makefile. You need to provide a SSCCE ideally, but if not that then at least we need to see how the NOW variable is set and the linker rule so we know what make is trying to build.
I should also point out that by convention you should not use CC to hold the C++ compiler; the CC variable holds the C compiler. Use CXX for the C++ compiler and CXXFLAGS for the C++ compiler flags.
One possibility is that you are assigning the NOW variable using a recursive assignment so that the timestamp is recreated every time the variable is evaluated; it could be that the timestamp changes over the lifetime of the makefile.
The other very common problem is that you created the pattern rule, but make is not using it because the targets make wants to build don't match the pattern.
So for example, if your link line looks like this:
SRCS = foo.cpp
OBJS = $(SRC:.cpp=.o)
myprog: $(OBJS)
$(CXX) ...
$(NOW)%.o : $(NOW)%.cpp
$(CXX) ...
then your pattern will not be matched because make is trying to build the file foo.o and your rule tells it how to build $(NOW)foo.o which are not the same thing.

Compile all source files into executables

I know that makefile is used for a project where files are related. But I want to use it in a different way.
Since I always write lots of test files, I need to type a bunch of flags every time I compile them, that's so troublesome. I just want to write a makefile that compiles all source files into executables with their corresponding names - like a.c to a and b.c to b, etc. so that I can get executables by simply typing make instead of the whole gcc ...
Is there any simple way to do it?
Make has a built in implicit rule like this:
% : %.c
$(CC) -o $# $(CFLAGS) $<
$(CFLAGS) would contain all your options.
Then, doing
make foo
Would try to produce foo from foo.c (if it existed).
To be able to compile all of them in one go, add another rule:
all: $(patsubst %.c,%,$(wildcard *.c))
This new rule, called 'all', has the list of your executables as its prerequisite. The wildcard function lists all .c files in the directory, and the patsubst removes the .c from each of them, leaving a list of the executables that would be produced from each .c file.
So doing
make all
causes it to try to compile each .c file into the corresponding executable.
Alright understood. I'm not too sure if you'll understand the syntax. I'll try to explain as much as I can.
you'll make a file called Makefile no extensions.
DIR=$(HOME)/../"Your directory"
all: "Whatever driver you may have"
purify: purify g++ -o "Your file" -Wall -pedantic -g "objective file .o extension"
# Makes clean file
clean:
rm -f *.o "Drivers"
new:
make clean
make
make has built in implicit rules to do that. Just type make a or make b or make a b or whatever you want. Add and export an environment variable called CFLAGS if you want to add any special options.

How to see exactly what make is doing

Ive got some large make files for a third party project that are not building due to linker issues.
From looking at the make files, I think it should be executing something like:
LIBS = -lm
CC = gcc
bin = bin
myapp: $(bin)/main.o $(bin)/other.o $(bin)/etc.o
$(CC) $(bin)/main.o $(bin)/other.o $(bin)/etc.o $(LIBS) -o myapp
gcc bin/main.o bin/other.o bin/etc.o -lm -o myapp
Instead from the error it seems to be failing on something like: It also didn't put any of the .o files in the expected bin/ location, but just left them in the source directory...
cc main.o -o myapp
But I cant locate anywhere that might come from. Is there some way to get some kind of stacktrace through the make files?
I am aware of -n and -d, but neither seems to tell me what target line and file yeilded that command, or which series of targets led there and the values of any $() expansions (The one im expecting is the only myapp: I can find in any of the makefiles...)
Check out the --debug option. From my manpage:
--debug[=FLAGS]
Print debugging information in addition to normal processing. If the
FLAGS are omitted, then the behavior is the same as if -d was specified.
FLAGS may be a for all debugging output (same as using -d), b for basic
debugging, v for more verbose basic debugging, i for showing implicit
rules, j for details on invocation of commands, and m for debugging
while remaking makefiles.
remake is a very good choice but in a pinch something like the following (saved as debug.mk) can be a good help too. It won't tell you as much as remake but it might tell you enough to start with.
# Use as: MAKEFILES=debug.mk make
OLD_SHELL := $(SHELL)
ifneq (undefined,$(origin X))
override X = -x
endif
SHELL = $(if $#,$(warning Running $#$(if $<, (from: $<))$(if $?, (newer: $?))))$(OLD_SHELL) $(X)
You can print out the other automatic variables there too if you wanted to see a bit more about what was going on.

Resources