# Source code
EXAMPLE_CUDA_SRC            := exampleCUDA.cu
EXAMPLE_HIP_SRC             := exampleHIP.cpp
EXAMPLE_MPI_SRC             := exampleMPI.c
EXAMPLE_OPENACC_SRC         := exampleOpenACC.c
EXAMPLE_OPENCL_SRC          := exampleOpenCL.c
EXAMPLE_OPENMP_SRC          := exampleOpenMP.c
EXAMPLE_OPENMP_UNIFIED_SRC  := exampleOpenMP-unified_shared_memory.c
EXAMPLE_KOKKOS_SRC          := exampleKokkos.cpp
EXAMPLE_KOKKOS_DUALVIEW_SRC := exampleKokkos.DualView.cpp
EXAMPLE_STDPAR_SRC          := exampleStdpar.cpp
EXAMPLE_SYCL_SRC            := exampleSYCL.cpp
EXAMPLE_SYCL_ACC_SRC        := exampleSYCL-accessor.cpp
EXAMPLE_THRUST_SRC          := exampleThrust.cu

# Executables
EXAMPLE_CUDA_EXE            := $(basename $(EXAMPLE_CUDA_SRC))
EXAMPLE_HIP_EXE             := $(basename $(EXAMPLE_HIP_SRC))
EXAMPLE_MPI_EXE             := $(basename $(EXAMPLE_MPI_SRC))
EXAMPLE_OPENACC_EXE         := $(basename $(EXAMPLE_OPENACC_SRC))
EXAMPLE_OPENCL_EXE          := $(basename $(EXAMPLE_OPENCL_SRC))
EXAMPLE_OPENMP_EXE          := $(basename $(EXAMPLE_OPENMP_SRC))
EXAMPLE_OPENMP_UNIFIED_EXE  := $(basename $(EXAMPLE_OPENMP_UNIFIED_SRC))
EXAMPLE_KOKKOS_EXE          := $(basename $(EXAMPLE_KOKKOS_SRC))
EXAMPLE_KOKKOS_DUALVIEW_EXE := $(basename $(EXAMPLE_KOKKOS_DUALVIEW_SRC))
EXAMPLE_STDPAR_EXE          := $(basename $(EXAMPLE_STDPAR_SRC))
EXAMPLE_SYCL_EXE            := $(basename $(EXAMPLE_SYCL_SRC))
EXAMPLE_SYCL_ACC_EXE        := $(basename $(EXAMPLE_SYCL_ACC_SRC))
EXAMPLE_THRUST_EXE          := $(basename $(EXAMPLE_THRUST_SRC))
ALL_EXE := \
    $(EXAMPLE_CUDA_EXE) \
    $(EXAMPLE_HIP_EXE) \
    $(EXAMPLE_MPI_EXE) \
    $(EXAMPLE_OPENACC_EXE) \
    $(EXAMPLE_OPENCL_EXE) \
    $(EXAMPLE_OPENMP_EXE) \
    $(EXAMPLE_OPENMP_UNIFIED_EXE) \
    $(EXAMPLE_KOKKOS_EXE) \
    $(EXAMPLE_KOKKOS_DUALVIEW_EXE) \
    $(EXAMPLE_STDPAR_EXE) \
    $(EXAMPLE_SYCL_EXE) \
    $(EXAMPLE_SYCL_ACC_EXE) \
    $(EXAMPLE_THRUST_EXE)

ifeq ($(COMPILER), AdaptiveCpp)
    CXX:=acpp
    CXXFLAGS:=-O2 -march=native -flto -Wall -Wextra
else ifeq ($(COMPILER), gnu)
    CC:=gcc
    CFLAGS:=-O2 -march=native -Wall -Wextra
    CXX:=g++
    CXXFLAGS:=-O2 -march=native -Wall -Wextra
else ifeq ($(findstring gcc, $(notdir $(APPTAINER_IMAGE))), gcc)
    # https://hub.docker.com/_/gcc
    COMPILER:=gnu@apptainer
    CC:=gcc
    CFLAGS:=-O2 -march=native -Wall -Wextra
    CXX:=g++
    CXXFLAGS:=-O2 -march=native -Wall -Wextra
