5

I am trying to learn how a Makefile should look like, when it comes to the flags, especially the linking ones. Here is my Makefile:

OBJS    = n.o
SOURCE  = n.cpp
# HEADER = there are no header files, so I commented that
OUT     =       test
CXX     = ../mpich-install/bin/mpic++
FLAGS   =       -I../intel/mkl/include  ../intel/mkl/lib/intel64/libmkl_scalapack_ilp64.a       -Wl,--start-group       ../intel/mkl/lib/intel64/libmkl_intel_ilp64.a ../intel/mkl/lib/intel64/libmkl_core.a  ../intel/mkl/lib/intel64/libmkl_sequential.a    -Wl,--end-group ../intel/mkl/lib/intel64/libmkl_blacs_intelmpi_ilp64.a -lpthread       -lm     -ldl

all: $(OBJS)
        $(CXX)  $(OBJS) -o $(OUT)       $(FLAGS)

# create/compile the individual files >>separately<<
n.o:    n.cpp
        $(CXX)  -c      n.cpp   $(FLAGS)

.PHONY : all
# clean house
clean:
        rm -f $(OBJS)

and then I am getting:

../mpich-install/bin/mpic++     -c      n.cpp   -I../intel/mkl/include  ../intel/mkl/lib/intel64/libmkl_scalapack_ilp64.a       -Wl,--start-group       ../intel/mkl/lib/intel64/libmkl_intel_ilp64.a   ../intel/mkl/lib/intel64/libmkl_core.a  ../intel/mkl/lib/intel64/libmkl_sequential.a    -Wl,--end-group ../intel/mkl/lib/intel64/libmkl_blacs_intelmpi_ilp64.a  -lpthread       -lm     -ldl
g++: warning: ../intel/mkl/lib/intel64/libmkl_scalapack_ilp64.a: linker input file unused because linking not done
g++: warning: ../intel/mkl/lib/intel64/libmkl_intel_ilp64.a: linker input file unused because linking not done
g++: warning: ../intel/mkl/lib/intel64/libmkl_core.a: linker input file unused because linking not done
g++: warning: ../intel/mkl/lib/intel64/libmkl_sequential.a: linker input file unused because linking not done
g++: warning: ../intel/mkl/lib/intel64/libmkl_blacs_intelmpi_ilp64.a: linker input file unused because linking not done
../mpich-install/bin/mpic++     n.o -o test     -I../intel/mkl/include  ../intel/mkl/lib/intel64/libmkl_scalapack_ilp64.a       -Wl,--start-group       ../intel/mkl/lib/intel64/libmkl_intel_ilp64.a   ../intel/mkl/lib/intel64/libmkl_core.a  ../intel/mkl/lib/intel64/libmkl_sequential.a    -Wl,--end-group ../intel/mkl/lib/intel64/libmkl_blacs_intelmpi_ilp64.a  -lpthread       -lm     -ldl

That means that I should use some flags only in the last part of the process. What is the correct way to handle such a case? Maybe create FLAGS1 and FLAGS2? It should work, but I want to know which the correct way.

gsamaras
  • 71,951
  • 46
  • 188
  • 305
  • 1
    The flags used for compiling and linking are different. You need to use the appropriate flags for each step in each step. Have a look at the output of `make -qp` (save it to a file) and look at the default rules that make has built-in for compiling and linking C and C++ files. That should help clarify things some. – Etan Reisner Jun 12 '15 at 18:35
  • You're using `FLAGS` as a generic "i don't care what phase of the build we're in" type of argument -- this isn't the right way to do things. Compilation flags are (mostly) different from linking flags, so you should not be joining them together. Instead, separate your `CFLAGS` (or `CPPFLAGS` in this case) from your `LFLAGS`. – mah Jun 12 '15 at 18:36
  • Thanks @mah and Etan!! – gsamaras Jun 13 '15 at 14:49

1 Answers1

4

"... but I want to know which the correct way."

