# Makefile confusion

1. Oct 16, 2014

### Matterwave

Hello guys, I am trying to run a pretty substantial piece of code, coded in Fortran. There are many many modules (~10) and the dependencies of one module/piece of code on another is quite complex. As I am not the original author of the code, I am still not intimately familiar with every single part of this code. However, I do understand what the code is supposed to do, and how it basically works in general. What I want to do is to modify a portion of the code and tag on another module in order to allow the code to do some extra stuff that I need it to do. I have made the modifications to the code, and have written my new module.

Now I am onto the part where I want to actually run the modified code. And here I run into a problem. In order to run the code originally, all I had to do was type in on my command line in a terminal was "make bulb-new" and then "auto.run", and the code will start running in that terminal. But since I have written a new module, and I need to use a different linear-algebra pack for finding eigen-values and eigen-vectors, I need to modify what the terminal is doing so that it will run the modified code. I think that in order to do this I have to modify the "makefile" file so that the terminal makes all the object files correctly. Sadly, I have never before had to modify a "makefile" so I don't understand very much what is going on.

Here is the makefile:

Code (Text):

MACH =  gfortran
include makefile.$(MACH) .DUMMY : init .DEFAULT : bulb-new zheev3 : cd zheevh3-F-1.0;$(MAKE) all F77='$(F77)' F77COMP='$(F77COMP)' FFLAGS='$(FFLAGS)' FOPT='$(FOPT)'

init   :
make zheev3