else ifeq ($(COMPILER), llvm)
    CC:=clang
    CFLAGS:=-O2 -march=native -Wall -Wextra
    CXX:=clang++
    CXXFLAGS:=-O2 -march=native -Wall -Wextra
else ifeq ($(findstring llvm, $(notdir $(APPTAINER_IMAGE))), llvm)
    # https://apt.llvm.org
    COMPILER:=llvm@apptainer
    CC:=clang-23
    CFLAGS:=-O2 -march=native -Wall -Wextra -fuse-ld=lld
    CXX:=clang++-23
    CXXFLAGS:=-O2 -march=native -Wall -Wextra -fuse-ld=lld
else ifeq ($(COMPILER), nvidia)
    CC:=nvc
    CFLAGS:=-O2 -tp=host -Minform=inform
    CXX:=nvc++
    CXXFLAGS:=-O2 -tp=host -Minform=inform
    NVCC:=nvcc
    NVCCFLAGS:=-O2 -ccbin='gcc' --forward-unknown-to-host-compiler -march=native -Wall -Wextra
else ifeq ($(findstring nvhpc, $(notdir $(APPTAINER_IMAGE))), nvhpc)
    # https://catalog.ngc.nvidia.com/orgs/nvidia/containers/nvhpc
    COMPILER:=nvidia@apptainer
    CC:=nvc
    CFLAGS:=-O2 -tp=host -Minform=inform
    CXX:=nvc++
    CXXFLAGS:=-O2 -tp=host -Minform=inform
    NVCC:=nvcc
    NVCCFLAGS:=-O2 -ccbin='gcc' --forward-unknown-to-host-compiler -march=native -Wall -Wextra
else ifeq ($(COMPILER), oneAPI)
    CC:=icx
    CFLAGS:=-O2 -xHost -ipo -Wall -Wextra
    CXX:=icpx
    CXXFLAGS:=-O2 -xHost -ipo -Wall -Wextra
else ifeq ($(findstring oneapi, $(notdir $(APPTAINER_IMAGE))), oneapi)
    # https://hub.docker.com/r/intel/oneapi-hpckit
    COMPILER:=oneAPI@apptainer
    CC:=icx
    CFLAGS:=-O2 -xHost -ipo -Wall -Wextra
    CXX:=icpx
    CXXFLAGS:=-O2 -xHost -ipo -Wall -Wextra
else ifeq ($(COMPILER), ROCm)
    CC:=amdclang
    CFLAGS:=-O2 -march=native -flto -Wall -Wextra
    CXX:=amdclang++
    CXXFLAGS:=-O2 -march=native -flto -Wall -Wextra
else ifeq ($(findstring rocm, $(notdir $(APPTAINER_IMAGE))), rocm)
    COMPILER:=ROCm@apptainer
    CC:=amdclang
    CFLAGS:=-O2 -march=native -flto -Wall -Wextra
    CXX:=amdclang++
    CXXFLAGS:=-O2 -march=native -flto -Wall -Wextra
else ifeq ($(notdir $(CC)), icx)
    COMPILER:=oneAPI
else ifeq ($(notdir $(CXX)), icpx)
    COMPILER:=oneAPI
else ifeq ($(notdir $(CC)), clang)
    COMPILER:=llvm
else ifeq ($(notdir $(CXX)), clang++)
    COMPILER:=llvm
else ifeq ($(notdir $(CC)), nvc)
    COMPILER:=nvidia
else ifeq ($(notdir $(CXX)), nvc++)
    COMPILER:=nvidia
else ifeq ($(notdir $(CC)), hipcc)
    COMPILER:=ROCm
else ifeq ($(notdir $(CXX)), hipcc)
    COMPILER:=ROCm
else ifeq ($(notdir $(CC)), amdclang)
    COMPILER:=ROCm
