-
Notifications
You must be signed in to change notification settings - Fork 3
Opening Projects
For project management I rely on the Emacs Development Environment (EDE), which is part of CEDET. This library provides a way to define projects and an interface to perform common operations on them. EDE supports different project types, some of which can be auto-loaded whenever a corresponding file is detected in the source tree (i.e. the same directory as a source file, or in a parent).
The EDE project type I use is my own, EDE-compdb. This is a package which can instantiate an EDE project based on the presence of a Compilation Database. The compilation database is in turn provided by Ninja, the build tool.
EDE-compdb is configured to load whenever a CMakeLists.txt
file is detected, as follows:
(ede-add-project-autoload
(ede-project-autoload "CMake"
:file 'ede-compdb
:proj-file "CMakeLists.txt"
:proj-root 'vc-project-root
:load-type 'my-load-cmake-project
:class-sym 'ede-compdb-project))
There are two functions here which are relevant, proj-root
which is used to locate the root directory for a given directory, and load-type
which is used to actually create the EDE project for a given directory. In the case of EDE-compdb there is a single object per project directory tree.
For proj-root
I call out to the built-in vc package. This is generally sufficient for locating the root directory for my projects. However I just need to wrap it in a trivial function, as follows.
(defun vc-project-root (dir)
"Return the root of project in DIR."
(require 'vc)
(let* ((default-directory dir)
(backend (vc-deduce-backend)))
(or (and backend (vc-call-backend backend 'root dir))
dir)))
Creating the project is then a matter of instantiating an ede-ninja-project
. This mild complexity here is due to the need to locate a build directory for the new project. With some projects I have a build
subdirectory beneath the project root. With other large projects I have an entirely separate (“out of source”) directory which is on a separate filesystem. As a further complication, there may be multiple build configurations such as “Debug” and “Release”, each of which has a corresponding build directory.
My project loading function is hence rather complicated, but it does an important job. It searches for a build directory and configuration type for the given project, and instantiates the project with the relevant settings.
(defvar my-project-build-directories
'(("None" . "build")
("Debug" . "build.dbg")
("Release" . "build.rel")
("RelWithDebInfo" . "build.r+d")))
(defun my-load-cmake-project (dir)
"Creates a project for the given directory sourced at dir"
(let* ((default-directory dir)
(projname (file-name-nondirectory (directory-file-name dir)))
(config-and-build-dirs
(mapcar (lambda (c)
(cons (car c)
;; Expand directory
(if (file-name-absolute-p (cdr c)) (expand-file-name projname (cdr c))
(expand-file-name (cdr c) dir))))
my-project-build-directories))
(active-config-and-dir
(car (cl-member-if (lambda (c)
(file-readable-p (expand-file-name "rules.ninja" (cdr c))))
config-and-build-dirs))))
(unless active-config-and-dir
(message "Couldn't determine build directory for project at %s" dir))
(ede-add-project-to-global-list
(ede-ninja-project
projname
:file (expand-file-name "CMakeLists.txt" dir)
:compdb-file (expand-file-name "rules.ninja" (cdr active-config-and-dir))
:configuration-default (or (car active-config-and-dir) (car (car my-project-build-directories)))
:configuration-directories (mapcar #'cdr config-and-build-dirs)
:configurations (mapcar #'car config-and-build-dirs)
))))
So, when I visit a new file in Emacs, this is what happens:
- EDE detects the presence of a
CMakeLists.txt
file, which in turn triggers my project autoload code - The
vc-project-root
function is invoked to find the project root directory - The
my-load-cmake-project
function searches for existing build directories based on the templates in themy-project-build-directories
list. The first one that contains arules.ninja
file is used. - The
ede-ninja-project
object is instantiated with the relevant project root and build directories. - The compilation database is loaded and used to ensure that the edit buffer is configured correctly for parsing
In other words, loading of the EDE project is an implicit part of visiting a file which is part of that project.
Note that EDE employs caching to ensure that subsequent files within the same project are loaded quickly without going through all of these steps.
This probably all sounds moderately complicated, but it is important to ensure that the compilation database is available when editing source files. This ensures that important compiler settings, such as the project include path, are made available to the Semantic parser and to other packages.