0

I run Mac OS X lion with the latest Xcode (4.3):

gfortran --version # -> GNU Fortran (GCC) 4.6.1
gcc --version # -> i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658)

My makefile gives an error:

gfortran temp/modules.o temp/testModules.o temp/mathFunctions.o temp/functionTest.o -o arenatest
ld: duplicate symbol ___rng_MOD_uni in temp/testModules.o and temp/modules.o for architecture x86_64
collect2: ld returned 1 exit status
make: *** [arenatest] Error 1

I don't understand what the reason is, so I tried writing a build script that does the same thing, and surprisingly it works wonders. I want to have a makefile and NOT a script, so could anyone spot the difference? I am completely out of ideas.

I know that there is a funky loop-replacement script for generating the .o objects in the right subdirectories. The build/compile-commands seem to match perfectly however. If there is a cleverer way of doing this, I'm open for suggestions.

Script:

echo remove old files
rm *.mod
rm *.o
rm -rf temp
rm arenatest

echo create directories and compile:
mkdir -p temp
gfortran -cpp -c ../modules/modules.f90 -o temp/modules.o -J../buildtest -I../buildtest
gfortran -cpp -c ../modules/mathFunctions.f90 -o temp/mathFunctions.o -J../buildtest -I../buildtest
gfortran -cpp -c testModules.f90 -o temp/testModules.o -J../buildtest -I../buildtest
gfortran -cpp -c functionTest.f90 -o temp/functionTest.o -J../buildtest -I../buildtest

echo do linking: gfortran -cpp temp/modules.o temp/testModules.o temp/mathFunctions.o temp/functionTest.o -o arenatest
gfortran temp/modules.o temp/testModules.o temp/mathFunctions.o temp/functionTest.o -o arenatest

echo DONE!

makefile:

PROGRAM = arenatest
BUILDDIR = temp
FC = gfortran
SRC = ../modules/modules.f90 ../modules/mathFunctions.f90 testModules.f90 functionTest.f90
OBJ = $(SRC:.f90=.o)
OBJECTS = $(foreach var, $(OBJ), $(BUILDDIR)/$(lastword $(subst /, , $(var))) )
FLAGS =-J../buildtest -I../buildtest


all: buildtest

buildtest: $(PROGRAM)

build_message:
    @echo
    @echo sources:
    @echo $(SRC)
    @echo objects:
    @echo $(OBJECTS)

clean:
    rm -rf temp
    rm arenatest
    rm *.mod
    rm *.o


mkdir:
    @echo create directories and compile:
    mkdir -p temp

# 
# gfortran -cpp -c ../modules/modules.f90 -o temp/modules.o -J../buildtest -I../buildtest
# gfortran -cpp -c ../modules/mathFunctions.f90 -o temp/mathFunctions.o -J../buildtest -I../buildtest
# gfortran -cpp -c testModules.f90 -o temp/testModules.o -J../buildtest -I../buildtest
# gfortran -cpp -c functionTest.f90 -o temp/functionTest.o -J../buildtest -I../buildtest
# 
$(OBJECTS) : $(SRC) | mkdir
    $(FC) -c $(FLAGS) $< -o $@
# link: #echo do linking: gfortran -cpp temp/modules.o temp/testModules.o temp/mathFunctions.o temp/functionTest.o -o arenatest
$(PROGRAM): $(OBJECTS) | build_message
    $(FC) $(FLAGS) $(OBJECTS) -o $(PROGRAM)

#echo DONE!
Jakob Ryden
  • 317
  • 2
  • 13
  • 1
    Make should echo all the commands it's running. Just take a look at its output, and make sure all the compiler invocations are exactly as you expect. – Oliver Charlesworth Mar 07 '12 at 10:22
  • It looks solid. It is just beyond me why it would work typing it into the command line and not by running make. I'll double check all the invocations this afternoon.. – Jakob Ryden Mar 07 '12 at 10:31

1 Answers1

0

The recipe for compiling the object files is wrong. After expansion of variables it will look like this:

temp/modules.o temp/mathFunctions.o temp/testModules.o temp/functionTest.o: ../modules/modules.f90 ../modules/mathFunctions.f90 testModules.f90 functionTest.f90 | mkdir
    $(FC) -c $(FLAGS) $< -o $@

Effectively, this means that each object file depends on all source files. Furthermore, each invocation of this recipe will set the automatic variable $< to the first one in this list of source files. This will have as a consequence that all object files are being compiled from the same single source file (and thus will of course all have definitions for the same symbols).

eriktous
  • 6,569
  • 2
  • 25
  • 35
  • That explains it! So how do I fix it? This doesn't seem to work: `$(BUILDDIR)/%.o : %.f90 | mkdir $(FC) $(FLAGS) $< -o $@` – Jakob Ryden Mar 07 '12 at 12:52
  • Nevermind, I have an issue with subdirectories, I'm finding a solution here: http://stackoverflow.com/questions/231229/how-to-generate-a-makefile-with-source-in-sub-directories-using-just-one-makefil – Jakob Ryden Mar 07 '12 at 12:59
  • 1
    Easiest solution? Stick to [Paul's Third Rule of Makefiles](http://mad-scientist.net/make/rules.html): don't use the `temp` directory, but build object files in the current working directory. Combined with `vpath` to locate the source files, you can then use a simple pattern rule, like `%.o: %.f90`, and marvel over how much simpler and easier to understand/maintain your Makefile has become. – eriktous Mar 07 '12 at 13:08