else ifeq ($(notdir $(CC)), amdclang++)
    COMPILER:=ROCm
else ifeq ($(notdir $(CC)), gcc)
    COMPILER:=gnu
else ifeq ($(notdir $(CXX)), g++)
    COMPILER:=gnu
endif

ifdef APPTAINER_IMAGE
    APPTAINER_EXEC:=apptainer exec --cleanenv $(APPTAINER_IMAGE)
    APPTAINER_EXEC:=apptainer exec --cleanenv --rocm $(APPTAINER_IMAGE)
#    APPTAINER_EXEC:=apptainer exec --cleanenv --nv --bind "${SCRATCH}" $(APPTAINER_IMAGE)
endif

# Disable implicit rules
.SUFFIXES:

##
# all
##
.PHONY:
all: $(ALL_EXE)


##
# CUDA
##
.PHONY:
CUDA: $(EXAMPLE_CUDA_EXE)

$(EXAMPLE_CUDA_EXE): $(EXAMPLE_CUDA_SRC) Makefile
ifeq      (${COMPILER}, llvm)
    # * --offload-arch=native -> /usr/bin/nvptx-arch
    # * NVIDIA GPU -> requirement CUDA
    # * AMD GPU -> not supported
	${CXX} ${CXXFLAGS} -x cuda --offload-arch=native "$<" -o "$@" -lcudart
else ifeq (${COMPILER}, llvm@apptainer)
	$(APPTAINER_EXEC) ${CXX} ${CXXFLAGS} -x cuda --offload-arch=native "$<" -o "$@" -L/usr/local/cuda/targets/x86_64-linux/lib -lcudart
else ifeq (${COMPILER}, nvidia)
	$(NVCC) ${NVCCFLAGS} --gpu-architecture=native "$<" -o "$@"
else ifeq (${COMPILER}, nvidia@apptainer)
	$(APPTAINER_EXEC) $(NVCC) ${NVCCFLAGS} --gpu-architecture=native "$<" -o "$@"
else
	@echo "Warning: Can't compile $< with ${CC}"
endif


##
# HIP
##
.PHONY:
HIP: $(EXAMPLE_HIP_EXE)

$(EXAMPLE_HIP_EXE): $(EXAMPLE_HIP_SRC) Makefile
ifeq      (${COMPILER}, llvm)
    # * --offload-arch=native -> /usr/bin/{amdgpu-arch,nvptx-arch}
    # * AMD GPU -> requirement ROCm
    # * NVIDIA GPU -> requirement CUDA
	${CXX} ${CXXFLAGS} -x hip --hip-link --offload-arch=native -foffload-lto "$<" -o "$@"
else ifeq      (${COMPILER}, llvm@apptainer)
	$(APPTAINER_EXEC) ${CXX} ${CXXFLAGS} -x hip --hip-link --offload-arch=native -foffload-lto "$<" -o "$@"
else ifeq (${COMPILER}, ROCm)
    # * --offload-arch=native -> /usr/bin/{amdgpu-arch,nvptx-arch}
    # * AMD GPU -> requirement ROCm
	hipcc ${CFLAGS} --offload-arch=native -foffload-lto "$<" -o "$@"
else ifeq (${COMPILER}, ROCm@apptainer)
	$(APPTAINER_EXEC) hipcc ${CFLAGS} --offload-arch=native -foffload-lto "$<" -o "$@"
else
	@echo "Warning: Can't compile $< with ${CC}"
endif


##
# OpenACC
##
.PHONY:
OpenACC: $(EXAMPLE_OPENACC_EXE)

$(EXAMPLE_OPENACC_EXE): $(EXAMPLE_OPENACC_SRC) Makefile
ifeq      (${COMPILER}, gnu)
	${CC} ${CFLAGS} -fopenacc "$<" -o "$@"
else ifeq (${COMPILER}, gnu@apptainer)
	$(APPTAINER_EXEC) ${CC} ${CFLAGS} -fopenacc "$<" -o "$@"
