diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1954172
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+test/test project/build/
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..f85420c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,16 @@
+language: vim
+
+addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ - kubuntu-backports
+ packages:
+ - g++-4.7
+ - cmake
+
+before_script: |
+ git clone https://github.com/junegunn/vader.vim.git
+
+script: |
+ vim -Nu 'test/.vimrc' -c 'Vader! test/cmake.vader'
diff --git a/README.md b/README.md
index 705e505..164523d 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,11 @@
# vim-cmake
+[](https://travis-ci.org/Squareys/vim-cmake)
+[](https://ci.appveyor.com/project/Squareys/vim-cmake)
vim-cmake is a Vim plugin to make working with CMake a little nicer.
-I got tired of navitating to the build directory each time, and I also
-disliked setting makeprg manually each time. This plugin does just that.
+I got tired of navigating to the build directory each time, and I also
+disliked setting makeprg manually each time. This plugin does just that.
## Usage
@@ -12,7 +14,7 @@ disliked setting makeprg manually each time. This plugin does just that.
* `:CMake` searches for the closest directory named build in an upwards search,
and whenever one is found, it runs the cmake command there, assuming the CMakeLists.txt
file is just one directory above. Any arguments given to :CMake will be directly passed
-on to the cmake command. It also sets the working directory of the make command, so
+on to the cmake command. It also sets the working directory of the make command, so
you can just use quickfix as with a normal Makefile project.
If you have the [AsyncRun plugin](https://github.com/skywind3000/asyncrun.vim)
installed, it will be used automatically and you will be able to check the
@@ -20,24 +22,35 @@ result of the cmake command in the quickfix as well.
* `:CMakeClean` deletes all files in the build directory. You can think of this as a CMake version of make clean.
+ * `: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.
+
### Variables
* `g:cmake_install_prefix` same as `-DCMAKE_INSTALL_PREFIX`
* `g:cmake_build_type` same as `-DCMAKE_BUILD_TYPE`
- * `g:cmake_cxx_compiler` same as `-DCMAKE_CXX_COMPILER`. The build directory will be cleared the next time you run :CMake.
+ * `g:cmake_cxx_compiler` same as `-DCMAKE_CXX_COMPILER`. Changes will have no effect until you run :CMakeClean and then :CMake.
- * `g:cmake_c_compiler` same as `-DCMAKE_C_COMPILER`. The build directory will be cleared the next time you run :CMake.
+ * `g:cmake_c_compiler` same as `-DCMAKE_C_COMPILER`. Changes will have no effect until you run :CMakeClean and then :CMake.
* `g:cmake_build_shared_libs` same as `-DBUILD_SHARED_LIBS`
+ * `g:cmake_project_generator` same as `-G`. Changes will have no effect until you run :CMakeClean and then :CMake.
+
+ * `g:cmake_export_compile_commands` same as `-DCMAKE_EXPORT_COMPILE_COMMANDS`.
+
+ * `g:cmake_ycm_symlinks` create symlinks to the generated compilation database for use with [YouCompleteMe](https://github.com/Valloric/YouCompleteMe/).
+
+ * `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.
+
## Installation
-If you don't have a preferred installation method, I recommend
-installing [pathogen.vim](https://github.com/tpope/vim-pathogen), and
-then simply copy and paste:
+
+### Vim-pathogen
+
+With [pathogen.vim](https://github.com/tpope/vim-pathogen) simply copy and paste:
cd ~/.vim/bundle
git clone git://github.com/vhdirk/vim-cmake.git
@@ -45,13 +58,25 @@ then simply copy and paste:
Once help tags have been generated, you can view the manual with
`:help cmake`.
+### Vundle
+With [Vundle.vim](https://github.com/VundleVim/Vundle.vim) simply add this repository to your plugins list:
+
+ Plugin 'vhdirk/vim-cmake'
## Acknowledgements
* Thanks to [Tim Pope](http://tpo.pe/), his plugins are really awesome.
- * Thanks to @SteveDeFacto for extending this with more fine grained control.
-
+ * 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.
+ * Also thanks to
+ * @SteveDeFacto for extending this with more fine grained control.
+ * @snikulov for enhancing makeprg.
+ * @dapicester for allowing specifying targets.
+ * @thomasgubler for the build dir option.
+ * @antmd for fixing a bug with handing of spaces in directory names.
+ * @jmirabel for fixing concatenation of cmake arguments.
+ * @T4ng10r for the project generator option.
+ * @Squareys for a small overhaul of the project, the initial test and travis setup.
## License
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000..7afdcd7
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,10 @@
+os: Visual Studio 2015
+
+install:
+ - cinst vim
+ - cinst cmake
+ - set PATH=%PATH%;C:\Program Files\CMake\bin
+ - git clone https://github.com/junegunn/vader.vim
+
+build_script:
+ - vim -Nu test/.vimrc -c 'Vader! test/cmake.vader' --not-a-term
diff --git a/doc/cmake.txt b/doc/cmake.txt
index e0868ef..bf86847 100644
--- a/doc/cmake.txt
+++ b/doc/cmake.txt
@@ -2,6 +2,7 @@
Authors: Dirk Van Haerenborgh
Steven Batchelor
+ Jonathan Hale
License: Same terms as Vim itself (see |license|)
@@ -19,8 +20,13 @@ COMMANDS *cmake-commands*
Also modifies the :make command to build in
that directory.
-:CMakeClean deletes all files in the build directory. You can
- think of this as a CMake version of make clean.
+:CMakeClean deletes all files in the build directory. You can
+ think of this as a CMake version of make clean.
+
+: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.
VARIABLES *cmake-variables*
@@ -28,18 +34,34 @@ g:cmake_install_prefix same as -DCMAKE_INSTALL_PREFIX
g:cmake_build_type same as -DCMAKE_BUILD_TYPE
-g:cmake_cxx_compiler same as -DCMAKE_CXX_COMPILER, however, do note that
- the build directory will be cleared the next time you
- run :CMake.
+g:cmake_cxx_compiler same as -DCMAKE_CXX_COMPILER, however, this will have
+ no effect until you run :CMakeClean and :CMake.
-g:cmake_c_compiler same as -DCMAKE_C_COMPILER, however, do note that the
- build directory will be cleared the next time you
- run :CMake.
+g:cmake_c_compiler same as -DCMAKE_C_COMPILER, however, this will have
+ no effect until you run :CMakeClean and :CMake.
g:cmake_build_shared_libs same as -DBUILD_SHARED_LIBS
g:cmake_build_dir set the cmake 'build' directory, default: 'build'
-g:cmake_project_generator set project generator
+g:cmake_project_generator set project generator, however, this will have
+ no effect until you run :CMakeClean and :CMake.
g:cmake_usr_args custom user arguments. Ex: 'let g:cmake_usr_args="-DDEBUG=YES"'
+
+b:build_dir 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.
+
+OPTIONS *cmake-options*
+
+g:cmake_export_compile_commands same as -DCMAKE_EXPORT_COMPILE_COMMANDS=ON, useful for
+ exporting a compilation database to be used with YCM
+ (https://github.com/Valloric/YouCompleteMe#c-family-semantic-completion)
+ CMake only supports this flag with Ninja and Makefile generators.
+
+g:cmake_ycm_symlinks create a symlink to the compile_commands.json file in the
+ root of the project (build/..) if the file is found.
+
diff --git a/plugin/cmake.vim b/plugin/cmake.vim
index 3d33cf0..998fb20 100644
--- a/plugin/cmake.vim
+++ b/plugin/cmake.vim
@@ -7,97 +7,156 @@ let s:cmake_plugin_version = '0.2'
if exists("loaded_cmake_plugin")
finish
endif
+
+" We set this variable here even though the plugin may not actually be loaded
+" because the executable is not found. Otherwise the error message will be
+" displayed more than once.
let loaded_cmake_plugin = 1
-" Utility function
-" Thanks to tpope/vim-fugitive
-function! s:fnameescape(file) abort
- if exists('*fnameescape')
- return fnameescape(a:file)
- else
- return escape(a:file," \t\n*?[{`$\\%#'\"|!<")
- endif
-endfunction
+" Set option defaults
+if !exists("g:cmake_export_compile_commands")
+ let g:cmake_export_compile_commands = 0
+endif
+if !exists("g:cmake_ycm_symlinks")
+ let g:cmake_ycm_symlinks = 0
+endif
-" Public Interface:
-command! -nargs=? CMake call s:cmake()
-command! CMakeClean call s:cmakeclean()
+if !executable("cmake")
+ echoerr "vim-cmake requires cmake executable. Please make sure it is installed and on PATH."
+ finish
+endif
-function! s:cmake(...)
+function! s:find_build_dir()
+ " Do not overwrite already found build_dir, may be set explicitly
+ " by user.
+ if exists("b:build_dir") && b:build_dir != ""
+ return 1
+ endif
let g:cmake_build_dir = get(g:, 'cmake_build_dir', 'build')
- let s:build_dir = finddir(g:cmake_build_dir, '.;')
+ let b:build_dir = finddir(g:cmake_build_dir, ';')
- if s:build_dir == ""
- echo g:cmake_build_dir
- silent call mkdir(g:cmake_build_dir, 'p')
- let s:build_dir = finddir(g:cmake_build_dir, '.;')
+ if b:build_dir == ""
+ " Find build directory in path of current file
+ let b:build_dir = finddir(g:cmake_build_dir, s:fnameescape(expand("%:p:h")) . ';')
endif
- if s:build_dir != ""
- let &makeprg='cmake --build ' . shellescape(s:build_dir) . ' --target '
+ if b:build_dir != ""
+ " expand() would expand "" to working directory, but we need
+ " this as an indicator that build was not found
+ let b:build_dir = fnamemodify(b:build_dir, ':p')
+ echom "Found cmake build directory: " . s:fnameescape(b:build_dir)
+ return 1
+ else
+ echom "Unable to find cmake build directory."
+ return 0
+ endif
- exec 'cd' s:fnameescape(s:build_dir)
+endfunction
- let s:cleanbuild = 0
- let l:argument=[]
+" Configure the cmake project in the currently set build dir.
+"
+" This will override any of the following variables if the
+" corresponding vim variable is set:
+" * CMAKE_INSTALL_PREFIX
+" * CMAKE_BUILD_TYPE
+" * CMAKE_BUILD_SHARED_LIBS
+" If the project is not configured already, the following variables will be set
+" whenever the corresponding vim variable for the following is set:
+" * CMAKE_CXX_COMPILER
+" * CMAKE_C_COMPILER
+" * The generator (-G)
+function! s:cmake_configure()
+ exec 'cd' s:fnameescape(b:build_dir)
+
+ let l:argument = []
+ " Only change values of variables, if project is not configured
+ " already, otherwise we overwrite existing configuration.
+ let l:configured = filereadable("CMakeCache.txt")
+
+ if !l:configured
if exists("g:cmake_project_generator")
- let l:argument+= [ "-G \"" . g:cmake_project_generator . "\"" ]
- endif
- if exists("g:cmake_install_prefix")
- let l:argument+= [ "-DCMAKE_INSTALL_PREFIX:FILEPATH=" . g:cmake_install_prefix ]
- endif
- if exists("g:cmake_build_type" )
- let l:argument+= [ "-DCMAKE_BUILD_TYPE:STRING=" . g:cmake_build_type ]
+ let l:argument += [ "-G \"" . g:cmake_project_generator . "\"" ]
endif
if exists("g:cmake_cxx_compiler")
- let l:argument+= [ "-DCMAKE_CXX_COMPILER:FILEPATH=" . g:cmake_cxx_compiler ]
- let s:cleanbuild = 1
+ let l:argument += [ "-DCMAKE_CXX_COMPILER:FILEPATH=" . g:cmake_cxx_compiler ]
endif
if exists("g:cmake_c_compiler")
- let l:argument+= [ "-DCMAKE_C_COMPILER:FILEPATH=" . g:cmake_c_compiler ]
- let s:cleanbuild = 1
- endif
- if exists("g:cmake_build_shared_libs")
- let l:argument+= [ "-DBUILD_SHARED_LIBS:BOOL=" . g:cmake_build_shared_libs ]
+ let l:argument += [ "-DCMAKE_C_COMPILER:FILEPATH=" . g:cmake_c_compiler ]
endif
+
if exists("g:cmake_usr_args")
let l:argument+= [ g:cmake_usr_args ]
endif
- let l:argumentstr = join(l:argument, " ")
+ if exists("g:cmake_install_prefix")
+ let l:argument += [ "-DCMAKE_INSTALL_PREFIX:FILEPATH=" . g:cmake_install_prefix ]
+ endif
+ if exists("g:cmake_build_type" )
+ let l:argument += [ "-DCMAKE_BUILD_TYPE:STRING=" . g:cmake_build_type ]
+ endif
+ if exists("g:cmake_build_shared_libs")
+ let l:argument += [ "-DBUILD_SHARED_LIBS:BOOL=" . g:cmake_build_shared_libs ]
+ endif
+ if g:cmake_export_compile_commands
+ let l:argument += [ "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON" ]
+ endif
- if s:cleanbuild > 0
- echo system("rm -r *" )
- endif
+ let l:argumentstr = join(l:argument, " ")
- let s:cmd = 'cmake '. l:argumentstr . " " . join(a:000) .' .. '
- echo s:cmd
- if exists(":AsyncRun")
- execute 'copen'
- execute 'AsyncRun ' . s:cmd
- execute 'wincmd p'
+ let s:cmd = 'cmake .. '. l:argumentstr . " " . join(a:000)
+ echo s:cmd
+ silent let s:res = system(s:cmd)
+ silent echo s:res
+
+ " Create symbolic link to compilation database for use with YouCompleteMe
+ if g:cmake_ycm_symlinks && filereadable("compile_commands.json")
+ if has("win32")
+ exec "mklink" "../compile_commands.json" "compile_commands.json"
else
- let s:res = system(s:cmd)
- echo s:res
+ silent echo system("ln -s " . s:fnameescape(b:build_dir) ."/compile_commands.json ../compile_commands.json")
endif
+ echom "Created symlink to compilation database"
+ endif
- exec 'cd - '
+ exec 'cd -'
+endfunction
+" Utility function
+" Thanks to tpope/vim-fugitive
+function! s:fnameescape(file) abort
+ if exists('*fnameescape')
+ return fnameescape(a:file)
else
- echo "Unable to find build directory."
+ return escape(a:file," \t\n*?[{`$\\%#'\"|!<")
endif
+endfunction
+" Public Interface:
+command! -nargs=? CMake call s:cmake()
+command! CMakeClean call s:cmakeclean()
+command! CMakeFindBuildDir call s:cmake_find_build_dir()
+
+function! s:cmake_find_build_dir()
+ unlet b:build_dir
+ call s:find_build_dir()
endfunction
-function! s:cmakeclean()
+function! s:cmake(...)
+ if !s:find_build_dir()
+ return
+ endif
- let s:build_dir = finddir('build', '.;')
- if s:build_dir !=""
- echo system("rm -r '" . s:build_dir. "'/*" )
- echo "Build directory has been cleaned."
- else
- echo "Unable to find build directory."
+ let &makeprg = 'cmake --build ' . shellescape(b:build_dir) . ' --target'
+ call s:cmake_configure()
+endfunction
+
+function! s:cmakeclean()
+ if !s:find_build_dir()
+ return
endif
+ silent echo system("rm -r '" . b:build_dir. "'/*")
+ echom "Build directory has been cleaned."
endfunction
+
diff --git a/test/.vimrc b/test/.vimrc
new file mode 100644
index 0000000..4113900
--- /dev/null
+++ b/test/.vimrc
@@ -0,0 +1,7 @@
+filetype off
+
+set rtp+=vader.vim
+set rtp+=.
+filetype plugin indent on
+syntax enable
+
diff --git a/test/cmake.vader b/test/cmake.vader
new file mode 100644
index 0000000..a18ee77
--- /dev/null
+++ b/test/cmake.vader
@@ -0,0 +1,65 @@
+Before:
+ " Ensure we are in the test directory
+ if isdirectory("test")
+ cd test
+ endif
+
+ if !exists("test_dir")
+ let test_dir = fnamemodify(getcwd(), ':p')
+ endif
+
+ Assert !isdirectory("test project/tmp-build"), "TEST ERROR: build directory was not properly deleted"
+ echo system("mkdir 'test project/tmp-build'")
+ Assert isdirectory("test project/tmp-build"), "TEST ERROR: build directory was not created"
+
+ " Under travis CI the entire project is in a build/ directory
+ " which will make the search from cwd always return a result.
+ " To be able to test searching build dir from current file, the
+ " build dir needs to be named differently as a workaround.
+ let g:cmake_build_dir = "tmp-build"
+After:
+ exec "cd" fnameescape(test_dir)
+ echo system("rm -rf 'test project/tmp-build'")
+ echo system("rm -f 'test project/compile_commands.json'")
+
+Execute (Find build directory from working dir):
+ cd test\ project
+ CMake
+
+ Assert filereadable("tmp-build/CMakeCache.txt"), "CMakeCache.txt should be generated"
+ Assert !filereadable("tmp-build/compile_commands.json"), "Compile commands should not be exported by default"
+
+Execute (Find build directory from currently open file):
+ e test\ project/CMakeLists.txt
+ CMake
+ Assert filereadable("test project/tmp-build/CMakeCache.txt"), "CMakeCache.txt should be generated"
+
+Execute (Create symlink to compilation database):
+ let g:cmake_export_compile_commands = 1
+ let g:cmake_ycm_symlinks = 1
+ cd test\ project
+ CMake
+
+ " Exporting compile commands does not work with Visual Studio generator
+ if !has("win32") && !has("win32unix")
+ Assert filereadable("tmp-build/compile_commands.json"), "Compile commands should be exported"
+ Assert filereadable(resolve("compile_commands.json")), "A symlink should be generated"
+ endif
+
+Execute (Open already configured cmake project):
+ cd test\ project/tmp-build
+ silent !cmake .. -DWITH_BYE=ON
+ e ../CMakeLists.txt
+ CMake
+ silent make
+
+ enew
+ if has("win32") || has("win32unix")
+ read !Debug/hello.exe
+ else
+ read !./hello
+ endif
+Expect:
+
+ Hello World
+ Bye World
diff --git a/test/test project/CMakeLists.txt b/test/test project/CMakeLists.txt
new file mode 100644
index 0000000..82ccdff
--- /dev/null
+++ b/test/test project/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(HelloWorld)
+
+option(WITH_BYE "Print bye world" OFF)
+
+configure_file(configure.h.cmake configure.h)
+add_executable(hello main.cpp)
+target_include_directories(hello PRIVATE ${CMAKE_BINARY_DIR})
diff --git a/test/test project/configure.h.cmake b/test/test project/configure.h.cmake
new file mode 100644
index 0000000..6fc9dad
--- /dev/null
+++ b/test/test project/configure.h.cmake
@@ -0,0 +1 @@
+#cmakedefine WITH_BYE
diff --git a/test/test project/main.cpp b/test/test project/main.cpp
new file mode 100644
index 0000000..f5879ca
--- /dev/null
+++ b/test/test project/main.cpp
@@ -0,0 +1,10 @@
+#include
+#include "configure.h"
+
+int main() {
+ std::cout << "Hello World" << std::endl;
+#ifdef WITH_BYE
+ std::cout << "Bye World" << std::endl;
+#endif
+ return 0;
+}