How to organize Header files - c

Using header files in this way gives me the error "undefined reference to somefunc". What is the proper way to make sure somefunc.c is seen so this error doesn't occur? It seems simply including somefile.h in main.c isn't enough to see the definitions in somefile.c
main.c
#include "somefile.h"
int main() {
somefunc();
return 0;
}
somefile.h
#ifndef SOMEFILE_H
#define SOMEFILE_H
void somefunc();
#endif
somefile.c
#include <stdio.h>
#include "somefile.h"
void somefunc() {
printf("hello\n");
}
I don't understand why I am getting errors because this is the same manner in which they are used in tutorials and videos i've been viewing while looking for an answer. The code above is an answer given earlier but it is still has the same error.

Undefined reference to somefunc is a linker error, not a compiler error.
This means that, although when compiling main.c the header somefile.h is found, you are not compiling the file somefile.c together with main.c. So when linking occurs the linker is not able to find the implementation of somefunc in any object file to resolve the call from main().
If you are using GCC or Clang just compile both source files to your command, eg
gcc somefunc.c main.c -o output
If you are using an IDE instead, make sure that somefile.c is compiled together with main.c when building the application.

This doesn't appear to be a problem with the header file.
This appears to be a problem in linking, which depends on how you build the project. If you use an IDE, it means that somefile.c is not included in the project. If you're using make and a makefile, it means that somefile.c is not listed in the makefile, or at least not included for the linker. If you're building at the command line (not using make or some build tool, but using gcc), then you're not including somefile.c in the command.
The undefined reference error means the linker couldn't find the code in somefile.c, because the linker didn't know to include it.

Related

Using library gives unknown reference error