else ifeq (${COMPILER}, nvidia)
    # NVIDIA GPU
	${CC} ${CFLAGS} -acc -target=gpu -gpu=ccnative "$<" -o "$@"
else ifeq (${COMPILER}, nvidia@apptainer)
    # NVIDIA GPU
	$(APPTAINER_EXEC) ${CC} ${CFLAGS} -acc -target=gpu -gpu=ccnative "$<" -o "$@"
else
	@echo "Warning: Can't compile $< with ${CC}"
endif


##
# OpenMP
##
.PHONY:
OpenMP: $(EXAMPLE_OPENMP_EXE) $(EXAMPLE_OPENMP_UNIFIED_EXE)

$(EXAMPLE_OPENMP_EXE): $(EXAMPLE_OPENMP_SRC) Makefile
ifeq      (${COMPILER}, gnu)
	${CC} ${CFLAGS} -fopenmp "$<" -o "$@"
else ifeq (${COMPILER}, gnu@apptainer)
	$(APPTAINER_EXEC) ${CC} ${CFLAGS} -fopenmp "$<" -o "$@"
else ifeq (${COMPILER}, llvm)
    # * --offload-arch=native -> /usr/bin/{amdgpu-arch,nvptx-arch}
    # * AMD GPU -> requirement ROCm
    # * NVIDIA GPU -> requirement CUDA
	${CC} ${CFLAGS} -fopenmp --offload-arch=native -foffload-lto "$<" -o "$@"
else ifeq (${COMPILER}, llvm@apptainer)
	export APPTAINERENV_PREPEND_PATH=/usr/local/cuda/bin; \
	$(APPTAINER_EXEC) ${CC} ${CFLAGS} -fopenmp --offload-arch=native -foffload-lto "$<" -o "$@"
else ifeq (${COMPILER}, ROCm)
	${CC} ${CFLAGS} -fopenmp --offload-arch=native -foffload-lto "$<" -o "$@"
else ifeq (${COMPILER}, ROCm@apptainer)
	$(APPTAINER_EXEC) ${CC} ${CFLAGS} -fopenmp --offload-arch=native -foffload-lto "$<" -o "$@"
else ifeq (${COMPILER}, nvidia)
	${CC} ${CFLAGS} -mp -target=gpu -gpu=ccnative "$<" -o "$@"
else ifeq (${COMPILER}, nvidia@apptainer)
	$(APPTAINER_EXEC) ${CC} ${CFLAGS} -mp -target=gpu -gpu=ccnative "$<" -o "$@"
else ifeq (${COMPILER}, oneAPI)
    # Intel GPU
	${CC} ${CFLAGS} -qopenmp -fopenmp-targets=spir64 -foffload-lto "$<" -o "$@"
else ifeq (${COMPILER}, oneAPI@apptainer)
	$(APPTAINER_EXEC) ${CC} ${CFLAGS} -qopenmp -fopenmp-targets=spir64 -foffload-lto "$<" -o "$@"
else
	@echo "Warning: Can't compile $< with ${CC}"
endif

$(EXAMPLE_OPENMP_UNIFIED_EXE): $(EXAMPLE_OPENMP_UNIFIED_SRC) Makefile
ifeq      (${COMPILER}, gnu)
	${CC} ${CFLAGS} -fopenmp "$<" -o "$@"
else ifeq (${COMPILER}, gnu@apptainer)
	$(APPTAINER_EXEC) ${CC} ${CFLAGS} -fopenmp "$<" -o "$@"
else ifeq (${COMPILER}, llvm)
    # * --offload-arch=native -> /usr/bin/{amdgpu-arch,nvptx-arch}
    # * AMD GPU -> requirement ROCm
    # * NVIDIA GPU -> requirement CUDA
	${CC} ${CFLAGS} -fopenmp --offload-arch=native -foffload-lto "$<" -o "$@"
else ifeq (${COMPILER}, llvm@apptainer)
	export APPTAINERENV_PREPEND_PATH=/usr/local/cuda/bin; \
	$(APPTAINER_EXEC) ${CC} ${CFLAGS} -fopenmp --offload-arch=native -foffload-lto "$<" -o "$@"
