You are not logged in.
Hi all,
I've rewritten a makefile for my project in a more "correct" way. Reason was not to recompile everything while debugging (complete rebuild takes about 10 seconds, maybe more). But it led to new troubles - now there are a lot of errors, showing that headers are included many times, despite header guards. In makefile, target "debug" is a new way build, "debug_old" - an old one which builds normally. I don't want the rules for each source file to be written manually.
Is it a problem in the makefile? How it can be corrected?
Makefile:
SOURCES=main.cpp data_types.cpp physics.cpp io.cpp
OBJECTS=$(addprefix obj/,$(SOURCES:.cpp=.o))
EXECUTABLE=bin/ThreadedParticles
DEBUG_FLAGS=-Wall -g -c
DEBUG_FLAGS_OLD=-lboost_thread-mt -Wall -g
LDFLAGS=-lboost_thread-mt
debug: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
g++ $(LDFLAGS) -o $@ $(OBJECTS)
$(OBJECTS): $(SOURCES)
g++ $(DEBUG_FLAGS) -o $@ $<
debug_old:
g++ $(DEBUG_FLAGS_OLD) -o $(EXECUTABLE) $(SOURCES)
$ make -B debug
g++ -Wall -g -c -o obj/main.o main.cpp
main.cpp: In function 'int main(int, char**)':
main.cpp:32:8: warning: enumeration value 'SUCCESS' not handled in switch
main.cpp:32:8: warning: enumeration value 'LINES_LEFT' not handled in switch
main.cpp:32:8: warning: enumeration value 'WRONG_VERSION' not handled in switch
main.cpp:32:8: warning: enumeration value 'FEW_PARTICLES' not handled in switch
main.cpp:34:2: warning: label 'WRONG_VERSION' defined but not used
main.cpp:37:2: warning: label 'FEW_PARTICLES' defined but not used
main.cpp:40:2: warning: label 'LINES_LEFT' defined but not used
main.cpp:42:2: warning: label 'SUCCESS' defined but not used
g++ -Wall -g -c -o obj/data_types.o main.cpp
main.cpp: In function 'int main(int, char**)':
# ...
# same warnings as for main.o
# ...
g++ -Wall -g -c -o obj/physics.o main.cpp
main.cpp: In function 'int main(int, char**)':
# ...
# same warnings as for main.o
# ...
g++ -Wall -g -c -o obj/io.o main.cpp
main.cpp: In function 'int main(int, char**)':
# ...
# same warnings as for main.o
# ...
g++ -lboost_thread-mt -o bin/ThreadedParticles obj/main.o obj/data_types.o obj/physics.o obj/io.o
obj/data_types.o: In function `main':
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.5.1/../../../../include/c++/4.5.1/exception:64: multiple definition of `main'
obj/main.o:/mnt/data/Coding/Current Projects/ThreadedParticles/main.cpp:9: first defined here
obj/physics.o: In function `main':
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.5.1/../../../../include/c++/4.5.1/exception:64: multiple definition of `main'
obj/main.o:/mnt/data/Coding/Current Projects/ThreadedParticles/main.cpp:9: first defined here
obj/io.o: In function `main':
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.5.1/../../../../include/c++/4.5.1/exception:64: multiple definition of `main'
obj/main.o:/mnt/data/Coding/Current Projects/ThreadedParticles/main.cpp:9: first defined here
obj/main.o: In function `main':
main.cpp:(.text+0x109): undefined reference to `prepareWorld(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, tpPhysicsGravity**, tpOutput**)'
main.cpp:(.text+0x157): undefined reference to `tpPhysics::iterationNumber()'
main.cpp:(.text+0x171): undefined reference to `tpPhysics::startThreads()'
main.cpp:(.text+0x17d): undefined reference to `tpOutput::start()'
main.cpp:(.text+0x189): undefined reference to `tpPhysics::stopThreads()'
main.cpp:(.text+0x195): undefined reference to `tpOutput::stop()'
main.cpp:(.text+0x1b5): undefined reference to `tpOutput::start()'
main.cpp:(.text+0x1c1): undefined reference to `tpOutput::stop()'
obj/main.o: In function `tpPhysicsGravity::~tpPhysicsGravity()':
main.cpp:(.text._ZN16tpPhysicsGravityD2Ev[_ZN16tpPhysicsGravityD5Ev]+0x13): undefined reference to `vtable for tpPhysicsGravity'
obj/data_types.o: In function `main':
# ...
# same "undefined reference" as for previous
# ...
obj/physics.o: In function `main':
# ...
# same "undefined reference" as for previous
# ...
obj/io.o: In function `main':
# ...
# same "undefined reference" as for previous
# ...
collect2: ld returned 1 exit status
make: *** [bin/ThreadedParticles] Error 1
Last edited by Kosmonavt (2010-11-30 08:16:56)
Offline
You did not share your header files. Do you have a main.h ? Why?
If so:
Did you declare the main function in that file?
Did you evaluate why io, data_types and physics need to know anything about main? Main generally needs to know about the other files, bit the other files should not need to know anything about main (or they are not reusable)
Nothing is too wonderful to be true, if it be consistent with the laws of nature -- Michael Faraday
Sometimes it is the people no one can imagine anything of who do the things no one can imagine. -- Alan Turing
---
How to Ask Questions the Smart Way
Offline
Situation is the following: there are also physics.hpp, io.hpp and data_types.hpp. main() is declared only in main.cpp one time, also not used by any classes/functions. It was surprising for me, since debug_old build normally, only warnings about enum are printed.
data_types.hpp:
#ifndef DATA_TYPES_HPP_INCLUDED
#define DATA_TYPES_HPP_INCLUDED
#include <valarray>
#include <vector>
#include <cmath>
// Common typedefs and (maybe) data types
typedef std::valarray<double> vector3;
typedef std::vector<vector3> vector_array;
typedef std::vector<double> d_array;
// Defining square of vector length
double norm( vector3 v );
#endif // DATA_TYPES_HPP_INCLUDED
io.hpp:
#ifndef IO_HPP_INCLUDED
#define IO_HPP_INCLUDED
#include <fstream>
// #include <boost/thread.hpp>
#include <string>
#include <sstream>
#include "data_types.hpp"
#include "physics.hpp"
// *** Output facility ***
class tpOutput
{
public:
tpOutput(std::string filename, int version, int skip, tpPhysics* physsystem);
~tpOutput() { }
void start();
void stop();
private:
std::ofstream outputFile;
// boost::thread outputWorker;
int skipSize;
int versionNumber;
tpPhysics* physSystem;
void writeResults();
void writeTableHeader();
void writeVersion();
void writeSettingOverview();
};
/////////////////////////////////////////////////////////////
// *** Input facility ***
enum prepareError { SUCCESS, LINES_LEFT, WRONG_VERSION, FEW_PARTICLES };
prepareError prepareWorld( std::string settingFileName, std::string outputFileName, int worker_num, tpPhysicsGravity** world, tpOutput** log );
namespace input
{
int parseSettings( std::ifstream& fin, long int& part_num, long int& iter_num, double& delta_t, int& skip, std::string& desc );
// 0 - if incompatible at all, nonzero - number of setting file ID
// for Ver2 setting file
void readParticleData_2( std::ifstream& fin, d_array& m_range, d_array& c_range, d_array& v_range );
// for coord/velocity, lower values are in 0-2,
// higher - in 3-5
// for Ver1 setting file; to be called for every particle in list
void readParticleData_1( std::ifstream& fin, double& m, vector3& c, vector3& v );
// Getting CSV key values
void getKey( std::ifstream& f, long int& result );
void getKey( std::ifstream& f, double& result );
void getKey( std::ifstream& f, int& result );
}
/////////////////////////////////////////////////////////////
#endif // IO_HPP_INCLUDED
physics.hpp:
#ifndef PARTICLES_HPP_INCLUDED
#define PARTICLES_HPP_INCLUDED
#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <cmath>
#include <vector>
#include <valarray>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include "data_types.hpp"
// General-purpose constants and types
const double G = 6.673e-11;
//////////////////////////////////////
// *** Physics facility ***
class tpPhysics
{
public:
tpPhysics( long int iter_num, long int part_num, double delta_t, int worker_num );
~tpPhysics() { }
void startThreads();
void stopThreads();
void addParticle( double m, vector3 c, vector3 v );
void generateParticles(d_array m, d_array c, d_array v);
void getPreviousState( long int num, double& m, vector3& c, vector3& v );
long int iterationNumber();
long int particleNumber();
double dt();
long int showTime();
protected:
void setWorkers(int worker_number);
// 1st set of parameters
vector_array coords_1;
vector_array velocity_1;
d_array mass_1;
// 2nd set of parameters
vector_array coords_2;
vector_array velocity_2;
d_array mass_2;
void setCurrentState( long int num, vector3 c, vector3 v );
void setCurrentState( long int num, double m, vector3 c, vector3 v );
void nextStep();
// Common parameters
const long int iterNumber;
const long int partNumber;
const double deltaT;
long int current_time;
int which_set; // 1 - if 1st set is current, 2 - if 2nd set is current
// Threading data
std::vector<long int> boundaries;
std::vector<boost::shared_ptr<boost::thread> > workerArray;
int workerCount;
virtual void singleCalculator(int lower, int higher) = 0;
};
class tpPhysicsGravity : public tpPhysics
{
public:
tpPhysicsGravity( long int iter_num, long int part_num, double delta_t, int worker_num )
: tpPhysics(iter_num, part_num, delta_t, worker_num) { }
~tpPhysicsGravity() { }
protected:
void singleCalculator(int lower, int higher);
};
//////////////////////////////////////////
#endif // PARTICLES_HPP_INCLUDED
Offline
Two things.
First, you are not compiling io.cpp, data_types.cpp, or tpPhysics.cpp. It would appear you are compiling main.cpp 4 times, first calling the output main.o, second time calling the output data_types.o, etc... At the end, the linker takes the four identical .o files and has a little bit of trouble resolving all of the references
Second, when the first problem is sorted out, I think you will need a semicolon after the declaration of the destructor for tpPhysics.
I am not an expert in Makefiles, but your problem is in the section that tells it how to build the .o files. Somehow you are always getting main.cpp rather than the associated .cpp. I need to go look deeper...
Last edited by ewaller (2010-11-26 23:39:15)
Nothing is too wonderful to be true, if it be consistent with the laws of nature -- Michael Faraday
Sometimes it is the people no one can imagine anything of who do the things no one can imagine. -- Alan Turing
---
How to Ask Questions the Smart Way
Offline
What if you replace the line
$(OBJECTS): $(SOURCES)
with
.cpp.o:
??
Nothing is too wonderful to be true, if it be consistent with the laws of nature -- Michael Faraday
Sometimes it is the people no one can imagine anything of who do the things no one can imagine. -- Alan Turing
---
How to Ask Questions the Smart Way
Offline
Yes, it was my fault. It really compiled only main.cpp because of the wrong usage of $<.
With the following makefile it basically builds, but initial target (recompile only if needed) isn't achieved. Using .cpp.o: target is bad - object files flood project root directory rather than obj/. Something like $(addprefix obj/,.cpp=.o) does not work. Also perspective of adding rules by hands is quite sad. Reading through official make manual hasn't given any adequate solution. If I could somehow get filename.o: filename.cpp for each entry from SOURCES and OBJECTS, it would be fine.
Maybe anyone knows a way to do this?
Current makefile:
SOURCES=main.cpp data_types.cpp physics.cpp io.cpp
OBJECTS=$(addprefix obj/,$(SOURCES:.cpp=.o))
EXECUTABLE=bin/ThreadedParticles
DEBUG_FLAGS=-Wall -g -c
DEBUG_FLAGS_OLD=-lboost_thread-mt -Wall -g
LDFLAGS=-lboost_thread-mt
debug: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
g++ $(LDFLAGS) -o $@ $(OBJECTS)
$(OBJECTS): $(SOURCES)
g++ $(DEBUG_FLAGS) -o $@ $(subst .o,.cpp,$(subst obj/,,$@))
debug_old:
g++ $(DEBUG_FLAGS_OLD) -o $(EXECUTABLE) $(SOURCES)
Offline
Okay, reading manual again and again thoroughly solved the issue. Using this Makefile everything automagically works:
OBJDIR=obj
SOURCES=main.cpp data_types.cpp physics.cpp io.cpp
EXECUTABLE=bin/ThreadedParticles
OBJECTS=$(addprefix $(OBJDIR)/,$(SOURCES:.cpp=.o))
DEBUG_FLAGS=-Wall -g
LDFLAGS=-lboost_thread-mt
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
g++ $(DEBUG_FLAGS) $(LDFLAGS) -o $@ $^
$(OBJDIR)/%.o: %.cpp
g++ $(DEBUG_FLAGS) -c -o $@ $<
Offline