Reputation: 1162
I've written a sample program about structs. I wrote 3 source file and a 1 header file. This is the complete source of the program:
main.c:
#include <stdio.h>
#include <stdlib.h>
#include "fish.h"
/*
struct fish
{
const char *name;
const char *species;
int teeth;
int age;
};
*/
/*
void catalog(struct fish f)
{
printf("%s is a %s with %i teeth. He is %i.",
f.name, f.species, f.teeth, f.age);
}
void label(struct fish f)
{
printf("Name: %s\n", f.name);
printf("Species: %s\n", f.species);
printf("Teeth: %i\n", f.teeth);
printf("Age: %i\n", f.age);
}
*/
int main()
{
struct fish snappy = {"Snappy", "Piranha", 69, 4};
catalog(snappy);
label(snappy);
return 0;
}
label.c:
#include "fish.h"
void label(struct fish f)
{
printf("Name: %s\n", f.name);
printf("Species: %s\n", f.species);
printf("Teeth: %i\n", f.teeth);
printf("Age: %i\n", f.age);
}
catalog.c:
#include "fish.h"
void catalog(struct fish f)
{
printf("%s is a %s with %i teeth. He is %i.",
f.name, f.species, f.teeth, f.age);
}
I also wrote a makefile:
fish.o: main.c label.c catalog.c fish.h
gcc -c main.c label.c catalog.c
fish: fish.o
gcc fish.o -o fish
I compile the program in cmd:
make fish
It says:
gcc -c main.c label.c catalog.c
label.c: In function 'label':
label.c:5:5: warning: incompatible implicit declaration of built-in function 'printf' [enabled by default]
catalog.c: In function 'catalog':
catalog.c:5:5: warning: incompatible implicit declaration of built-in function 'printf' [enabled by default]
cc fish.o -o fish
cc.exe: error: fish.o: No such file or directory
cc.exe: fatal error: no input files
compilation terminated.
make: *** [fish] Error 1
If I remove the comments in the main.c and compile only it, It works, But when I broke into small pieces as mentioned above it doesn't work.
What's the wrong?
Upvotes: 2
Views: 567
Reputation: 754910
This linking rule:
fish: fish.o
gcc fish.o -o fish
is appropriate for building a program fish
from a single object file fish.o
(which is presumably compiled from fish.c
).
You need a different rule:
OBJECTS = main.o label.o catalog.o
fish: ${OBJECTS}
${CC} -o $@ ${OBJECTS}
You can add ${CFLAGS}
and ${LDFLAGS}
and ${LDLIBS}
(or ${LDLIBES}
) to the link line as appropriate if you want to, but for simple programs, what I showed suffices.
You don't have to tell make
how to convert main.c
into main.o
; it knows that already. It will use a rule such as:
%.o: %.c
${CC} -c ${CFLAGS} $<
to create the .o
file from the matching .c
file. (This is the GNU Make notation; POSIX make
and other classic versions of make
use an alternative but loosely equivalent notation .c.o:
in place of %.o: %.c
.)
If you don't mind compiling all the sources each time, you can use a similar rule:
SOURCES = main.c label.c catalog.c
fish: ${OBJECTS}
${CC} ${CFLAGS} -o $@ ${SOURCES}
This time, ${CFLAGS}
is practically mandatory (though you'd just about get away without it in your bare-bones sample program).
Note that make
is fussy; the command lines such as the ${CC}
lines must start with a TAB; blanks will not do.
Upvotes: 2
Reputation: 10882
gcc main.c -o fish
only compiles main.c
. main.c
does not know about label.c
. It only knows that it has to call some function called "label", which is defined elsewhere. Then, the linker looks at all of the generated object files, and 'links' them into a single executable:
gcc main.c -c
gcc label.c -c
gcc catalog.c -c
ld main.o label.o catalog.o -o fish
This is the explicit version of
gcc main.c label.c catalog.c -o fish
Upvotes: 3
Reputation: 59637
You'll need to compile all of the .c files together so that you can use your functions defined in label.c and catalog.c in main.c.
You can do this with one step using gcc:
gcc main.c label.c catalog.c -o fish
This will compile each individual source file and produce object files, which will be linked together to produce your executable. The errors that you're seeing occur during the link phase, when gcc is trying to find the catalog
and label
functions.
Upvotes: 4