diff --git a/README.md b/README.md index e02351f5..1a848251 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Telegram](https://img.shields.io/badge/telegram-@cclsp-blue.svg)](https://telegram.me/cclsp) [![Gitter](https://img.shields.io/badge/gitter-ccls--project-blue.svg?logo=gitter-white)](https://gitter.im/ccls-project/ccls) -ccls, which originates from [cquery](https://github.com/cquery-project/cquery), is a C/C++/Objective-C language server. +This is a temporary fork of ccls with experimental CUDA support. `ccls` originates from [cquery](https://github.com/cquery-project/cquery), is a C/C++/Objective-C language server. * code completion (with both signature help and snippets) * [definition](src/messages/textDocument_definition.cc)/[references](src/messages/textDocument_references.cc), and other cross references @@ -17,6 +17,26 @@ ccls, which originates from [cquery](https://github.com/cquery-project/cquery), * semantic highlighting and preprocessor skipped regions * semantic navigation: `$ccls/navigate` +## CUDA quickstart + +Your `.ccls` configuration should look something like: +``` +%compile_commands.json +%cu --cuda-gpu-arch=sm_70 +%cu --cuda-path=/usr/local/cuda-9.2/ +``` +This fork changes the compile commands from the `compile_commands.json` file that look like: + + /usr/local/cuda/bin/nvcc -ccbin=gcc-6 -I../src -I../external/cutlass -I../external/cub -isystem=../external/googletest/googletest/include -Xcompiler -fopenmp --expt-extended-lambda --std=c++11 -gencode arch=compute_70,code=sm_70 -gencode arch=compute_70,code=compute_70 -g -x cu -c /home/max/dev/cuml/ml-prims/test/add.cu -o test/CMakeFiles/mlcommon_test.dir/add.cu.o && /usr/local/cuda/bin/nvcc -ccbin=gcc-6 -I../src -I../external/cutlass -I../external/cub -isystem=../external/googletest/googletest/include -Xcompiler -fopenmp --expt-extended-lambda --std=c++11 -gencode arch=compute_70,code=sm_70 -gencode arch=compute_70,code=compute_70 -g -x cu -M /home/max/dev/cuml/ml-prims/test/add.cu -MT test/CMakeFiles/mlcommon_test.dir/add.cu.o -o $DEP_FILE + +To something more like: + + clang -I../src -I../external/cutlass -I../external/cub -isystem=../external/googletest/googletest/include --std=c++11 --cuda-gpu-arch=sm_70 --cuda-path=/usr/local/cuda-9.2/ -c add.cu + +In other words, it whitelists includes (`-I`) and c++ standard flags, but ignores all the `nvcc` switches that `clang` doesn't understand. Note that clang understands CUDA files by default. + +## General Info + It has a global view of the code base and support a lot of cross reference features, see [wiki/FAQ](../../wiki/FAQ). It starts indexing the whole project (including subprojects if exist) parallelly when you open the first file, while the main thread can serve requests before the indexing is complete. Saving files will incrementally update the index. diff --git a/src/lsp.hh b/src/lsp.hh index b92578b8..a818dff9 100644 --- a/src/lsp.hh +++ b/src/lsp.hh @@ -261,6 +261,6 @@ struct ShowMessageParam { // Used to identify the language at a file level. The ordering is important, as // a file previously identified as `C`, will be changed to `Cpp` if it // encounters a c++ declaration. -enum class LanguageId { Unknown = -1, C = 0, Cpp = 1, ObjC = 2, ObjCpp = 3 }; + enum class LanguageId { Unknown = -1, C = 0, Cpp = 1, ObjC = 2, ObjCpp = 3, CUDA = 4 }; } // namespace ccls diff --git a/src/project.cc b/src/project.cc index 10359515..9343301c 100644 --- a/src/project.cc +++ b/src/project.cc @@ -51,6 +51,15 @@ using namespace clang; using namespace llvm; namespace ccls { + +template +auto as_integer(Enumeration const value) + -> typename std::underlying_type::type +{ + return static_cast::type>(value); +} + + std::pair lookupExtension(std::string_view filename) { using namespace clang::driver; auto I = types::lookupTypeForExtension( @@ -59,7 +68,9 @@ std::pair lookupExtension(std::string_view filename) { I == types::TY_ObjCXXHeader; bool objc = types::isObjC(I); LanguageId ret; - if (types::isCXX(I)) + if (I == types::TY_CUDA) + ret = LanguageId::CUDA; + else if (types::isCXX(I)) ret = objc ? LanguageId::ObjCpp : LanguageId::Cpp; else if (objc) ret = LanguageId::ObjC; @@ -123,6 +134,8 @@ struct ProjectProcessor { ok |= lang == LanguageId::ObjC; else if (A.consume_front("%objective-cpp ")) ok |= lang == LanguageId::ObjCpp; + else if (A.consume_front("%cu ")) + ok |= lang == LanguageId::CUDA; else break; } @@ -132,6 +145,7 @@ struct ProjectProcessor { args.push_back(arg); } } + entry.args = args; GetSearchDirs(entry); } @@ -326,6 +340,7 @@ int ComputeGuessScore(std::string_view a, std::string_view b) { } // namespace + void Project::LoadDirectory(const std::string &root, Project::Folder &folder) { SmallString<256> CDBDir, Path, StdinPath; std::string err_msg; @@ -412,11 +427,54 @@ void Project::LoadDirectory(const std::string &root, Project::Folder &folder) { DoPathMapping(entry.filename); std::vector args = std::move(Cmd.CommandLine); - entry.args.reserve(args.size()); - for (std::string &arg : args) { - DoPathMapping(arg); - if (!proc.ExcludesArg(arg)) - entry.args.push_back(Intern(arg)); + + auto [lang, header] = lookupExtension(entry.filename); + + // CMAKE splits nvcc compiles into 2 seperates commands, and has (mostly) non-clang arguments. Replace these with a simple call to clang with only "-I /path/header.h" arguments. + // .ccls will also need: + // clang + // %cu --cuda-gpu-arch=sm_70 --cuda-path=/usr/local/cuda-9.2/ --std=c++11 + if(lang == LanguageId::CUDA) { + entry.args.push_back(Intern("/usr/bin/clang-7")); + // entry.args.push_back(Intern("--cuda-gpu-arch=sm_70")); + // entry.args.push_back(Intern("--cuda-path=/usr/local/cuda-9.2/")); + // entry.args.push_back(Intern("-I/home/max/dev/cuml/thirdparty/cuml/googletest/googletest/include")); + // entry.args.push_back(Intern("--std=c++11")); + entry.args.push_back(Intern("-c")); + entry.args.push_back(Intern(entry.filename)); + LOG_S(INFO) << entry.filename << ": (CUDA) clang-7 -c filename"; + for (std::string &arg : args) { + // take header includes (-I/path/to/header.h) + if((arg.find("-I") != std::string::npos) + ) { + LOG_S(INFO) << entry.filename << ": (CUDA) Adding Arg: " << arg; + entry.args.push_back(Intern(arg)); + } + else if(arg.find("-isystem") != std::string::npos) { + auto equals = arg.find("="); + arg.replace(equals,1," "); + LOG_S(INFO) << entry.filename << ": (CUDA) Adding Arg: " << arg; + entry.args.push_back(Intern(arg)); + } + else if(arg.find("-std=") != std::string::npos) { + LOG_S(INFO) << entry.filename << ": (CUDA) Adding Arg: " << arg; + entry.args.push_back(Intern(arg)); + } + else { + LOG_S(INFO) << entry.filename << ": (CUDA) Ignoring arg: " << arg; + } + } + } + else { + entry.args.reserve(args.size()); + for (std::string &arg : args) { + DoPathMapping(arg); + if (!proc.ExcludesArg(arg)) { + // LOG_S(INFO) << entry.filename << ": Accepted arg: " << arg << + // "\n"; + entry.args.push_back(Intern(arg)); + } + } } entry.compdb_size = entry.args.size();