else ifeq (${COMPILER}, ROCm)
	${CC} ${CFLAGS} -fopenmp --offload-arch=native -foffload-lto "$<" -o "$@"
else ifeq (${COMPILER}, ROCm@apptainer)
	$(APPTAINER_EXEC) ${CC} ${CFLAGS} -fopenmp --offload-arch=native -foffload-lto "$<" -o "$@"
else ifeq (${COMPILER}, nvidia)
	${CC} ${CFLAGS} -mp -target=gpu -gpu=mem:unified "$<" -o "$@"
else ifeq (${COMPILER}, nvidia@apptainer)
	$(APPTAINER_EXEC) ${CC} ${CFLAGS} -mp -target=gpu -gpu=mem:unified "$<" -o "$@"
else ifeq (${COMPILER}, oneAPI)
    # Intel GPU
	${CC} ${CFLAGS} -qopenmp -fopenmp-targets=spir64 -foffload-lto "$<" -o "$@"
else ifeq (${COMPILER}, oneAPI@apptainer)
	$(APPTAINER_EXEC) ${CC} ${CFLAGS} -qopenmp -fopenmp-targets=spir64 -foffload-lto "$<" -o "$@"
else
	@echo "Warning: Can't compile $< with ${CC}"
endif

##
# OpenCL
##
.PHONY:
OpenCL: $(EXAMPLE_OPENCL_EXE)

$(EXAMPLE_OPENCL_EXE): $(EXAMPLE_OPENCL_SRC) Makefile
ifeq ($(COMPILER),$(filter $(COMPILER), gnu llvm oneAPI ROCm))
	${CC} ${CFLAGS} "$<" -o "$@" -lOpenCL
else ifeq (${COMPILER}, llvm@apptainer)
	$(APPTAINER_EXEC) ${CC} ${CFLAGS} "$<" -o "$@" -lOpenCL
else ifeq (${COMPILER}, nvidia@apptainer)
	export HPCSDK_VERSION=25.7; \
	export CUDA_VERSION=12.9; \
	export OPENCL_DIR=/opt/nvidia/hpc_sdk/Linux_x86_64/$${HPCSDK_VERSION}/cuda/$${CUDA_VERSION}/targets/x86_64-linux; \
	export OPENCL_INCL=$${OPENCL_DIR}/include; \
	export OPENCL_LIB=$${OPENCL_DIR}/lib; \
	$(APPTAINER_EXEC) ${CC} ${CFLAGS} -I$${OPENCL_INCL} -L$${OPENCL_LIB} "$<" -o "$@" -lOpenCL
else ifeq (${COMPILER}, oneAPI@apptainer)
	$(APPTAINER_EXEC) ${CC} ${CFLAGS} -I/opt/intel/oneapi/compiler/latest/include "$<" -o "$@" -lOpenCL
else ifeq (${COMPILER}, ROCm@apptainer)
	$(APPTAINER_EXEC) ${CC} ${CFLAGS} "$<" -o "$@" -lOpenCL
else
	@echo "Warning: Can't compile $< with ${CC}"
endif

##
# Kokkos
##
.PHONY:
Kokkos: $(EXAMPLE_KOKKOS_EXE) $(EXAMPLE_KOKKOS_DUALVIEW_EXE)

$(EXAMPLE_KOKKOS_EXE): $(EXAMPLE_KOKKOS_SRC) Makefile
$(EXAMPLE_KOKKOS_DUALVIEW_EXE): $(EXAMPLE_KOKKOS_DUALVIEW_SRC) Makefile

$(EXAMPLE_KOKKOS_EXE) $(EXAMPLE_KOKKOS_DUALVIEW_EXE):
ifeq (${COMPILER}, gnu)
    # CPU
	${CXX} ${CXXFLAGS} -fopenmp "$<" -o "$@" -lkokkoscore
