extern function in header file vs source file - c++

I have this C compilation issue.
It took me while to understand the root cause for the issue.
Although, now that i have intercepted the issue, I am not sure I fully understated the full C compilation flow logic.
I have two directoriess: inc and src
In the inc directories I have one file: test.h
In the src directories I have two file: test.c and main.c
The test.c file implements a function, let call it test(), and the main.c file call this test() function.
I declared this function in the test.h file
Now, I included this test.h file only in the main.c file, in order to let the main.c file to "see" the declaration of the test() function.
when compiling:
g++ -o test.o -c test.c
g++ -o main.o -c main.c
g++ -o test test.o main.o
In the last command I get an error of "undefined reference to 'test'
After debugging this issue, I found out that the missing include of the test.h file in the test.c file resolves the issue.
In other words, I need to includes the test.h file in both source files - main.c and test.c
My question is, why?
Is it not enough to include the header file, test.h file, only in the main.c file, in order to let it "see" the function declaration, and in linkage phase the compiler would "know" to associate the test() function used in the main.c file to its implementation in the test.c file?
I thought that the declaration of the test() function in the test.h file makes it "extern" declaration, and therefore it will signal the compiler to find the function implementation in linkage phase

The issue is because your prototype doesn't match implementation.
If you would be using C compiler, your would get interesting run-time errors due to wrong parameter and return value handling, because the generated symbol typically doesn't include parameter information.
With C++ the compiler generates a method signature that depends on parameter types. So two functions with the same name but different arguments will produce two distinct symbols, so linker would not confuse them.
So fix your prototype and it would work...

I don't think there should be any problem in just adding test.h in main.c and not in test.c. Please check your setup again.
You can either declare the function in test.h and include test.h in main.c
or declare the function as extern in main.c itself.
In both ways linker has to do the job of finding definition of test()
Include files are usually to separate interfaces from implementations.

Related

How does C++ know to use the Class.cpp file?

I have main.cpp, MyClass.cpp and MyClass.h files.
main.cpp
#include <iostream>
#include "MyClass.h"
int main(){
MyClass foo(123);
std::cout << foo.getNumber();
}
MyClass.h
#ifndef MYCLASS_H
#define MYCLASS_H
class MyClass
{
public:
MyClass(int n);
int getNumber();
private:
int fav_number;
};
#endif // MYCLASS_H
MyClass.cpp
#include "MyClass.h"
MyClass::MyClass(int n) {
fav_number = n;
}
MyClass::getNumber(){
return fav_number;
}
Now this program compiles and works fine as a project in CodeBlocks, but if I try to compile main seperately (not in a project) I get undefined reference to MyClass::MyClass(int). I think it is because in MyClass.h there is no body for the functions as they're in the cpp file.
So my question is: how does this program compile as a project even though MyClass.cpp isn't included anywhere in the main or the header?
When you add your cpp file to IDE it adds it to compile sources.
Depends on your IDE, for example XCode has section compile sources:
If you compile in console with g++, you need to type in console:
g++ main.cpp MyClass.cpp
This means which source files to compile, after that linker should link their main.o MyClass.o files. IDE just do all this stuff by himself.
You compile each .cpp file independently (indeed, if you look at your compiler output, you should see main.o and MyClass.o). The header files simply tell the code that the definitions exist somewhere and after compiling, a linker is used to "link" the two .o files together. It is during the linking stage that the definitions are resolved, so when main.o refers to code in MyClass.o, the linker is what puts these together.
CodeBlocks hides this from you, but its calling out to your compiler and linker to do this. (Actually, if you call gcc with all of your .cpp files, it will call the linker for you too, but this is simply a convenience and you can do it in multiple steps too. If you are using gcc to compile, your linker is usually ld)
You tell it to.
When using an IDE, the list of files in the "project" determines what list of filenames the IDE sends to the compiler, in a build command.
When invoking the build command manually, you have to do that yourself.
For example:
g++ -o myprogram main.cpp MyClass.cpp
Or:
g++ -c main.cpp
g++ -c MyClass.cpp
g++ -o myprogram main.o MyClass.o
Obviously add other flags as needed (include paths etc).
On MyClass.cpp you've forgotten return type specified on its header MyClass.h as follows
int MyClass::getNumber(){
return fav_number;
}
From a terminal console you must pass to the compiler g++ as argument all the files *.cpp which main depends on otherwise you will have an error as follows:
$ g++ main.cpp
/tmp/ccDTbMs5.o: In function `main':
main.cpp:(.text+0x15): undefined reference to `MyClass::MyClass(int)'
main.cpp:(.text+0x21): undefined reference to `MyClass::getNumber()'
collect2: error: ld returned 1 exit status
As you can see the compiler is trying to look for object code that is not found. When you compile main.cpp along with all the cpp files corresponding to the includes on your main. In this manner it will work for you as follows:
$ g++ main.cpp MyClass.cpp -o myprogram
$
$ ./myprogram
123
Option -o change the output program to "myprogram".
More complex situations can be treat using builders such as "Makefile".
In case you do not have the implementation files .cpp for each of your header files .h , you should have instead the binary object code. This should be passed to the g++ accordanly.
$ g++ -c MyClass.cpp
$ g++ -c main.cpp
The previous lines creates MyClass.o and main.o. Notice that the -c is passed to the compiler to indicate that only compilation will be done. Now you can pass the objects to the compiler as follows linking all of then together:
$ g++ -o prog MyClass.o main.o
$ ./prog
123

how to run c++ file if header, class, and main are not in the same folder?

The code::block IDE generates the following files:
./main.cpp
./include/class.h
./src/class.cpp It include class.h with #include "class.h"
How can I run this set of files, with the three files in three different folders?
First, this program can be run by clicking IDE "build and run" button.
This program need to take some arguments, like ./a.out arg[1] arg[2]. So I cannot input arguments by clicking "build and run" button, and thus I have to use g++ to compile an output first.
But g++ is not smart enough as the IDE in finding the three files(I try g++ -I./include main.cpp, it seems that it has no problem with class.h file, but cannot find class.cpp file)
So how can I compile the three files in three different locations?
BTW, how could the class.h file find the class.cpp file in IDE/g++(scan all the files in the directory to see which contains the definition of the class functions?)?
It's a bad idea to #include source files. But this will do it:
g++ -I./include -Isrc main.cpp
Normally one would expect that the IDE has some function to just build the application, especially when there's a function to build-and-run. In addition there are those that have the possibility to supply command line arguments for the program so build-and-run will run with supplied arguments.
You have to supply the source files and the search path for includes, normally one would write:
g++ -o exec-file-name -I./include main.cpp src/class.cpp
but that may depend a bit on how you include the header file. Another note is that you normally don't compile the header file separately - it's included when you compile the .cpp files that includes it.
If on the other hand you actually want to do what you write (compile the .h file that includes the .cpp file - which is higly unorthodox) you would do:
g++ -c -I./src include/class.h
g++ -c main.cpp
g++ -o exec-file-name main.o class.o
where you need to replace the .o extension if your platform uses another extension. Note that in this case you should probably not include class.h from main.cpp since that could lead to duplicate symbols.

Trouble making a header file

I am trying to make my own header file which will contain a class Vector.
To create a header file, as advised by some websites, I have created two different files :-
1) collections.h (contains declarations)
2) collections.cpp (contains definition)
Another file is main.cpp, which contains the main function, and in which I will be using collections.h
All these files are in the same directory
The trouble I am having is that compiler is showing the error
Undefined reference to Vector::Vector(int, int)
and so on for all the functions in my class.
I have made sure that there is a #include "collections.h" line in both collections.cpp as well as main.cpp
How can I solve the above problem?
I am using gcc compiler under ubuntu 12.04
First build the object files:
gcc -c main.cpp -o main.o
gcc -c collections.cpp -o collections.o
then link them together:
gcc collections.o main.o -o main
You need to build both source files and link them together.
On a Linux command line, you can do it simplest by providing both source files to gcc:
$ g++ -Wall main.cpp collections.cpp -o my_program
Note: I added the -Wall option to enable more warnings by default. It's always a very good habit to enable more warnings, as they can often point out logical errors or possible places where you have undefined behavior.

accessing functions declared in some other file using #include in c++

I have a file EnabledSets.cpp in which I am calling a function in following form
ChessImpl::SetEventAttribute(ec.getEventId(sid-1), DISABLE, transition.tid);
this I am doing in file named enabledSet.cpp in which I include ChessImpl.h
in chessImpl.h I am including Chess.h which in turn defines the function in Chess.cpp
but when I am running my code I get this error
EnabledSets.cpp $(.text+0xa0f): undefined reference to `ChessImpl::SetEventAttribute(EventId, unsigned int, unsigned int)'
Thanks in advance
This isn't java, you need to pass gcc ALL the .cpp files at once, or compile and link separately.
When you write a command like g++ file_name.cpp you're telling GCC to compile and link that file into a complete program. It fails because that single file isn't a complete program; parts of the program are in other source files.
You can either compile everything at once with:
g++ file1.cpp file2.cpp -o myprog
or you can compile each file individually (into a .o file) and then link them as a separate step:
g++ -c file1.cpp
g++ -c file2.cpp
g++ file1.o file2.o -o myprog
The first way is simpler if you're just typing commands at a prompt, but it's very inefficient when working on a large program since it recompiles everything, even if very little has changed. Large applications typically have build systems that compile source files individually, and only recompile the ones that have changed.

