Makefile not detecting changes to source file when running make - c

Issue Description
I have a Makefile that is not recognizing when changes to the underlying source code are made. When I attempt a build I get the following message to the console: "make: Nothing to be done for 'all'." My sense is that this probably has to do with a flawed understanding on my part regarding how to work with files in different directories. I have seen similar questions on StackOverflow but none seem to deal quite with this issue or the issue appears to result from other problems.
Project Structure
src: the source code files live here.
include: header files live here.
build: object files live here.
bin: executables live here.
test: test code lives here.
Makefile: the make file.
Makefiles
I have created a basic source file called main.c and placed it in src and implemented a simple make file as follows:
CC = gcc
CFLAGS = -DTESTABLE -Wall -std=c99 -g
all: bin/main
bin/main: build/main.o
build/main.o: src/main.c
clean:
rm -f build/main.o
rm -f bin/main
Source File
#include <stdio.h>
int main( int argc, char *argv[] )
{
printf( "Hi there. For real." );
}

These lines:
bin/main: build/main.o
build/main.o: src/main.c
tell make that to build bin/main it needs build/main.o and to build build/main.o it needs src/main.c, but you haven't actually told make how to build either build/main.o or bin/main. You have to provide a recipe that make can use to actually do the build; maybe:
bin/main: build/main.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $# $^ $(LDLIBS)
build/main.o: src/main.c
$(CC) $(CFLAGS) -c -o $# $<

Related

