├── Makefile ├── README.md ├── include └── cuda_kernel.cuh ├── main.cpp └── src └── cuda_kernel.cu /Makefile: -------------------------------------------------------------------------------- 1 | ########################################################### 2 | 3 | ## USER SPECIFIC DIRECTORIES ## 4 | 5 | # CUDA directory: 6 | CUDA_ROOT_DIR=/usr/local/cuda 7 | 8 | ########################################################## 9 | 10 | ## CC COMPILER OPTIONS ## 11 | 12 | # CC compiler options: 13 | CC=g++ 14 | CC_FLAGS= 15 | CC_LIBS= 16 | 17 | ########################################################## 18 | 19 | ## NVCC COMPILER OPTIONS ## 20 | 21 | # NVCC compiler options: 22 | NVCC=nvcc 23 | NVCC_FLAGS= 24 | NVCC_LIBS= 25 | 26 | # CUDA library directory: 27 | CUDA_LIB_DIR= -L$(CUDA_ROOT_DIR)/lib64 28 | # CUDA include directory: 29 | CUDA_INC_DIR= -I$(CUDA_ROOT_DIR)/include 30 | # CUDA linking libraries: 31 | CUDA_LINK_LIBS= -lcudart 32 | 33 | ########################################################## 34 | 35 | ## Project file structure ## 36 | 37 | # Source file directory: 38 | SRC_DIR = src 39 | 40 | # Object file directory: 41 | OBJ_DIR = bin 42 | 43 | # Include header file diretory: 44 | INC_DIR = include 45 | 46 | ########################################################## 47 | 48 | ## Make variables ## 49 | 50 | # Target executable name: 51 | EXE = run_test 52 | 53 | # Object files: 54 | OBJS = $(OBJ_DIR)/main.o $(OBJ_DIR)/cuda_kernel.o 55 | 56 | ########################################################## 57 | 58 | ## Compile ## 59 | 60 | # Link c++ and CUDA compiled object files to target executable: 61 | $(EXE) : $(OBJS) 62 | $(CC) $(CC_FLAGS) $(OBJS) -o $@ $(CUDA_INC_DIR) $(CUDA_LIB_DIR) $(CUDA_LINK_LIBS) 63 | 64 | # Compile main .cpp file to object files: 65 | $(OBJ_DIR)/%.o : %.cpp 66 | $(CC) $(CC_FLAGS) -c $< -o $@ 67 | 68 | # Compile C++ source files to object files: 69 | $(OBJ_DIR)/%.o : $(SRC_DIR)/%.cpp include/%.h 70 | $(CC) $(CC_FLAGS) -c $< -o $@ 71 | 72 | # Compile CUDA source files to object files: 73 | $(OBJ_DIR)/%.o : $(SRC_DIR)/%.cu $(INC_DIR)/%.cuh 74 | $(NVCC) $(NVCC_FLAGS) -c $< -o $@ $(NVCC_LIBS) 75 | 76 | # Clean objects in object directory. 77 | clean: 78 | $(RM) bin/* *.o $(EXE) 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This repo is a sample Makefile for building a project that has both C++ (.cpp and .h) and CUDA (.cu and .cuh) source files. This Makefile assumes a project file structure as the following: 2 | 3 | ``` 4 | |--> Project/ 5 | |--> Makefile 6 | |--> src/ (source files) 7 | |--> include/ (header files) 8 | |--> bin/ 9 | ``` 10 | 11 | For example, you could have multiple .cpp and .cu files in the source directory (src/), multiple .h and .cuh header files in the header directory (include/), and the file with the main() function (titled main.cpp in this example) in the base directory. An example of this could be the following: 12 | 13 | ``` 14 | |--> Project/ 15 | |--> Makefile 16 | |--> main.cpp 17 | |--> src/ 18 | |--> file1.cpp 19 | |--> file2.cpp 20 | |--> file_cuda1.cu 21 | |--> file_cuda2.cu 22 | |--> include/ 23 | |--> file1.h 24 | |--> file2.h 25 | |--> file1.cuh 26 | |--> file2.cuh 27 | |--> bin/ 28 | ``` 29 | 30 | The Makefile in this repo compiles a .cu and .cuh file called cuda_kernel.cu and cuda_kernel.cuh, which contains a simple CUDA device function. The cuda_kernel.cuh header file is included in the main.cpp file and called in the main() function. The Makefile will compile all the CUDA and C++ source files in src/ first, then compile the main.cpp file, and finally link them together. 31 | 32 | To use this Makefile in your own projects, a few parameters may need to be changed. First, the CUDA root directory should be specified for your machine. 33 | 34 | ``` 35 | ########################################################### 36 | 37 | ## USER SPECIFIC DIRECTORIES ## 38 | 39 | # CUDA directory: 40 | CUDA_ROOT_DIR=/usr/local/cuda 41 | 42 | ########################################################## 43 | ``` 44 | 45 | In addition, any changes to compiler options, flags, or alias should be made. 46 | 47 | ``` 48 | ########################################################## 49 | 50 | ## CC COMPILER OPTIONS ## 51 | 52 | # CC compiler options: 53 | CC=g++ 54 | CC_FLAGS= 55 | CC_LIBS= 56 | 57 | ########################################################## 58 | 59 | ## NVCC COMPILER OPTIONS ## 60 | 61 | # NVCC compiler options: 62 | NVCC=nvcc 63 | NVCC_FLAGS= 64 | NVCC_LIBS= 65 | 66 | ########################################################## 67 | ``` 68 | 69 | The project's file structure can be changed if necessary. 70 | 71 | ``` 72 | ########################################################## 73 | 74 | ## Project file structure ## 75 | 76 | # Source file directory: 77 | SRC_DIR = src 78 | 79 | # Object file directory: 80 | OBJ_DIR = bin 81 | 82 | # Include header file diretory: 83 | INC_DIR = include 84 | 85 | ########################################################## 86 | ``` 87 | 88 | Finally, and most important, all of the object files that will be created should be listed in the OBJS variable with a space between each entry. Each source file in your project should be listed here as $(OBJ_DIR)/yourfile.o , these are all of the compiled source files (object files) that will be linked together to create the executable file. 89 | 90 | ``` 91 | ########################################################## 92 | 93 | ## Make variables ## 94 | 95 | # Target executable name: 96 | EXE = run_test 97 | 98 | # Object files: 99 | OBJS = $(OBJ_DIR)/main.o $(OBJ_DIR)/cuda_kernel.o 100 | 101 | ########################################################## 102 | ``` 103 | 104 | Two final notes: 105 | 106 | 1. This Makefile was created on an Linux system and may not work for non-Linux OS. 107 | 108 | 2. You may clone this repository or copy and paste any component of this repository into your projects. I hope it helps. 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /include/cuda_kernel.cuh: -------------------------------------------------------------------------------- 1 | 2 | // List wrapper function callable by .cpp file. 3 | void kernel(double *A, double *B, double *C, int arraySize); 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | // Include C++ header files. 2 | #include 3 | 4 | // Include local CUDA header files. 5 | #include "include/cuda_kernel.cuh" 6 | 7 | 8 | 9 | 10 | int main() { 11 | 12 | // Initialize arrays A, B, and C. 13 | double A[3], B[3], C[3]; 14 | 15 | // Populate arrays A and B. 16 | A[0] = 1; A[1] = 2; A[2] = 3; 17 | B[0] = 1; B[1] = 1; B[2] = 1; 18 | 19 | // Sum array elements across ( C[0] = A[0] + B[0] ) into array C using CUDA. 20 | kernel(A, B, C, 3); 21 | 22 | // Print out result. 23 | std::cout << "C = " << C[0] << ", " << C[1] << ", " << C[2] << std::endl; 24 | 25 | return 0; 26 | } -------------------------------------------------------------------------------- /src/cuda_kernel.cu: -------------------------------------------------------------------------------- 1 | // CUDA libraries. 2 | #include 3 | #include 4 | 5 | // Include associated header file. 6 | #include "../include/cuda_kernel.cuh" 7 | 8 | 9 | 10 | 11 | 12 | /** 13 | * Sample CUDA device function which adds an element from array A and array B. 14 | * 15 | */ 16 | __global__ void cuda_kernel(double *A, double *B, double *C, int arraySize){ 17 | // Get thread ID. 18 | int tid = blockDim.x * blockIdx.x + threadIdx.x; 19 | 20 | // Check if thread is within array bounds. 21 | if ( tid < arraySize ) { 22 | // Add a and b. 23 | C[tid] = A[tid] + B[tid]; 24 | } 25 | } 26 | 27 | 28 | 29 | /** 30 | * Wrapper function for the CUDA kernel function. 31 | * @param A Array A. 32 | * @param B Array B. 33 | * @param C Sum of array elements A and B directly across. 34 | * @param arraySize Size of arrays A, B, and C. 35 | */ 36 | void kernel(double *A, double *B, double *C, int arraySize) { 37 | 38 | // Initialize device pointers. 39 | double *d_A, *d_B, *d_C; 40 | 41 | // Allocate device memory. 42 | cudaMalloc((void**) &d_A, arraySize * sizeof(double)); 43 | cudaMalloc((void**) &d_B, arraySize * sizeof(double)); 44 | cudaMalloc((void**) &d_C, arraySize * sizeof(double)); 45 | 46 | // Transfer arrays a and b to device. 47 | cudaMemcpy(d_A, A, arraySize * sizeof(double), cudaMemcpyHostToDevice); 48 | cudaMemcpy(d_B, B, arraySize * sizeof(double), cudaMemcpyHostToDevice); 49 | 50 | // Calculate blocksize and gridsize. 51 | dim3 blockSize(512, 1, 1); 52 | dim3 gridSize(512 / arraySize + 1, 1); 53 | 54 | // Launch CUDA kernel. 55 | cuda_kernel<<>>(d_A, d_B, d_C, arraySize); 56 | 57 | // Copy result array c back to host memory. 58 | cudaMemcpy(C, d_C, arraySize * sizeof(double), cudaMemcpyDeviceToHost); 59 | } 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | --------------------------------------------------------------------------------