Funzione di errore di linker a definizione multipla basata su GCC – Problema di Makefile

Quindi sto cercando di usare un Makefile per build un progetto, e sono relativamente nuovo per i makefile in generale. Ricevo errori di definizione multipli durante il collegamento per un sacco di funzioni e sono abbastanza sicuro che sia dovuto al mio makefile. Non riesco a pubblicare gran parte del progetto, in quanto è piuttosto grande, ma il makefile è al di sotto, non c’è nulla che risulti evidentemente sbagliato?

Avevo alcune funzioni dichiarate + definite in un’intestazione, e spostando le loro definizioni in un cpp rimuovevano quelle funzioni dagli errori del linker – ma non posso farlo per tutti loro (EDIT: il resto delle funzioni che vengono definite moltiplicate non sono nelle intestazioni, sono in file cpp / cc come standard, dicendo “non posso farlo per tutti” implicitamente erano tutti così, mi spiace), in quanto gran parte è un codebase che non posso modificare. Non ci dovrebbero essere errori nel codice anche se sta costruendo bene in un progetto separato senza le mie aggiunte (nessuno dei quali causa errori di linker), quindi immagino che debba essere il mio makefile, ma non riesco a capire cosa sto facendo male . Qualche idea?

# 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 "[email protected]" "$<" .cc.o: $(CXX) -c $(CPPFLAGS) -o "[email protected]" "$<" .cxx.o: $(CXX) -c $(CPPFLAGS) -o "[email protected]" "$<" $(EXEC): $(OBJS) $(CXX) $(OBJS) $(LDFLAGS) -o $(EXEC) rm $(OBJS) clean: rm -f $(OBJS) rm -f $(EXEC) 

Ho eliminato una o due cose inutili, quindi uno o due bit non hanno molto senso (perché avere un’opzione di metodo di rendering con un solo metodo disponibile per esempio) Sono un po ‘confuso se ho scritto correttamente le regole e questo potrebbe spiegare il mio problema? Anche se sembra uguale all’altro makefile che sembra funzionare quindi non sono sicuro di quale sia il problema. Qualcuno ha qualche idea? Posso fornire maggiori informazioni se necessario?

Ho avuto alcune funzioni dichiarate + definite in un’intestazione, e spostando le loro definizioni in un cpp le ho rimosse dagli errori del linker

Sembra che non fossero in linea, nel qual caso ti è stata concessa una sola definizione per il collegamento del programma.

Aggiungi in inline a qualsiasi definizione di funzione nelle intestazioni per risolvere il problema. Questo allenta la “regola di una definizione” per consentire la definizione di queste funzioni in più unità di traduzione, purché tutte le definizioni siano identiche.

AGGIORNAMENTO: Inoltre, la definizione di OBJS_SPLOTCH_DEFAULT contiene duplicati; cxxsupport/paramfile.o viene ripetuto e possono cxxsupport/paramfile.o altri. Dovrai rimuovere i duplicati. Raccomando di mantenere liste lunghe come questa in ordine alfabetico, per rendere più facile la ricerca e individuare i duplicati.

Il problema non è nel makefile. È qui:

Avevo alcune funzioni dichiarate + definite in un’intestazione, e spostando le loro definizioni in un cpp rimuovevo quelle funzioni dagli errori del linker – ma non posso farlo per tutti, poiché una porzione grande è un codebase che non posso modificare.

Il problema è che quando si include quell’intestazione in più di un file sorgente si ottiene più di una copia della definizione della funzione, e questo è ciò di cui si lamenta il linker. Quindi hai tre scelte: non usare quel codice (sul serio: in generale, questa è una pratica di codifica orribile); non usare quell’intestazione in più di un file sorgente; o aggiungi in linea, come suggerito da @Mike.

Se hai una funzione definita e dichiarata in un file .h , otterrai molti simboli definiti a meno che tu non possa ridurre l’ambito delle variabili attraverso opzioni di compilazione o l’uso di inline .

Se non riesci a riscrivere questi file .h per dichiarare le routine come inline , allora una brutta soluzione è creare un parallelo .h che semplicemente re-dichiara tutte queste routine (dichiara, mente, non definisce pure). Tutto il tuo codice #includes questo file .h parallelo.

Si crea un singolo file .c / .cpp che #includes il file .h dalla base di codice condivisa.

.o singolo risultato .o che espone le implementazioni che provengono dalla base di codice condivisa nella tua base di codice.

Questo è brutto, e un trucco, sarei sicuramente uno per usare la risposta di @ Mike piuttosto che questa.