DaemonForums  

Go Back   DaemonForums > Miscellaneous > Programming

Programming C, bash, Python, Perl, PHP, Java, you name it.

Reply
 
Thread Tools Display Modes
  #1   (View Single Post)  
Old 18th October 2008
JMJ_coder JMJ_coder is offline
VPN Cryptographer
 
Join Date: May 2008
Posts: 464
Thanked 8 Times in 8 Posts
Default 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.
Reply With Quote
  #2   (View Single Post)  
Old 18th October 2008
ocicat ocicat is offline
Administrator
 
Join Date: Apr 2008
Posts: 2,873
Thanked 190 Times in 160 Posts
Default

Quote:
Originally Posted by JMJ_coder View Post
When I went to make, I got a boatload of errors, such as methods already defined.
In other words, the linker is having a fit.

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.
Reply With Quote
  #3   (View Single Post)  
Old 18th October 2008
mdh's Avatar
mdh mdh is offline
Real Name: Matt D. Harris
FreeBSD 2.2.6 User
 
Join Date: Oct 2008
Location: West Virginia
Posts: 139
Thanked 8 Times in 8 Posts
Default

Here's the template Makefile I use for small stuff that doesn't require any sort of templating such as autoconf:
Code:
# CONFIG
CC=gcc
CFLAGS=-O -march=CHANGEME -pipe -I/usr/local/include
DFLAGS=-Wall -Wno-long-long -Wno-unused-variable -Wno-unused-value -ggdb
#DFLAGS=-Wno-long-long -Wno-pointer-sign
ENV=FREEBSD
LIBS=
BINARY=X
# /CONFIG

SRC=X1.c X2.c
OBJ=${SRC:%.c=%.o}

.c.o:
        $(CC) $(CFLAGS) $(DFLAGS) -DOS_$(ENV) -c $<

all:    $(OBJ)
        $(CC) $(CFLAGS) $(DFLAGS) -o $(BINARY) $(OBJ) $(LIBS)

build:  all

clean:
        rm -f $(OBJ) $(BINARY)

X1.o:       X1.c X1.h proj.h
X2.o:         X2.c X2.h proj.h
This will produce an application binary ``X'' from C source code files `X1.c' and `X2.c'. Just change CC to g++ and the .c to .cpp, then add lines for your files (at the bottom) plus add them to the SRC variable (whitespace delimited).

Hope this helps.
Reply With Quote
  #4   (View Single Post)  
Old 18th October 2008
J65nko J65nko is offline
Administrator
 
Join Date: May 2008
Location: Budel - the Netherlands
Posts: 3,135
Thanked 182 Times in 149 Posts
Default

Quote:
Originally Posted by JMJ_coder View Post
It had two header files and three .cpp files.
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
CAVEAT: I am not a C programmer, just studied that execellent Make tutorial by Adam de Boor for some Makefiles to transform XML into HTML with XSLT style/transformation sheets
__________________
You don't need to be a genius to debug a pf.conf firewall ruleset, you just need the guts to run tcpdump
Reply With Quote
  #5   (View Single Post)  
Old 19th October 2008
ocicat ocicat is offline
Administrator
 
Join Date: Apr 2008
Posts: 2,873
Thanked 190 Times in 160 Posts
Default

Quote:
Originally Posted by J65nko View Post
I don't see those two header files listed as dependencies in your Makefile.
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.
Reply With Quote
  #6   (View Single Post)  
Old 19th October 2008
J65nko J65nko is offline
Administrator
 
Join Date: May 2008
Location: Budel - the Netherlands
Posts: 3,135
Thanked 182 Times in 149 Posts
Default

Quote:
Originally Posted by ocicat View Post
Header files are not typically specified in Makefiles for the reasons I mentioned earlier.
Not the standard C header files of course.

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
Reply With Quote
  #7   (View Single Post)  
Old 19th October 2008
ocicat ocicat is offline
Administrator
 
Join Date: Apr 2008
Posts: 2,873
Thanked 190 Times in 160 Posts
Default

Quote:
Originally Posted by J65nko View Post
Not the standard C header files of course.
Of course. This was not the point of contention.
Reply With Quote
  #8   (View Single Post)  
Old 20th October 2008
ephemera's Avatar
ephemera ephemera is offline
Knuth's homeboy
 
Join Date: Apr 2008
Posts: 537
Thanked 49 Times in 43 Posts
Default

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.
Reply With Quote
  #9   (View Single Post)  
Old 21st October 2008
JMJ_coder JMJ_coder is offline
VPN Cryptographer
 
Join Date: May 2008
Posts: 464
Thanked 8 Times in 8 Posts
Default

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 */
};
thing.cpp
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)
Reply With Quote
Old 21st October 2008
ocicat ocicat is offline
Administrator
 
Join Date: Apr 2008
Posts: 2,873
Thanked 190 Times in 160 Posts
Default