I am currently creating a C library to accept input(similar to scanf), but after moving all the necessary files to the relevant places, this error is seen when I type this command (gcc main.c -o main.exe -linput)
undefined reference to `getInput
collect2.exe: error: ld returned 1 exit status
I have moved the C file and the header file to the GCC include folder, and I have moved libinput.a to the lib folder.
I have also done the same thing with another library I made, but that works fine.
After some further digging I found out that when I right-click on the function "getinput" and click "go to definition", it goes to the input.c file instead of the input.h. In the other libraries, it redirects me to the library.h file and not the library.c file. This might be the problem but I have no idea of how to fix it.
Note- running gcc main.c libinput.a works while having libinput.a in the same directory, but I
would prefer gcc main.c -o main.exe -linput(without having it in the same directory,
similar to how other libraries work). Having input.c and input.h in the same directory
and then linking it also works.
Environment - VS code on windows 10
Here is my code so far:
input.h
#ifndef INPUT_H
#define INPUT_H
void getInput(char *str, ...);
#endif
main.c(an example code where I am using the library)
#include <stdio.h>
#include <input.h>
int main()
{
char *s = NULL;
getInput("{s}", &s);
printf("%s\n", s);
}
Edit - I fixed it by moving the files to the following places
libinput.a = D:\mingw64\lib\gcc\x86_64-w64-mingw32\8.1.0
input.c and input.h = D:\mingw64\x86_64-w64-mingw32\include
You tell the linker to search other directories with -L searchdir. gcc will pass that option through to the linker.

Can GCC warn about undefined functions in libraries?

Consider the following test project:
test.h:
#ifndef TEST_H
#define TEST_H
void test1(int);
void test2(int);
#endif /* TEST_H */
text.c:
#include "test.h"
void test1(int x) { (void) x; }
Oops, I forgot to define test2()! I would like some kind of feedback when I do this, preferably refusal to compile although a warning at least would be nice. However GCC 10.2 (on Ubuntu 20.10) compiles it fine with no warnings:
gcc -Wall -Wextra -Wpedantic -std=c11 -o libtest.o -c test.c
I think I understand why: what if test2() is actually meant to come from another library, maybe a system library? Make it the problem of whichever program ends up linking everything into an executable! But I want to know about it before then. In this case, it's not declared in any included header file. It's not called anywhere. Can that be detected?
I've tried:
--no-undefined which resulted in gcc: error: unrecognized command-line option ‘--no-undefined’; did you mean ‘-Wno-undef’?
-Wno-undef - accepted but no warning
-z,defs - accepted but no warning
-Wimplicit-function-declaration - accepted but no warning
-Werror=missing-declarations - I know this is for the opposite situation but I was getting desperate.
This isn't possible, as no linking is performed at the stage of assembling a static library.
I'd suggest having a "test container" for your library. Set up your build system to build the test executable any time you are building the library. It could even just be a single .c file in the same directory as the library sources, but obviously not in the list of objects that are part of the library.
The test executable calls all of the functions that you wish to be entry points for the library.
Probably that is something you should be doing anyway in order to test the library's functionality before doing a release.

Can we include C source file in another way?

I am doing a bare metal project on Cyclone V and now I am trying to make a bare metal application in C. However, I have some issue in including source file.
For example, I use the function alt_fpga_state_get() from alt_fpga_manager.h but it gives me error message
"undefined reference to 'atl_fpga_state_get()'
Knowing that it needs a source file containing the function, I import the source file with no problem. However, here come another thing that inside alt_fpga_manager.c it also gives an error message
"undefined reference to 'alt_clock_is_enable'
Then I have to import source file for alt_clock_manager.h and the problem keep going on like that until I end up import the whole src folder. After that all the "undefined reference" problem are solved but it come with another problem telling me that my OCRAM is overflowed ( I think because of adding many source file ).
I would like to know if there is any solution for this because keep importing source file is not a convenient way to do. I did look at some examples and I found that in their makefile having this line
HWLIBS_SRC := alt_reset_manager.c alt_clock_manager.c alt_spi.c alt_globaltmr.c alt_timers.c alt_watchdog.c
I think it is the way they include the source file but I am not sure. Hope someone can give me a clue to solve this problem.
Thanks !
when you #include an header file you get the function declarations (etc depending on header file contents), that does not define them, you missed to link with needed object or lib files
Example :
main.c is
#include "f.h"
int main()
{
f();
}
f.h is
extern void f();
f.c is
void f() {}
If I just consider main.c :
/tmp % gcc main.c
/tmp/ccFs7Gyz.o: In function `main':
main.c:(.text+0xa): undefined reference to `f'
collect2: ld returned 1 exit status
But also considering f.c :
/tmp % gcc main.c f.c
Of course can also do in several steps
/tmp % gcc -c f.c
/tmp % gcc main.c f.o
etc
P.S. do not #include a source file, so no #include "f.c" in mainc.c

Using a function from another C file placed in another directory?

Say I have a parent directory A with two subdirectories B and C.
Sub-directory C has a helper.c and helper.h as shown:
//helper.c
void print(){
printf("Hello, World!\n");
}
//helper.h
void print();
Now, in sub directory B, I have a main.c which just calls the print function:
//main.c
#include<stdio.h>
#include"../C/helper.h"
void main(){
print();
}
I tried the following commands for compiling main.c:
Command 1: gcc main.c //Gives undefined reference to 'print' error
Command 2: gcc main.c ../C/helper.c //Compiles successfully
Now I removed the #include"../C/helper.h" from main .c and tried the Command 2 again. It still works.
So I have the following questions:
i) What difference does it make whether the helper.h file is included or
helper.c?
ii) Why command 1 fails?
iii) Is there a way to compile my C program without having to specify
helper.c everytime?
What happens when you execute:
Command 1: gcc main.c //Gives undefined reference to 'print' error
When execute gcc main.c
Compiler compiles main.c and creates objective file. This file will contain unresolved link to function print(). Because there is no implementation of function print() in main.c file.
After compilation gcc tries to make full executable file. To do this gcc combines all objective files and tries to resolve all unresolved links. As you remember there is unresolved link for function print(), gcc can't find implementation and raise the error.
When you execute
Command 2: gcc main.c ../C/helper.c //Compiles successfully
gcc compiles both files. Second file ../C/helper.c contains implementation of function print(), so linker can find it and resolve reference to it in function main().
i) What difference does it make whether the helper.h file is included or helper.c?
In your case helper.h contains forward declaration of function print(). This gives information to compiler how to make call of function print().
ii) Why command 1 fails?
See above.
iii) Is there a way to compile my C program without having to specify helper.c everytime?
Use make utility. Compile helper.c in separate objective file helper.o and use it in linkage command.
helper.o: ../C/helper.c ../C/helper.h
gcc -c ../C/helper.c
main.o: main.c main.h
gcc -c main.c
testprog: main.o helper.o
g++ main.o helper.o -o testprog
See make utility manual for details.
Commands should be indented by TAB.
First you need to understand that #include simply adds whatever text is in the #include parameter to the position in the file the statement is in, for example:
//file1.h
void foo();
//main.c
#include "file1.txt"
int main(int argc, char **argv)
{
foo();
return 0;
}
Will cause the pre-compilation to generate this unified file for compilation:
//main.c.tmp
void foo();
int main(int argc, char **argv)
{
foo();
return 0;
}
So to answer your first and second questions:
When you include a header file (or any file) that only contains declarations (i.e function signatures) without definitions (i.e function implementations), as in the example above, the linker will fail in finding the definitions and you will get the 'undefined reference' error.
When you include a c code file (or any file) that contains definitions, these definitions will be merged to your code and the linker will have them, that's why it works.
and as for your third question
It is bad practice to include c files directly in other c files, the common approach is to keep separate c files with headers exposing the functionality they provide, include the header files and link against the compiled c files, for example in your case:
gcc main.c helper.c -o out
Will allow you to include helper.c in main.c and still work because you instructed the compiler to compile both files instead of just main.c so when linking occurs the definitions from the compilation will be found and you will not get the undefined behavior error
This is, in a nutshell. I abstracted a lot of what's going on to pass on the general idea. this is a nice article describing the compilation process in fair detail and this is a nice overview of the entire process.
I'll try to answer:
i) What difference does it make whether the helper.h file is included or helper.c?
When you include a file, you don't want to expose your implementation, hence its better to include h files, that contains only the "signatures" - api of your implementation.
ii) Why command 1 fails?
When you compile you must add all your resources to the executable, otherwise he won't compile.
iii) Is there a way to compile my C program without having to specify
helper.c everytime?
You can use Makefile to compile your program. Maybe this tutorial can help you.
i) What difference does it make whether the helper.h file is included
or helper.c?
Including helper.c means that helper.c gets compiled each time as if it were part of main.c
Including helper.h lets the compiler know what argument types the function print() takes and returns so the compiler can give an error or warning if you call print() incorrectly
ii) Why command 1 fails?
The compiler is not being told where to find the actual code for the print function. As explained, including the .h file only helps the compiler with type checking.
iii) Is there a way to compile my C program without having to specify
helper.c everytime?
You can compile it once into an object file and optionally you can add that obj to a static or dynamically loaded library. You still need to help the compiler find that obj or library. For example,
gcc -c helper.c
gcc main.c helper.o
The correct way to avoid compiling modules that don't need compiling is to use a Makefile. A Makefile compares when a module was last compiled compared to when it was last modified and that way it knows what needs to be compiled and what doesn't.

Including source files in C

So I get the point of headers vs source files. What I don't get is how the compiler knows to compile all the source files. Example:
example.h
#ifndef EXAMPLE_H
#define EXAMPLE_H
int example(int argument); // prototype
#endif
example.c
#include "example.h"
int example(int argument)
{
return argument + 1; // implementation
}
main.c
#include "example.h"
main()
{
int whatever;
whatever = example(whatever); // usage in program
}
How does the compiler, compiling main.c, know the implementation of example() when nothing includes example.c?
Is this some kind of an IDE thing, where you add files to projects and stuff? Is there any way to do it "manually" as I prefer a plain text editor to quirky IDEs?
Compiling in C or C++ is actually split up into 2 separate phases.
compiling
linking
The compiler doesn't know about the implementation of example(). It just knows that there's something called example() that will be defined at some point. So it just generated code with placeholders for example()
The linker then comes along and resolves these placeholders.
To compile your code using gcc you'd do the following
gcc -c example.c -o example.o
gcc -c main.c -o main.o
gcc example.o main.o -o myProgram
The first 2 invocations of gcc are the compilation steps. The third invocation is the linker step.
Yes, you have to tell the compiler (usually through a makefile if you're not using an IDE) which source files to compile into object files, and the compiler compiles each one individually. Then you give the linker the list of object files to combine into the executable. If the linker is looking for a function or class definition and can't find it, you'll get a link error.
It doesn't ... you have to tell it to.
For example, whe using gcc, first you would compile the files:
gcc file1.c -c -ofile1.o
gcc file2.c -c -ofile2.o
Then the compiler compiles those files, assuming that symbols that you've defined (like your example function) exist somewhere and will be linked in later.
Then you link the object files together:
gcc file1.o file2.o -oexecutable
At this point of time, the linker looks at those assumtions and "clarifies" them ie. checks whether they're present. This is how it basically works...
As for your IDE question, Google "makefiles"
The compiler does not know the implementation of example() when compiling main.c - the compiler only knows the signature (how to call it) which was included from the header file. The compiler produces .o object files which are later linked by a linker to create the executable binary. The build process can be controlled by an IDE, or if you prefer a Makefile. Makefiles have a unique syntax which takes a bit of learning to understand but will make the build process much clearer. There are lots of good references on the web if you search for Makefile.
The compiler doesn't. But your build tool does. IDE or make tool. The manual way is hand-crafted Makefiles.

Resources