else ifeq (${COMPILER}, llvm)
    # CPU
	${CXX} ${CXXFLAGS} -fopenmp "$<" -o "$@" -lkokkoscore
else ifeq (${COMPILER}, oneAPI)
    # CPU
	${CXX} ${CXXFLAGS} -qopenmp "$<" -o "$@"
else ifeq (${COMPILER}, nvidia)
	nvcc_wrapper -fopenmp --extended-lambda "$<" -o "$@" -lkokkoscore -lcuda
else ifeq (${COMPILER}, nvidia@apptainer)
	$(APPTAINER_EXEC) nvcc_wrapper -fopenmp --extended-lambda "$<" -o "$@" -lkokkoscore -lcuda
else ifeq (${COMPILER}, ROCm)
	hipcc ${CXXFLAGS} --std=c++23 -fopenmp --offload-arch=native -foffload-lto "$<" -o "$@" -lkokkoscore
else ifeq (${COMPILER}, ROCm@apptainer)
	$(APPTAINER_EXEC) ${CXX} ${CXXFLAGS} --std=c++23 -fopenmp --offload-arch=native -foffload-lto "$<" -o "$@" -lkokkoscore
else
	@echo "Warning: Can't compile $< with ${CXX}"
endif

##
# C++ Standard Parallelism
##
.PHONY:
Stdpar: $(EXAMPLE_STDPAR_EXE)

$(EXAMPLE_STDPAR_EXE): $(EXAMPLE_STDPAR_SRC) Makefile
ifeq ($(COMPILER),$(filter $(COMPILER), gnu llvm oneAPI))
	${CXX} ${CXXFLAGS} -std=c++20 "$<" -o "$@" -ltbb
else ifeq  ($(COMPILER),$(filter $(COMPILER), gnu@apptainer llvm@apptainer oneAPI@apptainer))
	$(APPTAINER_EXEC) ${CXX} ${CXXFLAGS} -std=c++20 "$<" -o "$@" -ltbb
else ifeq (${COMPILER}, nvidia)
	${CXX} ${CXXFLAGS} -std=c++20 -Minfo=stdpar -Mneginfo=stdpar -stdpar=gpu -gpu=ccnative "$<" -o "$@"
else ifeq (${COMPILER}, nvidia@apptainer)
	$(APPTAINER_EXEC) ${CXX} ${CXXFLAGS} -std=c++20 -Minfo=stdpar -Mneginfo=stdpar -stdpar=gpu -gpu=ccnative "$<" -o "$@"
else ifeq (${COMPILER}, ROCm)
	hipcc ${CXXFLAGS} -std=c++20 --hipstdpar --hipstdpar-interpose-alloc --offload-arch=native -foffload-lto "$<" -o "$@"
else ifeq (${COMPILER}, ROCm@apptainer)
	$(APPTAINER_EXEC) hipcc ${CXXFLAGS} -std=c++20 --hipstdpar --hipstdpar-interpose-alloc --offload-arch=native -foffload-lto "$<" -o "$@"
else
	@echo "Warning: Can't compile $< with ${CXX}"
endif

##
# SYCL
##
.PHONY:
SYCL: $(EXAMPLE_SYCL_EXE) $(EXAMPLE_SYCL_ACC_EXE)

$(EXAMPLE_SYCL_EXE): $(EXAMPLE_SYCL_SRC) Makefile
$(EXAMPLE_SYCL_ACC_EXE): $(EXAMPLE_SYCL_ACC_SRC) Makefile

$(EXAMPLE_SYCL_EXE) $(EXAMPLE_SYCL_ACC_EXE):
ifeq (${COMPILER}, AdaptiveCpp)
    # AdaptiveCpp compiler for AMD GPU
	${CXX} ${CXXFLAGS} --acpp-targets=hip:gfx1032 "$<" -o "$@"
else ifeq (${COMPILER}, oneAPI)
    # Intel oneAPI compiler for Intel GPU
	${CXX} ${CXXFLAGS} -fsycl "$<" -o "$@"
    # Intel oneAPI compiler for NVIDIA GPU
	${CXX} ${CXXFLAGS} -fsycl -fsycl-targets=nvptx64-nvidia-cuda "$<" -o "$@"