The correct way is to keep up with make standard variable names, in particular CXXFLAGS and LDFLAGS.

You don't want to specify libraries for the linker flags like you try to do here (specifying subjects actually):

FLAGS   =  ... ../intel/mkl/lib/intel64/libmkl_scalapack_ilp64.a

Instead of using FLAGS and giving a direct subject for linking, you should rather use the standard LDFLAGS makefile variable to setup the path, and let the linker find the appropriate static or shared libraries:

  LDFLAGS += -L../intel/mkl/lib/intel64 -lmkl_scalapack_ilp64
# ^^^^^^^ Note the standard build system uses $(LDFLAGS) at the linker stage rule
# -L specifies the paths for finding libraries
# -l<MyLib> actually searches for certain libraries in the given paths,
#           expanding to search for files like libMyLib.a or libMyLib.so.

all: $(OBJS)
        $(CXX)  $(OBJS) -o $(OUT) $(CXXFLAGS) $(LDFLAGS)
#                                          ^^^^^^^^^^ Use them separately at
#                                                     linking stage  
        make    -f      Makefile        clean
#       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This whole line looks very (!!!) suspicious,
#                                             and would just make it harder to debug your
#                                             build system. It's an indicator, you did
#                                             dependencies management wrong.
#                                             Consider to use the compiler's --MF options 
#                                             family, to create a dependency file for the 
#                                             headers, and include it in your makefile.

Distinguish from compilation phase flags (CXXFLAGS), and linking stage flags (LDFLAGS).


Aside:

To avoid this

make    -f      Makefile        clean

action in your final target rule (that was probably added to avoid missing to catch up with header dependencies), add an -MF option to the CXXFLAGS, and include the results.

Here's more detailed information about the various techniques:

Auto-Dependency Generation

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • So, what `$(FLAGS)` should be in that case? – gsamaras Jun 13 '15 at 14:48
  • @gsamaras `$(CXXFLAGS)` – πάντα ῥεῖ Jun 13 '15 at 14:59
  • No that was not the case. I added that clean so that I can get rid of the objects files that made it hard for the testers to find the source and header files in my project (I had that from a previous Makefile with many files). Now, I am confused and what I have does not compile. Sorry. – gsamaras Jun 13 '15 at 15:03
  • @gsamaras You should better consider an [_out of source tree_](http://stackoverflow.com/questions/4894220/out-of-tree-builds-with-makefiles-and-static-pattern-rules) build to provide the artifacts, and separate them from the source code. Note, that the `clean` target should remove the just created executable target as well. – πάντα ῥεῖ Jun 13 '15 at 15:04
  • I do not think that's the ideal solution here. I think you focus too much into this `make -f Makefile clean`, so I just got rid of it. So just forget it, I am also deleting from the question. Maybe it would be good to edit your answer, since that's not the spirit of my question. I tried to play around with what you have in your answer, but it just fails and I am getting undefined references. I mean I want to accept your answer, but I just can't! – gsamaras Jun 13 '15 at 15:14
  • @gsamaras The main point was, you need to have different flag variables for different stages of constructing artifacts from your makefile. I don't see, how this doesn't finally answers your (a bit unclear) question. – πάντα ῥεῖ Jun 13 '15 at 15:24
  • That's a good comment, I agree. However, what you have there just doesn't compile. Anyway, I got the point, so +1. ;) – gsamaras Jun 13 '15 at 15:54
  • @gsamaras Well, I think you will be interested in having a look at [Using Implicit Rules](https://www.gnu.org/software/make/manual/html_node/Implicit-Rules.html) and [Variables Used by Implicit Rules](https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html#Implicit-Variables). Not too much point bothering about. – πάντα ῥεῖ Jun 13 '15 at 15:58
  • @gsamaras Pro tip: Using `make` to create build systems, follow to overide their intrinsic rule and variable namings as much as possible. – πάντα ῥεῖ Jun 13 '15 at 16:08