Compiling multiple C files with gcc - c

I have two files, main.o and modules.o, and I'm trying to compile them so that main.o can call functions in modules.o. I was explicitly told not to try #include module.o. I really don't know what I should be doing instead. I tried a few different versions of gcc (such as gcc -x c driver main.o modules.o), but nothing I get works: the compiler continuously returns
error: called object is not a function
The .o files are my source code files (I was instructed to put my source code in files with extension .o.) What do I do to compile this?

If you have your two source files, you can compile them into object files without linking, as so:
gcc main.c -o main.o -c
gcc module.c -o module.o -c
where the -c flag tells the compiler to stop after the compilation phase, without linking. Then, you can link your two object files as so:
gcc -o myprog main.o module.o
This is all perfectly normal behavior, you'll usually get your makefile to compile things separately and link them at the end, so you don't have to recompile every single source file every time you change one of them.
Talking about main.o "calling functions in" module.o is perfectly fine, but an .o file is not a source file, it's a compiled object file. If "put my source code in files with extension .o" actually meant "compile my source code into files with extension .o" then the situation would make a whole lot more sense.

You should define the functions that you want to call from modules.c into main.c into a header file, let us say modules.h, and include that header file in main.c. Once you have the header file, please compile both of the files together: gcc main.c modules.c -o output
Two additional notes. First, modules.o is an object file and it should not be included in a C source file. Second, we cannot have a C file have a .o extension. You should actually get an error when compiling a .o file. Something like:
$ cat t.o
int main() {
int x = 1;
return 0;
}
$
$ gcc t.o
ld: warning: in t.o, file is not of required architecture
Undefined symbols:
"_main", referenced from:
start in crt1.10.6.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
$

program: main.o
gcc -o main main.c anotherSource.c
This works for me.

You should be including .h files which are "headers". So if your main file is using modules then you should include module's header file.

Related

I don't know how to link multiple files

I'm learning how to use header files and I have a problem while linking these 3 files:
f.c:
#include "f.h"
int getfavoritenumber(void)
{
return 3;
}
f.h:
#ifndef _f_H_
#define _f_H_
int getfavoritenumber(void);
#endif
main.c:
#include <stdio.h>
#include "f.h"
int main (void)
{
printf("%d\n", getfavoritenumber());
return 0;
}
Compiling gcc main.c -o f I get this error:
Undefined symbols for architecture x86_64:
"_getfavoritenumber", referenced from:
_main in main-7be23f.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
But if I include the f.c file with gcc main.c f.c -o f it works.
So, when compiling, should I include each C file that I used in my project, or am I missing something? Because adding each single file to gcc is very annoying.
When you have multiple source files that together make an executable, they must be each compiled and then linked together. This is done by specifying each source file when the compiler is invoked as you've discovered.
Note also that you can either do the compiling and linking in one step as you've done, or you can separate them as follows:
gcc -c main.c
gcc -c f.c
gcc -o f main.o f.o
Managing multiple source files and their dependencies is where using a makefile comes into play.
You need to understand there are three stages from c source code to run able binary. For etch and every file this stages must be followed except for header file or .h file.
First Stage : Source to assembly. gcc -S -o source.s source.c
Second Stage : assembly to Compiled Binary Object. Which can not be runned directly. gcc -c source.s -o source.o
Third Stage : In this stage we marge all the compiled binary to a single compiled binary where an input binary object holds an entry function int main().This the file which we can run on our operating system.gcc -o OutputFile source1.o source2.o source3.o ......
After this three stages we can run our program by ./OutputFile. You can avoid making assembly file and directly make object file.
Yeah you must include all the file for compilation in you project. You can use automation tools like automake or linux shell script for doing this job.

C how to use library with multiple header tree