else ifeq (${COMPILER}, oneAPI@apptainer)
    # Intel oneAPI compiler for Intel GPU
	$(APPTAINER_EXEC) ${CXX} ${CXXFLAGS} -fsycl "$<" -o "$@"
    # Intel oneAPI compiler for NVIDIA GPU
	$(APPTAINER_EXEC) ${CXX} ${CXXFLAGS} -fsycl -fsycl-targets=nvptx64-nvidia-cuda "$<" -o "$@"
else ifeq (${COMPILER}, llvm)
	${CXX} ${CXXFLAGS} -std=c++20 -fsycl -fsycl-targets=nvptx64-nvidia-cuda-sycldevice -Xsycl-target-backend --cuda-gpu-arch=sm_90 "$<" -o "$@"
else ifeq (${COMPILER}, llvm@apptainer)
	$(APPTAINER_EXEC) ${CXX} ${CXXFLAGS} -std=c++20 -fsycl -fsycl-targets=nvptx64-nvidia-cuda-sycldevice -Xsycl-target-backend --cuda-gpu-arch=sm_90 "$<" -o "$@"
else
	@echo "Warning: Can't compile $< with ${CXX}"
endif

##
# Thrust
##
.PHONY:
Thrust: $(EXAMPLE_THRUST_EXE)

$(EXAMPLE_THRUST_EXE): $(EXAMPLE_THRUST_SRC) Makefile
ifeq (${COMPILER}, llvm)
	${CXX} ${CXXFLAGS} -x hip --offload-arch=native "$<" -o "$@"
else ifeq (${COMPILER}, llvm@apptainer)
    # LLVM for AMD GPUs
	$(APPTAINER_EXEC) ${CXX} ${CXXFLAGS} -fuse-ld=lld -x hip --offload-arch=native "$<" -o "$@"
    # LLVM for NVIDIA GPUs
	$(APPTAINER_EXEC) ${CXX} ${CXXFLAGS} -fuse-ld=lld -x cuda --offload-arch=native "$<" -o "$@" -I/usr/local/cuda/targets/x86_64-linux/include/cccl -L/usr/local/cuda/targets/x86_64-linux/lib -lcudart
else ifeq (${COMPILER}, ROCm)
	hipcc ${CXXFLAGS} -std=c++20 --offload-arch=native -foffload-lto "$<" -o "$@"
	# CPU: Threading Building Blocks (TBB)
	#hipcc -DTHRUST_DEVICE_SYSTEM=THRUST_HOST_SYSTEM_TBB ${CXXFLAGS} -std=c++20 "exampleThrust.cu" -o "exampleThrust" -ltbb
else ifeq (${COMPILER}, ROCm@apptainer)
	$(APPTAINER_EXEC) hipcc ${CXXFLAGS} -std=c++20 --offload-arch=native -foffload-lto "$<" -o "$@"
else ifeq (${COMPILER}, nvidia)
	${NVCC} ${NVCCFLAGS}  --extended-lambda --gpu-architecture=native "$<" -o "$@"
else ifeq (${COMPILER}, nvidia@apptainer)
	$(APPTAINER_EXEC) ${NVCC} ${NVCCFLAGS}  --extended-lambda --gpu-architecture=native "$<" -o "$@"
else
	@echo "Warning: Can't compile $< with ${CXX}"
endif

##
# MPI
##
.PHONY:
MPI: $(EXAMPLE_MPI_EXE)

$(EXAMPLE_MPI_EXE): $(EXAMPLE_MPI_SRC) Makefile
ifeq ($(COMPILER),$(filter $(COMPILER), gnu llvm nvidia))
	$${MPICC:-mpicc} ${CFLAGS} "$<" -o "$@" -lcudart
else
	@echo "Warning: Can't compile $< with ${CC}"
endif


##
# Clean
##
.PHONY:
clean:
	rm -fv $(ALL_EXE)
