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):

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.

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).

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

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?

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:

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.

#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.

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.

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.

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.