I am not understanding how I should compile with gcc the following .c and library.
example:
Files: "commons.h" and "commons.c" (the .c defines function etc...)
Files: "level1.h" and "level1.c", level1.c includes "commons.h"
Files: "level2.h" and "level2.c", level2.c includes "commons.h" and "level1.h"
I tried this and got "undefined reference to x" (where x is a function inside level1):
gcc commons.c -c -o commons.o (OK)
gcc level1.c -c -o level1.o (OK)
gcc level2.c -o level2.o (error, undefined reference to x)
I expect to have level2 to be execute, I will only execute this.
How should I compile? Which order? (an example with command line will help me understand)
Your last line should also use the -c flag in order to compile level2.c to an object file level2.o.
Afterwards the object files should be linked to create an executable, which is done via
gcc common.o level1.o level2.o -o my_executable
Alternatively you can directly supply all the source files to gcc without the -c flag, in which case it will perform all of the compilation and linking steps at once:
gcc common.c level1.c level2.c -o my_executable
Your error is currently caused, because you are instructing gcc without the -c option to compile and link the source file level2.c alone, but of course it can not be linked alone as it is missing symbols from the other source files.
The fact that level2.c contains main does not change anything about this. main is handled like any other function, only that it has a special meaning in the final executable as entry point.

Why doesn't putting my own C library file into ld search path work?

Currently I have two files
main.c
libxxx.a
main.c references some functions defined in the source code of a relocatable object file in libxxx.a.
Now the following command successfully compiles main.c and links it to libxxx.a:
gcc -o prog main.c libxxx.a
but if I put libxxx.a into one of the search paths of ld, the same directory with libc.a,
gcc -o prog main.c
just doesn't work. It seems that ld fails to find this archive file when searching in the directory. Can someone tell me why this happens?
but if I put libxxx.a into one of the search paths of lb linker, the same directory with libc.a,
gcc -o prog main.c
just doesn't work.
That is expected and desired: you wouldn't want every program you write to link against every library that is installed in the system search path. What you want is:
gcc -o prog main.c -lxxx
That is: copying the library into /usr/lib allows the linker to find it without any extra search arguments, but you still must tell the linker that you want to link against libxxx.

Proper way to include C code from directories other than the current directory

