Skip to content
garyo edited this page Dec 13, 2014 · 1 revision

As far as I can tell, SCons does not have a way to run custom clean actions - it only knows how to delete targets.

If you have some custom work for scons --clean to do, such as an 'ant clean', the following recipe worked for me. The code (for example package names) is approximate because I do not have scons on this computer and I do not have a printout. Also the behaviour below is to perform a clean action if it is specified on the command line or if '.' was specified and the clean was run from the top level dir.

The downside of doing it this way is that the actions are processed in the order that they are found, but that isn't usually a problem for clean actions.

  def CleanFlagIsSet() :
    import SCons.Script.Main
    return SCons.Script.Main.options.clean

  def LaunchedFromTopDir() :
    return DefaultEnvironment().GetLaunchDir() == Dir('#')

  def CleanAction(name,action) :
    if CleanFlagIsSet() :
      if     len(COMMAND_LINE_TARGETS) == 0 \
          or name in COMMAND_LINE_TARGETS \
          or LaunchedFromTopDir() and '.' in COMMAND_LINE_TARGETS \
          :
        Execute(action)

  #example usage
  Command('ant',['build.xml'],['$ANT_BIN/ant build'])
  CleanAction('ant',Action(['$ANT_BIN/ant clean']))

This way if you run 'scons -c ant' or just 'scons -c' and 'ant clean' will get run.

Awesome! Thanks! Here is my version that seems to work well. (little more rigorous about testing whether clean should be run e.g. if invoked from subdir with -u

# Take list of targets. Return '1' if they should be cleaned based on
# current command line, '0' otherwise.
def TestClean(targets):
    import os
    # want it to execute if:
    #     global clean
    #     higher directory clean
    #     target clean
    import SCons.Script.Main
    # test if clean specified on command line
    if not SCons.Script.Main.options.clean:
        return
    # normalize targets to absolute paths
    for i in range(len(targets)):
        targets[i] = File(targets[i]).abspath
    launchdir=DefaultEnvironment().GetLaunchDir()
    topdir=Dir("#").abspath
    cl_targets=COMMAND_LINE_TARGETS
    if len(cl_targets) == 0:
        cl_targets.append(".")
    for i in range(len(cl_targets)):
        full_target = ""
        if cl_targets[i][0] == '#':
            full_target = os.path.join(topdir,cl_targets[i][1:0])
        else:
            full_target = os.path.join(launchdir,cl_targets[i])
        full_target = os.path.normpath(full_target)
        for target in targets:
            if target.startswith(full_target):
                return 1
    return 0

def CleanAction( targets, action):
    if TestClean(targets):
        Execute(action)

Great - that helps a lot!

ButFile(targets[i]).abspathhas some troubles with directories, so - you are right - there is a new version with minor changes:

  • addenvparameter forAddMethod()
  • useenv.subst()to get absolute paths of Files and Dirs
  • useenv.GetOption('clean')instead ofFile(targets[i]).abspath
def TestClean(env, targets):
        import os
        if not env.GetOption('clean'):
                return
        # normalize targets to absolute paths
        targets = env.subst('${TARGETS.abspath}', target=targets).split()
        launchdir = env.GetLaunchDir()
        topdir = env.Dir("#").abspath
        cl_targets = COMMAND_LINE_TARGETS
        if len(cl_targets) == 0:
                cl_targets.append(".")
        for i in range(len(cl_targets)):
                full_target = ""
                if cl_targets[i][0] == '#':
                        full_target = os.path.join(topdir,cl_targets[i][1:0])
                else:
                        full_target = os.path.join(launchdir,cl_targets[i])
                full_target = os.path.normpath(full_target)
                for target in targets:
                        if target.startswith(full_target):
                                return 1
        return 0

def CleanActionFunc(env, targets, action):
        if TestClean(env, targets):
                env.Execute(action)

env.AddMethod(CleanActionFunc, 'CleanAction')
Clone this wiki locally