|
|||
Makefiles
Hello,
As I continue in my programming education, my programs are becoming increasingly large and complex. As a result I decided to start to learn how to write makefiles. I wrote one up for project I'm working on. It had two header files and three .cpp files. When I went to make, I got a boatload of errors, such as methods already defined. I put all the .cpp files into one file, and it works fine. What gives? I can get away with one large .cpp file in this project, but my next one (final project) will be too large for one file. I do have ifndef, defines for the header files. And each .cpp file called both header files. I don't know if that matters or not. Here is the Makefile I wrote (didn't work - it did when it was reduced to one .cpp file): Code:
hack_slash: main.o draw.o collision.o g++ main.o draw.o collision.o -o hack_slash -lcurses main.o: main.cpp g++ -c main.cpp draw.o: draw.cpp g++ -c draw.cpp collision.o: collision.cpp g++ -c collision.cpp clean: rm *.o Here are the errors I received: Code:
g++ main.o draw.o collision.o -lcurses draw.o: In function `thing::thing()': draw.cpp:(.text+0x0): multiple definition of `thing::thing()' main.o:main.cpp:(.text+0x0): first defined here draw.o: In function `thing::thing()': draw.cpp:(.text+0x6): multiple definition of `thing::thing()' main.o:main.cpp:(.text+0x6): first defined here draw.o: In function `thing::thing(int, int, char)': draw.cpp:(.text+0xc): multiple definition of `thing::thing(int, int, char)' main.o:main.cpp:(.text+0xc): first defined here draw.o: In function `thing::thing(int, int, char)': draw.cpp:(.text+0x34): multiple definition of `thing::thing(int, int, char)' main.o:main.cpp:(.text+0x34): first defined here draw.o: In function `thing::getx()': draw.cpp:(.text+0x5c): multiple definition of `thing::getx()' main.o:main.cpp:(.text+0x5c): first defined here draw.o: In function `thing::gety()': draw.cpp:(.text+0x66): multiple definition of `thing::gety()' main.o:main.cpp:(.text+0x66): first defined here draw.o: In function `thing::get_symbol()': draw.cpp:(.text+0x72): multiple definition of `thing::get_symbol()' main.o:main.cpp:(.text+0x72): first defined here draw.o: In function `agent::agent(int, int, char)': draw.cpp:(.text+0x80): multiple definition of `agent::agent(int, int, char)' main.o:main.cpp:(.text+0x80): first defined here draw.o: In function `agent::agent(int, int, char)': draw.cpp:(.text+0xd8): multiple definition of `agent::agent(int, int, char)' main.o:main.cpp:(.text+0xd8): first defined here draw.o: In function `agent::get_velx()': draw.cpp:(.text+0x130): multiple definition of `agent::get_velx()' main.o:main.cpp:(.text+0x130): first defined here draw.o: In function `agent::get_vely()': draw.cpp:(.text+0x144): multiple definition of `agent::get_vely()' main.o:main.cpp:(.text+0x144): first defined here draw.o: In function `agent::set_alive(bool)': draw.cpp:(.text+0x158): multiple definition of `agent::set_alive(bool)' main.o:main.cpp:(.text+0x158): first defined here draw.o: In function `agent::wall_collide()': draw.cpp:(.text+0x170): multiple definition of `agent::wall_collide()' main.o:main.cpp:(.text+0x170): first defined here draw.o: In function `agent::wall_crash()': draw.cpp:(.text+0x21c): multiple definition of `agent::wall_crash()' main.o:main.cpp:(.text+0x21c): first defined here draw.o: In function `agent::get_alive()': draw.cpp:(.text+0x25e): multiple definition of `agent::get_alive()' main.o:main.cpp:(.text+0x25e): first defined here draw.o: In function `agent::get_prevx()': draw.cpp:(.text+0x26e): multiple definition of `agent::get_prevx()' main.o:main.cpp:(.text+0x26e): first defined here draw.o: In function `agent::get_prevy()': draw.cpp:(.text+0x2c4): multiple definition of `agent::get_prevy()' main.o:main.cpp:(.text+0x2c4): first defined here draw.o: In function `dot::dot(int, int, char)': draw.cpp:(.text+0x31c): multiple definition of `dot::dot(int, int, char)' main.o:main.cpp:(.text+0x31c): first defined here draw.o: In function `dot::dot(int, int, char)': draw.cpp:(.text+0x358): multiple definition of `dot::dot(int, int, char)' main.o:main.cpp:(.text+0x358): first defined here draw.o: In function `guard::guard(int, int, char)': draw.cpp:(.text+0x394): multiple definition of `guard::guard(int, int, char)' main.o:main.cpp:(.text+0x394): first defined here draw.o: In function `guard::guard(int, int, char)': draw.cpp:(.text+0x3ba): multiple definition of `guard::guard(int, int, char)' main.o:main.cpp:(.text+0x3ba): first defined here draw.o: In function `hackbot::hackbot(int, int, char)': draw.cpp:(.text+0x3e0): multiple definition of `hackbot::hackbot(int, int, char)' main.o:main.cpp:(.text+0x3e0): first defined here draw.o: In function `hackbot::hackbot(int, int, char)': draw.cpp:(.text+0x41c): multiple definition of `hackbot::hackbot(int, int, char)' main.o:main.cpp:(.text+0x41c): first defined here draw.o: In function `slashbot::slashbot(int, int, char)': draw.cpp:(.text+0x458): multiple definition of `slashbot::slashbot(int, int, char)' main.o:main.cpp:(.text+0x458): first defined here draw.o: In function `slashbot::slashbot(int, int, char)': draw.cpp:(.text+0x494): multiple definition of `slashbot::slashbot(int, int, char)' main.o:main.cpp:(.text+0x494): first defined here draw.o: In function `guard::get_distance(int, int, int, int)': draw.cpp:(.text+0x526): multiple definition of `guard::get_distance(int, int, int, int)' main.o:main.cpp:(.text+0x4d0): first defined here draw.o: In function `guard::normalize_local_steer(float)': draw.cpp:(.text+0x5a0): multiple definition of `guard::normalize_local_steer(float)' main.o:main.cpp:(.text+0x54a): first defined here draw.o: In function `guard::flee(int, int, float)': draw.cpp:(.text+0x616): multiple definition of `guard::flee(int, int, float)' main.o:main.cpp:(.text+0x5c0): first defined here draw.o: In function `guard::seek(int, int, float)': draw.cpp:(.text+0x68e): multiple definition of `guard::seek(int, int, float)' main.o:main.cpp:(.text+0x638): first defined here draw.o: In function `guard::arrive(int, int, float, float, float)': draw.cpp:(.text+0x70a): multiple definition of `guard::arrive(int, int, float, float, float)' main.o:main.cpp:(.text+0x6b4): first defined here draw.o: In function `agent::normalize_vel()': draw.cpp:(.text+0x838): multiple definition of `agent::normalize_vel()' main.o:main.cpp:(.text+0x7e2): first defined here draw.o: In function `agent::normalize_steer()': draw.cpp:(.text+0x8b2): multiple definition of `agent::normalize_steer()' main.o:main.cpp:(.text+0x85c): first defined here draw.o: In function `guard::wall_avoid(int, int, float)': draw.cpp:(.text+0x92c): multiple definition of `guard::wall_avoid(int, int, float)' main.o:main.cpp:(.text+0x8d6): first defined here draw.o: In function `guard::evade(int, int, float, float, float)': draw.cpp:(.text+0xa24): multiple definition of `guard::evade(int, int, float, float, float)' main.o:main.cpp:(.text+0x9ce): first defined here draw.o: In function `guard::pursue(int, int, float, float, float)': draw.cpp:(.text+0xb06): multiple definition of `guard::pursue(int, int, float, float, float)' main.o:main.cpp:(.text+0xab0): first defined here draw.o: In function `agent::update()': draw.cpp:(.text+0xbe8): multiple definition of `agent::update()' main.o:main.cpp:(.text+0xb92): first defined here draw.o: In function `slashbot::move(dot, hackbot, thing*)': draw.cpp:(.text+0xcb6): multiple definition of `slashbot::move(dot, hackbot, thing*)' main.o:main.cpp:(.text+0xc60): first defined here draw.o: In function `hackbot::move(dot, slashbot, thing*)': draw.cpp:(.text+0xd8a): multiple definition of `hackbot::move(dot, slashbot, thing*)' main.o:main.cpp:(.text+0xd34): first defined here draw.o: In function `dot::player_steer(int)': draw.cpp:(.text+0xe30): multiple definition of `dot::player_steer(int)' main.o:main.cpp:(.text+0xdda): first defined here collision.o: In function `thing::thing()': collision.cpp:(.text+0x0): multiple definition of `thing::thing()' main.o:main.cpp:(.text+0x0): first defined here collision.o: In function `thing::thing()': collision.cpp:(.text+0x6): multiple definition of `thing::thing()' main.o:main.cpp:(.text+0x6): first defined here collision.o: In function `thing::thing(int, int, char)': collision.cpp:(.text+0xc): multiple definition of `thing::thing(int, int, char)' main.o:main.cpp:(.text+0xc): first defined here collision.o: In function `thing::thing(int, int, char)': collision.cpp:(.text+0x34): multiple definition of `thing::thing(int, int, char)' main.o:main.cpp:(.text+0x34): first defined here collision.o: In function `thing::getx()': collision.cpp:(.text+0x5c): multiple definition of `thing::getx()' main.o:main.cpp:(.text+0x5c): first defined here collision.o: In function `thing::gety()': collision.cpp:(.text+0x66): multiple definition of `thing::gety()' main.o:main.cpp:(.text+0x66): first defined here collision.o: In function `thing::get_symbol()': collision.cpp:(.text+0x72): multiple definition of `thing::get_symbol()' main.o:main.cpp:(.text+0x72): first defined here collision.o: In function `agent::agent(int, int, char)': collision.cpp:(.text+0x80): multiple definition of `agent::agent(int, int, char)' main.o:main.cpp:(.text+0x80): first defined here collision.o: In function `agent::agent(int, int, char)': collision.cpp:(.text+0xd8): multiple definition of `agent::agent(int, int, char)' main.o:main.cpp:(.text+0xd8): first defined here collision.o: In function `agent::get_velx()': collision.cpp:(.text+0x130): multiple definition of `agent::get_velx()' main.o:main.cpp:(.text+0x130): first defined here collision.o: In function `agent::get_vely()': collision.cpp:(.text+0x144): multiple definition of `agent::get_vely()' main.o:main.cpp:(.text+0x144): first defined here collision.o: In function `agent::set_alive(bool)': collision.cpp:(.text+0x158): multiple definition of `agent::set_alive(bool)' main.o:main.cpp:(.text+0x158): first defined here collision.o: In function `agent::wall_collide()': collision.cpp:(.text+0x170): multiple definition of `agent::wall_collide()' main.o:main.cpp:(.text+0x170): first defined here collision.o: In function `agent::wall_crash()': collision.cpp:(.text+0x21c): multiple definition of `agent::wall_crash()' main.o:main.cpp:(.text+0x21c): first defined here collision.o: In function `agent::get_alive()': collision.cpp:(.text+0x25e): multiple definition of `agent::get_alive()' main.o:main.cpp:(.text+0x25e): first defined here collision.o: In function `agent::get_prevx()': collision.cpp:(.text+0x26e): multiple definition of `agent::get_prevx()' main.o:main.cpp:(.text+0x26e): first defined here collision.o: In function `agent::get_prevy()': collision.cpp:(.text+0x2c4): multiple definition of `agent::get_prevy()' main.o:main.cpp:(.text+0x2c4): first defined here collision.o: In function `dot::dot(int, int, char)': collision.cpp:(.text+0x31c): multiple definition of `dot::dot(int, int, char)' main.o:main.cpp:(.text+0x31c): first defined here collision.o: In function `dot::dot(int, int, char)': collision.cpp:(.text+0x358): multiple definition of `dot::dot(int, int, char)' main.o:main.cpp:(.text+0x358): first defined here collision.o: In function `guard::guard(int, int, char)': collision.cpp:(.text+0x394): multiple definition of `guard::guard(int, int, char)' main.o:main.cpp:(.text+0x394): first defined here collision.o: In function `guard::guard(int, int, char)': collision.cpp:(.text+0x3ba): multiple definition of `guard::guard(int, int, char)' main.o:main.cpp:(.text+0x3ba): first defined here collision.o: In function `hackbot::hackbot(int, int, char)': collision.cpp:(.text+0x3e0): multiple definition of `hackbot::hackbot(int, int, char)' main.o:main.cpp:(.text+0x3e0): first defined here collision.o: In function `hackbot::hackbot(int, int, char)': collision.cpp:(.text+0x41c): multiple definition of `hackbot::hackbot(int, int, char)' main.o:main.cpp:(.text+0x41c): first defined here collision.o: In function `slashbot::slashbot(int, int, char)': collision.cpp:(.text+0x458): multiple definition of `slashbot::slashbot(int, int, char)' main.o:main.cpp:(.text+0x458): first defined here collision.o: In function `slashbot::slashbot(int, int, char)': collision.cpp:(.text+0x494): multiple definition of `slashbot::slashbot(int, int, char)' main.o:main.cpp:(.text+0x494): first defined here collision.o: In function `guard::get_distance(int, int, int, int)': collision.cpp:(.text+0x6b0): multiple definition of `guard::get_distance(int, int, int, int)' main.o:main.cpp:(.text+0x4d0): first defined here collision.o: In function `guard::normalize_local_steer(float)': collision.cpp:(.text+0x72a): multiple definition of `guard::normalize_local_steer(float)' main.o:main.cpp:(.text+0x54a): first defined here collision.o: In function `guard::flee(int, int, float)': collision.cpp:(.text+0x7a0): multiple definition of `guard::flee(int, int, float)' main.o:main.cpp:(.text+0x5c0): first defined here collision.o: In function `guard::seek(int, int, float)': collision.cpp:(.text+0x818): multiple definition of `guard::seek(int, int, float)' main.o:main.cpp:(.text+0x638): first defined here collision.o: In function `guard::arrive(int, int, float, float, float)': collision.cpp:(.text+0x894): multiple definition of `guard::arrive(int, int, float, float, float)' main.o:main.cpp:(.text+0x6b4): first defined here collision.o: In function `agent::normalize_vel()': collision.cpp:(.text+0x9c2): multiple definition of `agent::normalize_vel()' main.o:main.cpp:(.text+0x7e2): first defined here collision.o: In function `agent::normalize_steer()': collision.cpp:(.text+0xa3c): multiple definition of `agent::normalize_steer()' main.o:main.cpp:(.text+0x85c): first defined here collision.o: In function `guard::wall_avoid(int, int, float)': collision.cpp:(.text+0xab6): multiple definition of `guard::wall_avoid(int, int, float)' main.o:main.cpp:(.text+0x8d6): first defined here collision.o: In function `guard::evade(int, int, float, float, float)': collision.cpp:(.text+0xbae): multiple definition of `guard::evade(int, int, float, float, float)' main.o:main.cpp:(.text+0x9ce): first defined here collision.o: In function `guard::pursue(int, int, float, float, float)': collision.cpp:(.text+0xc90): multiple definition of `guard::pursue(int, int, float, float, float)' main.o:main.cpp:(.text+0xab0): first defined here collision.o: In function `agent::update()': collision.cpp:(.text+0xd72): multiple definition of `agent::update()' main.o:main.cpp:(.text+0xb92): first defined here collision.o: In function `slashbot::move(dot, hackbot, thing*)': collision.cpp:(.text+0xe40): multiple definition of `slashbot::move(dot, hackbot, thing*)' main.o:main.cpp:(.text+0xc60): first defined here collision.o: In function `hackbot::move(dot, slashbot, thing*)': collision.cpp:(.text+0xf14): multiple definition of `hackbot::move(dot, slashbot, thing*)' main.o:main.cpp:(.text+0xd34): first defined here collision.o: In function `dot::player_steer(int)': collision.cpp:(.text+0xfba): multiple definition of `dot::player_steer(int)' main.o:main.cpp:(.text+0xdda): first defined here collect2: ld returned 1 exit status make: *** [hack_slash] Error 1
__________________
And the WORD was made flesh, and dwelt among us. (John 1:14) Last edited by JMJ_coder; 18th October 2008 at 03:25 PM. |
|
|||
Quote:
This is indicative that global variables and/or functions have been fully defined within header files. In general, this is a practice frowned upon for exactly the reasons presented. This problem only manifests itself when header files are included in multiple translation units which are ultimately linked together. Recall that a compiler will simply convert a compilation/translation unit into an object file. Since compilers do not retain any information from the compilation of one file to another, its understanding of the overall application is incomplete. On the other hand, the linker has to resolve all references made within an object file which are not defined within the object file itself. In other words, the linker has to tie everything together. If the linker sees multiple references to where global variables and/or functions are defined in multiple locations, the decision it will make is simply to abort since it is clear that the programmer is not aware of or has resolved the presence of duplicate definitions. Although not relevant to this particular issue, it is important to also recognize that linkers treat libraries differently. If the linker finds several libraries implementing function foo(), the linker will used the first occurrence found. What you should take away with this comment is that the order in which libraries are specified to the linker matters. |
|
|||
I don't see those two header files listed as dependencies in your Makefile.
If you prefer the BSD make you can do something like this Code:
# ------- See 'Make --- A Tutorial' by Adam de Boor (section 3.1) # in /usr/share/doc/psd/12.make (OpenBSD) OBJS = main.o draw.o collision.o .SUFFIXES : .ccp .o .ccp.o : g++ -c ${.IMPSRC} hack_slash : ${OBJS} g++ ${OBJS} -o ${.TARGET} -lcurses ${OBJS} : joe.h plumber.h
__________________
You don't need to be a genius to debug a pf.conf firewall ruleset, you just need the guts to run tcpdump |
|
|||
Header files are not typically specified in Makefiles for the reasons I mentioned earlier. Header files should only contain function prototypes, structure declarations, & extern statements -- never executable code or variable definitions. Because Makefiles are concerned with compilation & linking, they typically only reference source code files.
|
|
|||
Quote:
The header files you create for your specific program form a dependency and thus should be listed as such in a Makefile rule. The only exception is Mr. Perfect Programmer, who writes his header file before everything else and never has to modify it.
__________________
You don't need to be a genius to debug a pf.conf firewall ruleset, you just need the guts to run tcpdump |
|
|||
Of course. This was not the point of contention.
|
|
||||
As Ocicat pointed out it looks like you have put the class function definitions in the header file.
The header file must only contain the interface not the implementation. The textbook method to avoid the problem is to have a header and corresponding cc file for classes, eg. agent.h and agent.cc, with the func. def. in the latter file. |
|
|||
Huh? I do use the header files to put whole classes. I didn't know that was a no-no. So I should have the class definition in one file (header file) and the class methods in another file (cpp file)? So for instance, in the project I have a thing class (actually, the professor wrote it) - so it should be structured like this?
thing.h Code:
class thing { public: thing(int, int, char); thing(); int getx(); /* x coordinates of character */ int gety(); /* y coordinates of character */ char get_symbol(); protected: int x, y; /* where thing is */ char symbol; /* what thing is represented by */ }; Code:
#include "thing.h" thing::thing() {} thing::thing(int xinit, int yinit, char s) { x = xinit; y = yinit; symbol = s; } int thing::getx() { return x; } int thing::gety() { return y; } char thing::get_symbol() { return symbol; } If that is so, what do I include in the main.cpp file - thing.h; thing.cpp; both; neither? Also I do have some global function prototypes in the header file, and some defines: Code:
#include <curses.h> #include <math.h> #define POSX 50 #define POSY 20 #define DOORTOP 7 #define DOORBOTTOM 13 /* forward declarations */ class agent; class dot; class guard; class hackbot; class slashbot; class thing; /* function prototypes */ void draw(WINDOW*, thing[], hackbot, slashbot, dot); bool check_wires(agent, thing[]); bool collide(agent, agent); Should these be in a header file?
__________________
And the WORD was made flesh, and dwelt among us. (John 1:14) |
|
|||
Quote:
Class declarations should be placed into header files, & most member functions should be implemented in a single source code file. The only exception to this convention is inline member functions or inline functions. Here, public symbols are not being generated for the linker to see. inline code is also often treated as code which is substituted elsewhere. Because of this, inline is essentially treated as #define preprocessor commands. However in C++, note that all inline member functions or member functions defined within the class's declaration (which means that they are to be inlined...) are not always inlined. Simple substitution is left up to compiler vendors to determine whether they can perform the substitution. As a rule of thumb, C++ compilers will not inline any code which implements a branch -- while-loops, for-loops. etc. Quote:
Think of the problem involving system headers. For example, the prototype for printf() is found in stdio.h, yet the implementation is found in code which ultimately is compiled & placed into /usr/lib/libc.so. What is required in application code? Mere inclusion of stdio.h is sufficient because all the compiler needs to know is the function's signature. It is the linker's responsibility to resolve all symbols where are present in other object files or libraries. So to answer the fundamental question, when a source code file containing main() instantiates (allocates memory...) a class, all the compiler needs to see beforehand is the class' declaration. Typically, this means that the header file containing the class declaration was included at the top of the source code file. Quote:
As for the remainder of what is specified above, no memory allocations are being specified (variable definitions) nor is any compilable code provided, so everything above is safe. So to be clear, the following is all that should ever be in header files:
Last edited by ocicat; 21st October 2008 at 01:53 AM. |
|
|||
Thank you ocicat, that was enlightening.
One more follow up question. With the class thing, adding it to the main.cpp, I would Code:
#include "thing.h" Code:
a.out: main.o thing.o g++ main.o thing.o Code:
#include "thing.h"
__________________
And the WORD was made flesh, and dwelt among us. (John 1:14) |
|
|||
Quote:
Quote:
I suspect you may be finding the following fact confusing & possibly a cause for some misunderstanding: functions like printf() appear to only require inclusion of stdio.h, & the linker magically links in the appropriate library. This is the correct behavior because the standard libc library is linked into applications by default. All functions found in libc are accessible within an application without explicitly telling the linker to resolve references to this particular library. This isn't done because of the #include, or by the fact that the #include statement is done with angle brackets (#include <stdio.h>). The code for printf() is magically linked into the application because libc is linked into the application by default. Last edited by ocicat; 21st October 2008 at 02:03 AM. |
|
|||
O.K.
One more question on your last point. If the #include isn't necessary for the standard library, why do we #include them?
__________________
And the WORD was made flesh, and dwelt among us. (John 1:14) |
|
|||
You weren't listening, it is necessary.. the compiler only links with libc, this is terminology you'll need to understand.
Let's take the prototype for printf for instance.. it's in stdio.h. Code:
int printf(const char *format, ...); This was a simple example, what you might want to do is read over the header files you're including.. it's most definitely beneficial to see what information they define. I'm not going to explain '...' (variable arguments), but you'll learn all this eventually yourself. |
|
|||
Quote:
Of course, C++ implements even more stringent type-checking than C. Type-checking is deemed to be important because it catches an entire class of subtle bugs, & error messages can be more precise in pointing out the root cause. What you should be taking away from this discussion is that errors can occur at different points in the process, & these errors manifest themselves in different ways.
Last edited by ocicat; 21st October 2008 at 04:32 PM. |
|
|||
Thanks.
Ah, the things they don't teach you in school.
__________________
And the WORD was made flesh, and dwelt among us. (John 1:14) |
|
||||
If we're getting technical here, GCC first calls the pre-processor, then converts the output of the pre-processor to asm, then compiles the asm output into a binary object file. Then the linker can be used to link those object files into something like an application program or a shared library.
|
|
||||
Not quite accurate mdh.
We usually call gcc through a front end (e.g. g++) which invokes the necessary programs to complete the indicated task. To compile, the front end has to parse the source files for the assembler. C, C++, and some dialects of Fortran get fed through a text pre processor first by default, which does not understand code. cpp the "C Pre Processor" knows nothing of C, it's as simple as sed s/search/replace/g for all most people need to care. The pre processed code is then parsed by the front end into the proper format and massaged into Register Transfer Language (RTL) by the back end. Which is then given to the the gnu assembler (as) for your platform, in order to create something that the GNU linker (ld) can understand. And eventually finding it's way into something that will be executed by your operating system. But most likely ocicats choice of words, were chosen to Keep It Simple for the Student. How much that's actually possible in C /or C++, I have no idea... lol.
__________________
My Journal Thou shalt check the array bounds of all strings (indeed, all arrays), for surely where thou typest ``foo'' someone someday shall type ``supercalifragilisticexpialidocious''. Last edited by TerryP; 21st October 2008 at 09:33 PM. |
Tags |
make, makefile |
Thread Tools | |
Display Modes | |
|
|