I have two directories, sorting and searching (children of the same directory), that have .c source files and .h header files:
mbp:c $ ls sorting
array_tools.c bubble_sort.c insertion_sort.c main selection_sort.c
array_tools.h bubble_sort.h insertion_sort.h main.c selection_sort.h
mbp:c $ ls searching
array_tools.c array_tools.h binary_search.c binary_search.h linear_search.c linear_search.h main main.c
Within searching, I am building an executable that needs to use insertion_sort function, declared in insertion_sort.h and defined in insertion_sort.c inside sorting. The following compilation successfully produces an executable:
mbp:searching $ clang -Wall -pedantic -g -iquote"../sorting" -o main main.c array_tools.c binary_search.c linear_search.c ../sorting/insertion_sort.c
However, I would like to be able to include functions from arbitrary directories by including a header using #include and then providing the compiler with the search path. Do I need to precompile the .c files to .o files beforehand? The man page for clang lists the following option:
-I<directory>
Add the specified directory to the search path for include files.
But the following compilation fails:
mbp:searching $ clang -Wall -pedantic -g -I../sorting -o main main.c array_tools.c binary_search.c linear_search.c
Undefined symbols for architecture x86_64:
"_insertion_sort", referenced from:
_main in main-1a1af0.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
main.c has the following includes:
#include <stdio.h>
#include <stdlib.h>
#include "linear_search.h"
#include "binary_search.h"
#include "array_tools.h"
#include "insertion_sort.h"
I do not understand the link between header files, source files, and object files. To include a function defined in a .c file, is it sufficient to include the homonymous header file, given that the .c file is in the same directory as the header? I have read multiple answers here on SO, the man page for clang and a number of tutorials, but was unable to find a definitive, clear answer.
In response to #spectras:
One by one, you give the compiler a source file to work on. For instance:
cc -Wall -Ipath/to/some/headers foo.c -o foo.o
Running
mbp:sorting $ clang -Wall insertion_sort.c -o insertion_sort.o
produces the following error:
Undefined symbols for architecture x86_64:
"_main", referenced from:
implicit entry/start for main executable
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Okay, it's mixed up a bit. Let's see how one typically compiles a simple multi-file project.
One by one, you give the compiler a source file to work on. For instance:
cc -c -Wall -Ipath/to/some/headers foo.c -o foo.o
The -c flag tells the compiler you want an object file, so it should not run the linker.
The compiler runs the preprocessor on the source file. Among other things, every time it sees a #include directive, it searches the include paths for named file and basically copy-pastes it, replacing the #include with the content. This is done recursively.
This is the step where all .h you include get merged into the source file. We call the whole thing a translation unit.
You can see the result of this step by using -E flag and inspect the result, for instance:
cc -Wall -Ipath/to/some/headers foo.c -E -o foo.test
Let's make this short as other steps are not relevant to your question. The compiler then creates an object file from the resulting source code. The object file contains binary version of all code and data that was in the translation unit, plus metadata that will be used to put everything together and some other stuff (like debugging info).
You can inspect the contents of an object file using objdump -xd foo.o.
Note that as this is done for each source file, this means that headers get parsed and compiled again and again and again. That's the reason they should only declare stuff and not contain actual code: you would end up with that code in every object file.
Once done, you link all the object files into an executable, for instance:
cc foo.o bar.o baz.o -o myprogram
This step will gather all, resolve dependencies and write everything into an executable binary. You may also pull in external object files using -l, like when you do -lrt or -lm.
For instance:
foo.c includes bar.h
bar.h contains a declaration of function do_bar: void do_bar(int);
foo.c can use it, and compiler will generate foo.o correctly
foo.o will have placeholders and the information that it requires do_bar
bar.c defines the implementation of do_bar.
so bar.o will have the information “hey if anyone needs do_bar, I got it here”.
linking step will replace placeholders with actual calls to do_bar.
Finally, when you pass multiple .c files to the compiled like you do in your question, the compiler does basically the same thing, only it won't generate the intermediate object files. Overall process behaves the same though.
So, what about your error?
Undefined symbols for architecture x86_64:
"_insertion_sort", referenced from:
_main in main-1a1af0.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
See? It says linking step failed. That means previous step went well. The #include worked. It's just in the linking step, it's looking for a symbol (data or code) called _insertion_sort, and does not find it. That's because that symbol was declared somewhere (otherwise source using it would not have compiled), but its definition is not available. Either no source file implemented it, or the object file that contains it was not given to the linker.
=> You need to make _insertion_sort's definition available. Either by adding ../sorting/insertion_sort.c to the source lists you pass or by compiling it into an object file and passing that. Or by building it into a library so it can be shared by your two binaries (otherwise they'll each have a copy embedded).
When you get there, usually starting to use a build toolsuite such as CMake is a good idea. It will take care of all the details for you.

How to use asm procedure and take return value in C

i've got a gcc version 2.95.2 19991024 (release) toolchain and now i need to use an Assembly function that is in a file positioned in the same folder of the makefile.
I've tried tons of ways to put that file in my toolchain, with no luck.
Basically i declare that in ASM:
.globl util_MyFunc
util_MyFunc:
...
And in the main void of C file:
extern void util_MyFunc();
int main(void) {
util_MyFunc();
...
When i compile i got the error related to not recognized:
/cygdrive/c/MyDev/tmp/main.o(.text+0x8bc): undefined reference to `util_MyFunc'
make: *** [test.o] Error 1
Thanks!
EDIT:
i've tried to use following to generate the ".o" file from the asm file
C:\MyDev>gcc -c test.asm -o test.o
It results:
gcc: utils.asm: linker input file unused since linking not done
or:
C:\MyDev>gcc test.asm -o test.o
but...:
ld: cannot open crt0.o: No such file or directory
The canonical extension for assembly files that gcc expects is .s. You should use that (or assemble using as directly). Also possibly put the -o test.o before the input file name. Finally, you will need libc development files if you want to use libc. Otherwise use -nostdlib switch.
You should try: gcc -o test main.c utils.s

Resources