
# Bulk build Makefile for MPI programs (C / C++ / Fortran)
# - Builds each single-source file into ./bin/<name>
# - Uses mpicc / mpicxx / mpifort
#
# Usage:
#   make         # build all
#   make clean   # remove bin/
#   make list    # show what will be built
#
# Override defaults:
#   make CFLAGS='-O3 -march=native' CXXFLAGS='-O3 -march=native' FFLAGS='-O3'

# Compilers
MPICC  ?= mpicc
MPICXX ?= mpicxx
MPIFC  ?= mpifort

# Flags
CSTD    ?= -std=c11
CFLAGS  ?= -O3 $(CSTD) -Wall -Wextra
CXXFLAGS?= -O3 -Wall -Wextra
FFLAGS  ?= -O3
LDFLAGS ?=
LDLIBS  ?= -lm

# Executable directory
BINDIR := bin

# Source discovery (relative to Makefile dir)
C_SRCS    := $(shell find . -maxdepth 5 -name '*.c'   -type f | sort)
CXX_SRCS  := $(shell find . -maxdepth 5 \( -name '*.cc' -o -name '*.cpp' -o -name '*.cxx' \) -type f | sort)
F_SRCS    := $(shell find . -maxdepth 5 \( -name '*.f90' -o -name '*.f95' -o -name '*.f' \) -type f | sort)

# Filter out helpers that are not standalone programs
HELPERS_EXCLUDE := hpc.c gfx.c
C_SRCS   := $(filter-out $(HELPERS_EXCLUDE),$(notdir $(C_SRCS)))
CXX_SRCS := $(notdir $(CXX_SRCS))
F_SRCS   := $(notdir $(F_SRCS))

# Map sources to executable paths (strip extension, prefix bin/)
C_PROGS    := $(addprefix $(BINDIR)/,$(basename $(C_SRCS)))
CXX_PROGS  := $(addprefix $(BINDIR)/,$(basename $(CXX_SRCS)))
F_PROGS    := $(addprefix $(BINDIR)/,$(basename $(F_SRCS)))
PROGS      := $(C_PROGS) $(CXX_PROGS) $(F_PROGS)

.PHONY: all list clean distclean vars
all: $(BINDIR) $(PROGS)

$(BINDIR):
	mkdir -p $(BINDIR)

# Pattern rules: compile single-source files directly to executables
$(BINDIR)/%: %.c | $(BINDIR)
	$(MPICC) $(CFLAGS) $< -o $@ $(LDFLAGS) $(LDLIBS)

$(BINDIR)/%: %.cc | $(BINDIR)
	$(MPICXX) $(CXXFLAGS) $< -o $@ $(LDFLAGS) $(LDLIBS)

$(BINDIR)/%: %.cpp | $(BINDIR)
	$(MPICXX) $(CXXFLAGS) $< -o $@ $(LDFLAGS) $(LDLIBS)

$(BINDIR)/%: %.cxx | $(BINDIR)
	$(MPICXX) $(CXXFLAGS) $< -o $@ $(LDFLAGS) $(LDLIBS)

$(BINDIR)/%: %.f90 | $(BINDIR)
	$(MPIFC) $(FFLAGS) $< -o $@ $(LDFLAGS) $(LDLIBS)

$(BINDIR)/%: %.f95 | $(BINDIR)
	$(MPIFC) $(FFLAGS) $< -o $@ $(LDFLAGS) $(LDLIBS)

$(BINDIR)/%: %.f | $(BINDIR)
	$(MPIFC) $(FFLAGS) $< -o $@ $(LDFLAGS) $(LDLIBS)

# List what we'll build
list:
	@echo "C sources:    $(C_SRCS)"
	@echo "C++ sources:  $(CXX_SRCS)"
	@echo "Fortran srcs: $(F_SRCS)"
	@echo "Executables:"
	@for p in $(PROGS); do echo "  $$p"; done

# Cleanup
clean:
	$(RM) -r $(BINDIR)
	$(RM) *.o */*.o

distclean: clean

# Debug variables
vars:
	@echo "MPICC=$(MPICC)"
	@echo "MPICXX=$(MPICXX)"
	@echo "MPIFC=$(MPIFC)"
	@echo "C_SRCS=$(C_SRCS)"
	@echo "CXX_SRCS=$(CXX_SRCS)"
	@echo "F_SRCS=$(F_SRCS)"
	@echo "PROGS=$(PROGS)"