Using a Makefile in C (make: *** No rule to make target .. needed by ... Stop

I'm trying to create a communication channel between two devices, such as two computers, that will work with the cryptographic network protocol Salt channelv2 and forward data to each other. I created 2 applications, where the first application demonstrates the functionality of the Salt channelv2 protocol and the second application creates a secure communication channel (specifically using the TCP / IP model). Applications are working, I compiled them using linking in the CLI and now I am trying to create a makefile file for easy compilation of the program for the user.
This is my Makefile:
CC=gcc
CFLAGS=-O2 -Wall -g -fcommon -I./salt_org -I./header_folders -I./library
#LDFLAGS=
all:program
program: salt_buffer.o libcrypto.a
$(CC) $(CFLAGS) -o program.exe salt_buffer.o libcrypto.a
randombytes.o: randombytes.c
$(CC) $(CFLAGS) -c randombytes.c
tweetnacl_modified.o: tweetnacl_modified.c tweetnacl_modified.h
$(CC) $(CFLAGS) -c tweetnacl_modified.c
tweetnacl_modified_wrapper.o: tweetnacl_modified_wrapper.c
$(CC) $(CFLAGS) -c tweetnacl_modified_wrapper.c
salt.o: salt.c salt.h salti_handshake.h salti_util.h
$(CC) $(CFLAGS) -c salt.c
salt_io.o: salt_io.c salti_util.h
$(CC) $(CFLAGS) -c salt_io.c
salti_handshake.o: salti_handshake.c salti_handshake.h
$(CC) $(CFLAGS) -c salti_handshake.c
salti_util.o: salti_util.c salti_util.h
$(CC) $(CFLAGS) -c salti_util.c
salt_modified.o: salt_modified.c salt_modified.h salt.h
$(CC) $(CFLAGS) -c salt_modified.c
salt_buffer.o: salt_buffer.c header_folders/salt.h \
header_folders/salti_handshake.h header_folders/salti_util.h \
header_folders/salt_modified.h header_folders/salt_io.h
$(CC) $(CFLAGS) -c salt_buffer.c
libcrypto.a: salt.o salti_handshake.o salti_util.o salt_io.o tweetnacl_modified_wrapper.o \
tweetnacl_modified.o randombytes.o salt_modified.o
ar -cvq -o libcrypto.a salt.o salti_handshake.o salti_util.o salt_io.o \
tweetnacl_modified_wrapper.o tweetnacl_modified.o randombytes.o salt_modified.o
clean:
rm -f program *.o *.a hlavickove_subory/*.gch
In one folder are source codes and folders such as salt_org, header_folders, library, salt_buffer.c, salt_modified.c and makefile. The main program is salt_buffer.c and salt_modified.c contains the source file I supplied with the body functions needed for the application that salt_buffer.c works with. With auxiliary source codes I try to create a static library libcrypto.a. Source codes such as randombytes.c, tweetnacl_modified.c, tweetnacl_modified_wrapper.c are in the library folder. Other source codes such as salt.c, salti_handshake.c, salti_util.c, salt_io.c are in the salt_org folder. All the header files I use are in the header_folders folder.
At work, I was inspired by the topic: enter link description here.
The problem I get when running the makefile file is:
gcc -o .o
gcc.exe: fatal error: no input files
compilation terminated.
make: *** [: .o] Error 1
In source files, I have paths to files like this for example salt_buffer.c:
#include "salt.h"
#include "salt_io.h"
#include "salti_util.h"
#include "salti_handshake.h"
#include "salt_modified.h"
I work with the Winlibs compiler with 11.2
Can you please advise me about my errors ?
First, when asking questions like this you should always include (via cut and paste) the actual compile line that generated the errors, not just the errors. The reason for errors like this is always found on the compile line.
Second, your problem is that you should never include the header files on the compile line. The compiler will include the headers because of the #include ... commands inside the source file: you must not include them on the compilation line as well. Rules like this:
salt.o: salt.c salt.h salti_handshake.h salti_util.h
$(CC) $(CFLAGS) -c salt.c salti_handshake.h salti_util.h
should simply be:
salt.o: salt.c salt.h salti_handshake.h salti_util.h
$(CC) $(CFLAGS) -c salt.c
and that's all. Ditto for all other recipes where header files appear on the compilation line.
There are many better ways to write this makefile so you don't have to repeat yourself so many times, but fixing the above should allow your current makefile to work properly.

Why am I getting this error Makefile: No rule to make target 'timer.c', needed by 'timer.o'. Stop

My working directory looks like this:
main.c
Makefile
my_memmove.h
my_memmove.c
c-timer-lib
timer.c
timer.h
My makefile looks like this:
CC := gcc
CFLAGS := -std=gnu99 -g -Wall -Wextra -Ic-timer-lib
TARGET := output
output: main.o my_memmove.o timer.o
$(CC) $(CFLAGS) main.o my_memmove.o timer.o -o $(TARGET)
main.o: main.c
gcc -c main.c
my_memmove.o: my_memmove.c my_memmove.h
gcc -c my_memmove.c
timer.o: c-timer-lib/timer.c c-timer-lib/timer.h
gcc -c c-timer-lib/timer.c -o $#
clean:
rm *.o $(TARGET)
I don't understand why I keep getting the "Makefile: No rule to make target 'timer.c', needed by 'timer.o'. Stop." error. I believe that it's because the timer.c and timer.h files can't be found.
So much confusion here! :)
First, this is definitely wrong:
$(CC) $(CFLAGS) -I main.o ...
The -I main.o tells the compiler that it should use main.o as the name of a directory to search for include files. That clearly won't work. You should remove the -I here.
On to your problem: you have to realize that there are two completely different programs at play here: make which figures out how to run commands, and the commands that are being run, in this case the compiler gcc.
The -I option is an option to the compiler so that the compiler knows where to look for header files that are included by your source code with #include.
That option means nothing to make; it doesn't understand that option. It's just some text to pass to the compiler. Make is looking for the source file timer.c and it can't find it because you haven't told make where it is.
You have to write your rule to look in the correct place, like this:
timer.o: c-timer-lib/timer.c c-timer-lib/timer.h
gcc -c c-timer-lib/timer.c -o $#
(you should always use -o $# so that your compile line puts the output file where make expects to find it, which will be put into the $# variable by make before it evaluates your recipe.)
ETA
Also, are you sure that -DUNITS="ms" is right? We can't tell without seeing how UNITS is used in the source, but I suspect you probably need an extra level of quotes here, like -DUNITS='"ms"'
Really, you are trying to do too much in this makefile. Make already knows how to correctly build object files from source files. If you don't force the issue by writing your own rules, then make's built-in rules will do the job for you. Your makefile can be written like this:
CC := gcc
CFLAGS := -std=gnu99 -g -Wall -Wextra -Ic-timer-lib -DUNITS='"ms"'
TARGET := output
$(TARGET): main.o my_memmove.o c-timer-lib/timer.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $# $^ $(LDLIBS)
my_memmove.o: my_memmove.h
c-timer-lib/timer.o: c-timer-lib/timer.h
clean:
rm *.o $(TARGET)
make doesn't know which headers your source requires so you have to add the prerequisites by hand, although you can add extra rules to allow it to figure that out for itself.

Makefile for C Program

I am trying to use this Makefile for a C Program. Could you please share with me a way how I can understand the Make utility better? I am trying the following:
# stack/Makefile
CC := gcc
CFLAGS += -std=c99
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -g
VPATH = main src
all: bin/main.exe clean run
bin/main.exe: bin/main.o bin/stack.o
$(CC) -o $# $^ $(LDFLAGS) $(LDLIBS)
bin/main.o: main.c
bin/stack.o: stack.c stack.h
bin/%.o: %.c
$(CC) $(CFLAGS) -c -o $# $<
demo:
../bin/main.exe
clean:
rm -f bin/*.o
run:
bin/main.exe
.PHONY: all clean run
And I getting this message:
gcc -std=c99 -Wall -Wextra -g -c -o bin/main.o main.c
error: unable to open output file 'bin/main.o': 'No such file or directory'
1 error generated.
make: *** [bin/main.o] Error 1
The error stems from the fact that your Makefile wants to
generate the executable and object files in subdirectory bin but it
contains no rule to ensure that bin exists when it is
needed. As #JonathanLeffler comments, you can solve that
just by manually creating bin yourself.
But it is often desired that a Makefile itself will ensure
that a subdirectory, or some other resource, exists when it
is needed, and you probably assumed that the pattern-rule
bin/%.o: %.c
would create bin as needed. It won't.
Your Makefile can ensure the existence of bin if you
amend it like this:
Somewhere below the all rule, add a new target:
bin:
mkdir -p $#
This is to make the bin subdirectory if it doesn't exist.
Then change the rule:
bin/%.o: %.c
$(CC) $(CFLAGS) -c -o $# $<
to:
bin/%.o: %.c | bin
$(CC) $(CFLAGS) -c -o $# $<
The additional | bin is an example of an order-only prequisite
It means: If any of the targets (the bin/%.o things) needs to be remade from any of preceding prequisites (the ones before |, i.e. the %.c
things), then bin must be made first. So, as soon as anything needs to be made in bin, bin will be made first.
There is another more basic flaw in your Makefile. all is dependent on clean, so every time you successfully build
your program the object files are deleted. I understand that you intend this, but it entirely
defeats the purpose of make, which is to avoid the need to rebuild everything (object files, executables) every
time by instead just rebuilding those things that have become out-of-date with respect to their prerequisites.
So all should not depend on clean, and then an object file will be recompiled only if it needs to
be recompiled, i.e. is older than the corresponding source file. If and when you want to clean out the
object files, run make clean.
Finally, your demo rule:
demo:
../bin/main.exe
is inconsistent with the others. The others assume that the bin where the executable
is put is in the current directory. The demo rule assumes it is in the parent of
the current directory. If you correct the demo rule then it will be identical to
the run rule, so it is superfluous, but if it were not superfluous then it should
be added it to the .PHONY targets.
The best way to learn the proper way to use makefiles is to read the manual. Also, you can Google for some simple tutorials.

Handling #include <folder/file.h> in C with makefiles

I am in the process of porting some code that was developed in the codeblocks IDE. I am transferring it to a Linux server where I can only use the command line to compile the code. The code is quite large (maybe 100 files) and I need to update the include commands in many files. For when I try to compile it errors on for instance: #include <gsl/gsl_math.h> with a file cannot be found error. I am assuming it cannot be found because the location of the gsl folder was declared in one of the search directory field options in the IDE. I could go through each file an update to the correct path, but is there a better way of doing this for use with a makefile?
Thanks!
EDIT Makefile In Question
# -c : do not link, just create object file
# -o : output file name
CFLAGS += -c -O2 -I../ctraj -I../cspice/include -I../SGP4 -I../cconj -I../GSL-1.13/include
LIBS = -L../ctraj -lctraj -L../cspice/lib -lcspice -L../SGP4 -lsgp4 -L../cconj -lcconj -L./ -lgsl-0 -lgslcblas-0 -lm
DEPS = light.h ../ctraj/ctraj.h ../cconj/cconj.h
OBJ = light.o tle.o propagator.o orbitfit.o conjunction.o light_displacement.o forces_LF.o
OUT = light.exe
%.o: %.c $(DEPS)
gcc -o $# $< $(CFLAGS)
light: $(OBJ)
cd ../ctraj/; make
gcc -o $(OUT) $(OBJ) $(LIBS)
clean:
rm *.o $(OUT)
Edit 2
Folder Structure
light->(GSL-1.13, Light, cconj, ctraj)
the makefile is inside the Light folder.
Error Message
cd ../ctraj/; make
make[1]: Entering directory `/light/ctraj'
gcc -o forces.o forces.c -c -Wall -Wno-maybe-uninitialized -Wno-unused-but-set-variable -O2 -I../cspice/include -Inrlmsise
In file included from ../Light/../cconj/cconj.h:12:0,
from ../Light/light.h:13,
from forces.c:3:
../Light/../cconj/../GSL-1.13/include/gsl/gsl_blas.h:26:28: fatal error: gsl/gsl_vector.h: No such file or directory
compilation terminated.
make[1]: *** [forces.o] Error 1
make[1]: Leaving directory /light/ctraj'
make: *** [light] Error 2
EDIT 3
Second makefile in cconj
# -c : do not link, just create object file
# -o : output file name
#-L../cconj -lcconj
CFLAGS += -c -O2 -I./ -I../GSL-1.13/include
LIBS = -L./ -lgsl-0 -lgslcblas-0 -lm
INC= -I../GSL-1.13/include
DEPS = cconj.h
OBJ = cconj_util.o ellipse_intersect.o collision_prob_real.o rcs2size.o
OUT = libcconj.a
%.o: %.c $(DEPS)
gcc -o $# $< $(CFLAGS)
cconj: $(OBJ)
ar rcs $(OUT) $(OBJ)
clean:
rm *.o $(OUT)
Try adding this line to your makefile, and tell us if it works:
CFLAGS += -I../GSL-1.13/include
In order to compile source code and produce object files, Make must use a rule. (If you don't put such a rule in the makefile, Make has a default rule for that purpose.) It looks something like this:
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#
Without digging too deeply into how that works, we can say that CFLAGS is a list of arguments to be passed to the compiler. When we add -I../GSL-1.13/include, we tell the compiler "if you want to #include something and can't find it elsewhere, look in ../GSL-1.13/include".
If this approach doesn't work, then there's probably a rule in the makefile we must find and alter.
EDIT:
The problem isn't in this makefile (which already contains a reference to GSL-1.13/include). In this command:
cd ../ctraj/; make
this makefile launches a second Make process, which uses the Makefile in light/cconj/. According to the compiler output (gcc -o forces.o ...), that makefile does not include the reference. So try adding the same line there, and if that doesn't work, post that makefile and we'll keep looking.
Use -I option of gcc to specify where to look for includes.

How do I make a simple makefile for gcc on Linux?

I have three files: program.c, program.h and headers.h.
program.c includes program.h and headers.h.
I need to compile this on Linux using gcc compiler. I'm not sure how to do this. Netbeans created one for me, but it's empty.
Interesting, I didn't know make would default to using the C compiler given rules regarding source files.
Anyway, a simple solution that demonstrates simple Makefile concepts would be:
HEADERS = program.h headers.h
default: program
program.o: program.c $(HEADERS)
gcc -c program.c -o program.o
program: program.o
gcc program.o -o program
clean:
-rm -f program.o
-rm -f program
(bear in mind that make requires tab instead of space indentation, so be sure to fix that when copying)
However, to support more C files, you'd have to make new rules for each of them. Thus, to improve:
HEADERS = program.h headers.h
OBJECTS = program.o
default: program
%.o: %.c $(HEADERS)
gcc -c $< -o $#
program: $(OBJECTS)
gcc $(OBJECTS) -o $#
clean:
-rm -f $(OBJECTS)
-rm -f program
I tried to make this as simple as possible by omitting variables like $(CC) and $(CFLAGS) that are usually seen in makefiles. If you're interested in figuring that out, I hope I've given you a good start on that.
Here's the Makefile I like to use for C source. Feel free to use it:
TARGET = prog
LIBS = -lm
CC = gcc
CFLAGS = -g -Wall
.PHONY: default all clean
default: $(TARGET)
all: default
OBJECTS = $(patsubst %.c, %.o, $(wildcard *.c))
HEADERS = $(wildcard *.h)
%.o: %.c $(HEADERS)
$(CC) $(CFLAGS) -c $< -o $#
.PRECIOUS: $(TARGET) $(OBJECTS)
$(TARGET): $(OBJECTS)
$(CC) $(OBJECTS) -Wall $(LIBS) -o $#
clean:
-rm -f *.o
-rm -f $(TARGET)
It uses the wildcard and patsubst features of the make utility to automatically include .c and .h files in the current directory, meaning when you add new code files to your directory, you won't have to update the Makefile. However, if you want to change the name of the generated executable, libraries, or compiler flags, you can just modify the variables.
In either case, don't use autoconf, please. I'm begging you! :)
For example this simple Makefile should be sufficient:
CC=gcc
CFLAGS=-Wall
all: program
program: program.o
program.o: program.c program.h headers.h
clean:
rm -f program program.o
run: program
./program
Note there must be <tab> on the next line after clean and run, not spaces.
UPDATE Comments below applied
all: program
program.o: program.h headers.h
is enough. the rest is implicit
The simplest make file can be
all : test
test : test.o
gcc -o test test.o
test.o : test.c
gcc -c test.c
clean :
rm test *.o
Depending on the number of headers and your development habits, you may want to investigate gccmakedep. This program examines your current directory and adds to the end of the makefile the header dependencies for each .c/cpp file. This is overkill when you have 2 headers and one program file. However, if you have 5+ little test programs and you are editing one of 10 headers, you can then trust make to rebuild exactly those programs which were changed by your modifications.

Resources