bulb-new   :  params.o parallel.o helectron.o keep_clocks.o bulb-new.o  rannyu.o spline.o splint.o
$(F90PAR)$(LDFLGS) $(FOPT) -o bulb-new bulb-new.o params.o helectron.o keep_clocks.o parallel.o rannyu.o spline.o splint.o zheevh3-F-1.0/*.o$(FLIBS)
bulb-new3   :  params.o parallel.o keep_clocks.o bulb-new3.o  rannyu.o
$(F90PAR)$(LDFLGS) $(FOPT) -o bulb-new3 bulb-new3.o params.o helectron.o keep_clocks.o parallel.o rannyu.o$(FLIBS)
keep_clocks.o  : keep_clocks.F90 params.o
$(F90)$(FFLAGS) $(FOPT) -c keep_clocks.F90 params_numeric.o : params_numeric.F90$(F90) $(FFLAGS)$(FOPT) -c params_numeric.F90
params.o  : params.F90
$(F90)$(FFLAGS) $(FOPT) -c params.F90 helectron.o : helectron.F90$(F90) $(FFLAGS)$(FOPT) -c helectron.F90
parallel.o  : params.o parallel.F90
$(F90)$(FFLAGS) $(FOPT) -c parallel.F90 cdfsave.o : params_numeric.o cdfsave.F90$(F90) $(FFLAGS)$(FOPT) $(INCNETCDF) -c cdfsave.F90 bulb-new.o : params.o parallel.o keep_clocks.o bulb-new.F90$(F90) $(FFLAGS)$(FOPT) -c bulb-new.F90
bulb-new3.o  : params.o parallel.o keep_clocks.o bulb-new3.F90
$(F90)$(FFLAGS) $(FOPT) -c bulb-new3.F90 rannyu.o : rannyu.f$(F77) $(F77FLGS)$(FOPT) -c rannyu.f
spline.o   : spline.f
$(F77)$(F77FLGS) $(FOPT) -c spline.f splint.o : splint.f$(F77) $(F77FLGS)$(FOPT) -c splint.f
plotit   : plotit.F90
$(F90)$(FFLAGS) $(FOPT) -o plotit plotit.F90$(LIBGRACE)
plotdens   :  params_numeric.o plotdens.F90
$(F90)$(FFLAGS) $(FOPT) -o plotdens plotdens.F90 params_numeric.o$(LIBGRACE) $(LIBCDF) # needed cdfsave.o in above two lines also for cdf data file printhvv : params.o printhvv.F90$(F90) $(FFLAGS)$(FOPT) -o printhvv printhvv.F90 params.o
printhe   : params.o printhe.F90
$(F90)$(FFLAGS) $(FOPT) -o printhe printhe.F90 params.o tar : tar -cvf laptop.tar cdfsave.F90 keep_clocks.F90 params.F90 bulb-new.F90 rannyu.f plotit.F90 printhvv.F90 printhe.F90 parallel.F90 params_numeric.F90 plotdens.F90 params_numeric.F90 cdfsave.F90 helectron.F90 splint.f spline.f Makefile makefile* bulb*in* *run* zheevh3-F-1.0 clean : \rm *.o bulb-new Anyone know of a good tutorial on make-files and how to write them, and the syntax in them, etc? It's hard for me to parse what is happening in this document. Essentially what I need to do is incorporate the new linear algebra pack zheev since I am running a different linear-algebra pack for parts of the code (but zheev3 will still be used in parts of the code as well), and then create and include my new module "spincohere.f90", which is only used by the main program "bulb.new" and not any other modules. That should be a pretty quick fix to this makefile right? Last edited: Oct 16, 2014 2. Oct 16, 2014 ### Matterwave I have added the line: Code (Text): spincohere.o : spincohere.F90 params.o parallel.o helectron.o keepclocks.o$(F90) $(FFLAGS)$(FOPT) -c spincohere.F90

After the bulb-new3 line.

However, this made me realize something. The main program is bulb-new. In this main file bulb-new.f90 there are 2 modules and several subroutines. I need to use these 2 modules "angles" and "parallel" in my new module "spincohere", but nowhere in this makefile are these two modules mentioned...am I to assume that these modules would not be accessible to my "spincohere" module then? If I need them to be accessible, can I compile them as separate object files even though their code is written in bulb-new.f90?

3. Oct 16, 2014

### phinds

MAKEFILES !!! AAAEEEIIIII *sign of the cross* --- makefiles are evil. I didn't even know people still USED makefiles. I haven't used on it probably 20 years

Sorry, I know this wasn't helpful but I couldn't resist.

4. Oct 16, 2014

### Staff: Mentor

It is not clear what you did. Naming code files is one thing. The names of functions are more important. The order in which you link the object files determines whether a given object is "picked up" and it's symbols used as entry points. In plain English - use distinct function names everywhere.
What error do you get?

5. Oct 16, 2014

### Staff: Mentor

@phinds: And. makefiles are not evil. You just program so high above the machine code that it does not matter. Fortran and C applications are normally built that way. As you well know.

6. Oct 16, 2014

### gsal

Yes, Matterwave, if you are going to use modules in more than place, I would take them out of the main file and place them in their own file; I put one module per file.

You can find tutorials on line on how to put together make files; they are very convenient, powerful, intelligent...but it is best if you understand what you are doing and put together your own file.

One thing you need to keep in mind is that those indented lines that you see actually start with a tab character and not a series of blank spaces...just make sure you do that...many of us have configured our editors to automatically emulate tabs by replacing them with blank spaces...but when typing make files, one needs to let the tab be at the beginning of those command lines.

7. Oct 16, 2014

### FactChecker

A fairly standard reference for makefiles is the O'Rilley book "Managing Projects with GNU Make" by Robert Mecklenburg (or the earlier book "Managing Projects with Make"). But a lot of information is available by Googling.

A quick thing to try:
If you put the new module in a separate file, mimic how a file like spline.f is treated. Also insert your new .o file where spline.o appears. Everywhere you see those, add something similar for your new code file. Use the correct Fortran version for your additions. Is that something you were attempting with bulb-new3 or was that already there?

P.S. Be very careful to mimic (or not change) any whitespace at the beginning and end of lines (tabs, spaces). Make can be sensitive to that.

Last edited: Oct 16, 2014
8. Oct 16, 2014

### FactChecker

There are a great many tools in the Unix/Linux world that are just a GUI front-end to a makefile generator. Makefiles are still the main way to build programs there. And Windows still has nmake.

9. Oct 16, 2014

### phinds

Yeah, you're right on all counts. I DO know, but I HATE the damned things and always did. GUI's are SO much easier and I love easy :D

10. Oct 16, 2014

### FactChecker

My specialty is automating long, tedious (or complicated) processes with scripts. In that world, the GUIs are evil whereas being able to modify and run makefiles with scripts is great.

11. Oct 16, 2014

### Matterwave

The code as I wrote in the OP is the original code, I did not modify it what so ever. I have emulated the other parts of the makefile code by inserting the off-set text:

Code (Text):

MACH =  gfortran
include makefile.$(MACH) .DUMMY : init .DEFAULT : bulb-new zheev3 : cd zheevh3-F-1.0;$(MAKE) all F77='$(F77)' F77COMP='$(F77COMP)' FFLAGS='$(FFLAGS)' FOPT='$(FOPT)'

init   :
make zheev3

bulb-new   :  params.o parallel.o helectron.o keep_clocks.o bulb-new.o  rannyu.o spline.o splint.o
$(F90PAR)$(LDFLGS) $(FOPT) -o bulb-new bulb-new.o params.o helectron.o keep_clocks.o parallel.o rannyu.o spline.o splint.o zheevh3-F-1.0/*.o$(FLIBS)
bulb-new3   :  params.o parallel.o keep_clocks.o bulb-new3.o  rannyu.o
$(F90PAR)$(LDFLGS) $(FOPT) -o bulb-new3 bulb-new3.o params.o helectron.o keep_clocks.o parallel.o rannyu.o$(FLIBS)

spincohere.o :   spincohere.F90 params.o parallel.o helectron.o keepclocks.o
$(F90)$(FFLAGS) $(FOPT) -c spincohere.F90 keep_clocks.o : keep_clocks.F90 params.o$(F90) $(FFLAGS)$(FOPT) -c keep_clocks.F90
params_numeric.o  : params_numeric.F90
$(F90)$(FFLAGS) $(FOPT) -c params_numeric.F90 params.o : params.F90$(F90) $(FFLAGS)$(FOPT) -c params.F90
helectron.o  : helectron.F90
$(F90)$(FFLAGS) $(FOPT) -c helectron.F90 parallel.o : params.o parallel.F90$(F90) $(FFLAGS)$(FOPT) -c parallel.F90
cdfsave.o  : params_numeric.o  cdfsave.F90
$(F90)$(FFLAGS) $(FOPT)$(INCNETCDF) -c cdfsave.F90
bulb-new.o  : params.o parallel.o keep_clocks.o bulb-new.F90
$(F90)$(FFLAGS) $(FOPT) -c bulb-new.F90 bulb-new3.o : params.o parallel.o keep_clocks.o bulb-new3.F90$(F90) $(FFLAGS)$(FOPT) -c bulb-new3.F90
rannyu.o  : rannyu.f
$(F77)$(F77FLGS) $(FOPT) -c rannyu.f spline.o : spline.f$(F77) $(F77FLGS)$(FOPT) -c spline.f
splint.o   : splint.f
$(F77)$(F77FLGS) $(FOPT) -c splint.f plotit : plotit.F90$(F90) $(FFLAGS)$(FOPT) -o plotit plotit.F90 $(LIBGRACE) plotdens : params_numeric.o plotdens.F90$(F90) $(FFLAGS)$(FOPT) -o plotdens plotdens.F90 params_numeric.o  $(LIBGRACE)$(LIBCDF)
#  needed cdfsave.o in above two lines also for cdf data file
printhvv   : params.o printhvv.F90
$(F90)$(FFLAGS) $(FOPT) -o printhvv printhvv.F90 params.o printhe : params.o printhe.F90$(F90) $(FFLAGS)$(FOPT) -o printhe printhe.F90 params.o
tar   :
tar -cvf laptop.tar cdfsave.F90 keep_clocks.F90 params.F90 bulb-new.F90 rannyu.f plotit.F90 printhvv.F90 printhe.F90 parallel.F90 params_numeric.F90 plotdens.F90 params_numeric.F90 cdfsave.F90 helectron.F90 splint.f spline.f Makefile makefile* bulb*in* *run* zheevh3-F-1.0
clean   :
\rm *.o bulb-new

I don't know if this will work, and since I don't yet know how to incorporate the other modules and the linear algebra pack, I have not attempted to actually run the code...

I have looked up some makefile tutorials online, but I am still really confused by this. For example, this makefile has a bulb-new.o compile command, but the prerequisites is clearly missing the module helectron.o ... looking at the code, there is definitely a "use helectron" command.

So...I don't get why sometimes prerequisites are there and sometimes not?

Also does the ordering matter in how the objects are created? The tutorial I read said the order doesn't matter as long as the executable is the first one.

Last edited: Oct 16, 2014
12. Oct 17, 2014

### Staff: Mentor

You will need to add instructions to compile zheev and link to it when compiling bulb-new.

Since bulb-new.o is being compiled as an object, it is only when the bulb-new executable is being compiled that the compiler/linker must access helectron.o. In the current state of the Makefile, a problem would appear if the module conatined in helectron.F90 was modified in such a way that an already existing bulb-new.o would be incompatible with the module definition inside helectron.F90, as bulb-new.o would not be recompiled. What you wrote for spincohere.o will ensure that any modifications to params.F90, parallel.F90, helectron.F90, or keepclocks.F90 will force a recompilation of spincohere.o.

Can you give a link for that? I always thought that the order was not important, that make would find the rules whatever the order they are in in the makefile.

13. Oct 17, 2014

### Matterwave

Yes, in here: http://kiwi.atmos.colostate.edu/fortran/docs/fortran90-mar30.pdf page 7, it says that the first target should be the one that is built, and all subsequent target's orders do not matter.

I have modified the makefile in the following manner:

Code (Text):

MACH =  gfortran
include makefile.$(MACH) .DUMMY : init .DEFAULT : bulb-new zheev3 : cd zheevh3-F-1.0;$(MAKE) all F77='$(F77)' F77COMP='$(F77COMP)' FFLAGS='$(FFLAGS)' FOPT='$(FOPT)'

init   :
make zheev3

bulb-new   :  params.o parallel.o helectron.o keep_clocks.o spincohere.o bulb-new.o rannyu.o spline.o splint.o
$(F90PAR)$(LDFLGS) $(FOPT) -o bulb-new bulb-new.o params.o helectron.o spincohere.o keep_clocks.o parallel.o rannyu.o spline.o splint.o zheevh3-F-1.0/*.o$(FLIBS)
bulb-new3   :  params.o parallel.o keep_clocks.o bulb-new3.o  rannyu.o
$(F90PAR)$(LDFLGS) $(FOPT) -o bulb-new3 bulb-new3.o params.o helectron.o keep_clocks.o parallel.o rannyu.o$(FLIBS)
keep_clocks.o  : keep_clocks.F90 params.o
$(F90)$(FFLAGS) $(FOPT) -c keep_clocks.F90 params_numeric.o : params_numeric.F90$(F90) $(FFLAGS)$(FOPT) -c params_numeric.F90
params.o  : params.F90
$(F90)$(FFLAGS) $(FOPT) -c params.F90 helectron.o : helectron.F90$(F90) $(FFLAGS)$(FOPT) -c helectron.F90

angles.o  :   angles.F90 params.o helectron.o
$(F90)$(FFLAGS) $(FOPT) -c angles.F90 neutrinodist.o : neutrinodist.F90 params.o helectron.o$(F90) $(FFLAGS)$(FOPT) -c neutrinodist.F90

parallel.o  : parallel.F90 params.o
$(F90)$(FFLAGS) $(FOPT) -c parallel.F90 cdfsave.o : cdfsave.F90 params_numeric.o$(F90) $(FFLAGS)$(FOPT) $(INCNETCDF) -c cdfsave.F90 spincohere.o : spincohere.F90 params.o parallel.o helectron.o keepclocks.o angles.o neutrinodist.o$(F90) $(FFLAGS)$(FOPT) -c spincohere.F90

bulb-new.o  : bulb-new.F90 params.o parallel.o keep_clocks.o helectron.o angles.o neutrinodist.o spincohere.o
$(F90)$(FFLAGS) $(FOPT) -c bulb-new.F90 bulb-new3.o : bulb-new3.F90 params.o parallel.o keep_clocks.o$(F90) $(FFLAGS)$(FOPT) -c bulb-new3.F90
rannyu.o  : rannyu.f
$(F77)$(F77FLGS) $(FOPT) -c rannyu.f spline.o : spline.f$(F77) $(F77FLGS)$(FOPT) -c spline.f
splint.o   : splint.f
$(F77)$(F77FLGS) $(FOPT) -c splint.f plotit : plotit.F90$(F90) $(FFLAGS)$(FOPT) -o plotit plotit.F90 $(LIBGRACE) plotdens : params_numeric.o plotdens.F90$(F90) $(FFLAGS)$(FOPT) -o plotdens plotdens.F90 params_numeric.o  $(LIBGRACE)$(LIBCDF)
#  needed cdfsave.o in above two lines also for cdf data file
printhvv   : params.o printhvv.F90
$(F90)$(FFLAGS) $(FOPT) -o printhvv printhvv.F90 params.o printhe : params.o printhe.F90$(F90) $(FFLAGS)$(FOPT) -o printhe printhe.F90 params.o
tar   :
tar -cvf laptop.tar cdfsave.F90 keep_clocks.F90 params.F90 bulb-new.F90 rannyu.f plotit.F90 printhvv.F90 printhe.F90 parallel.F90 params_numeric.F90 plotdens.F90 params_numeric.F90 cdfsave.F90 helectron.F90 splint.f spline.f Makefile makefile* bulb*in* *run* zheevh3-F-1.0
clean   :
\rm *.o bulb-new

I think I should have at least made the spincohere module correctly. I have moved the modules "angles" and "neutrinodist" to outside of the bulb-new.F90 file and created them separately. Also, I added "helectron.o" to the prerequisites for compiling bulb-new.o. I couldn't quite understand your comment on that, will this somehow make compiling bulb-new.o worse or not work? Because I don't really see any difference between this module "helectron.o" that was missing from the prerequisites and any of the other 3 modules that were there...

I am now at a loss as to how to incorporate zheev. Are you familiar at all in implementing these linear algebra packs? I downloaded the whole LAPACK version 3.5 and there are a TON of files which I'm sure are not all used by zheev. There are also a bunch of different makefile's in a bunch of different directories, and I can't understand the documentation...like...at all...T_T

14. Oct 17, 2014

### Staff: Mentor

Ok, I see. This is just in order to make the executable the default build. But this is not mandatory.

It is better to have it as a prerequisite.

Yes, I am familiar! You basically have two options. The first is to compile and install the full LAPACK and BLAS libraries. This may actually have already been done. Check /usr/lib or /usr/local/lib (or some other appropriate directory with library files) to see if there is anything with "lapack" or "blas" in the name. If this is not the case, then you can compile the libraries yourself. Usually, you simply need to go into the main directory, issue the command "./configure", then "make", and finally, "make install" (you may need to be root to do that).

If all that sounds too complicated (although do check first if LAPACK is installed), go to http://www.netlib.org/cgi-bin/search.pl and search for zheev. The fisrt result you should get should be a link to the zheev code, and you will notice a link next to it called "plus dependencies". If you click that link, it will allow you to download only zheev and all the other subroutines zheev needs, but nothing more. You can then either put them in a directory and use something similar to what is in your makefile for zheev3, or put the content of all the files in one big .f file and compile into a .o object that as you would any Fortran file.

15. Oct 17, 2014

### Matterwave

Ah, this is where my lack of computing prowess really shows! So if I actually "installed LAPACK" on my computer (that's the first option right?), then I can use its functions, like zheev, while running my fortran code in my terminal without having to link this function zheev in my code's executable? In other words, if I have "installed LAPACK", do I need something like a "-o zheev.o" in my executable line in my makefile for my bulb-new code?

For the second option, I assume that I do have to create an object zheev.o and then link it?

I think eventually I will have to run this code on a supercomputer...so...probably the second option will be better for me in the long run since I don't know if the supercomputer has LAPACK installed? Maybe it does...o.o

16. Oct 17, 2014

### Staff: Mentor

When object files are made part of a library, they are not individually accessible. In the linking stage (where the executable is produced), you have to add the library itself, using "-llapack" (that's -l followed by the name of the library).

Right.

I would be surprised if a supercomputer doesn't have LAPACK already installed. Usually, these libraries (meaning LAPACK but especially BLAS, on which LAPACK relies) are finely tuned to be optimal on such systems. It is always preferable to use the precompiled libraries instead of compiling the LAPACK code as part of your program.

17. Oct 17, 2014

### Matterwave

Thanks for the information!
Ok, so say I install lapack in some directory (don't know what yet), all I have to add to my makefile is a line -llapack and that's it? Do I have to tell my code were to find lapack, in which directory, etc?

Also, the part of my code which actually uses zheev (i.e. which actually has the line "call zheev(___)" is the module spincohere (which will of course be used by the main code). Do I have to type -llapack in the prerequisites for compiling spincohere?

EDIT: I think I should mention that trying to compile my code now with all the modifications I've made, everything works (i.e. I see all the pieces compiling) until it gets to creating the executable, at which point I'm getting some errors which I assume is because I have not installed lapack...(i hope), so this is indeed where I'm at in trying to run this code lol.

Last edited: Oct 17, 2014
18. Oct 18, 2014

### Matterwave

Follow up question: is there a way to install lapack in ubuntu just from the terminal? I tried sudo apt-get install lapack and sudo apt-get install liblapack and both times the terminal said it couldn't find it. :(

EDIT: I tried sudo apt-get install liblapack-dev and something actually happened, like it was trying to install it, except I get an error saying there are certain archives not found...I'm not sure...what's up...I seem to be just bumbling around here. It seems to be trying to install version 3.4 instead of the newest version 3.5...

Code (Text):

gfortran  -O3  -o bulb-new bulb-new.o params.o helectron.o spincohere.o keep_clocks.o parallel.o rannyu.o spline.o splint.o zheevh3-F-1.0/*.o -llapack
zheevh3-F-1.0/sqrabs.o: file not recognized: File format not recognized
collect2: error: ld returned 1 exit status

I am so confused because zheevh3 was never a problem before, when I ran the old code! In fact, I reverted to the old version of the code, and I'm getting this same error now, and I can't even run the non-modified code! I am really really confused...:(

Last edited: Oct 18, 2014
19. Oct 20, 2014

### Staff: Mentor

That depends. Usually, environment variables are such that if it is in /use/lib or /use/local/lib, the compiler will find it by itself. Otherwise, you can sepecity the directory using -L, as in "-L/usr/local/lib".

No, the compiler only needs to access the library when merging the object files into an executable, so it only needs to be specified when building the executable.

Not sure I can help you here. Maybe you should try installing liblapack3.

Could the compiler have been modified when you tried those installs? I suggest you remove all objects files from that directory and try recompiing:
Code (Text):

rm zheevh3-F-1.0/*.o
make

20. Oct 20, 2014

### Matterwave

Thanks for the continued help!

I have actually tried to remove the object files and recompile zheevh3...however it was written in F77 and the makefile for zheevh3 requires f77 which I don't have. Can I change it to gfortran? Will that work?