GCC compiler multiple files issues - c

I have a compiled C file, called Hello.o. in Hello.o:
I have a main function
and a function called int myfunc().
I wonder if I were to create a new file, hello2.c that contains a main function as well, and declare myfunc at the top of hello2.c,
will i be able to compile hello2.c and link hello.o to it using a gcc command?
Thanks all in advance.

If you want to just use myfunc() in hello2.c you can try linking the two objects files using gcc.Declare the function in a header file Hello.h and include it in hello2.c and generate Hello.o and hello2.c before linking them together by
$ gcc -o output Hello.o hello2.o
I think this should help you
How do I link object files in C? Fails with "Undefined symbols for architecture x86_64"

Object files are linked completely, or not at all. So this won't work.
GCC adds all the files specified in the command line as .o to the binary. Then the libraries (.a) are used to find needed symbols.
If there are duplicate symbols, an error is reported. (It doesn't know which main).
If a library contains more than one .o file, it can ignore the .O files which are not required. These may have duplicates with the binary.

Related

Is the GCC link option truly necessary when linking to a static library?

I've been playing around with GCC lately and have been experimenting with the linking options. I'm somewhat confused why the link option -l is necessary when statically linking to an archive file. It seems like you can just toss the .a file as if it were an ordinary object file.
For example, take the following make file:
test1 : main.c libfunc.a
gcc main.c -L. -lfunc -o main.out
test2 : main.c libfunc.a
gcc main.c libfunc.a -o main.out
libfunc.a : func1.c func2.c
gcc func1.c -c
gcc func2.c -c
ar cr libfunc.a func1.o func2.o
Make target test1 uses GCC's linking options to link to the archive file. Target test2 instead just includes the archive file direct. Building and running each output seem to result in the same executable.
There are several ways you can tell gcc what file(s) to use. An argument of the form -lname (or the two arguments -l name) says “Search for a library named name”. Per the GCC documentation, this argument is passed to the linker (typically the ld command). The linker looks for a file with a name like libname.extension, where extension is one of the known library files extensions such as .a or .so, and it looks for files with those names in a list of library directories it has. You can add directories to search with the -L switch.
When the linker finds the library, it uses it just as if you had specified the path, so the end result is the same whether you specify the library with -l or with its path.
By using the path, you can specify libraries that are not in the known library directories or that have unusual names.
Note that the linker does not process libraries the same way as object files. When the linker processes an object file, it incorporates everything in the object file into the output file being constructed. When the linker processes a library file, it incorporates only those modules within the library that provide a symbol definition for a symbol referenced by a prior module and not yet resolved. For example, if you write a program that uses sqrt but does not use sin, then, when the linker processes libm.a after reading your object module, it will take the sqrt module from the library but not the sin module.

How can main.o not be created last during compilation of C project?

I've watched the installation of GNU make on my computer wth some
attention. It is a relatively simple compilation : it creates successively
an .o file from each .c file, then creates an executable by linking
all the .o files, in the order in which they were created :
gcc -g -O2 -rdynamic -o make ar.o arscan.o commands.o default.o dir.o expand.o
file.o function.o getopt.o getopt1.o guile.o implicit.o job.o load.o loadapi.o
main.o misc.o output.o read.o remake.o rule.o signame.o strcache.o variable.o
version.o vpath.o hash.o remote-stub.o glob/libglob.a
What I don't get here is the following : how can main.o
not appear last on this list ? Because using the executable on
some arguments is equivalent to calling function main in
main.c on those arguments, so anything created after main.o
seems useless.
The order in which object files are specified in the gcc command line are irrelevant. All are linked into an executable, and that executable knows where the main function lives.
When all object files are read in, the linker ensures that the main function exists along with any functions called directly or indirectly from main.
Just because an object file is called main.o doesn't necessarily mean that the main function lives in that file.
The other files contain functions called by main directly or indirectly. Without them, make can't function.

How to link and compile with .so file in Linux

I am having .c and .so file. I tried by using the following compilation: gcc main.c -ldl. In that .c file i linked to .so file through dlsym(). How to compile using .so file with .c.
Probably you can do this:
when linking do:
g++ -o prog prog.o -ldllname
If libdllname.so is not in the system directory then add its directory to the library path:
g++ -o prog prog.o -L/path/to/my/library/folder -ldllname
This is based on your further comments. First guard the declarations of your header file.
#ifndef HEADER_PROTECT
#define HEADER_PROTECT
---------- Here is the content of header
#endif
Next, check in your code, are you defining multiple definitions. Or are you re-defining the standard functions again? Can you please post your code to guide you better?
Looks like you have re-defined Close_Comm(), can you check it? Error says that the definition is there in main.c also.
The following is the general way to compile shared object and link it.
To compile shared objects.
-g : for debug information
fPIC: for position independent code
$gcc -fPIC -g myfile
The following will create the shared object libmyfile.so
$gcc -shared -o libymyfile.so myfile.o
Now,In order to link it with your main.c.
I assume that the libmyfile.so is in your current path, thus -L./
$gcc main.c -o main.out -L./ -lmyfile
Now, you need to export the LD_LIBRARY_PATH on the bash; in order to execute the binary.
$LD_LIBRARAY_PATH=$LD_LIBRARAY_PATH:./
$./main.out
The dlsym is to load the symbol from the shared object at the run-time. If you want to load the shared object at run time, this can be used. The following is one of the example of dlsym Hack the standard function in library and call the native library function afterwards
dlsym() is used to find a symbol in an open library file.
you first need to use dlopen() in order to open the file, and only then use dlsym()

Building object files that depends on other object files

EDITS: Including link to my makefile
I have a main program that calls a bunch of functions defined in other source files. This is not a problem because I am using cc -c functionSource.c functionHeader.h and generating object files before compiling my main program with cc main.c func1.o func2.o .... -o test.o
I am having problems when one of my functions depends on another function.
For example:
My main program calls an shuffle function which is defined in it's own source file and the shuffle function calls a swap function which in turn is defined in it's own source file.
When i try to generate the shuffle.o file for my main program using cc -c shuffle.o I get an undefined reference to swap error.
When I try to cc shuffle.c swap.o i get an undefined reference to main error.
Here is my makefile
How do I go about fixing this?
Found the problem. I had a swap function declared inside insertionSort.h and shuffle.h but no implementations.
Have a look to the man page: '-c' makes the compiler generating object files only (not trying to link).
Do the following:
cc -c insertionSort.c # => gives insertionSort.o
cc -c -c functionSource.c # => gives functionSource.o
cc insertionSort.o functionSource.o ...and-so-on... main.c -o test
It's not necessary to specify header files - it doesn't help.
BTW: If you have mor than one implementation file, it is rather useful
(a) to learn make
(b) stick to the convention that object files and programs should be named like th sources.
E.g:
foo.c => foo.o
bar.c => bar
etc - you get the picture.
This has nothing to do with make. You need to get a book on introductory C programming, that will explain how to use the preprocessor, and you need to examine the documentation for your compiler so you understand what the different compiler flags do (such as when you want to use the -c flag and when you don't, and what the difference is).
It's wrong to include header files (.h files) on the compile line. Only source files (.c) should be included on the command line when building object (.o) files. You should be adding the headers you need into your .c files using the #include directive: #include "insertionSort.h". If you're missing a reference to a function, then #include the header file that declares that function: #include "swap.h".

object file from .a not included in .so

I have created a .c file which is being converted to a .o file along with around 300 other .c files and included in a .a static library. This library, along with many others is being used to create a .so dynamic library. On analyzing both the .a and the .so file with nm, I found that for some reason the symbols defined in the .c file are present in the .a file but not in the .so file. I can think of no reason this should happen. Can somebody please help me out here? The steps used to create the two binaries are:
gcc -fvisibility=hidden -c foo.c -o foo.c.o
ar cr libbar.a foo.c.o ...
gcc -fvisibility=hidden -fPIC -o libfinal.so libbar.a x.o y.a ...
The reason I have specified visibility hidden here is that I want to expose only a few selected symbols. To expose the symbols from foo.c I have specified the visibility attribute so that the functions signatures in the header foo.h look like:
extern int _____attribute_____ ((visibility ("default"))) func();
EDIT: The command nm libbar.a | grep Ctx gives:
000023c5 T CtxAcquireBitmap
000026e9 T CtxAcquireArray
00001e77 T CtxCallMethod
However, nm libfinal.so | grep Ctx does not show anything.
UPDATE: Found another post which discusses the uses of the --whole-archive option. Also, stumbled across the --export-dynamicoption which apparently tells the linker to retain unreferenced symbols. Investigating further.
Try using --whole-archive linker option to include all objects into your shared library when linking
gcc -o libfinal.so -Wl,--whole-archive libbar.a x.o y.a -Wl,--no-whole-archive
From man ld:
--whole-archive
For each archive mentioned on the command line after the --whole-archive option, include every object file in the archive in the
link, rather than searching the archive for the required object files. This is normally used to turn an archive file into a shared
library, forcing every object to be included in the resulting shared library. This option may be used more than once.
Two notes when using this option from gcc: First, gcc doesn't know about this option, so you have to use -Wl,-whole-archive.
Second, don't forget to use -Wl,-no-whole-archive after your list of archives, because gcc will add its own list of archives to your
link and you may not want this flag to affect those as well.
As far as I know, when compiling against a .a, gcc will only pull out the objects that are referenced by the other modules. If your intent is to include the whole content of the .a in the .so, a plain "compile/link x.c into libfinal.so using content in libbar.a" is not what you want.
Creating a dummy reference for the required symbols in my main file did not solve the problem. The referenced symbols appeared in the binary dump (obtained using nm) with a U (= undefined) marker. I managed to solve the problem by linking the object file directly when creating the .so file instead of including it in the .a library first. As these functions were marked extern they were included in the .so even though they were not being referenced within the library. Had they not been marked extern, they would not have been included just like sylvainulg said.
Thanks to Dmitry for pointing out the --whole-archive option. I did not know that such an option exists.

Resources