Missing symbol compile error in C. Basic header file setup - c

I'm working on a C project implementing some generic containers and am having this weird issue when compiling. Here is some sample code that also replicates the error.
foo.h
void fooprint(void);
foo.c
#include "foo.h"
#include <stdio>
void fooprint(void){
printf("bar");
return;
}
main.c
#include "foo.h"
int main(void){
fooprint();
return 0;
}
I compile by typing
gcc main.c -o main
and this is what terminal outputs
Undefined symbols:
"_fooprint", referenced from:
_main in ccfMXGzj.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
I'm compiling this on an OSX system but have also tried compiling on a red hat machine with the same effect.
The solution is probably painfully obvious but I have had multiple friends I'm working with look at this and they couldnt see the problem. I've googled around a lot but most symbol error issues are usually pertaining to objective C.

You need to compile them together:
gcc -Wall -Wextra -o main main.c foo.c
Or maybe make a Makefile ?
all: main
main: main.o foo.o
main.o: main.c
foo.o: foo.c

You have to compile also foo.c into an object file and link all of them together:
gcc -o foo.o foo.c
gcc -o main.o main.c
gcc -o main main.o foo.o
Yes, this is simple, so I recommend you to read a good C book and step these easy steps.

Related

Unable to identify issue GNU archiver. Compiling with *.o works but libname.a dosen't

I'm trying to make a static library (.a) but facing issues that I'm unable to understand. So in brief compiling with *.o succeeds but archiving them using ar and then using the .a file to compile gives me an undefined reference to 'symbol' error.
So here is a simple code.
test.c
#include <stdio.h>
#include <string.h>
int main()
{
hello_world();
return 0;
}
hello_world.c
#include<stdio.h>
void hello_world (void) {
printf("Hello World\n");
}
Compile.
gcc -c -o hello_world.o hello_world.c
ar crs libhello.a hello_world.o
gcc libhello.a -o test test.c
gives me the error
/tmp/ccsO7AJl.o: In function `main':
test.c:(.text+0xa): undefined reference to `hello_world'
Instead doing this works(Compiles and runs fine)
gcc -c -o hello_world.o hello_world.c
gcc hello_world.o -o test test.c
I have no idea what I have done wrong so any help is appreciated.
This is an almost duplicate of Why does the order of '-l' option in gcc matter? - but the behaviour can be replicated without the -l switch by specifying the archive name on command line.
The GNU linker as executed by GCC will, by default, link from left to right, and only use those .o files from the library archive that are needed to satisfy undefined references so far. Since your library precedes the main translation unit on the command line, hello_world is not required at the time the linker is processing it.
The solution is to mention the library after the translation units/object files that depend on it:
gcc -o test test.c libhello.a

Undefined reference error but symbol existing in the library

I get an undefined reference error for the example below. I have seen lots of questions that relate to this issue but believe I gave a stripped, reproducible, conceptual example as opposed specific issues in other questions,
dynlib.h:
void printMe_dyn();
dynlib.c:
#include <stdio.h>
#include "dynlib.h"
void printMe_dyn() {
printf("I am execuded from a dynamic lib");
}
myapp.c:
#include <stdio.h>
#include "dynlib.h"
int main()
{
printMe_dyn();
return 0;
}
Build steps:
gcc -Wall -fpic -c dynlib.c
gcc -shared -o libdynlib.so dynlib.o
gcc -Wall -L. -ldynlib myapp.c -o myapp
Error:
/tmp/ccwb6Fnv.o: In function `main':
myapp.c:(.text+0xa): undefined reference to `printMe_dyn'
collect2: error: ld returned 1 exit status
Proof that the symbol is in the library:
nm libdynlib.so | grep printMe_dyn
00000000000006e0 T printMe_dyn
Am I using the correct compiler flags for building the dynamic
library?
Is the proof I've presented really an unambiguous proof?
What other approach could be taken to diagnose the issue?
The order of appearance of libraries matter.
To quote the online gcc manual
It makes a difference where in the command you write this option; the linker searches and processes libraries and object files in the order they are specified. Thus, foo.o -lz bar.o searches library z after file foo.o but before bar.o. If bar.o refers to functions in z, those functions may not be loaded.
You should be changing your compilation statement to
gcc -o myapp -Wall -L. myapp.c -ldynlib
to tell gcc to search for the symbols used in (compiled) myapp.c to be present in dynlib.
Just as additional notice. The same behavior one may obtain when the library has been built by gcc and linked to the c++ project. Like follows:
gcc -Wall -fpic -c dynlib.c
gcc -shared -o libdynlib.so dynlib.o
g++ -o myapp -Wall -L. myapp.cpp -ldynlib
In such case the reason is name-mangling used by g++. To have it turned off one must wrap C-function prototypes by extern "C" within C-library. For example like follows:
dynlib.h:
#ifdef __cplusplus
extern "C"{
#endif
void printMe_dyn();
#ifdef __cplusplus
}
#endif
The order of libraries in linker command line matters. Fix:
gcc -o myapp -Wall -L. myapp.c -ldynlib

C program Compilation error : reference to main

