What's the wrong with this C Code? - c

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?

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.

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

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.

Related

C - multiple definition with makefile

I am trying to compile my C program using make and I've come across this problem that I can't quite understand. I have 3 files in the 'calc' folder of my project: add.c sub.c and main.c. I have my Makefile located in the root folder of my project, which has the calc folder that I mentioned in it. This is what my Makefile looks like:
CC=gcc
OBJECTS=obj/main.o obj/add.o obj/sub.o
elf/new: ${OBJECTS}
${CC} -o elf/new ${OBJECTS}
obj/main.o: calc/main.c
${CC} -c -g calc/main.c -o obj/main.o
obj/add.o: calc/add.c
${CC} -c -g calc/add.c -o obj/add.o
obj/sub.o: calc/sub.c
${CC} -c -g calc/sub.c -o obj/sub.o
clean:
rm obj/${OBJECTS} elf/new
When I type 'make' into the terminal to compile, I get an error like this:
gcc -c -g calc/add.c -o obj/add.o
gcc -c -g calc/sub.c -o obj/sub.o
gcc -o elf/new obj/main.o obj/add.o obj/sub.o
obj/add.o: In function `add':
/home/bigger/workspace/test/calc/add.c:1: multiple definition of `add'
obj/main.o:/home/bigger/workspace/test/calc/add.c:1: first defined here
obj/sub.o: In function `sub':
/home/bigger/workspace/test/calc/sub.c:1: multiple definition of `sub'
obj/main.o:/home/bigger/workspace/test/calc/sub.c:1: first defined here
collect2: error: ld returned 1 exit status
makefile:5: recipe for target 'elf/new' failed
make: *** [elf/new] Error 1
And my code are there:
bigger#linux:~/workspace/test> cat calc/add.c
int add(int a, int b){
return a+b;
}
bigger#linux:~/workspace/test> cat calc/sub.c
int sub(int a, int b) {
return a-b;
}
bigger#linux:~/workspace/test> cat calc/main.c
#include <stdio.h>
#include "add.c"
#include "sub.c"
int main(int argc, char* argv[])
{
int a = 10;
int b = 5;
printf("add: %d\nsub:%d\n", a+b, a-b);
return 0;
}
When you include it is making the functions add and sub part of your main.c, then when you make you are linking main (which already has the functions by include) to the add and sub objects which have the same function symbols. You need to include header files with function declarations rather than include function definitions. See http://www.cprogramming.com/declare_vs_define.html for a longer discussion.

Linking two object files together causes segmentation fault 11

