2

So I am trying to use a Makefile to build a project, and im relatively new to makefiles in general. I am getting multiple definition errors when linking for loads of functions, and im pretty sure it is due to my makefile. I cannot post much of the project, as it is pretty large, but the makefile is below, does anything stand out as obviously wrong?

I had some functions declared + defined in a header, and moving their definitions into a cpp removed those functions from the linker errors - but I cannot do this for all of them (EDIT: The rest of the functions that are being multiply defined are not in headers, they are in cpp/cc files as standard, saying "i cannot do this for all of them" implied they were all like that, sorry), as a large portion is a codebase I cannot edit. There shouldnt be any errors in the code though as it is building fine in a separate project without my additions (none of which are causing linker errors), so I figure it must be my makefile, but I cant figure out what I am doing wrong. Any Ideas?

    # Compiler
    CXX = g++

    # Linker settings
    LDFLAGS = -lGL -lGLU -lXext -lX11        

    # Executable name
    EXEC = SplotchPreviewer

    # Optimizations for compilation
    OPTIMIZE = -std=c++98 -pedantic -Wno-long-long -Wfatal-errors -Wextra -Wall -Wstrict-aliasing=2 -Wundef -Wshadow -Wwrite-strings -Wredundant-decls -Woverloaded-virtual -Wcast-qual -Wcast-align -Wpointer-arith -O2 -g


    # Pre-processor settings
    CPPFLAGS = $(OPTIMIZE) -I. -Icxxsupport -Ic_utils

    # Default Splotch objects
    OBJS_SPLOTCH_DEFAULT =  cxxsupport/error_handling.o reader/mesh_reader.o cxxsupport/mpi_support.o cxxsupport/paramfile.o \
                    cxxsupport/string_utils.o cxxsupport/announce.o reader/gadget_reader.o reader/millenium_reader.o \
                    reader/bin_reader.o reader/tipsy_reader.o splotch/splotchutils.o splotch/scenemaker.o \
                    cxxsupport/walltimer.o c_utils/walltime_c.o booster/mesh_creator.o booster/randomizer.o \
                    booster/p_selector.o booster/m_rotation.o cxxsupport/paramfile.o cxxsupport/error_handling.o \
                     c_utils/walltime_c.o cxxsupport/string_utils.o cxxsupport/announce.o \
                    cxxsupport/walltimer.o

    # Default Previewer objects
    OBJS_PREVIEWER_DEFAULT = main.o previewer/Previewer.o previewer/libs/core/Parameter.o previewer/libs/core/ParticleSimulation.o \
                     previewer/libs/core/WindowManager.o previewer/libs/core/Camera.o previewer/libs/core/ParticleData.o \
                     previewer/libs/core/MathLib.o previewer/libs/core/FileLib.o previewer/libs/events/OnQuitApplicationEvent.o \
                     previewer/libs/events/OnKeyReleaseEvent.o previewer/libs/events/OnKeyPressEvent.o previewer/libs/events/OnExposedEvent.o \
                     previewer/libs/events/OnButtonReleaseEvent.o previewer/libs/events/OnButtonPressEvent.o previewer/libs/core/Texture.o \
                     previewer/libs/animation/AnimationSimulation.o

    #temp force render method
    RENDER_METHOD = FFSDL
    # Current build specific objects
    ifeq ($(RENDER_METHOD),FFSDL)

    OBJS_BUILD_SPECIFIC = previewer/libs/renderers/FF_DrawList.o     previewer/libs/materials/FF_ParticleMaterial.o

    endif


    # All objects for this build
    OBJS = $(OBJS_SPLOTCH_DEFAULT) $(OBJS_PREVIEWER_DEFAULT) $(OBJS_BUILD_SPECIFIC)

    # Rules (note: object files automatically removed when building)

    .SUFFIXES: .o .cc .cxx .cpp

    .cpp.o:
        $(CXX) -c $(CPPFLAGS) -o "$@" "$<"  

    .cc.o:
        $(CXX) -c $(CPPFLAGS) -o "$@" "$<"

    .cxx.o:
        $(CXX) -c $(CPPFLAGS) -o "$@" "$<"


    $(EXEC): $(OBJS)
        $(CXX) $(OBJS) $(LDFLAGS) -o $(EXEC)
        rm $(OBJS)


    clean:
        rm -f $(OBJS)
        rm -f $(EXEC)

Ive cut out one or two unneccesary things, hence one or two bits of it not making much sense (why have a render method option with only one method available for example) Im a bit hazy on whether I have written the rules correctly, and figure this could account for my issue? Although it looks the same as the other makefile which seems to work so Im not sure what the issue is. Anyone have any idea? I can provide more info if necessary?

