I have four files containing C code.
Headers.h - (contain all necessary) headers
AddStudent.h - that file include Headers.h also introduce some function delegation
AddStudent.c - contains functions described in AddStudent.h
main.c - contains main()
The question is how to compile the code with cc ?
In your case, your probably just need:
cc main.c AddStudent.c
The right thing to do is make a makefile. Here's a (probably a bit naive) example:
myapp: main.o AddStudent.o
cc -o myapp main.o AddStudent.o
main.o: main.c AddStudent.h Headers.h
cc -c -o main.o main.c
AddStudent.o: AddStudent.c AddStudent.h Headers.h
cc -c -o AddStudent.o AddStudent.c
The best place to learn about make is the GNU Make Manual.
Bonus note - if you're starting to learn C, you might want to check out clang. It gives way better error messages than gcc does, in addition to supporting C99 without special flags and being much faster at compiling.
Related
I am new to coding so please bear with me. I have searched and have not been able to find a solution for my problem. I working in C and I have multiple files that I have to compile using the c11 compiler and one file that I need to use GNU gcc with. Is there a way to create a makefile that can do this with both compilers or is there a high level way that I am unaware of?
Thanks in advance
The CC make variable tells make what C compiler to use. With GNU make it can be defined globally or on a per-target basis. The following should do what you want (assuming foo.c is the source file you want to compile with gcc):
CC := c11
foo.o: CC=gcc
Demonstration (with clang instead of c11 because I do not have this one):
$ ls
bar.c baz.c foo.c Makefile
$ cat Makefile
all: $(patsubst %.c,%.o,$(wildcard *.c))
CC := clang
foo.o: CC=gcc
$ make
gcc -c -o foo.o foo.c
clang -c -o bar.o bar.c
clang -c -o baz.o baz.c
My teacher is not the best at explain C so I'm having a bit of trouble understanding the connection of makefiles. I have already added the code for complex.c, complex.h, and main.c. I'm just having trouble compiling it all using the make command. I followed the example on the powerpoint he handed up and I don't understand why its failing to get to complex.
makefile
complex: main.o complex.o
gcc -o complex main.o complex.o
main.o: main.c complex.h
gcc -c main.c -lm
complex.o: complex.c complex.h
gcc -c complex.c -lm
clean:
rm*.o complex
ls
main.o
main.o: complex.h
gcc -c main.c
complex.o
complex.o: complex.h
gcc -c complex.c
Error
mason% make
gcc -o complex main.o complex.o
ld: fatal: file main.o: unknown file type
ld: fatal: file processing errors. No output written to complex
collect2: error: ld returned 1 exit status
*** Error code 1
make: Fatal error: Command failed for target `complex'
It looks like you have put Makefile fragments inside main.o and complex.o. These should be generated by the compiler, not by you.
Delete these files, and make again.
Additionally, your make clean rule is missing a space.
clean:
rm *.o complex
ls
One more thing. No need for -lm in the compile lines.
main.o: main.c complex.h
gcc -c main.c
complex.o: complex.c complex.h
gcc -c complex.c
You should add -lm at the linking phase.
complex: main.o complex.o
gcc -o complex main.o complex.o -lm
The "Makefile" defines and controls the build dependencies.
For example, you can't build the main executable binary without first building the binary object/module files that go with it. In this case, those are main.o and complex.o.
Generally any object file you need also needs a rule (though some rules can use "wildcards" to build more).
This is all rather academic. Best to take errors at their word and try to disprove them (this one basically says that main.o exists and is incorrect). In this case the hypothesis that main.o exists is supported by the fact that it didn't compile when you ran the make command.
Until you learn more you could invoke "make" using "targets". Like: make clean and make complex. It might help bring clarity.
A lot of makefiles put an "all" target to sort of reset the build. That then depends on "clean" and the executable and library targets. Like:
all: clean complex
So then you "make all" to clean and build.
A good tutorial is here. Mrbook Makefile Tutorial
I've just started to create my own C libraries to keep my commonly used functions tidy. However, I've hit a new problem and I struggled to find information on the best route to take.
I generate my library of two functions using the following:
gcc -I. -c -fpic rand_site.c
gcc -I. -c -fpic rand_spin.c
gcc -shared -o libstatphys.so rand_site.o rand_spin.o
Each of these source files contained a single function. I was hoping to create a third function for my library that uses the two functions above but I'm not sure how to use functions from within the same library.
Am I going about this the right way? What is the best practice for doing this?
Yes, you can.
Create a header file rand_site.h and put the declaration of the function defined in rand_site.c in it.
Create a header file rand_spin.h and put the declaration of the function defined in rand_spin.c in it.
Use #include to include the two .h files in the third file, say foo.c.
Then compile foo.c and add it to the library using:
gcc -I. -c -fpic foo.c
gcc -shared -o libstatphys.so rand_site.o rand_spin.o foo.o
If you would like to create a second shared library that has foo.o, you can use:
gcc -I. -c -fpic foo.c
gcc -shared -o libfoo.so foo.o -lstatphys
If you would like to create an executable using foo.o, you can use:
gcc -I. -c foo.c
gcc foo.o -lstatphys
For a project, I was working with a partner writing a decision tree implementation. Since both of us are relative newcomers to C and had to work quickly, we basically dumped all the functionality in a single file, which ended up being over 1600 lines. It was a quick and dirty project to get working, but now the next assignment has us responsible for extending and re-implementing the code. In its current condition, that isn't going to happen.
Right now, I'm breaking up the original source based on function responsibility. Thing is, many of the functions are intertwined, and I'm getting major errors with my make file. More specifically, the other source files are reporting implicit declaration of functions that are declared in a separate file.
I really have no experience with multiple file makefiles. The current syntax is borrowed from a simple shell implmentation in last years Systems Programming class, although this current project is an order of magnitude greater in complexity.
cc= gcc
CFLAGS= -g -Wall -lm
proj2: main.o split.o tree.o id3.o output.o
$(CC) $(CFLAGS) -o proj2 main.o split.o tree.o id3.o output.o
I also tried a previous version where each object file was compiled separately like
main.o: main.c split.c tree.c id3.c output.c
$(CC) $(CFLAGS) -o main.c split.c tree.c id3.c output.c
and this repeated to create a .o file for each source, which then was compiled into an executable.
However, that didn't work and I got about 500 lines of compiler complaints and warnings, mainly about implicit function declarations.
So, essentially I have two related questions:
is it possible to intertwined function calls between different source files?
if so, how can I make it possible here?
First a word about your makefiles.
proj2: main.o split.o tree.o id3.o output.o
$(CC) $(CFLAGS) -o proj2 main.o split.o tree.o id3.o output.o
This should work (if the code is correct) but if you're using GNUMake (which you should) you can tidy it up:
proj2: main.o split.o tree.o id3.o output.o
$(CC) $(CFLAGS) -o $# $^
Now you have only one copy of the object list to maintain.
The other version is just wrong:
main.o: main.c split.c tree.c id3.c output.c
$(CC) $(CFLAGS) -o main.c split.c tree.c id3.c output.c
First, you're trying to compile all of the source files into one object file, which kind of defeats the purpose of object files. Second, you're naming your one object file main.o when that name should really belong to an object file made from main.cc. Third, the command tells the compiler to compile all of the other source files (split.c, tree.c, ...) into an object file called "main.c"-- not illegal, but you're bound to trip yourself up.
Also, you should try to use C++, not C, but that's for another day.
Now for breaking up the Big Ball of Mud. I assume you know how to break big functions into smaller ones, so the problem is segregating functions into different source files (and then compiling and linking them correctly). Suppose main() calls a function foo():
/* main.c */
void foo()
{
// do foo things
}
int main()
{
// do main things
foo();
return(0);
}
As you know, the foo must come first, otherwise the compiler would balk when main tried to call an undeclared function. But we can declare foo beforehand:
/* main.c */
void foo();
int main()
{
// do main things
foo();
return(0);
}
void foo()
{
// do foo things
}
When the compiler reaches the call to foo(), it already knows that such a function exists, and trusts us to define it later. Now here's the trick: if we instruct the compiler to compile, but not link (that is, produce an object file like main.o, not an executable like proj2), it will trust us even farther:
/* main.c */
void foo();
int main()
{
// do main things
foo();
return(0);
}
That will compile into main.o quite nicely. The compiler trusts us to provide the definition of void foo() in some other object file when we link things together into an executable. The definition will be in another file like so:
/* foo.c */
void foo()
{
// do foo things
}
We could build this by hand:
gcc -g -Wall -lm -c foo.c -o foo.o
gcc -g -Wall -lm -c main.c -o main.o
gcc -g -Wall -lm foo.o main.o -o proj2
But that gets tedious fast, so we'll write a makefile:
cc= gcc
CFLAGS= -g -Wall -lm
proj2: main.o foo.o
$(CC) $(CFLAGS) -o $# $^
%.o: %.c
$(CC) $(CFLAGS) -c -o $# $<
So far so good. If this much is clear then we can move on to header files...
You need to create header files for each of the source code to have the declarations in them. You then #include the appropriate header files at the top of the source code.
To clarify things, let's suppose I'm compiling a program (prg) with 3 files, main.c, person.h and person.c.
If I use a concise way of writing the makefile, like this (more specifically the two last lines):
prg : main.o person.o
gcc -Wall -o prg -c $^
main.o : person.h
person.o : person.h
Will the -Wall be applied to main.o and person.o automatically? Or that doesn't even matter?
I know that, as the file says, if person.o needs to be re-compiled, prg will need a re-build too. But, I don't know if specifying -Wall only in the main goal is enough to enable it the other targets so warnings are emitted as the others are compiled.
Maybe I'm missing something really important, or I'm saying something that makes no sense; but take it easy, I'm just a beginner :P
Since you apply the -Wall to the link phase (when collecting the object files into an executable), but the option applies to the compilation phase (converting the source files into object files), it provides no benefit where it is written.
You should modify the compilation by setting macros.
Normally, the rule for compiling an C source file to an object file looks something like:
${CC} ${CFLAGS} -c $*.c
There could be other bits in there, and the notation might use something other than $*.c to identify the source file - there are similar (roughly equivalent) methods for specifying that, but it is tangential to the point I'm making. The $(CC) notation is equivalent to ${CC} too.
So, to change the compiler, you specify 'CC=new_c_compiler' and to change to compilation options, you (cautiously) specify 'CFLAGS=-Wall'.
This can be done in the makefile, or on the command line. The command line overrides the makefile.
Hence:
CFLAGS = -Wall
prg : main.o person.o
${CC} ${CFLAGS} -o prg -c $^
main.o : person.h
person.o : person.h
Why cautiously? Because in more complex situations, there may be a complex definition of CFLAGS which build it up from a number of sources, and blithely setting CFLAGS = -Wall may lose your include paths, macro definitions, and all sorts. In your case, it looks like you can simply set it as shown.
If you use GNU Make, you can simply add -Wall to CFLAGS:
CFLAGS += -Wall
This does not necessarily work with all varieties of make.
Your link line may eventually need to collect some library-related options too.
No, the flags will not magically be applied to other targets.
Add a line like this to the top of your Makefile, above the rules:
CFLAGS=-Wall
Then try without the explicit line for prg.