Create target that only runs other target

Hi everyone,

I’m currently building a cmake for compiling and flashing microcontroller applications (avr).
The important part looks like that:

function(add_avr_executable targetName)
    add_executable(${targetName} ${ARGN})
    set_target_properties(${targetName} PROPERTIES OUTPUT_NAME "${targetName}.elf")

    add_custom_command(TARGET ${targetName} POST_BUILD BYPRODUCTS ${targetName}.hex
        COMMAND ${CMAKE_OBJCOPY} -O ihex -j .data -j .text ${targetName}.elf ${targetName}.hex 
    )

    add_custom_target(${targetName}_run )
    add_dependencies(${targetName}_run ${targetName}_clean ${targetName} ${targetName}_upload)

    add_custom_target(${targetName}_upload COMMAND ${AVRDUDE} -p ${MCU} -c ${PROGRAMMER} -U #[[-P ${PORT} -b ${BAUD}]] flash:w:${targetName}.hex:i DEPENDS ${targetName}.hex)
    add_custom_target(${targetName}_size COMMAND ${AVR_SIZE} --mcu=${MCU} -C --format=avr ${targetName}.elf )#DEPENDS ${targetName}.elf)
    add_custom_target(${targetName}_nm COMMAND ${CMAKE_NM} --size-sort -S -C -t decimal ${targetName}.elf DEPENDS ${targetName}.elf)
    add_custom_target(${targetName}_clean COMMAND ${CMAKE_COMMAND} -E remove ${targetName}.hex ${targetName}.elf)
    add_custom_target(${targetName}_fuses COMMAND ${AVRDUDE} -v -p ${MCU} -c ${PROGRAMMER} -Pusb -U lfuse:w:0xe2:m -U hfuse:w:0xdb:m -U efuse:w:0xff:m)
endfunction()

So the basic “workflow” is:
clean -> build -> flash -> size

When I used just makefiles, I created a target “run”, which will just run all these targets in the specified order. I tried the same as you can see with add_dependencies().
But my first experience is that it sometimes work, but sometimes it doesn’t. It seems to give no gurantee that the specified order will also be the order of execution.

How can I achieve that I have a target run, which does build the other targets in a specified order?

Thanks everyone! Also, if you have any more feedback on how to improve that code snippet, I would appreciate it a lot. I’m quite new to cmake :slight_smile:

There is no order specified between these targets except that _run happens after _clean and _upload. The order of the add_custom_target() commands don’t matter and the ordering can be anything unless specified with `add_dependencies().

I think you missunderstood me.
I added one target:

add_custom_target(${targetName}_run )

This target should do nothing else than call other targets:
targetName_clean -> targetName -> targetName_upload

in exactly this order! So first cleaning, then building, then flashing
This is why I added these as dependencies:

add_dependencies(${targetName}_run ${targetName}_clean ${targetName} ${targetName}_upload)

But it turns out, that cmake doesn’t respect this order. Sometimes it calls upload before building, or cleans the projects at the end, which doesn’t make a lot of sense

To make it more clear, here is my command:
cmake --build build --target targetName_clean targetName targetName_upload

It’s quite a long command and I would like to simplify it with a “shortcut target”, which will do the exact same thing.
cmake --build build --target targetName_run

Targets don’t call other targets.

The command ensures that a top-level <target> depend on other top-level targets to ensure that they build before <target> does. It does not ensure that there is any specific ordering of the “other top-level targets” between themselves which is what you seem to expect.

I would be surprised if clean and upload swapped when using the project over and over again. But I would not be surprised it it changed when regenerating the project and the new project had a different order.

Try this instead which has the inter-target dependency you describe.

add_dependencies(${targetName}_run ${targetName}_upload)
add_dependencies(${targetName}_upload ${targetName})
add_dependencies(${targetName} ${targetName}_clean)

My worry is that unless you changed a source code file then ${targetName} doesn’t need to build and the post build event to generate the hex file won’t run.

I think that you may be better off just having ${targetName}_run call all the necessary commands instead. add_dependencies can accept more than one command.

hich is what you seem to expect
At least I hoped it would behave like that, but it didn’t.

Try this instead which has the inter-target dependency you describe.

add_dependencies(${targetName}_run ${targetName}_upload)
add_dependencies(${targetName}_upload ${targetName})
add_dependencies(${targetName} ${targetName}_clean)

This goes in the right direction. In fact I kinda have it already like that I think as upload depends on hex. And it actually always rebuilds the elf/hex file if anything changes, which is perfect.
But add_dependencies(${targetName} ${targetName}_clean) that’s not true. While it’s certainly one use case to call “clean” before “build”, it’s certainly not necessary. I mean, I could live with that … I haven’t figured yet out, when I need to clean the project, so I do it always anyway.

But say, I want a shortcut, which does all that and prints the size at the end (which is what arduino does). Then this approach is not possible anymore, as ${targetName}_size should certainly not depend on run or upload.
So I was looking for a more generic approach, which allows me to run targets in a specific order with only one command, without having any dependencies between them.

I think that you may be better off just having ${targetName}_run call all the necessary commands instead

I guess, I have to use this approach. But I really don’t like copy and pasting. It’s not even possible to refactor the commands in the target (by using custom_command) and use them in multiple targets.
For me this is a missing feature in cmake.

Just noticed the typo. I’ll try to fix it if I can. But here is an example of what I was trying to convey.

add_custom_target(${targetName}_run 
  COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR } --target ${targetName}_clean
  COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR } --target ${targetName}
  COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR } --target ${targetName}_upload
  )

add_custom_target(${targetName}_run_size 
  COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR } --target ${targetName}_run
  COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR } --target ${targetName}_size
  )

Then you don’t need additional add_dependencies in the function add_avr_executable. You just issue the targets to be executed: clean elf and hex, build elf and hex, and upload. Then you can reuse the commands in new commands. For example ${targetName}_run_size. Or you can issue it from the command line using the --build CMake option or from the build tool like make.

That’s smart! It’s exactly what I wanted, just a little bit more complicated :smiley: Maybe cmake will add in future a feature to reference them directly.

I was just wondering:

There is no option to get the call options, right?

So that I could do something like:
COMMAND ${CMAKE_COMMAND} CMAKE_CALL_OPTIONS --target ${targetName}_clean

So the options I use for $targetName_run will be reused for the other targets for example --build /some/directiory. That would make it perfect :slight_smile: