Search code examples
makefilecompilation

How to place object files into a different directory using Makefile?


Consider the following Makefile fragment:

FORTRAN = ifort -c
PATH_MOD = mod/
FILE_MOD = mod_constant.f90 mod_rot.f mod_test.f90
SOURCE_MOD = $(FILE_MOD:%=$(PATH_MOD)%)
OBJECT_MOD = $(FILE_MOD:%.f*=%.o)

$(OBJECT_MOD): $(SOURCE_MOD)
   $(FORTRAN) $(SOURCE_MOD)

clean:
   rm -f *.o

This script executes the command ifort -c mod_constant.f90 mod_rot.f mod_test.f90.

However, I would like to achieve that all files listed in $(FILE_MOD) [but none of the other files in directory $(PATH_MOD)$] will be compiled in separate lines, placing the object files into directory lnk. In the present case, the script should run the following sequence of commands:

ifort -c mod_constant.f90 -o lnk/mod_constant.o
ifort -c mod_rot.f -o lnk/mod_rot.o
ifort -c mod_test.f90 -o lnk/mod_test.o

Is there any way to do this?


Solution

  • This rule ...

    $(OBJECT_MOD): $(SOURCE_MOD)
        $(FORTRAN) $(SOURCE_MOD)
    

    Says that each target in the list to which $(OBJECT_MOD) expands has as prerequisites all the files in the list to which $(SOURCE_MOD) expands, and should be built by the command to which $(FORTRAN) $(SOURCE_MOD) expands. That's not at all what you want.

    I would like to achieve that all files listed in $(FILE_MOD) [but none of the other files in directory $(PATH_MOD)$] will be compiled in separate lines, placing the object files into directory lnk.

    Since you seem already commited to GNU's version of make, the natural way to go about this is to write a pattern rule. Or two, actually, because you have two distinct source name patterns. If you want the object files to go into a different directory than their corresponding sources, then that would also be handled in such rules. For example,

    lnk/%.o : %.f
            $(FORTRAN) -c $< -o $@
    
    lnk/%.o : %.f90
            $(FORTRAN) -c $< -o $@
    

    The % can be interpreted as a wildcard, with the caveat that the appearance in the rule's target and those in its prerequisite list have to expand to the same string.

    The $< is an automatic variable that expands to the first actual element of the rule's prerequisite list, subject to expansion of the %. The $@ expands to the actual target being built.

    Also, note well that those rules tell how to build the wanted files, but you still need somehow to tell make that they need to be built at all. That would typically be by making them prerequisites of some rule, though you could rely instead on requesting one or more of them explicitly, from the make command line.