Adding "--run" functionality?

For reference cargo has a way to just run your app from the command line.

$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/hello_cargo`
Hello, world

Perhaps it would be worth it to add this sort of functionality to CMake?

Thoughts?

run is not a default target, but you can easily make one yourself. Note that in your reference it only runs the executable. Which one is run when we have more than one?

If you have more than one you can use --target just like CMake already does for building a target.

# https://cmake.org/cmake/help/latest/manual/cmake.1.html#build-a-project

--target <tgt>..., -t <tgt>...

    Build <tgt> instead of the default target. Multiple targets may be given, separated by spaces.

So I guess the syntax for --run would borrow heavily from --build

The syntax, sure, but there’s more backend work that needs done. Targets don’t “exist” at cmake --build time (to CMake) and --target just gives the name off to the backend build tool. There’s no actual understanding of what the string means. For example, cmake --build . --target Source/CMakeFiles/cpack.dir/CPack/cpack.cxx.o works just fine because ninja knows that. So there’s no actual knowledge of what the --target argument means at this point and that information would need to be recreated, so this is not a “small” problem.

Gotcha that makes a lot of sense. Yeah now that I think about it, it would be a lot of work to add.

with a target level dependency (run tgt1 depends on build tgt1) the executable exists before execution. The generated build system can understand that without CMake to know.

What happens with cargo run if there are multiple targets? Does it run one in particular or abort in error?

Target Selection

When no target selection options are given, cargo run will run the binary target. If there are multiple binary targets, you must pass a target flag to choose one. Or, the default-run field may be specified in the [package] section of Cargo.toml to choose the name of the binary to run by default.
--bin nameRun the specified binary.--example nameRun the specified example.
1 Like

It strikes me that Cargo and CMake are very different things, in this context.

cargo is a packaging tool (with compiler integration) for a single language (Rust). Other analogous tools: npm (Node.js), pip (Python), gem (Ruby), etc.

  • cargo run exists because most Rust packages contain one or more binary targets, defined in their own documentation as “executable programs that can be run after being compiled.” Its metadata format (Cargo.toml) allows tagging a binary target as default-run.

  • npm run is actually an alias for npm run-script, which works with the scripts object of its JSON metadata format (package.json). There, arbitrary commands can be named as “scripts”, runnable both automatically at certain stages of the package lifecycle, or manually using npm run. This is necessary because no JS packages are standalone executable binaries. npm is therefore an overachiever on this front.

  • pip run does not exist, because most Python modules are not executable as such, they are scripts to run through an interpreter, and many are library packages meant to be called from other Python code rather than directly.
    Some packages do install one or more “entry-points”, scripts used to launch a module, but even those require an installed package. (If a module is runnable from the build directory, those semantics are for the most part up to the author.) An entry point script or python3 -m <module> is the preferred way to launch a runnable module.

  • gem run does not exist, because most Ruby gems are not executable as such, they are scripts to be run through an interpreter. (etc, etc.)

CMake, OTOH, is a build system generator that supports (in theory) building any type of output, for any platform, in any source language. While C/C++/Fortran are the most common, and while CMake does have the concept of an “executable target”, the run semantics of that target are impossibly diverse:

  • It could be cross-compiled, in which case it’s not runnable on the current host platform
  • It may be a binary component of a macOS application Bundle, in which case it requires a particular filesystem layout from which to be run
  • It may be a Windows executable, in which case it may require a specific %PATH% environment variable and/or the consolidation of .dll dependencies in order to be runnable.
  • It may have been compiled using SKIP_BUILD_RPATH, BUILD_WITH_INSTALL_RPATH, or other options that may render it non-executable from the build directory.
  • It may be a Qt program, and require further configuration of plugin dirs or other paths via a qt.conf file in order to be properly executable.

The notion of “running the results of a CMake build” really isn’t as concrete a notion as “running a compiled Rust binary”, not to the point where it would be as easy (or as useful) to generalize it into a built-in utility command. But, like @hex suggested, there’s certainly nothing stopping you from using add_custom_target() to create a run target, with COMMAND arguments defining how your executable(s) should be run (much like npm's scripts definitions), and then using cmake --build <builddir> --target run to run it.

2 Likes

Hah! Interesting, and very coincidental.

Qt Creator, like many IDEs, does have a “run project” feature in their build system, so they had the same problem of not being able to automatically detect what exactly should be run, when the user clicks “Run”.

For Creator 5 (which brings greatly expanded CMake support across the board), they’ve settled on using a target FOLDER property, set to a specific magic value of "qtc_runnable", to designate the default run target.

So,

set_target_properties(main_executable PROPERTIES FOLDER "qtc_runnable")

I have to imagine some sort of UI for managing that property would be coming along eventually, because applying it in the source like that is kind of magical and weird.

Details in the recent blog post (see the “Selecting a default run target” heading.)

thank you for bringing this up. In lack of anything else i might just adopt this name. The configuration should not be tight to the source tree, though. Offering an automatic setup can be convenient but also makes the user expect such convenience for every project, even for projects where it doesn’t make sense. A sane default selection for a target is not always possible, and opinionated at best.

Making it a user setting is much better, which could be tied to the IDE project, or CMake build tree.

Sorry to say that but what a dumb idea by QtCreator developers thinking that they are the only used IDE in a project to capture target’s FOLDER property like that.

they use a prefix to avoid conflicts and the property can be read before written

Well, sure. But I might want to use FOLDER for my organization. Why commandeer an existing property instead of making a new one like _qtc_runnable that is set to TRUE or FALSE?

2 Likes

Can someone please comment on that blog post that using FOLDER is terrible? I’ll go file an issue I guess…

I’ve already raised this internally with the Qt Creator team.

3 Likes

Hello, Craig, what do you think about adding another property (like PROJECT_RUN_TARGET)? As the MSVC, xcode supports running specified target and this option is stored in its project files.
The CMake-based IDEs like Qt Creator could simply fall back into this property and use it.
Thanks for attention.

One of the things identified by the internal discussions was that most target properties are not available through the file API. The reason the FOLDER property was used is that it does have a dedicated field in the file API, so it can be read by IDEs like Qt Creator. One would likely need to extend the file API to support queries asking for specific properties to avoid that. If that were implemented, then I guess having a “blessed” property that is expected to act as this meaning for all IDEs would make sense, but a look at how the different IDEs implement or support this sort of feature and what such a property would need to represent would have to occur first.

1 Like

is it desired / necessary to use CMake for this? The complete list of existing targets is available to the IDE. It could provide the necessary GUI elements to the user to decide which targets are eligible for a run target, and the set of targets enabled for run. These preferences could be tied to the GUI instead of the configured CMake project.

I don’t know about “necessary”, but I can see how it would be desirable, in particular for people who are creating CMake projects that will be built and run by others.

I can certainly see where it would be particularly helpful in an education/tutorial context. There’s certainly an appeal to being able to import a Git repository into Qt Creator, and have a default assignment for the Run target already present. (Without having to define yet another proprietary/non-standard metadata file with which to embed that information into the source tree.)

the majority of tutorials only have a single target of type executable. When there are options, pressing run could ask for choosing one once at first launch. This can certainly cover a large chunk of use cases already.

To cover all remaining cases, the vendor field in CMake presets seems more suitable for these setup than fileAPI, because, as i currently understand it, Qt Creator is itself handling the run target. There is no standard CMake implementation of a run target.