timdykes
  • 610
  • 6
  • 12
  • You've changed lots of things and you're getting lots of errors. When you start with the old makefile (and sources and headers) you get no errors. So what's the first change that causes an error? – Beta Aug 13 '12 at 18:58
  • Thanks for the response - Ol' "Sharpeyes" Mike Seymour saw that I had duplicated a fair few object files in the OBJS_SPLOTCH_DEFAULT list. Good plan though thanks - I think the main issue was I started a new one and copy pasted what I needed from the old one, while changing the majority of it, and wasnt careful enough :/ – timdykes Aug 13 '12 at 19:02

3 Answers3

7

I had some functions declared + defined in a header, and moving their definitions into a cpp removed those functions from the linker errors

That sounds like they weren't inline, in which case you're only allowed a single definition when linking the program.

Add inline to any function definitions in headers to fix the problem. This relaxes the "one definition rule" to allow these functions to be defined in multiple translation units, as long as all the definitions are identical.

UPDATE: Also, your definition of OBJS_SPLOTCH_DEFAULT contains duplicates; cxxsupport/paramfile.o is repeated, and there may be others. You'll need to remove the duplicates. I recommend keeping long lists like this in alphabetical order, to make it easier to search and to spot duplicates.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • That may well have been the problem with those particular functions - but I think this is different issue to that, for example the very first multiple definition I get is: 'cxxsupport/paramfile.o: In function `paramfile::param_unread(std::string const&) const': /home/tims/Code/new/Splotch_Previewer/cxxsupport/paramfile.cc:46: multiple definition of `paramfile::param_unread(std::string const&) const' cxxsupport/paramfile.o:/home/tims/Code/new/Splotch_Previewer/cxxsupport/paramfile.cc:46: first defined here' Which leads me to think they are somehow being linked twice or something? – timdykes Aug 13 '12 at 18:43
  • @timofiend: It looks like your makefile will print the command it uses for linking. Have you looked at that and checked for duplicate object files? – Mike Seymour Aug 13 '12 at 18:48
  • Well it seems to do this for each file once: 'g++ -c -std=c++98 -pedantic -Wno-long-long -Wfatal-errors -Wextra -Wall -Wstrict-aliasing=2 -Wundef -Wshadow -Wwrite-strings -Wredundant-decls -Woverloaded-virtual -Wcast-qual -Wcast-align -Wpointer-arith -O2 -g -I. -Icxxsupport -Ic_utils -o "previewer/libs/materials/FF_ParticleMaterial.o" "previewer/libs/materials/FF_ParticleMaterial.cpp"' Then does this at the end, with all of the .o files mentioned, i have cut out all but one for space g++ cxxsupport/error_handling.o -lGL -lGLU -lXext -lX11 -o SplotchPreviewer – timdykes Aug 13 '12 at 18:52
  • Is that what its supposed to do? sorry for the terrible formatting there – timdykes Aug 13 '12 at 18:53
  • @timofiend: Yes, that's to compile each file (using the rules like `.cpp.o:` to compile individual object files). At the end there will be a much larger line, without the `-c` in it, linking all the object files (using the `$(EXEC):` rule). You'll find that that contains `paramfile.o` twice, because you've duplicated it in your definition of `OBJS_SPLOTCH_DEFAULT`. That's your problem, as I've explained in my updated answer. – Mike Seymour Aug 13 '12 at 18:54
  • Oh god. Thats what I get for copy pasting and not double checking. I must have pasted a line or two twice by accident. Thankyou very much! Im rather embarrassed now lol – timdykes Aug 13 '12 at 19:00
1

The problem isn't in the makefile. It's here:

I had some functions declared + defined in a header, and moving their definitions into a cpp removed those functions from the linker errors - but I cannot do this for all of them, as a large portion is a codebase I cannot edit.

The problem is that when you include that header in more than one source file you get more than one copy of the function definition, and that's what the linker is complaining about. So you have three choices: don't use that code (seriously: in general, that's a horrible coding practice); don't use that header in more than one source file; or add inline, as @Mike suggested.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
  • The rest of the multiply defined functions are not being defined in a header, they are in a cc file defining methods for a class – timdykes Aug 13 '12 at 18:46
1

If you have a function defined and declared in a .h file, then you're going to get multiply defined symbols unless you can reduce the scope of the variables through compile options or the use of inline.

If you can't rewrite these .h files to declare the routines as inline, then an ugly solution is to create a parallel .h that simply re-declares all these routines (declares, mind, not defines as well). All your code #includes this parallel .h file.

You create a single .c/.cpp file which #includes the .h files from the shared codebase.

You link the resulting single .o which exposes the implementations that came from the shared codebase into your codebase.

This is ugly, and a hack, I'd definitely be one for using @Mike's answer rather than this one.

Anya Shenanigans
  • 91,618
  • 3
  • 107
  • 122
  • Thanks for the comment, if you could refer to my comment on Mikes post, the rest of the multiply defined functions are not actually in header files, I shouldnt have mentioned that as that seems to have been an unrelated problem with the same symptoms. – timdykes Aug 13 '12 at 18:47