diff --git a/CHANGELOG.md b/CHANGELOG.md index f230ddb7ebc7ea5821955a96aab70963015b5d41..54e78e0a18d9bcd495dec076ee7d2681e8e466ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # FSL base project changelog +## 2111.6 (Friday 19th November 2021) + +* New convention for compiling C++ files which are part of a CUDA library or + executable, using `${CUDACXXFLAGS}`. + + ## 2111.5 (Friday 19th November 2021) * Set `-std=c++14` for `nvcc`-compiled code, as CUDA 11.0 is the first version diff --git a/README.md b/README.md index 92ebb8ac0af58af9b639bb0747d19e4c1267b9a5..b24e8fc57bcde99830ff71eac5e600d8a50da81d 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,57 @@ behaviour of various aspects of the `base` project. All tests are written in Python, and are executed with `pytest`. +## Standard conventions for C/C++/CUDA projects. + +Commands for compilation of intermediate object files should have the +form: + + $(CC) $(CFLAGS) <input/output files> # for .c files + $(CXX) $(CXXFLAGS) <input/output files> # for .cc files + $(CXX) $(CUDACXXFLAGS) <input/output files> # for .cc files which are to + # be linked into CUDA + # libraries/executables + $(NVCC) $(NVCCFLAGS) <input/output files> # for .cu files + +And commands for compilation and linking of executables and libraries +should have the form: + + $(CC) $(CFLAGS) <input/output files> ${LDFLAGS} # for c libs/exes + $(CXX) $(CXXFLAGS) <input/output files> ${LDFLAGS} # for c++ exes + $(CXX) $(CXXFLAGS) -shared <input/output files> ${LDFLAGS} # for c++ libs + $(NVCC) $(NVCCFLAGS) -shared <input/output files> ${NVCCLDFLAGS} # for CUDA libs + $(NVCC) $(NVCCFLAGS) <input/output files> ${NVCCLDFLAGS} # for CUDA exes + + +`LDFLAGS` *must* come at the end, to ensure proper linking. + +An example C++ `Makefile` might look like this: + +``` +include ${FSLCONFDIR}/default.mk + +PROJNAME = myproject +SOFILES = libmylib.so +XFILES = myexe1 myexe2 + +# Instead of explicitly defining this rule, +# We could instead rely on implicit Make +# rules for generating *.o files from *.cc +# files. +%.o: %.cc + $(CXX) $(CXXFLAGS) -c -o $@ $< + +libmylib.so: myobj1.o myobj2.o + $(CXX) $(CXXFLAGS) -shared -o $@ $^ $(LDFLAGS) + +myexe1: myexe1.o myobj1.o + $(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) + +myexe2: myexe2.o myobj2.o + $(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) +``` + + ## Building FSL CUDA projects. Some FSL projects (e.g. [`fsl/eddy`(https://git.fmrib.ox.ac.uk/fsl/eddy) use @@ -42,3 +93,21 @@ using static linking: The `Makefile` for each FSL CUDA project may provide additional options for controlling compilation. + +An example `Makefile` for a C++/CUDA project might look like this: + +``` +include ${FSLCONFDIR}/default.mk + +PROJNAME = myproject +XFILES = myexe + +%.o: %.cu + $(NVCC) $(NVCCFLAGS) -c -o $@ $< + +%.o: %.cc + $(CXX) $(CUDACXXFLAGS) -c -o $@ $< + +myexe: + $(NVCC) $(NVCCFLAGS) -o $@ $< $(NVCCLDFLAGS) +``` diff --git a/config/buildSettings.mk b/config/buildSettings.mk index a958de299a892946a94b6a63a52cad1d3041c35f..f01ec640b3bad5304c5bc0c34a1b37e880a2ef68 100644 --- a/config/buildSettings.mk +++ b/config/buildSettings.mk @@ -65,6 +65,9 @@ ARCHLIBS = # armadillo structures may have different byte-alignment # to equivalent g++-compiled structures (see # include/armadillo_bits/compiler_setup.hpp) +# +# - Set -std=c++14. This is the newest C++ standard +# supported by nvcc for CUDA<11.0. ARCHNVCCFLAGS = -DARMA_ALLOW_FAKE_GCC -std=c++14 # Linker flags for CUDA projects. @@ -171,13 +174,14 @@ ifneq (${NVCC}, ) # "-ccbin" rather than "--compiler-bindir" here, # because the conda-forge nvcc wrapper checks for # -ccbin, and adds its own if not present. - NVCCFLAGS ?= -I${CUDA_HOME}/include \ - ${GENCODEFLAGS} \ - -ccbin $(CXX) - NVCCLDFLAGS ?= -L${CUDA_HOME}/lib \ - -L${CUDA_HOME}/lib64 \ - -L${CUDA_HOME}/lib/stubs \ - -L${CUDA_HOME}/lib64/stubs + CUDACXXFLAGS ?= -I${CUDA_HOME}/include + NVCCFLAGS ?= ${GENCODEFLAGS} \ + -ccbin $(CXX) \ + ${CUDACXXFLAGS} + NVCCLDFLAGS ?= -L${CUDA_HOME}/lib \ + -L${CUDA_HOME}/lib64 \ + -L${CUDA_HOME}/lib/stubs \ + -L${CUDA_HOME}/lib64/stubs # Link CUDA libraries statically, if compilation # was invoked with "make CUDA_STATIC=1". @@ -197,10 +201,10 @@ ifneq (${NVCC}, ) # cublas_Lt_static, in addition to culibos ifeq ($(patsubst 9.%,,${CUDA_VER}),) CUBLAS_STATIC = -lcublas_static -lculibos - NVCCFLAGS += --cudart=static + NVCCLDFLAGS += --cudart=static else CUBLAS_STATIC = -lcublas_static -lcublasLt_static -lculibos - NVCCFLAGS += --cudart=static --cudadevrt=static + NVCCLDFLAGS += --cudart=static --cudadevrt=static endif # Other CUDA toolkit components will @@ -209,9 +213,9 @@ ifneq (${NVCC}, ) $(subst -lcurand,-lcurand_static,${CUDALIBS})) else ifeq ($(patsubst 9.%,,${CUDA_VER}),) - NVCCFLAGS += --cudart=shared + NVCCLDFLAGS += --cudart=shared else - NVCCFLAGS += --cudart=shared --cudadevrt=static + NVCCLDFLAGS += --cudart=shared --cudadevrt=static endif _CUDALIBS += ${CUDALIBS} endif diff --git a/config/vars.mk b/config/vars.mk index dd4358974a964c3ad267dcc4f4ead73acc7dc532..fe402f5c776903a567e364ab629338beac4b9d3c 100644 --- a/config/vars.mk +++ b/config/vars.mk @@ -22,13 +22,13 @@ PROJNAME = USRLDFLAGS = # Linker flags USRINCFLAGS = # Include directories -USRCFLAGS = # Compiler flags for C projects -USRCXXFLAGS = # Compiler flags for C++ projects +USRCFLAGS = # Compiler flags for C files +USRCXXFLAGS = # Compiler flags for C++ files USRCPPFLAGS = # Preprocessor flags LIBS = # Libraries to link against for C and C++ projects - # these are incorporated into the final LDFLAGS, below. -USRNVCCFLAGS = # Compiler flags for CUDA projects -USRNVCCLDFLAGS = # Linker flags for CUDA projects +USRNVCCFLAGS = # Compiler flags for CUDA files +USRNVCCLDFLAGS = # Linker flags for CUDA libraries/executables CUDALIBS = # CUDA libraries to link against (e.g. curand, cublas, etc) - # these are incorporated into the final NVCCLDFLAGS, below. # -lcuda and -lcudart are automatically added, so do not @@ -84,20 +84,25 @@ INCFLAGS = ${USRINCFLAGS} -I. -I${DEVINCDIR} -I${INCDIR} # All projects must use these flags for compilation/linking. # Commands for compilation of intermediate object files # should have the form: -# -# $(CC) $(CFLAGS) <input/output files> -# $(CXX) $(CXXFLAGS) <input/output files> -# $(NVCC) $(NVCCFLAGS) <input/output files> + +# $(CC) $(CFLAGS) <input/output files> # for .c files +# $(CXX) $(CXXFLAGS) <input/output files> # for .cc files +# $(CXX) $(CUDACXXFLAGS) <input/output files> # for .cc files which are to +# # be linked into CUDA +# # libraries/executables +# $(NVCC) $(NVCCFLAGS) <input/output files> # for .cu files # # And commands for compilation and linking of executables # and libraries should have the form: # -# $(CC) $(CFLAGS) <input/output files> ${LDFLAGS} -# $(CXX) $(CXXFLAGS) <input/output files> ${LDFLAGS} -# $(NVCC) $(NVCCFLAGS) <input/output files> ${NVCCLDFLAGS} +# $(CC) $(CFLAGS) <input/output files> ${LDFLAGS} # for c libs/exes +# $(CXX) $(CXXFLAGS) <input/output files> ${LDFLAGS} # for c++ exes +# $(CXX) $(CXXFLAGS) -shared <input/output files> ${LDFLAGS} # for c++ libs +# $(NVCC) $(NVCCFLAGS) -shared <input/output files> ${NVCCLDFLAGS} # for CUDA libs +# $(NVCC) $(NVCCFLAGS) <input/output files> ${NVCCLDFLAGS} # for CUDA exes +# +# `LDFLAGS` *must* come at the end, to ensure proper linking. # -# LDFLAGS *must* come at the end, to ensure proper linking. - # The order in which the final FLAGS variables are # constructed here is important: # @@ -113,12 +118,13 @@ INCFLAGS = ${USRINCFLAGS} -I. -I${DEVINCDIR} -I${INCDIR} # the default options specified in buildSettings.mk, # which in turn can override options provided by the # environment. -CPPFLAGS += ${ARCHCPPFLAGS} ${USRCPPFLAGS} -CFLAGS += ${CPPFLAGS} ${ARCHCFLAGS} ${USRCFLAGS} ${INCFLAGS} -CXXFLAGS += ${CPPFLAGS} ${ARCHCXXFLAGS} ${USRCXXFLAGS} ${INCFLAGS} -LDFLAGS += ${ARCHLDFLAGS} ${USRLDFLAGS} \ - -L. -L${DEVLIBDIR} -L${LIBDIR} \ - ${LIBS} ${ARCHLIBS} +CPPFLAGS += ${ARCHCPPFLAGS} ${USRCPPFLAGS} +CFLAGS += ${CPPFLAGS} ${ARCHCFLAGS} ${USRCFLAGS} ${INCFLAGS} +CXXFLAGS += ${CPPFLAGS} ${ARCHCXXFLAGS} ${USRCXXFLAGS} ${INCFLAGS} +CUDACXXFLAGS += ${CXXFLAGS} ${USRNVCCFLAGS} +LDFLAGS += ${ARCHLDFLAGS} ${USRLDFLAGS} \ + -L. -L${DEVLIBDIR} -L${LIBDIR} \ + ${LIBS} ${ARCHLIBS} # Remove any -std=c++ options, as we are already setting # -std in ARCHNVCCFLAGS (seee buildSettings.mk), and # passing another one via --compiler-options will confuse