I am new to C programming and need help in resolving the compilation issue :
There are 3 .c files (main.c, file1.c , file2.c) file1.c and file2.c just contain the function definitions that are called in main.c. When I am trying to compile my main.c file using the below command, it gives me the errors:
gcc -Wall ./trigger-solve/main.c
_approx_help", referenced from:
_print_help in main-9e2c6e.o
"_approximate", referenced from:
_main in main-9e2c6e.o
"_free_matrix", referenced from:
_main in main-9e2c6e.o
"_print_matrix", referenced from:
_main in main-9e2c6e.o
"_read_matrix", referenced from:
_main in main-9e2c6e.o
"_read_sparse_matrix", referenced from:
_main in main-9e2c6e.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
However after reading about this error , I figured out its happening because file1.c and file2.c do not contain the main function . So I added this main function in both files :
int main()
{
return 1;
}
At this point when I compile file1.c and file2.c they DO NOT give me errors , however I am still getting the same compilation errors while running main.c. Also I don't know after compiling file1.c and file2.c how should I link them to main.c ?
Can someone please help .
You need to link all your translation units together. Perhaps all in one wash, like this:
gcc -Wall main.c file1.c file2.c
Now you have an executable file called a.out ready for your enjoyment.
Of course rebuilding the entire project every time you change one file isn't feasible, so normally you'd compile each TU separately and then link everything in a final step (and give the output file a better name):
gcc -Wall -c main.c
gcc -Wall -c file1.c
gcc -Wall -c file2.c
gcc -o myprog main.o file1.o file2.o
Did you do any research yourself on this? There are plenty of relevant examples available online.
You should not define main function in file1.c and file2.c. You should compile all .c files with -c option and then link them to main like this :
gcc main.o file1.o file2.o
you can just
gcc -Wall *.c
will compile all .c files in the current directory... thats a good shortcut if you save your each of your project in a separate folder
Basically, you have got the linking error. Remember, any program has only one main() function. In your example, this main() must be finally linked with the other files to create an executable. The main() is the entry point of any C program. Thus, there should be only one main() in your source code in order to create an executable. For your case, I will say use the Makefile for compiling and linking. The makefile saves time of compilation and is quite handy.
I will say - use the Makefile. The Makefile makes the job easier. In future, if you have to extend the functionality, add a new file and add a new entry in the makefile. This is the simplest form of makefile here.
Once you issue make - the executable name - app will be created. Next, run the ./app
Makefile
target = file1.0 file2.o main.o
[tab] gcc file1.o file2.o main.o -o app
file1.o: file1.c
[tab] gcc -c file1.c -o file1.o
file2.o: file2.c
[tab] gcc -c file2.c -o file2.o
main.o: main.c
[tab] gcc -c main.c -o main.o
Now, run the Makefile.
$make target

Create a simple dynamic library

What linking step am I missing? I'm trying to make a dynamic library from file c.c:
#include "a.h"
#include "b.h"
int my_function(void)
{
return a() + EIGHT;
}
which depends on a.c:
int a(void)
{
return 1;
}
and b.h:
enum {
EIGHT = 8,
};
I run gcc -c c.c -o c.o to compile the object file. Then I run
gcc -Wall -dynamiclib -o libc.dylib c.c
and I get this error.
Undefined symbols for architecture x86_64:
"_a", referenced from:
_b in ccx5LSkL.o
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status
How can I properly link the files? References addressing this specific problem would be awesome.
So your first line, gcc -c c.c -o c.o, compiled the object file c.o. Now you then have to use c.o for creating the final result. So your linking step should be using c.o, not c.c.
Next, the error you are getting is that the symbol "_a" was not found. This is coming from you calling the function a(), but not including it in the linking step. To do that you need to also compile a.c and include it when linking your final product.
So in total, your process should be:
1) compile:
gcc -c a.c -o a.o
gcc -c c.c -o c.o
2) link:
gcc -Wall -dynamiclib -o libc.dylib a.o c.o
Note that to compile libc.dylib, you had to include all the sources that the final result would depend on.
Finally, you don't actually need to compile all of the object files separately. You can compile and link together in one combined step by just providing the *.c files right away.
gcc -Wall -dynamiclib -o libc.dylib a.c c.c
So your problem was really just about not including both sources together. (Other than -dynamiclib, everything actually works basically just like compiling a regular executable.)

Creating libraries in C/C++ - ld can't find my library

I'm trying to learn how to create a C/C++ library in a linux environment but I'm having a problem (probably a trivial one) that online tutorials had not helped to solve.
For definiteness let's say I have a foo.c file with the following code:
//file: foo.c
#include <stdio.h>
void hello(void)
{
printf("hello!\n");
}
a foo.h:
//file: foo.h
void hello(void);
and a program that uses the function hello() from foo.c, named prog.c:
//file: prog.c
#include "foo.h"
int main(void)
{
hello();
return 0;
}
The three files are all on the same directory. Then I compiled foo.c with:
gcc -fPIC -c foo.c
and got a foo.o file. Then I used ld to create the library file:
ld -G foo.o -o libfoo.so
But when I try to compile prog.c with:
gcc -o prog prog.c -lfoo
I got an error message:
/usr/bin/ld: cannot find -lfoo
collect2: ld returned 1 exit status
I'm convinced that this is some kind of trivial path problem, but I couldn't find the solution. So my question is really if this procedure above is wrong or if I have to put the libfoo.so file in a special path.
Another question is how this changes if I'm using g++ instead of gcc.
Thanks.
EDIT:
I know I can compile both prog.c and foo.c to prog.o and foo.o an then link them to make an executable. But in my original problem I want to compile foo.c in a way that I can distribute to people who will use my functions in their own programs.
ld doesn't search the current directory by default. If you want it to do this you need to use the -L command line option, so if your library is in the current directory you need to add -L. to the last gcc call. If the library is dynamically linked you also need to add the current directory to the environment variable LD_LIBRARY_PATH (I assume you're on linux).
Of course, if your library is in any other non-standard path you need to use that instead of the current directory.
Try
gcc -o prog prog.c -lfoo -L.
The -L switch adds its argument to the set of paths that ld looks in for library files. The syntax is identical for g++.

Resources