Linking files in g++

Recently I have tried to compile a program in g++ (on Ubuntu). Usually i use Dev-C++ (on Windows) and it works fine there as long as I make a project and put all the necessary files in there.
The error that occurs when compiling the program is:
$filename.cpp: undefined reference to '[Class]::[Class Member Function]'
The files used are as following:
The source code (.cpp) file with the main function.
The header file with the function prototypes.
The .cpp file with the definitions for each function.
Any help will be appreciated.
You probably tried to either compile and link instead of just compiling source files or somehow forgot something.
Variation one (everything in one line; recompiles everything all the time):
g++ -o myexecutable first.cpp second.cpp third.cpp [other dependencies, e.g. -Lboost, -LGL, -LSDL, etc.]
Variation two (step by step; if no -o is provided, gcc will reuse the input file name and just change the extension when not linking; this variation is best used for makefiles; allows you to skip unchanged parts):
g++ -c first.cpp
g++ -c second.cpp
g++ -c third.cpp
g++ -o myexecutable first.o second.o third.o [other dependencies]
Variation three (some placeholders):
Won't list it but the parameters mentioned above might as well take placeholders, e.g. g++ -c *.cpp will compile all cpp files in current directory to o(bject) files of the same name.
Overall you shouldn't worry too much about it unless you really have to work without any IDE. If you're not that proficient with the command line syntax, stick to IDEs first.
The command line of gcc should look like:
g++ -o myprogram class1.cpp class2.cpp class3.cpp main.cpp
Check in which cpp file the missing class member function is defined. You may have not given it to gcc.
You can also check for correct #include tags within filename.cpp. Assume that filename.cpp uses code contained in myclass.h present in the same directory as filename.cpp. Assume that the class that g++ says is undefined is contained in myclass.h and defined in myclass.cpp. So, to correctly include myclass.h within filename.cpp, do the following:
In filename.cpp:
#include <iostream>
#include <myclass.h>
//..source code.
In the makefile:
filename.o: myclass.C myclass.h filename.cpp
g++ -I./ -c filename.cpp -o filename.o
myclass.o: myclass.C myclass.h
g++ -c myclass.C -o myclass.o
In the above, note the use of -I. option when compiling filename.cpp. The -I<directory> asks g++ to include the path following the -I part into the search path. That way myclass.h is correctly included.
In the absence of more information (the source maybe), it is difficult to say with any accuracy where the problem lies. All attempts will be but stabs in the dark.
I assume that you have declared a member function (usually in a .h or .hpp file) but have ommited the respective definition of the member function (usually in a .cpp file).
In c++, it is possible to declare a class like so:
class foo {
void x();
void y();
}
with a cpp file that goes like so
void foo::x() {
do_something()
}
Note, there is no foo::y().
This poses no problem to the compiling/linking process as long as the member function foo::y() is referenced nowhere throughout the compiled code.