Quote:
Originally Posted by JMJ_coder View Post
So I should have the class definition in one file (header file) and the class methods in another file (cpp file)?
Definitions imply that memory is being allocated.

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:
If that is so, what do I include in the main.cpp file - thing.h; thing.cpp; both; neither?
Including source code files is never, ever done. Never.

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:
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?
#define statements are simply instructions to the preprocessor to perform substitutions. Preprocessor commands can safely be placed in header files.

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:
  • Function prototypes.
  • extern statements.
  • Preprocessor directives.
  • Declaration of structures & classes.
  • inline functions which do not create public symbols recognized by the linker.

Last edited by ocicat; 21st October 2008 at 01:53 AM.
Reply With Quote
Old 21st October 2008
JMJ_coder JMJ_coder is offline
VPN Cryptographer
 
Join Date: May 2008
Posts: 464
Thanked 8 Times in 8 Posts
Default

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"
and then would I link in the Makefile
Code:
a.out: main.o thing.o
        g++ main.o thing.o
or would the simple
Code:
#include "thing.h"
automatically link what needs to be linked?
__________________
And the WORD was made flesh, and dwelt among us. (John 1:14)
Reply With Quote
Old 21st October 2008
ocicat ocicat is offline
Administrator
 
Join Date: Apr 2008
Posts: 2,873
Thanked 190 Times in 160 Posts
Default

Quote:
Originally Posted by JMJ_coder View Post
With the class thing, adding it to the main.cpp, I would
Code:
#include "thing.h"
and then would I link in the Makefile
Code:
a.out: main.o thing.o
        g++ main.o thing.o
Correct.
Quote:
or would the simple
Code:
#include "thing.h"
automatically link what needs to be linked?
The #include preprocessor directive passes no information on to the linker. The #include command is simply used to supply the compiler sufficient information for it to create the corresponding object file. No more.

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.
Reply With Quote
Old 21st October 2008
JMJ_coder JMJ_coder is offline
VPN Cryptographer
 
Join Date: May 2008
Posts: 464
Thanked 8 Times in 8 Posts
Default

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)
Reply With Quote
Old 21st October 2008
BSDfan666 BSDfan666 is offline
Real Name: N/A, this is the interweb.
Helpful companion
 
Join Date: Apr 2008
Location: Ontario, Canada
Posts: 2,223
Thanked 193 Times in 184 Posts
Default

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, ...);
From this, we know the printf() function exists in libc.. we know the arguments the function takes.. and now, so does the compiler.

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.
Reply With Quote
Old 21st October 2008
ocicat ocicat is offline
Administrator
 
Join Date: Apr 2008
Posts: 2,873
Thanked 190 Times in 160 Posts
Default

Quote:
Originally Posted by JMJ_coder View Post
If the #include isn't necessary for the standard library, why do we #include them?
Unfortunately, gcc(1) hides the call to the linker, but you need to realize that there are two phases which generating binary:
  • The compiler itself only translates source code into object files. Nothing more.

    #include statements are required by the compiler for type-checking reasons. The compiler wants to know a priori whether a symbol it encounters represents a variable, struct, class, function, etc. If the compiler cannot deduce what a symbol represents, it flags the symbol as undeclared.
  • All object files are then passed to the linker. Note that the only library the linker will consult when creating the resulting binary is libc by default. Any other library which will be required must be explicitly mentioned on the command-line.
Historically, some C compilers prior to the ANSI standard didn't require a #include statement for functions found in libc, but the stronger type-checking required by the ANSI standard forced explicit inclusion of all necessary headers.

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.
  • #include statements are preprocessor directives needed to allow compilation to complete. Nothing more.
  • The linker has no knowledge of what happened during compilation nor does it need to care. The linker simply takes all explicitly supplied object files + all explicitly supplied libraries + libc & attempts to splice together the resulting binary. Nothing more.
There is a reason why it is all referred to as a toolchain...

Last edited by ocicat; 21st October 2008 at 04:32 PM.
Reply With Quote
Old 21st October 2008
JMJ_coder JMJ_coder is offline
VPN Cryptographer
 
Join Date: May 2008
Posts: 464
Thanked 8 Times in 8 Posts
Default

Thanks.

Ah, the things they don't teach you in school.
__________________
And the WORD was made flesh, and dwelt among us. (John 1:14)
Reply With Quote
Old 21st October 2008
mdh's Avatar
mdh mdh is offline
Real Name: Matt D. Harris
FreeBSD 2.2.6 User
 
Join Date: Oct 2008
Location: West Virginia
Posts: 139
Thanked 8 Times in 8 Posts
Default

Quote:
Originally Posted by ocicat View Post
[*] The compiler itself only translates source code into object files. Nothing more.
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.
Reply With Quote
Old 21st October 2008
TerryP's Avatar
TerryP TerryP is offline
Arp Constable
 
Join Date: May 2008
Location: USofA
Posts: 1,547
Thanked 112 Times in 104 Posts
Default

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.
Reply With Quote
Reply

Tags
make, makefile

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT. The time now is 03:29 PM.


Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Content copyright © 2007-2010, the authors
Daemon image copyright ©1988, Marshall Kirk McKusick