Question

I want to be able to call avrdude from SCons as a target. For example, running scons erase-device should run the avrdude command for doing so.

I'm attempting to do this by creating Builder objects that call avrdude and adding them to the environment.

# a string forming a base avrdude command that we can just add on to in the targets
avrdude_base = 'avrdude -p ' + env['MCU'] + ' -c ' + icspdevice

# target to erase everything--flash, EEPROM, and lock bits (but not fuse bits)
erase_dev = Builder(action = avrdude_base + ' -e')
env.Append(BUILDERS = {'EraseDevice' : erase_dev})
ed = env.EraseDevice()
eda = env.Alias('erase-device', ed)
env.AlwaysBuild(eda)

# target to write the AVR fuses and lock bits
write_fuse = Builder(action = avrdude_base + ' -U lfuse:w:' + lfuse + ':m -U hfuse:w:' + hfuse + 
                    ':m -U efuse:w:' + efuse + ':m -U lock:w:' + lockbits + ':m')
env.Append(BUILDERS = {'WriteFuses' : write_fuse})
wf = env.WriteFuses()
wfa = env.Alias('write-fuses', wf)
env.AlwaysBuild(wfa)

With this code, scons always exits saying that there is nothing to do. I think this is because, the way the code is shown, I don't give any source files to these Builders (env.EraseDevice() and env.WriteFuses()); therefore, SCons assumes that they don't need to be called.

So that's what I tried next. I just passed in an existing filename into those two Builders to make scons happy, even though it isn't needed. The problem now is that, regardless of whether I want to run scons write-fuses, scons erase-flash, or other targets that use avrdude, scons acts as though I'm trying to write the fuses. If, for example, the file name I passed in were foo.hex, then scons now thinks that it has to run the write-fuses target every time because scons thinks that 'avrdude' was supposed to generate an output file called foo, but that file is never generated.

Also, doing this means that I have to build the hex file before erasing the device or programming the fuse bits, which wouldn't normally be necessary.

How can I create targets in SCons that do not require any sources for input and that do not generate any output?

Thanks!

Was it helpful?

Solution

You're on the right track in saying that scons isn't running anything because it doesn't have any sources to turn into outputs, but the key is that scons wants to generate targets and it didn't think there were any to build.

One easy workaround is to give the erase-device and write-fuse commands dummy targets. These target files will never be generated, so if scons determines that this target needs to be built (because it was specified on the command line or is a dependency of something on the command line), scons will always run the appropriate avrdude ... command.

I think the use of Builders is adding extra complexity that you don't need. Builders are good for creating new source to target mappings, but you don't really need to involve files.

ed = env.Command('erase.dummy', [], avrdude_base + ' -e')
ed = env.EraseDevice()
env.AlwaysBuild(ed)
env.Alias('erase-device', ed)
...

As a side note, scons --tree=all is a nice way to see scons' calculated dependency tree. If you're mystified by what scons is doing, seeing the dependency tree can help with debug where your model diverges from scons.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top