Makefile clean not removing *.o files? - makefile

I wonder why this won't delete/clean *.o files generated when running make?
# UNIX Makefile
CXX = g++
LD = g++
CXXFLAGS = -g
testlfunction: lfunction.o lfunctionlist.o lprocessor.o testlfunction.o
$(LD) -o $# $^
clean:
rm *.o testlfunction
before it use to be
$(RM) *.o testlfunction
but it didn't work also ;(
Why is this?

To check what really happens, run "make clean" and examine the output of that command.
Is it nothing? Then there might be a file called "clean" in the current directory. Remove it and try again.
Does it start with "rm ..."? Then it seems to be normal.
In all other cases, tell us the exact output you get.
To check whether the commands are really run, insert some "echo" commands before and after the "rm" command. Are they executed?
And finally, did you distinguish between tab characters and spaces? In Makefiles the difference is important. Commands must be indented using tabs.

One way that make clean can 'fail' to execute anything is if there is a file called clean in your directory, possibly the result of running make -t clean. This would create a file, so when you next ran make clean, it would appear up to date - it has no dependencies, so there is no reason to run the action.
If you use GNU Make, ensure that you have the line:
.PHONY: clean
That will stop make -t from creating clean and will ensure that the actions are run.

Related

Is there a way to run a job from another job in GNU Make? [duplicate]

I have a makefile structured something like this:
all :
compile executable
clean :
rm -f *.o $(EXEC)
I realized that I was consistently running "make clean" followed by "clear" in my terminal before running "make all". I like to have a clean terminal before I try and sift through nasty C++ compilation errors. So I tried to add a 3rd target:
fresh :
rm -f *.o $(EXEC)
clear
make all
This works, however this runs a second instance of make (I believe). Is there a right way to get the same functionality without running a 2nd instance of make?
Actually you are right: it runs another instance of make.
A possible solution would be:
.PHONY : clearscr fresh clean all
all :
compile executable
clean :
rm -f *.o $(EXEC)
fresh : clean clearscr all
clearscr:
clear
By calling make fresh you get first the clean target, then the clearscreen which runs clear and finally all which does the job.
EDIT Aug 4
What happens in the case of parallel builds with make’s -j option?
There's a way of fixing the order. From the make manual, section 4.2:
Occasionally, however, you have a situation where you want to impose a specific ordering on the rules to be invoked without forcing the target to be updated if one of those rules is executed. In that case, you want to define order-only prerequisites. Order-only prerequisites can be specified by placing a pipe symbol (|) in the prerequisites list: any prerequisites to the left of the pipe symbol are normal; any prerequisites to the right are order-only: targets : normal-prerequisites | order-only-prerequisites
The normal prerequisites section may of course be empty. Also, you may still declare multiple lines of prerequisites for the same target: they are appended appropriately. Note that if you declare the same file to be both a normal and an order-only prerequisite, the normal prerequisite takes precedence (since they are a strict superset of the behavior of an order-only prerequisite).
Hence the makefile becomes
.PHONY : clearscr fresh clean all
all :
compile executable
clean :
rm -f *.o $(EXEC)
fresh : | clean clearscr all
clearscr:
clear
EDIT Dec 5
It is not a big deal to run more than one makefile instance since each command inside the task will be a sub-shell anyways. But you can have reusable methods using the call function.
log_success = (echo "\x1B[32m>> $1\x1B[39m")
log_error = (>&2 echo "\x1B[31m>> $1\x1B[39m" && exit 1)
install:
#[ "$(AWS_PROFILE)" ] || $(call log_error, "AWS_PROFILE not set!")
command1 # this line will be a subshell
command2 # this line will be another subshell
#command3 # Use `#` to hide the command line
$(call log_error, "It works, yey!")
uninstall:
#[ "$(AWS_PROFILE)" ] || $(call log_error, "AWS_PROFILE not set!")
....
$(call log_error, "Nuked!")
You already have a sequential solution which could be rewritten as:
fresh:
$(MAKE) clean
clear
$(MAKE) all
This is correct and a very safe approach.
Sequential target execution is possible in GNU make with a proper dependency graph:
fresh: _all
_all: _clear
Recipe for all
_clear: _clean
Recipe for clear
_clean:
Recipe for clean
The above rules define the following dependency graph: fresh <- _all <- _clear <- _clean which guarantees the following recipe execution order: Recipe for clean, Recipe for clear, Recipe for all.
Recipes can be shared with multiple targets using:
target1 target2 target…:
recipe1
Merging your script with the above concepts results in:
all _all :
compile executable
clean _clean :
rm -f *.o $(EXEC)
clear _clear :
clear
fresh: _all
_all: _clear
_clear: _clean
With syntactic sugar using chains.mk from https://github.com/pkoper/mk/ you can write:
all all#fresh :
compile executable
clean clean#fresh :
rm -f *.o $(EXEC)
clear clear#fresh :
clear
#fresh = clean clear all
include chains.mk
fresh: #fresh
Or better:
all: compile
#fresh = clean clear compile
include chains.mk
fresh: #fresh
compile compile#fresh:
compile executable
clear clear#fresh:
clear
clean clean#fresh:
rm -f *.o $(EXEC)
If you removed the make all line from your "fresh" target:
fresh :
rm -f *.o $(EXEC)
clear
You could simply run the command make fresh all, which will execute as make fresh; make all.
Some might consider this as a second instance of make, but it's certainly not a sub-instance of make (a make inside of a make), which is what your attempt seemed to result in.

MY computer can't find my makefile on Cygwin (windows)

