Ошибка построения компоновщика с несколькими определениями функции в GCC — проблема с Makefile

Итак, я пытаюсь использовать Makefile для создания проекта, и я относительно новичок в makefiles в целом. Я получаю несколько ошибок определения при связывании множества функций, и я почти уверен, что это связано с моим make-файлом. Я не могу опубликовать большую часть проекта, так как он довольно большой, но ниже приведен make-файл. Есть ли что-то явно неправильное?

У меня были некоторые функции, объявленные + определенные в заголовке, и перемещение их определений в cpp удалило эти функции из ошибок компоновщика, но я не могу сделать это для всех из них (EDIT: остальные многократно определенные функции не в заголовках они стандартно находятся в файлах cpp/cc, фраза «я не могу сделать это для всех из них» подразумевает, что они все такие, извините), так как большая часть представляет собой кодовую базу, которую я не могу редактировать. В коде не должно быть никаких ошибок, поскольку он отлично строится в отдельном проекте без моих дополнений (ни одно из которых не вызывает ошибок компоновщика), поэтому я полагаю, что это должен быть мой make-файл, но я не могу понять, что я делаю неправильно . Любые идеи?

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

Я вырезал одну или две ненужные вещи, поэтому одна или две части не имеют особого смысла (например, зачем иметь параметр метода рендеринга, когда доступен только один метод). Я немного не уверен, правильно ли я написал правила, и думаю это может объяснить мою проблему? Хотя он выглядит так же, как и другой make-файл, который работает, поэтому я не уверен, в чем проблема. У кого-нибудь есть идеи? Я могу предоставить больше информации, если это необходимо?


person timdykes    schedule 13.08.2012    source источник
comment
Вы изменили много вещей, и вы получаете много ошибок. Когда вы начинаете со старым make-файлом (и исходниками, и заголовками), вы не получаете никаких ошибок. Итак, какое первое изменение вызывает ошибку?   -  person Beta    schedule 13.08.2012
comment
Спасибо за ответ. Старина Шарпей Майк Сеймур заметил, что я продублировал довольно много объектных файлов в списке OBJS_SPLOTCH_DEFAULT. Хороший план, спасибо - я думаю, что основная проблема заключалась в том, что я начал новый и скопировал то, что мне нужно, из старого, изменив большую часть этого и не был достаточно осторожен :/   -  person timdykes    schedule 13.08.2012


Ответы (3)


У меня были некоторые функции, объявленные + определенные в заголовке, и перемещение их определений в cpp удалило эти функции из ошибок компоновщика.

Похоже, они не были встроенными, и в этом случае вам разрешено только одно определение при компоновке программы.

Добавьте inline к любым определениям функций в заголовках, чтобы решить проблему. Это ослабляет «правило одного определения», позволяя определять эти функции в нескольких единицах перевода, если все определения идентичны.

ОБНОВЛЕНИЕ. Кроме того, ваше определение OBJS_SPLOTCH_DEFAULT содержит дубликаты; cxxsupport/paramfile.o повторяется, и могут быть другие. Вам нужно будет удалить дубликаты. Я рекомендую хранить такие длинные списки в алфавитном порядке, чтобы упростить поиск и обнаружение дубликатов.

person Mike Seymour    schedule 13.08.2012
comment
Это вполне могло быть проблемой с этими конкретными функциями, но я думаю, что это другая проблема, например, самое первое множественное определение, которое я получаю: '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:: строка const&) const' cxxsupport/paramfile.o:/home/tims/Code/new/Splotch_Previewer/cxxsupport/paramfile.cc:46: впервые определено здесь' Что наводит меня на мысль, что они каким-то образом связаны дважды или что-то в этом роде? - person timdykes; 13.08.2012
comment
@timofend: Похоже, ваш makefile напечатает команду, которую он использует для связывания. Вы смотрели на это и проверяли наличие дубликатов объектных файлов? - person Mike Seymour; 13.08.2012
comment
Кажется, это делается для каждого файла один раз: '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' Затем сделайте это в конце, со всеми упомянутыми файлами .o, я вырезал все, кроме одного для места g++ cxxsupport/error_handling.o ‹вставить все остальные файлы› -lGL -lGLU -lXext -lX11 -o SplotchPreviewer - person timdykes; 13.08.2012
comment
Это то, что он должен делать? извините за ужасное форматирование там - person timdykes; 13.08.2012
comment
@timofiend: Да, это для компиляции каждого файла (с использованием таких правил, как .cpp.o:, для компиляции отдельных объектных файлов). В конце будет строка гораздо большего размера, без -c, связывающая все объектные файлы (используя правило $(EXEC):). Вы обнаружите, что оно содержит paramfile.o дважды, потому что вы продублировали его в своем определении OBJS_SPLOTCH_DEFAULT. Это ваша проблема, как я объяснил в своем обновленном ответе. - person Mike Seymour; 13.08.2012
comment
О Боже. Это то, что я получаю за копирование, а не двойную проверку. Я, должно быть, дважды случайно вставил пару строк. Большое тебе спасибо! мне уже стыдно, лол - person timdykes; 13.08.2012

Проблема не в makefile. Это здесь:

У меня были некоторые функции, объявленные + определенные в заголовке, и перемещение их определений в cpp удалило эти функции из ошибок компоновщика, но я не могу сделать это для всех из них, так как большая часть — это кодовая база, которую я не могу редактировать.

Проблема в том, что когда вы включаете этот заголовок более чем в один исходный файл, вы получаете более одной копии определения функции, и на это жалуется компоновщик. Итак, у вас есть три варианта: не использовать этот код (серьезно: в общем, это ужасная практика кодирования); не используйте этот заголовок более чем в одном исходном файле; или добавить встроенный, как предложил @Mike.

person Pete Becker    schedule 13.08.2012
comment
Остальные многократно определенные функции не определяются в заголовке, они находятся в файле cc, определяющем методы для класса. - person timdykes; 13.08.2012

Если у вас есть функция, определенная и объявленная в файле .h, вы получите многократно определенные символы, если только вы не сможете уменьшить область действия переменных с помощью параметров компиляции или использования inline.

Если вы не можете переписать эти .h файлы, чтобы объявить подпрограммы как inline, то уродливым решением будет создание параллельного .h, который просто повторно объявляет все эти подпрограммы (заметьте, объявляет, а не определяет). Весь ваш код #includes в этом параллельном .h файле.

Вы создаете один файл .c/.cpp, который содержит #includes файлы .h из общей кодовой базы.

Вы связываете полученный единственный .o, который предоставляет реализации, которые пришли из общей кодовой базы, в вашу кодовую базу.

Это уродливо и хак, я бы определенно использовал ответ @Mike, а не этот.

person Petesh    schedule 13.08.2012
comment
Спасибо за комментарий, если бы вы могли сослаться на мой комментарий к сообщению Майка, остальные многократно определенные функции на самом деле не находятся в файлах заголовков, я не должен был упоминать об этом, поскольку это, похоже, была несвязанная проблема с теми же симптомами. - person timdykes; 13.08.2012