├── .gitignore ├── .travis.yml ├── README.md ├── appveyor.yml ├── doc └── cmake.txt ├── plugin └── cmake.vim └── test ├── .vimrc ├── cmake.vader └── test project ├── CMakeLists.txt ├── configure.h.cmake └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | test/test project/build/ 2 | doc/tags 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: vim 2 | 3 | addons: 4 | apt: 5 | sources: 6 | - ubuntu-toolchain-r-test 7 | - kubuntu-backports 8 | packages: 9 | - g++-4.7 10 | - cmake 11 | 12 | before_script: | 13 | git clone https://github.com/junegunn/vader.vim.git 14 | 15 | script: | 16 | vim -Nu 'test/.vimrc' -c 'Vader! test/cmake.vader' 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vim-cmake 2 | [![Travis (Linux)](https://travis-ci.org/vhdirk/vim-cmake.svg?branch=master)](https://travis-ci.org/vhdirk/vim-cmake) 3 | [![AppVeyor (Windows)](https://ci.appveyor.com/api/projects/status/ns1o9252o2rrmv6g?svg=true)](https://ci.appveyor.com/project/vhdirk/vim-cmake) 4 | 5 | vim-cmake is a Vim plugin to make working with CMake a little nicer. 6 | 7 | I got tired of navigating to the build directory each time, and I also 8 | disliked setting makeprg manually each time. This plugin does just that. 9 | 10 | ## Usage 11 | 12 | ### Commands 13 | 14 | * `:CMake` searches for the closest directory named build in an upwards search, 15 | and whenever one is found, it runs the cmake command there, assuming the CMakeLists.txt 16 | file is just one directory above. Any arguments given to :CMake will be directly passed 17 | on to the cmake command. It also sets the working directory of the make command, so 18 | you can just use quickfix as with a normal Makefile project. 19 | If you have the [AsyncRun plugin](https://github.com/skywind3000/asyncrun.vim) 20 | installed, it will be used automatically and you will be able to check the 21 | result of the cmake command in the quickfix as well. 22 | 23 | * `:CMakeClean` deletes all files in the build directory. You can think of this as a CMake version of make clean. 24 | 25 | * `:CMakeFindBuildDir` resets the build directory path set for the current buffer and then tries to find a new one. Useful if it previously found a wrong path to then reset it after a new build folder has been created for example. 26 | 27 | ### Variables 28 | 29 | * `g:cmake_install_prefix` same as `-DCMAKE_INSTALL_PREFIX` 30 | 31 | * `g:cmake_build_type` same as `-DCMAKE_BUILD_TYPE` 32 | 33 | * `g:cmake_cxx_compiler` same as `-DCMAKE_CXX_COMPILER`. Changes will have no effect until you run :CMakeClean and then :CMake. 34 | 35 | * `g:cmake_c_compiler` same as `-DCMAKE_C_COMPILER`. Changes will have no effect until you run :CMakeClean and then :CMake. 36 | 37 | * `g:cmake_build_shared_libs` same as `-DBUILD_SHARED_LIBS` 38 | 39 | * `g:cmake_toolchain_file` same as `-DCMAKE_TOOLCHAIN_FILE` 40 | 41 | * `g:cmake_project_generator` same as `-G`. Changes will have no effect until you run :CMakeClean and then :CMake. 42 | 43 | * `g:cmake_export_compile_commands` same as `-DCMAKE_EXPORT_COMPILE_COMMANDS`. 44 | 45 | * `g:cmake_ycm_symlinks` create symlinks to the generated compilation database for use with [YouCompleteMe](https://github.com/Valloric/YouCompleteMe/). 46 | 47 | * `b:build_dir` is the path to the cmake build directory for the current buffer. This variable is set with the first :CMake or :CMakeFindBuildDir call. Once found, it will not be searched for again unless you call :CMakeFindBuildDir. If automatic finding is not sufficient you can set this variable manually to the build dir of your choice. 48 | 49 | 50 | ## Installation 51 | 52 | 53 | ### Vim-pathogen 54 | 55 | With [pathogen.vim](https://github.com/tpope/vim-pathogen) simply copy and paste: 56 | 57 | cd ~/.vim/bundle 58 | git clone git://github.com/vhdirk/vim-cmake.git 59 | 60 | Once help tags have been generated, you can view the manual with 61 | `:help cmake`. 62 | 63 | ### Vundle 64 | 65 | With [Vundle.vim](https://github.com/VundleVim/Vundle.vim) simply add this repository to your plugins list: 66 | 67 | Plugin 'vhdirk/vim-cmake' 68 | 69 | ## Acknowledgements 70 | 71 | * Thanks to [Tim Pope](http://tpo.pe/), his plugins are really awesome. 72 | * Thanks to [Junegunn Choi](https://junegunn.kr/), for [vader.vim](https://github.com/junegunn/vader.vim), which is the testing framework used for this plugin. 73 | * Also thanks to 74 | * @SteveDeFacto for extending this with more fine grained control. 75 | * @snikulov for enhancing makeprg. 76 | * @dapicester for allowing specifying targets. 77 | * @thomasgubler for the build dir option. 78 | * @antmd for fixing a bug with handing of spaces in directory names. 79 | * @jmirabel for fixing concatenation of cmake arguments. 80 | * @T4ng10r for the project generator option. 81 | * @Squareys for a small overhaul of the project, the initial test and travis setup. 82 | 83 | ## License 84 | 85 | Copyright (c) Dirk Van Haerenborgh, @SteveDeFacto. Distributed under the same terms as Vim itself. 86 | See `:help license`. 87 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | os: Visual Studio 2015 2 | 3 | install: 4 | - cinst vim 5 | - cinst cmake 6 | - set PATH=%PATH%;C:\Program Files\CMake\bin 7 | - git clone https://github.com/junegunn/vader.vim 8 | 9 | build_script: 10 | - vim -Nu test/.vimrc -c 'Vader! test/cmake.vader' --not-a-term 11 | -------------------------------------------------------------------------------- /doc/cmake.txt: -------------------------------------------------------------------------------- 1 | *cmake.txt* Vim plugin to make working with CMake a little nicer 2 | 3 | Authors: Dirk Van Haerenborgh 4 | Steven Batchelor 5 | Jonathan Hale 6 | License: Same terms as Vim itself (see |license|) 7 | 8 | 9 | INTRODUCTION *cmake* 10 | 11 | When working on a CMake project, this plugin provides a single command that 12 | changes the makeprg make command's working directory to the closest 'build' 13 | directory (see g:cmake_build_dir) upwards 14 | 15 | COMMANDS *cmake-commands* 16 | 17 | :CMake [args] Runs the cmake command as 'cmake ..', starting in 18 | first directory called 'build', found in an upwards 19 | search. All arguments are directly passed on to CMake. 20 | Also modifies the :make command to build in 21 | that directory. 22 | 23 | :CMakeClean deletes all files in the build directory. You can 24 | think of this as a CMake version of make clean. 25 | 26 | :CMakeFindBuildDir resets the build directory path set for the current buffer 27 | and then tries to find a new one. Useful if it previously 28 | found a wrong path to then reset it after a new build folder 29 | has been created for example. 30 | 31 | VARIABLES *cmake-variables* 32 | 33 | g:cmake_install_prefix same as -DCMAKE_INSTALL_PREFIX 34 | 35 | g:cmake_build_type same as -DCMAKE_BUILD_TYPE 36 | 37 | g:cmake_cxx_compiler same as -DCMAKE_CXX_COMPILER, however, this will have 38 | no effect until you run :CMakeClean and :CMake. 39 | 40 | g:cmake_c_compiler same as -DCMAKE_C_COMPILER, however, this will have 41 | no effect until you run :CMakeClean and :CMake. 42 | 43 | g:cmake_build_shared_libs same as -DBUILD_SHARED_LIBS 44 | 45 | g:cmake_toolchain_file same as -DCMAKE_TOOLCHAIN_FILE 46 | 47 | g:cmake_build_dir set the cmake 'build' directory, default: 'build' 48 | 49 | g:cmake_project_generator set project generator, however, this will have 50 | no effect until you run :CMakeClean and :CMake. 51 | 52 | g:cmake_usr_args custom user arguments. Ex: 'let g:cmake_usr_args="-DDEBUG=YES"' 53 | 54 | b:build_dir the path to the cmake build directory for the current buffer. 55 | This variable is set with the first :CMake or :CMakeFindBuildDir call. 56 | Once found, it will not be searched for again unless you call 57 | :CMakeFindBuildDir. If automatic finding is not sufficient you can set 58 | this variable manually to the build dir of your choice. 59 | 60 | OPTIONS *cmake-options* 61 | 62 | g:cmake_export_compile_commands same as -DCMAKE_EXPORT_COMPILE_COMMANDS=ON, useful for 63 | exporting a compilation database to be used with YCM 64 | (https://github.com/Valloric/YouCompleteMe#c-family-semantic-completion) 65 | CMake only supports this flag with Ninja and Makefile generators. 66 | 67 | g:cmake_ycm_symlinks create a symlink to the compile_commands.json file in the 68 | root of the project (build/..) if the file is found. 69 | 70 | -------------------------------------------------------------------------------- /plugin/cmake.vim: -------------------------------------------------------------------------------- 1 | " cmake.vim - Vim plugin to make working with CMake a little nicer 2 | " Maintainer: Dirk Van Haerenborgh 3 | " Version: 0.2 4 | 5 | let s:cmake_plugin_version = '0.2' 6 | 7 | if exists("loaded_cmake_plugin") 8 | finish 9 | endif 10 | 11 | " We set this variable here even though the plugin may not actually be loaded 12 | " because the executable is not found. Otherwise the error message will be 13 | " displayed more than once. 14 | let loaded_cmake_plugin = 1 15 | 16 | " Set option defaults 17 | if !exists("g:cmake_export_compile_commands") 18 | let g:cmake_export_compile_commands = 0 19 | endif 20 | if !exists("g:cmake_ycm_symlinks") 21 | let g:cmake_ycm_symlinks = 0 22 | endif 23 | if !exists("g:cmake_use_smp") 24 | let g:cmake_use_smp = 0 25 | endif 26 | 27 | if !executable("cmake") 28 | echoerr "vim-cmake requires cmake executable. Please make sure it is installed and on PATH." 29 | finish 30 | endif 31 | 32 | function! s:find_build_dir() 33 | " Do not overwrite already found build_dir, may be set explicitly 34 | " by user. 35 | if exists("b:build_dir") && b:build_dir != "" 36 | return 1 37 | endif 38 | 39 | let g:cmake_build_dir = get(g:, 'cmake_build_dir', 'build') 40 | let b:build_dir = finddir(g:cmake_build_dir, ';') 41 | 42 | if b:build_dir == "" 43 | " Find build directory in path of current file 44 | let b:build_dir = finddir(g:cmake_build_dir, s:fnameescape(expand("%:p:h")) . ';') 45 | endif 46 | 47 | if b:build_dir != "" 48 | " expand() would expand "" to working directory, but we need 49 | " this as an indicator that build was not found 50 | let b:build_dir = fnamemodify(b:build_dir, ':p') 51 | echom "Found cmake build directory: " . s:fnameescape(b:build_dir) 52 | return 1 53 | else 54 | echom "Unable to find cmake build directory." 55 | return 0 56 | endif 57 | 58 | endfunction 59 | 60 | " Configure the cmake project in the currently set build dir. 61 | " 62 | " This will override any of the following variables if the 63 | " corresponding vim variable is set: 64 | " * CMAKE_INSTALL_PREFIX 65 | " * CMAKE_BUILD_TYPE 66 | " * CMAKE_BUILD_SHARED_LIBS 67 | " If the project is not configured already, the following variables will be set 68 | " whenever the corresponding vim variable for the following is set: 69 | " * CMAKE_CXX_COMPILER 70 | " * CMAKE_C_COMPILER 71 | " * The generator (-G) 72 | function! s:cmake_configure(cmake_vim_command_args) 73 | exec 'cd' s:fnameescape(b:build_dir) 74 | 75 | let l:argument = [] 76 | " Only change values of variables, if project is not configured 77 | " already, otherwise we overwrite existing configuration. 78 | let l:configured = filereadable("CMakeCache.txt") 79 | 80 | if !l:configured 81 | if exists("g:cmake_project_generator") 82 | let l:argument += [ "-G \"" . g:cmake_project_generator . "\"" ] 83 | endif 84 | if exists("g:cmake_cxx_compiler") 85 | let l:argument += [ "-DCMAKE_CXX_COMPILER:FILEPATH=" . g:cmake_cxx_compiler ] 86 | endif 87 | if exists("g:cmake_c_compiler") 88 | let l:argument += [ "-DCMAKE_C_COMPILER:FILEPATH=" . g:cmake_c_compiler ] 89 | endif 90 | 91 | if exists("g:cmake_usr_args") 92 | let l:argument+= [ g:cmake_usr_args ] 93 | endif 94 | endif 95 | 96 | if exists("g:cmake_install_prefix") 97 | let l:argument += [ "-DCMAKE_INSTALL_PREFIX:FILEPATH=" . g:cmake_install_prefix ] 98 | endif 99 | if exists("g:cmake_build_type" ) 100 | let l:argument += [ "-DCMAKE_BUILD_TYPE:STRING=" . g:cmake_build_type ] 101 | endif 102 | if exists("g:cmake_build_shared_libs") 103 | let l:argument += [ "-DBUILD_SHARED_LIBS:BOOL=" . g:cmake_build_shared_libs ] 104 | endif 105 | if exists("g:cmake_toolchain_file") 106 | let l:argument += [ "-DCMAKE_TOOLCHAIN_FILE:FILEPATH=" . g:cmake_toolchain_file ] 107 | endif 108 | if g:cmake_export_compile_commands 109 | let l:argument += [ "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON" ] 110 | endif 111 | 112 | let l:argumentstr = join(l:argument, " ") 113 | let l:escaped_build_dir=s:fnameescape(b:build_dir) 114 | let l:home_dir = "-H".l:escaped_build_dir."/.." 115 | let l:build_dir_path = "-B".l:escaped_build_dir 116 | let s:cmd = 'cmake '.l:home_dir.' '.l:build_dir_path.' '.l:argumentstr . " " . join(a:cmake_vim_command_args) 117 | 118 | echo s:cmd 119 | if exists(":AsyncRun") 120 | execute 'copen' 121 | execute 'AsyncRun ' . s:cmd 122 | execute 'wincmd p' 123 | else 124 | silent let s:res = system(s:cmd) 125 | silent echo s:res 126 | endif 127 | 128 | " Create symbolic link to compilation database for use with YouCompleteMe 129 | if g:cmake_ycm_symlinks && filereadable("compile_commands.json") 130 | if has("win32") 131 | exec "mklink" "../compile_commands.json" "compile_commands.json" 132 | else 133 | silent echo system("ln -s " . s:fnameescape(b:build_dir) ."/compile_commands.json ../compile_commands.json") 134 | endif 135 | echom "Created symlink to compilation database" 136 | endif 137 | 138 | exec 'cd -' 139 | endfunction 140 | 141 | " Utility function 142 | " Thanks to tpope/vim-fugitive 143 | function! s:fnameescape(file) abort 144 | if exists('*fnameescape') 145 | return fnameescape(a:file) 146 | else 147 | return escape(a:file," \t\n*?[{`$\\%#'\"|!<") 148 | endif 149 | endfunction 150 | 151 | function! s:find_smp() 152 | if executable('nproc') 153 | let l:nproc = system('nproc') 154 | let b:smp = '-j' . substitute(l:nproc, '\n\+$', '', '') 155 | return 1 156 | endif 157 | return 0 158 | endfunction 159 | 160 | command! -complete=customlist,ListTargets -nargs=1 Make :make 161 | function! ListTargets(A, L, C) 162 | if !exists("b:build_dir") 163 | return [] 164 | endif 165 | let all_targets = split(system("cmake --build ". b:build_dir . " --target help | awk ' NR > 1 {print $2}'"), '\n') 166 | let targets = filter(all_targets, "v:val =~ '^" .. a:A .. "'") 167 | return targets 168 | endfunction 169 | 170 | " Public Interface: 171 | command! -nargs=? CMake call s:cmake() 172 | command! CMakeClean call s:cmakeclean() 173 | command! CMakeFindBuildDir call s:cmake_find_build_dir() 174 | 175 | function! s:cmake_find_build_dir() 176 | unlet! b:build_dir 177 | call s:find_build_dir() 178 | endfunction 179 | 180 | function! s:cmake(...) 181 | if !s:find_build_dir() 182 | return 183 | endif 184 | 185 | if g:cmake_use_smp && s:find_smp() 186 | let l:smp = ' ' . shellescape(b:smp) 187 | else 188 | let l:smp = '' 189 | endif 190 | 191 | let &makeprg = 'cmake --build ' . shellescape(b:build_dir) . l:smp . ' --target' 192 | call s:cmake_configure(a:000) 193 | endfunction 194 | 195 | function! s:cmakeclean() 196 | if !s:find_build_dir() 197 | return 198 | endif 199 | 200 | silent echo system("rm -r '" . b:build_dir. "'/*") 201 | echom "Build directory has been cleaned." 202 | endfunction 203 | 204 | -------------------------------------------------------------------------------- /test/.vimrc: -------------------------------------------------------------------------------- 1 | filetype off 2 | 3 | set rtp+=vader.vim 4 | set rtp+=. 5 | filetype plugin indent on 6 | syntax enable 7 | 8 | -------------------------------------------------------------------------------- /test/cmake.vader: -------------------------------------------------------------------------------- 1 | Before: 2 | " Ensure we are in the test directory 3 | if isdirectory("test") 4 | cd test 5 | endif 6 | 7 | if !exists("test_dir") 8 | let test_dir = fnamemodify(getcwd(), ':p') 9 | endif 10 | 11 | Assert !isdirectory("test project/tmp-build"), "TEST ERROR: build directory was not properly deleted" 12 | echo system("mkdir 'test project/tmp-build'") 13 | Assert isdirectory("test project/tmp-build"), "TEST ERROR: build directory was not created" 14 | 15 | " Under travis CI the entire project is in a build/ directory 16 | " which will make the search from cwd always return a result. 17 | " To be able to test searching build dir from current file, the 18 | " build dir needs to be named differently as a workaround. 19 | let g:cmake_build_dir = "tmp-build" 20 | After: 21 | exec "cd" fnameescape(test_dir) 22 | echo system("rm -rf 'test project/tmp-build'") 23 | echo system("rm -f 'test project/compile_commands.json'") 24 | 25 | Execute (Find build directory from working dir): 26 | cd test\ project 27 | CMake 28 | 29 | Assert filereadable("tmp-build/CMakeCache.txt"), "CMakeCache.txt should be generated" 30 | Assert !filereadable("tmp-build/compile_commands.json"), "Compile commands should not be exported by default" 31 | 32 | Execute (Find build directory from currently open file): 33 | e test\ project/CMakeLists.txt 34 | CMake 35 | Assert filereadable("test project/tmp-build/CMakeCache.txt"), "CMakeCache.txt should be generated" 36 | 37 | Execute (Create symlink to compilation database): 38 | let g:cmake_export_compile_commands = 1 39 | let g:cmake_ycm_symlinks = 1 40 | cd test\ project 41 | CMake 42 | 43 | " Exporting compile commands does not work with Visual Studio generator 44 | if !has("win32") && !has("win32unix") 45 | Assert filereadable("tmp-build/compile_commands.json"), "Compile commands should be exported" 46 | Assert filereadable(resolve("compile_commands.json")), "A symlink should be generated" 47 | endif 48 | 49 | Execute (Open already configured cmake project): 50 | cd test\ project/tmp-build 51 | silent !cmake .. -DWITH_BYE=ON 52 | e ../CMakeLists.txt 53 | CMake 54 | silent make 55 | 56 | enew 57 | if has("win32") || has("win32unix") 58 | read !Debug/hello.exe 59 | else 60 | read !./hello 61 | endif 62 | Expect: 63 | 64 | Hello World 65 | Bye World 66 | -------------------------------------------------------------------------------- /test/test project/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.12) 2 | 3 | project(HelloWorld) 4 | 5 | option(WITH_BYE "Print bye world" OFF) 6 | 7 | configure_file(configure.h.cmake configure.h) 8 | add_executable(hello main.cpp) 9 | target_include_directories(hello PRIVATE ${CMAKE_BINARY_DIR}) 10 | -------------------------------------------------------------------------------- /test/test project/configure.h.cmake: -------------------------------------------------------------------------------- 1 | #cmakedefine WITH_BYE 2 | -------------------------------------------------------------------------------- /test/test project/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "configure.h" 3 | 4 | int main() { 5 | std::cout << "Hello World" << std::endl; 6 | #ifdef WITH_BYE 7 | std::cout << "Bye World" << std::endl; 8 | #endif 9 | return 0; 10 | } 11 | --------------------------------------------------------------------------------