I am experimenting with externs and various methods of linking to better understand the linking process.
I have three files:
foo.c:
#include "foo.h"
int a = 4;
test.c:
#include <stdio.h>
#include "foo.h"
int main(int, char**);
int mymain();
int mymain() {
main(0, 0);
printf("test\r\n");
return 0;
}
int main(int argc, char** argv) {
printf("extern a has %d\r\n", a);
return 0;
}
foo.h:
extern int a; // defined in foo.c
If I build each file together and link at compile time using gcc like this:
gcc *.c -o final.bin
I can execute final.bin as:
./final.bin
and get expected output
extern a has 4
However, if I compile (but don't link) test.c and foo.c separately, then try and link the object files together at runtime to produce a binary, I get a segmentation fault 11 (which from what I can gather is some generic memory corruption bug like a normal segfault(?)
Here is my makefile I'm using to compile and link separately. Note I am specifying my own entry point and linking against libc to get printf()...
all: test.o foo.o
#echo "Making all..."
ld test.o foo.o -o together.bin -lc -e _mymain
test.o: test.c
#echo "Making test..."
gcc -c test.c -o test.o
foo.o: foo.c
#echo "Making foo..."
gcc -c foo.c -o foo.o
Output when running 'together.bin':
./together.bin
extern a has 4
test
Segmentation fault: 11
Perhaps my function signature for 'mymain' is wrong? My guess is that something is wrong with my 'myentry' usage.
Also, if anyone has any recommendations on good books for how linkers and loaders work, I am certainly in the market for one. I've heard mixed things about 'Linkers and Loaders', so I'm waiting on more opinions before I invest the time in that book in particular.
Thanks for any help on this... My understanding of linkers is sub-par to say the least.
Unless if you have a good reason to do so, just use gcc to link:
$ gcc test.o foo.o "-Wl,-e,_mymain" -o ./final.bin; ./final.bin
extern a has 4
test
gcc calls ld---though, with a few more arguments than you are providing in your example. If you want to know exactly how gcc invokes ld, use the -v option. Example:
$ gcc -v test.o foo.o "-Wl,-e,_mymain" -o ./final.bin
Apple LLVM version 8.0.0 (clang-800.0.38)
Target: x86_64-apple-darwin15.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld" -demangle -dynamic -arch x86_64 -macosx_version_min 10.12.0 -syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk -o ./final.bin test.o foo.o -e _mymain -lSystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/8.0.0/lib/darwin/libclang_rt.osx.a

Hierarchical Linking in C

I want to link three files but in hierarchical way.
// a.c
int fun1(){...}
int fun2(){...}
// b.c
extern int parameter;
int fun3(){...//using parameter here}
// main.c
int parameter = 1;
int main(){...// use fun1 fun2 fun3}
So, I first compile three files separately into object file a.o, b.o and main.o. And then I want to combine a.o and b.o into another object file tools.o. And eventually use tools.o and main.o to generate executable file.
But, when I try to combine a.o and b.o like ld -o tools.o a.o b.o, the linker says undefined reference to 'parameter'. How could I link those object files into an intermediate object file?
You want the -r option to produce a relocatable object file (think 'reusable'):
ld -o tools.o -r a.o b.o
Working code
abmain.h
extern void fun1(void);
extern void fun2(void);
extern void fun3(void);
extern int parameter;
a.c
#include <stdio.h>
#include "abmain.h"
void fun1(void){printf("%s\n", __func__);}
void fun2(void){printf("%s\n", __func__);}
b.c
#include <stdio.h>
#include "abmain.h"
void fun3(void){printf("%s (%d)\n", __func__, ++parameter);}
main.c
#include <stdio.h>
#include "abmain.h"
int parameter = 1;
int main(void){fun1();fun3();fun2();fun3();return 0;}
Compilation and execution
$ gcc -Wall -Wextra -c a.c
$ gcc -Wall -Wextra -c b.c
$ gcc -Wall -Wextra -c main.c
$ ld -r -o tools.o a.o b.o
$ gcc -o abmain main.o tools.o
$ ./abmain
fun1
fun3 (2)
fun2
fun3 (3)
$
Proved on Mac OS X 10.11.6 with GCC 6.1.0 (and the XCode 7.3.0 loader, etc). However, the -r option has been in the ld command on mainstream Unix since at least the 7th Edition Unix (circa 1978), so it is likely to be available with most Unix-based compilation systems, even if it is one of the more widely unused options.

How to include helper functions in C?

There are 4 files:
helper.h //contains the signatures of functions in helper.c
helper.c //implements the signatures in helper.h
file.h //has all the includes needed to run file.h
file.c //this file includes file.h and helper.h
In file.c, I need to use the function that is defined in helper.c in my main function. However, file.c is saying that there is an undefined reference to 'func_found_in_helper.c'
Is this structure correct?
Yes, provided file.c contains
#include "helper.h"
and when building your program you link together helper.o and file.o.
You also need to ensure you compile each of the files with -c so that the compiler only compiles (and not links); do the link later with all the object files.
Here's a working example (I don't actually need a main.h but if you have one of those, #include it from main.c):
main.c
#include <stdio.h>
#include <stdlib.h>
#include "helper.h"
int
main (int argc, char **argv)
{
test ();
exit (0);
}
helper.c
#include <stdio.h>
void
test ()
{
printf ("Hello world\n");
}
helper.h
void test ();
To compile
gcc -Wall -Werror -c -o main.o main.c
gcc -Wall -Werror -c -o helper.o helper.c
To link
gcc -Wall -Werror -o test main.o helper.o
In a Makefile
test: main.o helper.o
gcc -Wall -Werror -o test main.o helper.o
%.o: %.c
gcc -c -Wall -Werror -o $# $<
clean:
rm -f *.o test
To run
$ ./test
Hello world
It's a bit difficult to tell what else might be wrong without the program; my guess is you simply forgot the -c flag to gcc, or forgot to link in helper.o.
undefined reference to 'func_found_in_helper.c'
That's a little odd, as it suggests you have tried to call the function using the '.c' extension, rather than just the function name. Maybe the '.' is just a typo in the question ?
Also a linker will flag an undefined symbol, so it may also be that you have not told the linker where to find helper.o ( the helper.c file compiled to the an object file ). The compiler will start the linker automatically. Did you compile helper.c first ?

Link a static library in gcc without having to specify the 'lib' prefix

According to this question, gcc's -l command requires your library to be named libXXX.a.
Is there a way to link a static library using a different command with gcc? The goal is to avoid this lib- prefix.
Just pass the library as in input file like so:
gcc main.c yourlibrary.a -o prog
Like nunzio said. Just pass it in directly as an input file. He beat me to it, but here's a full example anyway.
mylib.c:
#include <stdio.h>
void say_hi(void)
{
printf("hi\n");
}
main.c:
extern void say_hi(void);
int main(int argc, char**argv)
{
say_hi();
return 0;
}
Makefile:
main: main.c mylib.a
gcc -o main main.c mylib.a
mylib.a: mylib.o
ar rcs mylib.a mylib.o
mylib.o: mylib.c
gcc -c -o $# $^
I realize this assumes some background knowledge in Make. To do the same thing w/o make, run these commands in order:
gcc -c -o mylib.o mylib.c
ar rcs mylib.a mylib.o
gcc -o main main.c mylib.a

Resources