I don't like waiting for compilations to finish, or for unit tests to run. In the ideal case, output from compiling and running tests should be available whenever I decide to look at it. Focus shouldn't have to leave the code editor.
After a series of iterations, I've created a setup that is not in the way. A setup that automatically rebuilds when code is changed, and executes tests that have been affected. A setup where I can use global hotkeys to issue a full rebuild, launch the main program, or run all tests.
This is what the end result looks like.
Note that focus never leaves the editor!
I'll go through each of the necessary pieces of the puzzle, and put it together along the way.
This section describes a script that issues a rebuild whenever a source file changes.
If you understand the following snippet
|Line 1-6:||Finds all relevant projects files.|
|Line 7:||Finds the 'last modified' timestamp for all files.|
|Line 8:||Reduces the above to a single md5 hash.|
find-utility, one can list all files with
particular extension with
$ find . -name "*.cpp"
To find both
$ find . -name "*.cpp" -or -name "*.h"
To avoid finding hidden files:
$ find . -name "[!\.]*.cpp" -or -name "[!\.]*.h"
To do the same but limit results to
$ find ./src -name "[!\.]*.cpp" -or -name "[!\.]*.h"
Putting it together: Find all non-hidden files in
./src directory with
.cpp .h .tpp extensions, any
SConscript* files, and also
SConstruct file in root directory:
$ find ./src ./SConstruct \ -name "[!\.]*.cpp" -or \ -name "[!\.]*.h" -or \ -name "[!\.]*.tpp" -or \ -name "SConscript*" -or \ -name "SConstruct"
stat shows detailed timestamp information of a file.
$ stat SConstruct File: `SConstruct' Size: 778 Blocks: 24 IO Block: 4096 regular file Device: 14h/20d Inode: 1208177 Links: 1 Access: (0664/-rw-rw-r--) Uid: ( 1000/ okami) Gid: ( 1000/ okami) Access: 2013-06-21 09:08:13.198346996 +0200 Modify: 2013-06-21 09:08:13.030346998 +0200 Change: 2013-06-21 09:08:13.030346998 +0200 Birth: -
To only list modification time:
$ stat SConstruct -c %y
2013-06-21 09:08:13.030346998 +0200
Putting it together: Determine the last modified timestamp of all files found by
$ find ./src ./SConstruct \ -name "[!\.]*.cpp" -or \ -name "[!\.]*.h" -or \ -name "[!\.]*.tpp" -or \ -name "SConscript*" -or \ -name "SConstruct" | xargs stat -c %y
md5 is a hashing algorithm
that reduces any chunk of information to a 128-bit value. To compute the md5
Computing the md5 hash of
$ md5sum myfile.txt
Or pipe the content to md5:
$ cat myfile.txt | md5sum
Putting it together: By piping all the timestamps above, we reduce the information to a single value. If any timestamp changes, the value changes.
$ find ./src ./SConstruct \ -name "[!\.]*.cpp" -or \ -name "[!\.]*.h" -or \ -name "[!\.]*.tpp" -or \ -name "SConscript*" -or \ -name "SConstruct" | xargs stat -c %y | md5sum
I compile each test suite into its own executable, and put each executable in a particular directory. Automatic test-execution becomes as simple as monitoring a directory, and executing tests if they change. This is what it looks like:
This python-script does just that. It monitors executables in a directory, and executes any that change.
Taking advantage of terminals, and redirecting output to a specific TTY is central to the setup. It allows us to set up global hotkeys that run scripts that send the output to a particular terminal. The TTY demystified is a good article on TTYs if you want to read more about it, but from a practical point of view, this is all you need to know:
Setting up global hotkeys is a distro-specific issue, so it won't be covered. The global hotkey should trigger a script that determines the correct project path and redirects output to a particular tty.
I use three scripts for the following:
|recompile:||Does a full build from scratch|
|run-main:||Runs the executable created by the compilation.|
|run-tests:||Runs all the tests.|
I suggest writing additional scripts to help the 'compile', 'run-main' and 'run-tests' script:
|marktty:||Writes your current |
|markttytest:||Writes your current |
|markproj:||Writes the |
Creating two terminal windows, starting automatic building, starting
automatic test execution, registering each
tty to receive
global triggered scripts... it takes time. Roughly half a minute.
It would be nice to have a way to automate this as well. There are several tools that can help you.
One such is
tmuxinator. Here is the setup script I use.
|Line 9:||Top pane for autobuild, set to execute |
|Line 10:||Bottom pane for autodirexec, set to
monitor test directory.|
This concludes my first article. If you would like clarification on any particular aspect, let me know. I'm happy to get any tips, or suggestions as to how to improve it, both the article and setup.
Using this setup has been very useful to me, and hopefully this might give some inspiration to set up something similar, or devise something better. Maybe you already have, and would like to share.