44142

Making and compiling C++ projects with multiple files

Question:

I am new to C/C++, I already know the basics and I am starting to learn more advanced concepts now.

Currently I am developing a project using C++ and it is quite a big one, so structuring my project will be better.

From what I have already seen, a good structure relies on, at least, to folders: /src and /include. All .cpp files should go in /src folder and .hpp ones in /include. Here the first doubt arose: how to include a header which is not in the same directory nor in a standard one? After searching about it I concluded that the best way is to pass the option -I../include to the compiler.

I had three source files: main.cpp, GraphData.cpp and RandomGraphGenerator.cpp. I have read that it is best practice to have a header for each of these files, to separate declaration from definition. Now I also have two headers, but I am not getting how to compile all of these.

I am focusing making GraphData.cpp to be linked correctly to main.cpp, I commented everything that needs RandomGraphGenerator.cpp. This is my main file:

// main.cpp #include <iostream> #include <string> #include <Snap.h> #include <GraphData.hpp> int main() { std::string file_path; char path[1024]; DataPoint **data_set; int motif_size, num_null_models; std::cin >> file_path; std::cin >> motif_size; std::cin >> num_null_models; data_set = new DataPoint*[num_null_models]; strncpy(path, file_path.c_str(), sizeof(path)); path[sizeof(path) - 1] = 0; //read input PNGraph G = TSnap::LoadEdgeList<PNGraph>(path, 0, 1); //enumerate and classify k-subgraphs in G GD::extractData(&G, motif_size, data_set[0]); //generate random graphs and enumerate and calssify k-subgraphs on them for(int i=1; i<=num_null_models; i++) { //GM::randomize(&G); GD::extractData(&G, motif_size, data_set[i]); } //detect motifs GD::discoverMotifs(data_set); return 0; }

My GraphData header:

#ifndef GRAPHDATA_HPP_INCLUDED #define GRAPHDATA_HPP_INCLUDED #include <Snap.h> struct DataPoint; namespace GD { void extractData(PNGraph*, int, DataPoint*); DataPoint* discoverMotifs(DataPoint**); } #endif // GRAPHDATA_HPP_INCLUDED

And my GraphData file:

#include <GraphData.hpp> struct DataPoint { int label; int frequency = 0; }; void GD::extractData(PNGraph* G, int k, DataPoint* data_array) { //stuff } DataPoint* GD::discoverMotifs(DataPoint** data_set) { //dummy code DataPoint* dp; dp = new DataPoint[2]; dp[0].label = 10; dp[1].label = 99; return dp; }

I am trying to compile, under Ubuntu 14.10 with GCC 4.9.2, using:

g++ -o main main.cpp /usr/include/Snap-2.3/snap-core/Snap.o -I../include -I/usr/include/Snap-2.3/snap-core -I/usr/include/Snap-2.3/glib-core

But it gives me an error of undefined referece:

main.cpp:(.text+0x179): undefined reference to `GD::extractData(TPt<TNGraph>*, int, DataPoint*)' main.cpp:(.text+0x1b9): undefined reference to `GD::extractData(TPt<TNGraph>*, int, DataPoint*)' main.cpp:(.text+0x1dd): undefined reference to `GD::discoverMotifs(DataPoint**)' collect2: error: ld returned 1 exit status

I am a little bit lost with it, what am I missing?

Answer1:

g++ by default invokes the linker (ld) as soon as it has finished compiling all the input files. There are many ways to produce the binary executable, but the two most common are:

<ol><li>Include all source files in a single g++ command. You would need to add GraphData.cpp and main.cpp to the same call to g++. This method ensures the linker has access to all the symbols to create the executable. </li> <li>Compile each file into an object file separately and link them in a separate step (this is more common for large software projects). To do this, pass the -c switch to g++ for each cpp file, then call g++ again and pass the .o files instead of the .cpp files.</li> </ol>

Either way, at some point, you have to give all the symbols to the linker at once so it can create the executable.

