1

I currently have this Makefile which :

  • Finds all *.f in the directory it is run
  • Looks for matching *.o in the specified subdir (as defined in Objets_dir)
  • Compiles and links

Code :

    # Paths
    # -----

    # Where to put the *.o
    Objets_dir = temp\Win

    # Where to check for the *.o
    VPATH = $(Objets_dir)

    # Where to put the resulting binary
    Executable = D:\Documents\out.exe

    # List of needed objects
    Objets = $(patsubst %.f,%.o,$(wildcard *.f))

    # Rules
    # -----

    F_compilo = gfortran
    F_compilo_options = -O3 -ffpe-trap=invalid,zero,overflow -mfpmath=sse -fmax-errors=3
    Link = x86_64-w64-mingw32-gfortran
    Link_options =

    # Let's go
    # --------

    # Compile (generation of .o)
    %.o:%.f
        $(F_compilo) $(F_compilo_options) -c $< -o $(Objets_dir)\$@

    # Link (generation of .exe)
    $(Executable): $(Objets)
        $(Link) $(Link_options) -o $@ $(addprefix $(Objets_dir)\, $(Objets))

For information, I am using mingw32-make to execute this Makefile.

I would like to edit it so that I could specify a list of subfolders where it would also (in addition to the current folder) look for source files (*.f). It would then be a bit less generic but I would be very fine with this.

This makefile is something I retreived from the internet years ago and barely ever touched except to add some commentaries or edit compile flags. I suppose the line that would require editing is the one with the "wildcard" call, but I am completely (completely) ignorant regarding Make language.

Can you suggest how to edit it ?

Parker Lewis
  • 323
  • 1
  • 9

1 Answers1

1

There is an instructive example of finding files in a list of sub-directories at: https://www.gnu.org/software/make/manual/html_node/Foreach-Function.html

Based on this, I've come up with the following. I've tested this using some example files on a linux system so can't guarentee it'll work "out of the box" on Windows, but shouldn't be far off.

It looks for all .f files in the directories given in dirs then proceeds much as before.

# Paths
# -----

# Where to put the *.o
Objets_dir = temp\Win

# Where to put the resulting binary
Executable = D:\Documents\out.exe

# List of directories to search for .f files:
dirs := . a b c d

# Extra directories to check for dependencies
VPATH = a b c d

# Make a list of *.f source files found in dirs
Sources := $(foreach dir,$(dirs),$(wildcard $(dir)\*.f))

# List of needed objects
Objets = $(patsubst %.f,%.o,$(Sources))

# Objects with full path names to their location in temp dir.
TempObjets = $(addprefix $(Objets_dir)\, $(notdir $(Objets)))

# Rules
# -----

F_compilo = gfortran
F_compilo_options = -O3 -ffpe-trap=invalid,zero,overflow -mfpmath=sse -fmax-errors=3
Link = x86_64-w64-mingw32-gfortran
Link_options =

# Let's go
# --------

# Compile (generation of .o)
$(Objets_dir)\%.o:%.f
    $(F_compilo) $(F_compilo_options) -c $< -o $(Objets_dir)\$(notdir $@)

# Link (generation of .exe)
$(Executable): $(TempObjets)
    $(Link) $(Link_options) -o $@ $^

clean:
    rm -f $(TempObjets) $(Executable)

Note that it strips the subdirectories off the filenames for building and linking, otherwise you'd need to create a bunch of matching temporary directories. So it is convenient to just dump all the .o files in the temporary directory. Note, however, that this will fail if some of the .f files in the subdirectories share the same name. In that case, you would need to set VPATH to a list of the temp directories (the list separator is ; on Windows, : on other systems) and remove the $(nordir ...) clauses from the build and link rules. However, you'll need to then create a directory in temp\Win to match each source directory.

Finally, it should be noted that this doesn't really count as a recursive use of make. For that, see: How to generate a Makefile with source in sub-directories using just one makefile

Community
  • 1
  • 1
Halzephron
  • 328
  • 1
  • 10
  • Ok, everything runs fine... except all files inside the subdirs get recompiled every time. I set up `dirs` as `dirs:= . aaa`. All .f inside the current directory are found correctly and recompiled only if needed (if modified), which is the expected behaviour. But those inside the `aaa` directory get recompiled every time. Help ? – Parker Lewis Nov 07 '16 at 12:28
  • Have made some edits. Should do the right thing now, hopefully. – Halzephron Nov 07 '16 at 16:07
  • Thanks. It seems to work with a few last edits : although I am on Windows, the `Sources` line definition needs to be `Sources := $(foreach dir,$(dirs),$(wildcard $(dir)/*.f))` (notice the `/`, not `\ ` ), otherwise it doesn't find any source files and stops right there. Same modification for `TempObjets = $(addprefix $(Objets_dir)/, $(notdir $(Objets)))` and `$(Objets_dir)/%.o:%.f`. The other `\ ` are fine though :) – Parker Lewis Nov 08 '16 at 14:32
  • Also, I changed `VPATH = $(dirs)` to avoid having to copy paste the whole list of subdirs. Seems to work fine. – Parker Lewis Nov 08 '16 at 14:36