Problem with simple C++ code

Discussion in 'Mac Programming' started by papermonkey11, Apr 20, 2012.

  1. papermonkey11, Apr 20, 2012
    Last edited: Apr 20, 2012

    macrumors newbie

    Joined:
    Apr 20, 2012
    #1
    Hello everyone! I have been writing Java for quite some time now and I though I'd try C++. So I have a problem I can't quite figure out.

    The code I tried to write is simply calling a function from another class (located in another file) to print a simple message. The following is the code:

    The main class file
    Code:
    #include <iostream>
    #include <string>
    #include <vector>
    #include <algorithm>
    #include <cmath>
    
    #include "Printer.h"
    
    using namespace std;
    
    //inline void keep_window_open() {char ch; cin>>ch;}
    
    int main(){
    	
    	Printer printer;
    	printer.actualPrint();
    	
    	return 0;
    }
    The "class the function is in"'s header file (Printer.h):

    Code:
    #include <iostream>
    
    using namespace std;
    
    class Printer{
    
    public:
    	
    	//Declaration of the printing function
    	void actualPrint();
    };
    The second class (Printer.cc):

    Code:
    #include "Printer.h"
    
    	void Printer::actualPrint(){
    		std::cout<<"Hooray!! Printing from another class!!!\n";
    	}
    This code runs perfectly fine on Windows (using Microsoft Visual C++ 2010 Express) but on my Mac i get the following error:

    Code:
    Undefined symbols:
      "Printer::actualPrint()", referenced from:
          _main in ccnldy3J.o
    ld: symbol(s) not found
    collect2: ld returned 1 exit status
    Now the akward part. On my Mac if I change the following line in the main file

    Code:
    #include "Printer.h"
    to

    Code:
    #include "Printer.cc"
    everything runs smoothly (on Windows it did not compile, as I expected). The thing is everywhere I looked I'm supposed to include the header file in the main class not the .cc file (Changing the extension was just sheer coincidence). I'm pretty sure including the .cc is the wrong way to go.


    Any help on why this is happening would be greatly appreciated.

    Edit: Code compiled with g++

    Code:
    Using built-in specs.
    Target: i686-apple-darwin10
    Configured with: /var/tmp/gcc/gcc-5666.3~6/src/configure --disable-checking --enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.2/ --with-slibdir=/usr/lib --build=i686-apple-darwin10 --program-prefix=i686-apple-darwin10- --host=x86_64-apple-darwin10 --target=i686-apple-darwin10 --with-gxx-include-dir=/include/c++/4.2.1
    Thread model: posix
    gcc version 4.2.1 (Apple Inc. build 5666) (dot 3)
     
  2. macrumors 603

    Joined:
    Aug 9, 2009
    #2
    How are you compiling the source code? Are you using Xcode? The Terminal command-line? A makefile?

    You wrote "Code compiled with g++", but Xcode is capable of compiling with g++, so it doesn't answer the question.

    If you're using a Terminal command-line, please post the exact command(s) used to compile.

    Basically, if Printer.cc and main.cc (or whatever you called it) are in separate files, then you need to compile them individually to produce .o files. You then "compile" the .o files to produce a single executable (I put "compile" in quotes because it's really only linking the .o files together, even though the command is still the g++ compiler, not a separate linker program).

    Completely fabricated example:
    Code:
    g++ -c Printer.cc
    g++ -c main.cc
    g++ Printer.o main.o -o runme
    ./runme
     
  3. thread starter macrumors newbie

    Joined:
    Apr 20, 2012
    #3
    Hi! Thank you for the swift response.

    Compiling/linking is done though the Terminal with a single command.

    Code:
    g++ main.cc -o Object
    and then

    Code:
    ./Object
    I also have to thank you because your way of individually compiling and THEN linking worked like a charm!

    Would I be asking too much of you, if I asked if you knew the reason for the need to individually compile and then link?

    Thanks again. :)
     
  4. chown33, Apr 20, 2012
    Last edited: Apr 20, 2012

    macrumors 603

    Joined:
    Aug 9, 2009
    #4
    There isn't a need to individually compile. You can compile and link both source files in one command line:
    Code:
    g++ main.cc Printer.cc -o runme
    ./runme
    
    But since you have two separate source files (main.cc and Printer.cc), you must compile them both (at some point), and also tell the linker that they're both needed to produce the single executable. You can do that with one command-line or with several, but it must still be done.

    The larger issue is how scalable the single command-line is. After about a half-dozen source files, it begins to take a noticeable amount of time to recompile every file every time. That's why there are separately linkable files in the first place: to avoid having to recompile every file every time. This is also why there are things like makefiles, that list the dependencies between headers and source: to know when to recompile and when not to.

    The simple-minded approach is to recompile every file when any file changes. This scales poorly, though, hence the desire to only recompile the minimum set of files that encompass the changes since the last build.

    You might not be aware that an IDE (such as Xcode or Visual C++) is only recompiling some files, and not recompiling others. Most IDEs are designed to hide this from you, because it's only a build-level detail. But since you're now compiling at the command-line, you have to be aware of all these build-level details.

    If you want to remain blissfully unaware of such details, you should use an IDE (such as Xcode), or learn to use a build system like make, maven, ant, or countless others whose names I don't even recall.


    If you have g++ installed, you probably also have make installed, so that would be a simple place to start. Not that make is all that simple (the O'Reilly book is good), but at least you won't have to install (or build) another build-system to get started.

    And there's a certain simplicity and clarity in makefiles, at least for simple multi-file projects. Things really only get hairy when there's many files in many sub-dirs, or a wide variety of build options (like conditional compilation for multi-platform targets).

    The classic test for make's presence is this command:
    Code:
    make love
    
    If it says "not war?" you have a classic make. If it says there's no rule to make target love, you have plain old mundane make. Either will work.
     
  5. thread starter macrumors newbie

    Joined:
    Apr 20, 2012
    #5
    Thanks again for all the useful information.

    I'll look into make as it sounds exactly like what I need.
     

Share This Page