Here’s an example:
{
"shell_cmd": "g++ \"${file}\" -o \"${file_path}/${file_base_name}\"",
"file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
"working_dir": "${file_path}",
"selector": "source.c++",
"variants":
[
{
"name": "Run",
"shell_cmd": "g++ \"${file}\" -o \"${file_path}/${file_base_name}\" && \"${file_path}/${file_base_name}\""
}
]
}
The file_regex
here is what allows Sublime to detect the file, line, column and error message. The only things that are going to match are lines that match this regex. Anything that doesn’t match is entirely ignored.
So, vitally important step #1: if you want to navigate between errors, this regex needs to be able to match them. If passing extra command line arguments to the tool you’re running changes the way the error messages are presented, then you also need to change this, or it’s not going to match, and you’re not going to be able to navigate.
Now, presume an error message like this:
/home/tmartin/test.c:8:13: error: expected ‘;’ before ‘}’ token
The name of the file is absolute; it is always possible to know exactly what file on my hard drive is the one that triggered the error.
On the flip side:
test.c:8:13: error: expected ‘;’ before ‘}’ token
Ok, a file named test.c
has an error. Which one? There can be arbitrarily many of them. I could be some sort of freak with a test.c
in every folder on my entire hard drive. Which one is it referring to? Sublime can’t know, it’s not the thing that generated the error message, the external tool is. This is the inherent problem with relative
paths. They’re relative to some known location, but what is that location?
"working_dir": "${file_path}",
This part of the build system says “while you are executing this tool, as a first step please change the current working directory to be the path in which the currently active file is stored”.
Given this, Sublime can presuppose that if it has a relative filename, it has to be relative to something, and the only information it has is the directory that was currently active while the tool was running. So, it will stick the relative filename onto this working directory path and see if that opens the file.
Vitally important step #2: If you don’t set the working directory, OR the tool that you’re executing changes it, AND the error message is a relative filename, there’s no way to find and open the file.
The import of the my original statement is something like this:
(master *%>) tmartin:dart:~/local/src/dragonWarrior> make
make[1]: Entering directory '/home/tmartin/local/src/dragonWarrior/external'
make[2]: Entering directory '/home/tmartin/local/src/dragonWarrior/external/lua'
make[2]: Nothing to be done for 'install'.
make[2]: Leaving directory '/home/tmartin/local/src/dragonWarrior/external/lua'
make[2]: Entering directory '/home/tmartin/local/src/dragonWarrior/external/mersenne'
make[2]: Nothing to be done for 'install'.
make[2]: Leaving directory '/home/tmartin/local/src/dragonWarrior/external/mersenne'
make[2]: Entering directory '/home/tmartin/local/src/dragonWarrior/external/md5'
make[2]: Nothing to be done for 'install'.
This build is recursive
; every time it goes into a folder, it’s changing what the currently active directory is. If your build does that, AND your tool outputs a relative filename like hello.c
, then you’re screwed and you can’t open the file because Sublime has no way to know what file it could possibly be; the external tool changed information out from under it.