I'm trying to run the make utility of cygwin, and it keeps telling me that "***No targets specified and no Makefile found. Stop"
I don't get it. This is my makefile if it helps, it's called Makefile.mak:
TestSet.out: TestSet.o Set.o
g++ -o TestSet.out TestSet.o Set.o
TestSet.o: TestSet.cpp Set.h SetInterface.h
g++ -c TestSet.cpp
Set.o: Set.cpp Set.h SetInterface.h
g++ -c Set.cpp
clean:
rm TestSet.out TestSet.o Set.o
This is my makefile if it helps, it's called Makefile.mak
Well that's your problem then.
That isn't one of the names that make looks for by default.
You either need to rename the file or use make -f Makefile.mak
See http://www.gnu.org/software/make/manual/make.html#Makefile-Arguments
You should also make sure you have the man-pages installed for Cygwin, then you can run man make and you will see:
If no -f option is present, make will look for the makefiles GNUmakefile, makefile, and Makefile, in that order.
That would also have answered your question, because it says nothing about files named Makefile.mak

Change make's working directory without long command line

I would like to change the working directory of a makefile.
(Extraneous info: I have a legacy makefile that I mostly want to reuse, though many targets and generated deps files make assume that the working directory will not be different. My idea is to create a makefile for my newer project, which is in a different directory, and include the old one, and set the working directory to the old directory.)
I easily can do this from the command line with
make -f /path/to/new/makefile -C /path/to/old/makefile
The users of this makefile would like not to type that out every time.
Attempt 1
Use MAKEFLAGS in the makefile itself. But neither of these seem to have any effect. (I understand why -f couldn't have an effect; I'm really wondering about -C.)
I've looked at http://www.gnu.org/software/make/manual/html_node/Options-Summary.html, but I can't find anything about what is allowed in MAKEFLAGS and what isn't.
Attempt 2
Create a makefile2 with the new targets
include path/to/old/makefile
foo: bar
and then makefile passes everything through
%:
$(MAKE) -f $(abspath makefile2) -C path/to/old/makfele /$*
I don't get nice autocompletion, parallel jobs don't work, and debug options (dry run) doesn't work.
So
(1) Why doesn't -C work MAKEFLAGS (it does work, but I made a mistake; it doesn't work, and it is documented; it doesn't work, and it is not documented but it is intentional; it doesn't work, and it is a bug)?
(2) Is there a better way of change a makefile's working directory?
Some things are wrong here :
make -f /path/to/new/makefile -C /path/to/old/makefile
The -f options specifies the name of the Makefile to be found when searched in the directory specified with -C (or the current directory if not provided). So it is more :
make -C /path/to/old/Makefile -f name_of_old_makefile
If the name is simply Makefile or makefile, there is no need to provide the -foption.
The MAKEFLAGS variable does not contains -f or -C in the called sub-Makefile.
To be able to pass multiple targets to another makefile, you need the MAKECMDGOALS variable.
Ultimately, all you have to do in your new Makefile is to have someting like this :
all:
$(MAKE) $(MAKEFLAGS) -C /path/to/old/Makefile -f old_Makefile_name $#
%:
$(MAKE) $(MAKEFLAGS) -C /path/to/old/Makefile -f old_Makefile_name $(MAKECMDGOALS)

Copy a file using a makefile at runtime

I used to compile my programs with batch scripts on windows but I recently discovered makefiles which are much more efficient.
I had this line in my .bat file that copied some dlls to the current directory at runtime and it worked perfectly.
copy C:\lib\glfw\glfw.dll
I tried the same line in my makefile and even tried the alternative cp but my terminal prints this error even tho the file is IN the location I specified
process_begin: CreateProcess(NULL, copy C:\lib\glfw\glfw.dll, ...) failed
make (e=2): The system cannot find the file specified.
make: *** [core.exe] Error 2
Here is the full makefile that I am using. Mind you, absent the copy line it works like a charm.. what am I doing wrong or is this possible?
EXEC = core.exe
OBJS = src/obp.o
CC = g++
CFLAGS = -W -Wall
LIBS = -lSOIL -lglew32 -lglfw -lopengl32
LDFLAGS =
$(EXEC): $(OBJS)
$(CC) $(LDFLAGS) -o $# $(OBJS) $(LIBS)
copy C:\lib\glfw\glfw.dll
clean:
rm -f $(EXEC) $(OBJS) *~
It looks like you are running this from an MSYS (or MinGW) environment, which does not know about copy. Instead, you can use
cp C:\lib\glfw\glfw.dll .
If you want to avoid the *nix like cp, then you could use xcopy as follows:
xcopy //Y C:\lib\glfw\glfw.dll
Note the double // which is required to escape the /.
Or you could run this in a regular MS-DOS environment, in which case your clean target will not work because rm will not be found and you should use del.
With your current setup, any built-in DOS command will not be found. See Choosing the shell to read about how make determines which shell to use.
You may need to double the backslashes in order for make to understand what you want:
copy c:\\lib\\glfw\\glfw.dll
Make comes from a Unix background where the file separator is /, so it's sometimes a bit awkward to use it in a Windows environment.

How to Overwrite a variable in makefile from terminal

I have created a simple makefile i.e.
COMMON=hello
all:
gcc $(COMMON).c -o $(COMMON).o
The directory in which I am running the makefile contains three files: hello.c add.c multiply.c factorial.c and subtraction.c.
When I am compiling this in the terminal using the make command, the hello gets printed. Now I want to make changes in the program such that when I write "make add" or "make multiply" or "make factorial", the corresponding program will compile.
Just supply it on the command line.
make COMMON=bye
If the target is predictable from file names in the current directory, you don't really need a Makefile at all, because Make already knows how to make multiply from multiply.c.
.PHONY: all
all: hello add multiply factorial
If you really want an explicit recipe, try something like this.
%: %.c
gcc -o $# $^

Resources