SCons rebuilds generated source files every launch
Problem
In a large project that uses SCons, VariantDir, and source code generation, happens one of the following:
- generated source files are rebuilt every time when
scons
is launched - if
.sconsign.dblite
is removed manually,scons
crashes with the following trace:
OSError: [Errno 2] No such file or directory: '.sconsign.dblite':
File "/usr/lib64/python2.7/site-packages/SCons/Script/Main.py", line 1372:
_exec_main(parser, values)
File "/usr/lib64/python2.7/site-packages/SCons/Script/Main.py", line 1335:
_main(parser)
File "/usr/lib64/python2.7/site-packages/SCons/Script/Main.py", line 1099:
nodes = _build_targets(fs, options, targets, target_top)
File "/usr/lib64/python2.7/site-packages/SCons/Script/Main.py", line 1297:
jobs.run(postfunc = jobs_postfunc)
File "/usr/lib64/python2.7/site-packages/SCons/Job.py", line 113:
postfunc()
File "/usr/lib64/python2.7/site-packages/SCons/Script/Main.py", line 1294:
SCons.SConsign.write()
File "/usr/lib64/python2.7/site-packages/SCons/SConsign.py", line 109:
syncmethod()
File "/usr/lib64/python2.7/site-packages/SCons/dblite.py", line 127:
self._os_unlink(self._file_name)
Exception OSError: OSError(2, 'No such file or directory') in
<bound method dblite.__del__ of <SCons.dblite.dblite object at 0x7fa287435c10>> ignored
Unfortunately, I was unable to reproduce this outside of my project.
Reason
The problem occurs because:
- SCons creates individual
.sconsign
files for the source directory and build directory (VariantDir) - for some reason, SCons writes build metainfo for generated sources to the
.sconsign
under the build directory but searches for it in the.sconsign
under the source directory - since SCons can’t find build metainfo for generated sources, it assumes that they should be (re)built, and this happens every time
You can check if this is your case with the following command:
$ scons --debug=explain
...
scons: Cannot explain why `<FILENAME>' is being rebuilt: No previous build information found
Solution
The workaround is to use single global .sconsign
for the whole project. This feature is enabled by setting the SConsignFile
to an absolute path:
import os.path
env.SConsignFile(os.path.join(env.Dir('#').abspath, '.sconsign.dblite'))