Compile any C Program using just "make" (From a Makefile) - compilation

I'm learning C Programming through "Learn C the Hard Way." I am currently (for quite a long time) on Exercise 2, which can be found here: http://c.learncodethehardway.org/book/ex2.html
In the extra credit section, there is a challenge which asks us to edit the Makefile so we can compile the .c file (ex1.c) using just the command "make". This is what the challenge exactly says:
Create an all: ex1 target that will build ex1 with just the command make.
Through looking here and a bunch of other places, this is the code I think is correct:
CFLAGS="-Wall" -g
all: ex1
CFLAGS="-Wall" -g
clean:
rm -f ex1
However, when I try to run this, I get the compiled file and keep getting an error:
cc "-Wall" -g ex1.c -o ex1
CFLAGS="-Wall" -g
/bin/sh: 1: -g: not found
make: *** [all] Error 127
What is happening here? What is the reason behind the error message? How can I fix this?
Thanks guys.

If all is the first target in your makefile (I'm making a wild guess here since you've not showed the entire Makefile), make would choose that as the first target to build, when you do not pass an explicit target from the command line (i.e. mere make)
ex1 is a pre-requisite for all, so it builds it first and hence you see the following line:
cc "-Wall" -g ex1.c -o ex1
After ex1 is built, make tries to execute the recipe for all, where it executes the following command:
CFLAGS="-Wall" -g
Since -g by itself is not a valid command or application that can be executed in the shell, you get this error:
/bin/sh: 1: -g: not found
Solution:
You've already defined CFLAGS in the beginning of the makefile, so no need to define it once again in the recipe. Even if you wish to override the variable CFLAGS, you should not be using it directly as part of the recipe.
Define all and clean as PHONY targets, if you've not already done so. The target all and clean do not create a file named all or clean after the recipe is executed, so it is a good practice to classify these targets as PHONY.
You don't need double quotes around -Wall
The following Makefile has all these corrections:
CFLAGS = -Wall -g
all: ex1
clean:
rm -f ex1
.PHONY: all clean

CFLAGS = -Wall -g
all: ex1
clean:
rm -f ex1
Should be all you need since make has a built-in default rule to compile a .c file to an executable.
Your mistake is to use a variable assignment as a command. The part with
CFLAGS="-Wall" -g
tries to run the command -g with a one-shot variable assignment CFLAGS="-Wall".

I would like to suggest one adjustment so that you can build ex1 just by entering make, regardless if this is the first compilation or a recompilaiton of the source code.
Source: ex1.c
Makefile:
CFLAGS=-Wall -g
all : clean ex1
clean:
rm -rf ex1 ex1.dSYM
.PHONY: all clean
By adding the clean Phony Target as the first prerequisite for all, it will execute the rm -rf ex1 ex1.dSYM command prior to executing the implied cc command with the ex1 prerequisite.
Also, on Mac OS-X using .PHONY all clean is not necessary for make to execute the commands in the Makefile, however, it is probably good precedent to set so that anyone reading the code later on realizes that all and clean are not actual target files.
Oh and a big thank you to Zed A. Shaw for making Learn the Hard Way free to read at his site Learn C the Hard Way.

Related

Makefile stops running at the middle [duplicate]

Hopefully this is a very simple question. I have a makefile pattern rule that looks like this:
%.so : %.f %.pyf
f2py -c -L${LAPACK_DIR} ${GRASPLIBS} -m $* $^ ${SOURCES} --opt='-02' --f77flags='-fcray-pointer' >> silent.txt
I want the makefile to build a number of .so files, so I tried to get it to build two files (radgrd_py.so and lodiso_py.so) by doing this:
radgrd_py.so lodiso_py.so:
%.so : %.f %.pyf
f2py -c -L${LAPACK_DIR} ${GRASPLIBS} -m $* $^ ${SOURCES} --opt='-02' --f77flags='-fcray-pointer' >> silent.txt
and then tried this:
radgrd_py.so:
lodiso_py.so:
%.so : %.f %.pyf
f2py -c -L${LAPACK_DIR} ${GRASPLIBS} -m $* $^ ${SOURCES} --opt='-02' --f77flags='-fcray-pointer' >> silent.txt
But in each case, it only builds the first target that I specify. If I run 'make radgrd_py.so' it works fine, I'm just not sure how to specify a list of files that need to be built so I can just run 'make'.
The usual trick is to add a 'dummy' target as the first that depends on all targets you want to build when running a plain make:
all: radgrd_py.so lodiso_py.so
It is a convention to call this target 'all' or 'default'. For extra correctness, let make know that this is not a real file by adding this line to your Makefile:
.PHONY: all
Best way is to add:
.PHONY: all
.DEFAULT: all
all: radgrd_py.so lodiso_py.so
Explanations:
make uses the first target appearing when no .DEFAULT is specified.
.PHONY informs make that the targets (a coma-separated list, in fact) don't create any file or folder.
all: as proposed by schot

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

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 $# $^

Makefile clean not removing *.o files?

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.

Resources