I'm writing a C++ program where each file has it's own set of global variable declarations. Most of these files make use of global variables that were defined in the other files using extern.
Here's an example similar to my program:
Main.cpp
#include "stdafx.h"
#include <iostream>
#include "Other_File.cpp"
int var1;
int var2;
int main()
{
var1 = 1;
var2 = 2;
otherFunction();
var4 = 4; // From Other_File.cpp
std::cout << var1 << " " << var2 << " " << var3 << " " << var4 << std::endl;
return(0);
}
Other_File.cpp
extern int var1;
extern int var2;
int var3;
int var4;
void otherFunction()
{
var3 = var1 + var2;
var4 = 0;
}
When I build this code in Visual Studio (Windows), everything runs fine and the output is correct. But when I attempt to build using g++ on Linux I receive the following error:
g++ -o Testing Testing.o Other_File.o Other_File.o:(.bss+0x0): multiple definition of
var3' Testing.o:(.bss+0x0): first defined here Other_File.o:(.bss+0x4): multiple definition of
var4' Testing.o:(.bss+0x4): first defined here Other_File.o: In functionotherFunction()': Other_File.cpp:(.text+0x0): multiple definition of
otherFunction()' Testing.o:Testing.cpp:(.text+0x0): first defined here collect2: ld returned 1 exit status make: *** [Testing] Error 1
Is this because I'm "including" the other file in my main file?
If not what's the issue with my code?
Edit: This is the content of my Makefile for g++:
Testing: Testing.o Other_File.o
g++ -o Testing Testing.o Other_File.o
Testing.o: Testing.cpp
g++ -c -std=c++0x Testing.cpp
Other_File.o: Other_File.cpp
g++ -c -std=c++0x Other_File.cpp
clean:
rm *.o Calculator
An include effectively pastes the included file into the including file before the compiler starts working, so what this looks like to the compiler is:
By itself this isn't a problem. It's funny looking, but it's not a problem. There are no duplicated variables.
tells the compiler that somewhere else the there exists
var1
. It will be found and linked later. Carry on. The linker will complain if you lied. In this case, there it is about 10 lines down.The problem comes when Other_File.cpp is compiled and linked with Main.cpp. The linker finds a full definition of
var3
andvar4
in both Main.o and Other_File.oYou can exclude Other_File.cpp from the build, likely what Visual Studio did for you, and all will be good except for a serious violation of convention: Never include a .cpp file.
Why? Because cpp files, by convention, define stuff and make them real. You can botch a .h file just as badly by defining a variable or function in the header. eg:
Everyone who includes badheader.h now has a variable named
fubar
whether they want it or not and when the linker comes along to assemble the program, whichfubar
is the realfubar
? All of them. Whoops. All the poor linker can do is spit out an error and wait for you to fix the ambiguity.At the end of the day you can
#include
anything. It won't compile, but you could include a Word doc. You can even perform little tricks likewhere array.h is simply
Useful when you have something like Matlab spitting out filter coefficients, but prefer sticking to the convention to prevent confusion among your fellow coders.
Anyway, C++ lets you do all sorts of stuff. Most of them you better think over a few times before doing them.
Don't
#include
a source file into another source file. There times and places when that is okay, but only in like less than 0.001% of all programs is that needed.What you should do is create a header file which contains declarations of the things needed in both source files.
Then your code would look like this:
main.cpp
source fileother_file.cpp
source file, just like you have it nowother_file.h
header file, a new fileBoth source files would then be compiled separately and linked together to form the final executable. This linking step is where your build fails. It will notice that the variables defined in
other_source.cpp
are defined in the object file created from that source file, but since you include it into themain.cpp
source file then the object file created from that source file as well.This is why you need to learn about translation units, which is what the compiler actually see. A C++ source file goes through many phases of translation, each one doing its own special part. Roughly a translation unit is a single source file with all the headers included.
This is also a good reason to learn what the preprocessor
#include
directive does. It basically inserts the included file, as is, into the source file being preprocessed. Where the#include
directive was, after preprocessing it will be the contents of the included file, and that is what the compiler will see.