Search code examples
sconsbuild-system

SCons reports a dependency cycle when source and target file have the same suffix


I am trying to get SCons to call uglify on a series of JavaScript files, for continuous integration reasons...

However even though the 'duplicate=False' flag is passed to 'env.SConscript' calls; to prevent scons from copying sources to the build output folder. It flags files with the same source and target extension as a dependency cycle. Take for example the following simplified project structure:

SConstruct
applications/SConscript
applications/frontend/SConscript
applications/frontend/scripts/app.js

-- SContruct --
UglifyBuilder = env.Builder(
  action = 'uglify --source $SOURCE --output $TARGET',
  suffix = '.js',
  single_source = True)

env['BUILDERS']['Uglify'] = UglifyBuilder

env.SConscript('applictions/SConscript', 'env',
    variant_dir=os.path.join('build', 'debug', 'applications'),
    duplicate=False)

-- applications/SConscript --
env.SConscript('frontend/SConscript', 'env', duplicate=False)

-- applications/frontend/SConscript --
env.Uglify('scripts/app.js')

When you run SCons on this (clean or not) the following output is generated; Stating that there is a dependency cycle between the target files:

$ scons applications/frontend/
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
scons: building associated VariantDir targets: build/debug/applications/frontend
scons: `applications/frontend' is up to date.
scons: done building targets.

scons: *** Found dependency cycle(s):
  build/debug/applications/frontend/scripts/app.js -> build/debug/applications/frontend/scripts/app.js

I also tried to pass an absolute path to the source file, but unfortunately with the same result. And sure I could change the output suffix to '.min.js', but there are other cases to come up with that output files with the same leader-path/filename as some arbitrary input source.

Am I misunderstanding SCons here? Or can somebody point me in the right direction of solving this?

Because if this is one of those cases where 'it isn't a bug it's a feature' applies I am going to pull my hair out. :)

Thanks!


Solution

  • I'm really sorry for you and your hair, but this behaviour doesn't have anything to do with variant_dir, and the "duplicate" option won't help you out either. What your example boils down to is:

    • You have a file "app.js".
    • You have an Uglify Builder, mapping *.js files to *.js files.
    • You tell this Builder to do his stuff with "app.js".

    Of course this leads to a dependency cycle, because your source and target have the same filename. Note, that SCons detects the cycle from build/debug/.../app.js to itself...and not to applications/frontend/scripts/app.js.

    For breaking this cycle, you have to either rename one of your suffixes (*.in for source files?), or the file stem, e.g. you could name your source file "app_pretty.js" and then call

    env.Uglify('scripts/app.js', 'scripts/app_pretty.js')