开发者

configuring emacs for cmake

开发者 https://www.devze.com 2022-12-17 17:32 出处:网络
gcc 4.4.2 cmake 2.6 I have just started using cmake. Coming from writing my own Makefiles. However, I have this directory st开发者_开发技巧ructure and using out-of-source build. To separate the sour

gcc 4.4.2 cmake 2.6

I have just started using cmake. Coming from writing my own Makefiles.

However, I have this directory st开发者_开发技巧ructure and using out-of-source build. To separate the source files from the build files.

project
    src
        my_c_files.c
        CMakeLists.txt
    build
        Makefile

Before I would write my own Makefiles in the src directory and then press F5 and I was able to compile my program. And emacs would list any warning or errors. However, it seems that I have to open a terminal and go to the build directory to run

cmake ../src

and then

make

I would like to run make from within emacs the same as pressing F5. But as the Makefile as been generated in the build directory, and emacs is looking for it in the src directory.

Even when I set a soft link to the Makefile in the src directory to link to the Makefile in the build directory. All this did was give me a list of errors.


For exactly the same purpose I found .dir-locals.el to be extremely helpful, here's how one of mine looks like:

((nil . ((tab-width . 8)
     (indent-tabs-mode . t)))
 (c++-mode . ((c-basic-offset . 8)
          (tab-width . 8)
          (indent-tabs-mode . t)
          (compile-command . "make -C ../build -j 2 run_tests")))
 ((c-mode . ((c-basic-offset . 8)
         (tab-width . 8)
         (indent-tabs-mode . t)
         (compile-command . "make -C ../build -j 2 run_tests")))))

Obviously I can have paths specified in different .dir_locals.el according to their location and such, say some build run_tests for unit test, some build the real target and so on.

Then I put a dummy makefile in the build directory, which looks like this:

all: run_tests

run_tests:
    @cmake ..
    @make -j 2

This way I can make a checkout and just run M-x compile in whichever file I like and it will do the right thing. I use git and have that Makefile ignored from monitoring by git like so:

git update-index --assume-unchanged Makefile

and if I want to modify and commit it I do

git update-index --no-assume-unchanged Makefile.

This way the newly created by cmake Makefile won't show in git status as modified, and I won't commit it accidentally.

Benefits of this approach:

  • since cmake uses absolute paths internally, there's absolutely no problem jumping through compilation errors in compilation buffer by just pressing enter on them.

  • you can specify whatever indentation rules you want there, and they can be different in different projects or even directories if you so please :)

  • you can specify any amount of targets you want in different projects, even directories, still use the same old M-x compile (I have it bound to C-c b) and get Emacs to do the right thing.

The only drawback there is having .dir-locals.el in your subdirectories, which I hardly find bad.

EDIT: robUK, to answer your comment:

Here is documentation for Per-Directory Local Variables as they call it in Emacs manual. It is not a package, it's a part of Emacs, although I'm not sure if it was available in pre-23 versions, I'm using 23.1.1.

EDIT2: liwp, to answer your question:

As Charles already pointed out, and as documentation says:

If you put a file with a special name .dir-locals.el in a directory, Emacs will read it when it visits any file in that directory or any of its subdirectories, and apply the settings it specifies to the file's buffer. Emacs searches for .dir-locals.el starting in the directory of the visited file, and moving up the directory tree. (To avoid slowdown, this search is skipped for remote files.)

You don't need .dir-locals.el everywhere in your project tree. Note, however, it probably depends on the complexity of your code base structure.

I normally would go for a fairly simple layout like this:

/project_root_dir
    /build
    /src
    /test

and I would have slightly different targets specified in different .dir-locals.el, say in /test I would only build testrunner and have it executed, I'd spend most of the development time building this target. Then in /src I would first build the same testrunner, have it executed,and if everything goes well there, it would build me my main project target. If you don't need this, you could be fine with just one .dir-locals.el under /project_root_dir. If your source structure and requirements are a lot more sophisticated, it could mean you'd need a bit more path- and target-related wizardry.


A more general solution for compile-command would be:

cd ${PWD%/src/*}/build && cmake ../src && make

The environment variable PWD holds the directory the file you're editing is in; expanding it with %/src/* gets you back to the project root without having to worry about how many ../s you need.


Simple solution: install cpputils-cmake, then you are good to go.

Explanation: CMake already put all the information in the build directory. You just need hack the ELisp variable compile-command in your c++-mode-hook and c-mode-hook if you get the right information from cmake.

Two points for a perfect solution:

  1. You elisp code should detect whether current project is using CMake by scanning source directory before hacking compile-command

  2. The out-of-source build directory's full path should be automatically detected and appended to the make -C command.

I wrote an emacs plugin cpputils-cmake https://github.com/redguardtoo/cpputils-cmake which will solve these two issues. Check my code and you can install it though Emacs's package manager.

BTW, After build directory is created by cmake, usually cmake should not be explicitly called in the command line. make -C out-of-source-build-dir is smart enough because the Makefile in that directory will call cmake anyway. Even after you change CMakeLists.txt, calling make -C out-of-source-build-dir is still enough. I'm pretty sure about this because I've been using cmake for four years.

Many previous answers won't work because:

  1. Any assumption about source tree layout could be wrong. For example, I name my root source directory to "mysrc" instead of "src"

  2. How I use out-of-source strategy is complicated. For example, I may build only one component by using out-of-source.


I'm using EDE from Cedet to configure projects for work with CMake. Look into my CEDET config, starting with line 105, for example of code for project configuration. I use separate Debug & Release directories for different builds, and by default, compilation is running only for Debug mode....


You can change the current working directory that emacs uses with M-x cd<enter> <path to build dir><enter>. After this, when you run M-x compile, make will be executed in the new working directory. This is effectively the same as running make on the terminal in the build directory, so it should work for you just fine.


How about using -C option for make ?

Press F5, or M-x compile, when emacs asks compile-command, type:

make -C ../build


Change the command to use the absolute instead of relative pat. EG:

cmake ~/workspace/project/src && make
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号