As Joachim explained, anything beyond a couple files becomes a huge pain, at which point learning a build system can be quite profitable. He mentions make, but I would also consider looking into <a href="http://cmake.org" rel="nofollow">cmake</a> which has simpler syntax and is cross platform. It can even generate Makefiles for you automatically.

Answer2:

[Note: This isn't an answer to the question, it's just an explanation on how to compile multiple files one by one]

You <em>can</em> compile the source files separately, but then you have to tell g++ to create <em>object files</em>, which you then link together.

Something like this:

$ g++ -Wall -g -c -I../include -I/usr/include/Snap-2.3/snap-core -I/usr/include/Snap-2.3/glib-core main.cpp $ g++ -Wall -g -c -I../include -I/usr/include/Snap-2.3/snap-core -I/usr/include/Snap-2.3/glib-core GraphData.cpp $ g++ -g main.o GraphData.o /usr/include/Snap-2.3/snap-core/Snap.o -o main

The option -Wall tells g++ to enable more warnings, this is good because warnings are signs of something that you might be doing wrong (like causing <a href="http://en.wikipedia.org/wiki/Undefined_behavior" rel="nofollow"><em>undefined behavior</em></a>). The -g options tells g++ to generate debug information, always good to have while developing in case you need to run the program in a debugger. Finally the -c option is what tells g++ to generate an <em>object file</em> instead of an executable program.

Then you have a separate command that links the object files together to form the final executable.

If you get more than a couple of files this all becomes kind of a pain in the backside, and then you should learn about <a href="http://www.gnu.org/software/make/" rel="nofollow">make</a> which is a program which can automate much of this for you. It will, for example, check time-stamps on the files to make sure you don't compile unmodified files.

Recommend

  • Lots of edges on a graph plot in python
  • plotting in python with congruent x-values
  • How do I use a button to switch between two different graphs in matplotlib
  • cluster location in graphviz python
  • Cron job: how to run a script that requires to open display?
  • C# How to kill a blocked thread?
  • When will the computation graph be freed if I only do forward for some samples?
  • Boost Graph as basis for a simple DAG Graph?
  • Application get stuck when drawing nearly 40 Scatter Plots using Core Plot in IPad
  • Using both POST and GET http request in AsyncTask
  • How to run naive Bayes from NLTK with Python Pandas?
  • How to start new graphics window AND/or graphics page in R
  • Find the minimal common path from any nodes to one node
  • Scripted Dashboards for Graphite
  • How do I export charts from Excel as graphics
  • Which version of Silverlight is it the safest to use in production?
  • Advantages and disadvantages of encoding objects with NSCoding or simply writing data to files
  • So we've got MEF working with MVC4, how about the convention based model?
  • Find all paths in directed cyclic graph as regular expression
  • How to project IR image on a 2D plane using OpenCV and PCL
  • Easy way to plot and display arrays?
  • Why is this way of randomly generating a graph unfair?
  • dc.js / d3.js - How to hide a bar chart x-axis category value if its bar value equals zero?
  • Is there a simple MVC4 html helper for collapsible (multi-level) Bootstrap 3 menus?
  • Using a support vector classifier with polynomial kernel in scikit-learn
  • Add chart on phpoffice/phpword
  • matplotlib issues when nan first in list
  • How to find specific subgraph in Neo4j using where clause
  • LatLong falls within a given polygon in D3 + Leaflet
  • How do references in functions work?
  • Collapsible Sankey Diagram - D3
  • Accessing Rows In A LINQ Result Without A Foreach Loop?
  • Copy to all folders batch file?
  • Scrapy recursive link crawler
  • NetLogo BehaviorSpace - Measure runs using reporters
  • How to add a column to a Pandas dataframe made of arrays of the n-preceding values of another column
  • How to handle AllServersUnavailable Exception
  • Why joiner is not used after Sequence generator or Update statergy
  • Android Heatmap on canvas or ImageView
  • Net Present Value in Excel for Grouped Recurring CF