C: Header file and include question. Need help!
It is my understanding that C has makefiles and include statements so you don't have singular monster size files and that you sho开发者_StackOverflow社区uld functionally decompose your code. Therefore, if I'm right, I should be able to make functional calls across .c files if I do my headers and makes correctly.
I'm trying to do that but unfortunately I am getting an error.
The files have the following contents:
File 1)test.c:
#include<stdio.h>
#include"suc.h"
main()
{
printf("Hello World\n\n");
printf("This is the number: %d \n\n", suc(6));
}
File 2)makefile:
CC=gcc
CFLAGS=-c -Wall
test: suc.o
$(CC) -Wall -o test test.c
suc.o: suc.c
$(CC) $(CFLAGS) suc.c
File 3)suc.h
#ifndef SUC_H_GUARD
#define SUC_H_GUARD
// returns the successor of i (i+1)
int suc(int i);
#endif
File 4)suc.c
#include "suc.h"
int suc(int i)
{
return i + 1;
}
When I make (make -B) the top I get:
gcc -c -Wall suc.c
gcc -Wall -o test test.c
test.c:7: warning: return type defaults to 'int'
/tmp/cc/7w7qCJ.o: In function 'main':
test.c: (.text+0x1d): undefined reference to 'suc'
collect2: ld returned 1 exit status
make: *** [test] Error 1
However: Both produce the expected results: A) This single file program works ok!
#include<stdio.h>
main()
{
printf("Hello World\n\n");
printf("This is the number: %d \n\n", suc(6));
}
int suc(int i)
{
return i + 1;
}
B) All the files in the original but with the following change to test.c:
#include<stdio.h>
#include"suc.h" //suc() is still defined b/c suc.h is included
main()
{
printf("Hello World\n\n");
printf("This is the number: %d \n\n", 4); //HERE! -> no function call
}
Help, please and thank you! I don't quite understand what the error messages are trying to tell me.
You need to separately compile the source files to their object files and then link the object file to get the executable test
.
So you need:
CC=gcc
CFLAGS=-c -Wall
test: test.o suc.o
<tab>$(CC) -Wall -o test test.o suc.o
test.o: test.c
<tab>$(CC) $(CFLAGS) test.c
suc.o: suc.c
<tab>$(CC) $(CFLAGS) suc.c
where <tab>
is a tab.
The problem in your current makefile is here:
test: suc.o
$(CC) -Wall -o test test.c
which says test
depends on suc.o
and to get test
you need to do:
$(CC) -Wall -o test test.c
but look at that compile/link line, it does not include any source/object file that has the suc
function defined.
You can add a suc.o
as:
$(CC) -Wall -o test test.c suc.o
But it is considered bad because say you change only suc.c
file then your makefile will regenerate suc.o
and will also have to regenerate test
, but for regenerating test
you are re-compiling test.c
even thought it was not changed.
In your case, you compile two files "suc.c" and "test.c" into two different object files - "suc.o" and "test.o". However, when you link your program, you specify only one object file, which makes it impossible for linker to find a definition or "suc" function. You have to correct your make files to something like:
suc.o: suc.c
$(CC) $(CFLAGS) suc.c
test.o: test.c
$(CC) $(CFLAGS) test.c
test: suc.o test.o
$(CC) -Wall -o test suc.o test.o
Good luck!
You need to tell the linker to include the compiled code in suc.o
(produced in the first compilation step) because the C linker is pretty stupid; it doesn't know about the function implementation by magic. (It's even occasionally useful that it is this way!)
Doing the second step of the compilation with this should work:
gcc -Wall -o test test.c suc.o
In addition to all the answers telling you to link with "suc.o", the warning return type defaults to 'int'
is telling you that you have neglected to declare a return type for your main()
function.
The correct definition is something like:
int main(int argc, char *argv[])
When building test, you're not linking suc.o
in.
Compile both test.c
and suc.c
into object files, then link them both into the final test
executable.
This makefile should work (make sure you replace the spaces with tabs in the rules):
CC=gcc
CFLAGS=-c -Wall
.PHONY: all
all: test
test: test.o suc.o
$(CC) -Wall test.o suc.o -o test
test.o: test.c
$(CC) $(CFLAGS) test.c
suc.o: suc.c
$(CC) $(CFLAGS) suc.c
gcc -c file.c
will compile file.c
to object file file.o
.
gcc -o test test.c
will compile and link test.c
to executable.
But in order to create the executable, you have to link with all the object files that are needed, in your case suc.o
, so you have to write either
gcc -c test.c
gcc -c sic.c
gcc -o test test.o sic.o
either
gcc -o test test.c sic.c
This dependency line fails:
test: suc.o
$(CC) -Wall -o test test.c
because you don't link with suc.o (and, btw, test depends on suc.o AND test.o)
your lines should be:
test: test.o suc.o
$(CC) -Wall -o test test.o suc.o
test.o : test.c
$(CC) -c test.c
There are certainly already enough answers on here. One more can't hurt. Make is (generally) pretty smart. Let it use it's knowledge of standard build rules and simplify your Makefile down to the single line:
test: test.o suc.o
Do not bother giving it simple build rules, because it can generally guess them. (I'm thinking about gnu make, but most (if not all) versions will do the same thing.)
Also, as a side note, consider renaming your executable. The name "test" is the cause of much confusion, since whenever you try to run it you will unexpectedly get either the shell built-in or /bin/test.
精彩评论