3

I want to automate the compilation of a toy library using CUDA and C++. Then I write a Makefile as follows

CC=g++
NVCC=nvcc
CXXFLAGS= -fopenmp -O3 -Wextra -std=c++11
CUDAFLAGS= -std=c++11 -c -arch=sm_20
LIBS= -lopenblas -lpthread -lcudart -lcublas
LIBDIRS=-L/usr/local/cuda-7.5/lib64
INCDIRS=-I/usr/local/cuda-7.5/include
matrix_cuda.o: marix_cuda.cu
     $(NVCC) $(CUDAFLAGS)   matrix_cuda.cu
all: matrix_cuda.o
        $(CC) -o test matrix_blas.cpp alg.cpp test.cpp matrix_cuda.o $(LIBDIRS) $(INCDIRS) $(LIBS) $(CXXFLAGS)
clean:
    rm -rf test *.o

Typing make I get

make: *** No rule to make target `marix_cuda.cu', needed by `matrix_cuda.o'.  Stop.

I never wrote a Makefile before. Where did I go wrong?

pateheo
  • 430
  • 1
  • 5
  • 13
  • How would you build the library using the command line, without Make? – Beta Dec 06 '15 at 06:30
  • `nvcc -std=c++11 -c -arch=sm_20 matrix_cuda.cu` and then `g++ -o test matrix_blas.cpp alg.cpp test.cpp matrix_cuda.o -L/usr/local/cuda-7.5/lib64 -I/usr/local/cuda-7.5/include -lopenblas -lpthread -lcudart -lcublas -fopenmp -O3 -Wextra -std=c++11` – pateheo Dec 06 '15 at 10:56
  • please try from this tutorial/example: https://docs.google.com/document/d/e/2PACX-1vStJ4SiboX3JeoPpNxnNS6kr8UB-SurWjqvSUUVd9dCmEOcjGZMQGhQicAFItnlwjr165BAEEVU3JQ_/pub – Talgat Jun 26 '18 at 10:35

4 Answers4

8

I think you have a typo in the CUDA file name

matrix_cuda.o: marix_cuda.cu
     $(NVCC) $(CUDAFLAGS)   matrix_cuda.cu

IMHO it should be

matrix_cuda.o: matrix_cuda.cu
     $(NVCC) $(CUDAFLAGS)   matrix_cuda.cu
Quicky
  • 403
  • 1
  • 4
  • 10
3

This may take a couple of iterations.

1) First try this:

nvcc -std=c++11 -c -arch=sm_20 matrix_cuda.cu

If that works (and produces matrix_cuda.o, I presume), remove matrix_cuda.o and

2) try this makefile:

matrix_cuda.o: matrix_cuda.cu
    nvcc -std=c++11 -c -arch=sm_20 matrix_cuda.cu

If that works,

3) try this:

g++ -o test matrix_blas.cpp alg.cpp test.cpp matrix_cuda.o -L/usr/local/cuda-7.5/lib64 -I/usr/local/cuda-7.5/include -lopenblas -lpthread -lcudart -lcublas -fopenmp -O3 -Wextra -std=c++11

If that works, remove test and

4) try this makefile:

test: matrix_cuda.o
    g++ -o test matrix_blas.cpp alg.cpp test.cpp matrix_cuda.o -L/usr/local/cuda-7.5/lib64 -I/usr/local/cuda-7.5/include -lopenblas -lpthread -lcudart -lcublas -fopenmp -O3 -Wextra -std=c++11

matrix_cuda.o: matrix_cuda.cu
    nvcc -std=c++11 -c -arch=sm_20 matrix_cuda.cu

If that works, remove test and matrix_cuda.o and

5) try that makefile again.

If that works, there are further refinements we can make.

Beta
  • 96,650
  • 16
  • 149
  • 150
  • It stops at step 2). I typed `make all` and then `make: *** No rule to make target marix_cuda.cu, needed by matrix_cuda.o. Stop.` – pateheo Dec 07 '15 at 09:04
  • @pateheo: Is `matrix_cuda.cu` present in the working directory (the directory you are in)? – Beta Dec 07 '15 at 14:25
1

I want to add some commentary on this Makefile for future reference and better automation :

1. NVCC=nvcc environment variable is superfluous. There is only one compiler for NVIDIA GPUs and you would nonetheless have to change a lot of flags to compile for other architectures like AMD.

  1. -arch=native is better suited if you want to deploy your code on multiple machines with GPUs having different architectures

  2. -dc is the flag for separate compilation. The architecture must be specified before -dc see (with a generic Makefile): https://developer.nvidia.com/blog/separate-compilation-linking-cuda-device-code/

  3. You should add automatic rule to avoid these typos errors :

%.o: %.cu
     nvcc -dc $(CUDAFLAGS) $< -o $@

The Makefile will look for all dependencies ending by .o. If it needs to build one, it looks if it has the corresponding .cu file. I would actually remove the -dc from flags and be explicit here that I want to build object files. $@ is the name of the rule target. $< is the first prerequisite. Only one file at a time can be passed to nvcc with the -dc flag, so here $< is better than $^.

  1. You may add the name of the executable in a variable so that you delete the same executable that you generated (and facilitate name change).

  2. I added a .PHONY rule. This only removes the confusion that happens whenever someone writes a file named clean in the directory. The Makefile can not differenciate between the file and the make clean rule.

CC=g++
CXXFLAGS= -fopenmp -O3 -Wextra -std=c++11
CUDAFLAGS= -std=c++11 -arch=sm_20
LIBS= -lopenblas -lpthread -lcudart -lcublas
LIBDIRS=-L/usr/local/cuda-7.5/lib64
INCDIRS=-I/usr/local/cuda-7.5/include
PROGRAM= test
%.o: %.cu
     nvcc -dc $(CUDAFLAGS) $< -o $@
all: matrix_cuda.o
        $(CC) -o $(PROGRAM) matrix_blas.cpp alg.cpp test.cpp matrix_cuda.o $(LIBDIRS) $(INCDIRS) $(LIBS) $(CXXFLAGS)
.PHONY: clean
clean:
    rm -rf $(PROGRAM) *.o
Dimitri Lesnoff
  • 317
  • 1
  • 14
0

Also your first make rule corresponds to compiling the object file matrix_cuda.o. The all make rule should come first since the first rule in the make file is the one that gets updated first when invoking the command make. GNU Make has great documentation explaining how to make simple to complex makefiles. You can check it out here:

https://www.gnu.org/software/make/manual/make.html.

Also another issue you are going to run into is that in your make recipe for the all rule, you are supposed to be linking together only object files to create the final executable. However you are trying to include matrix_blas.cpp alg.cpp test.cpp in this linking step. Instead of .cpp versions of these files they need to be .o versions (the compiled objects). Make can generate these object files for you. You just need to have a make rule and recipe for each one. For example:

matrix_blas.o: matrix_blas.cpp
    $(CC) $(CXXFLAGS) -c matrix_blas.cpp -o matrix_blas.o
jmc1337
  • 91
  • 1
  • 6