-
Notifications
You must be signed in to change notification settings - Fork 271
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce top level commands commands for Dafny #2036
Comments
dafny
CLI
One tiny cosmetic things we might consider doing along with this change, which is already hinted at in #2351 but not explicitly stated: using |
I missed this discussion, thanks @atomb for reviving it ! And thanks @keyboardDrummer for starting a draft on this nice feature. I'm already defining the command "format" in this PR, but we can always make it compatible with whatever format we chose. I would also like to quote my post 20 days earlier My remarks on the diff between the two.
|
Not having been involved in this discussion before, the proposed definitions seem reasonably intuitive to me |
Should we merge the discussion here with the discussion on #2534 ? I notice that we're starting to repeat things between these two. |
Shall we keep this issue focussed on just the commands, since that's what it was originally scoped to? I agree that in #2534 we need to tackle both this issue and the redesign of command line options, but maybe we can keep the issue separate? |
Just because we can doesn't mean we should. What would be the use-case of offering compilation to a target language compilation artefact? To me it seems such an artefact it not well defined. It may or may not work on operating systems other than the current one; it may or may not need additional target language runtimes to be installed before it can be executed; and in the case of languages that are not compiled, the output would be the same as that of To take .NET as an example, I think it would be better to let Dafny users that want to generate a .exe or .dll, run the |
I think it's pretty well defined for C# and Java. |
I often try to build projects in languages that Dafny supports but that I don't know well. It's convenient that Dafny can build an executable that I can then run multiple times. Even better would be if it told me what comment it runs to build. |
So it's really a performance issue of running |
It's not just about that. It's about the part of a decent programming language to offer to compile to binary its source files. That's everyone's expectation. |
FWIW, I agree with Mikael. I like the ability to translate to source files and also to produce the compiled executable from those sources -- and it is a nuisance to go figure out how to construct the compile line for simple cases, especially for unfamiliar languages. Even for Java, which I know the best of these, the compile command is not immediately obvious. |
You could think of it that way? But I see the source code that Dafny generates as an internal detail (just like dotnet doesn't give me a textual representation of IL as its default output), so by default I'd expect to get a binary, not source code. |
The source code seems more useful since you can use it to invoke target language build tools. Suppose you want to publish a .NET package, wouldn't you then rather start with .cs and .csproj files than with a .dll?
How are you distributing? Are you publishing to a package repository using the target language package manager? Do you then really prefer something that's already further compiled instead of source files? Relevant discussion is in this issue: #1322 @jonhnet writes:
|
Tentatively added this to Dafny 4.0, not because it is a breaking change but because it offers a fresh API where we can make breaking changes that aren't actually breaking, so I think it's relevant for planning purposes. :) |
Of course, target language files and csproj files are very important. We are not arguing that .cs and .csproj files are better than a .dll. |
Ok, that's part of the proposal right?
Which it? |
The ability to run (and thus compile and leave the executable of) a program. |
|
My suggestion here would be to have our "compile targets" be more precise, to name not just the target programming language used but also the actual artifact produced. We could have The meaning of the top-level commands would become:
The idea of a compile target is then quite flexible, as long as there is some way to execute the artifact(s) produced whenever there is a main method defined. We could even support the Dafny interpreter under construction in the |
I expect once we have a Dafny project file it will be extremely useful to specify multiple |
I don't think "dll" wouldn't be specific enough to point to C#, but you could have "csdll". Which options would this pass to the C# compiler? Would you then also have an option
Would
I can see that being useful for projects that target multiple languages, but I don't see it being useful for generating different types of artefacts for the same language, like both .cs and c# based .dll files. |
@robin-aws, I like a lot the idea of reusing
Fair enough. Let me suggest an approach that should be consistent and does not remove features that we had been offering to users until now. Let's have every compiler declare what targets they can generate. Common targets would include
Corollaries:
I designed the above targets so that they are easy to remember, correspond to what we would have expected before and now, and don't reduce the possibilities that compilers offer.
Of course that could be great, but first, we would probably name this option |
A cpp compiler could also generate a .a or .so (so target:lib ?) |
For the interpreter this is not needed, since it does not assume that the code has been verified.
I don't like it too much. The target language and the kind of output to produce seem pretty orthogonal to me. I would much prefer have separate |
I agree we could have So unless we have a language whose name is "run" or "translate", "csproj", "dll" or "exe", the fact that these concepts are orthogonal is perfect to gather them in one place unambiguously. |
@MikaelMayer can we take a step back and first look at the use-cases? I'd prefer to let our UI reflect the use-cases instead of focussing on what the CLI can do. Three use-cases I see are:
For use-case (1), we currently have For use-case (3), we currently have For use-case (2), we currently have I think ideally we'd have We will let |
Agreed, based on the discussions. The option
I disagree respectfully. For users, one way to integrate with another project is to simply create a stand-alone verified DLL or JAR (a library that does not need to be run, but that is 100% Dafny). That was one of the promises of Dafny: To create verified libraries in target platforms. Also, I still largely prefer
As said in my paragraph above, the binary artefact might just be a library and not be executable per se, but it could be useful for another executable application.
I see |
I agree.
Are you saying that a user running I doubt this is a useful workflow for users since it doesn't give them control over the artefact that's produced by the target language build system. Even for one of the least configurable target platforms, .NET, the user still wouldn't know whether the created .dll has been optimised for running or debugging, and whether it's built for a particular platform or requires the .NET framework. Even if the .dll happens to be what they need, then wouldn't users in general prefer a workflow where they explicitly call Integrating a Dafny library as part of a bigger application also means that the user is already familiar with the target language build system, so is there really a downside to asking them to invoke it? I think
I think
Agreed |
I vote in favor of both the use cases of
As for names, I prefer 'translate' for the step of emitting source code. |
Good job for the issue description rewriting @keyboardDrummer .
I think you meant
Let's choose between
What did you have in mind with
Could I please have an option Missing in the discussion and alternatives
|
What should this option do besides leaving out the project file? Should it bundle all produces sources into a single source file with the Dafny runtime inlined? How will it be used?
That's a good point. I'm curious how much time it'll take to generally test a Dafny program versus verifying it. Generally languages have a way of running just resolution checking without running tests, since checking resolution is much cheaper. I made the assumption that testing a Dafny program was at a similar weight level as verifying, and thus users would generally want to do both at the same time, but thinking about that again I'm not so sure. Maybe testing is in a sense less bounded in runtime than verification, since you can generate large amounts of inputs for testing. In that case, I'd prefer having
You wouldn't be able to do that in one step. I think it's fundamental about the verb system that you have to make choices about what you want to achieve, and once you choose one verb, results and options of other verbs may not be available. You could create combined verbs like
Interesting point, I thought about this too. However, I don't see how |
After reflection, It looks like it's already the case that /spillTargetCde outputs jar dependencies, or necessary headers of cpp. Well, in that case, we can ignore this. I can always ignore the project file and have it overriden when I'm trying to call Dafny on multiple test files.
Looks good to me.
Making choice about what you want to achieve needs not to be exclusive. Being able to put multiple verbs next to each other makes sense in our case. We have to consider that the verbs "translate", "build" and "run" describe three phases of our pipeline, each depending on the previous one. The choice to make is whether we want to emit intermediate outputs or not. Why forcing the user to choose between the three? Moreover, this isn't added complexity in the implementation, we already do this in the current CLI. I'm talking only about a migration to a better command line, that is easier to remember.
It's useful for developers of the Dafny language. We do not need to consider it at this stage. But please put it in the "out of scope" section of the handling of this issue. |
I think the way commands work is that you can't have two commands for one invocation, so while you could add a combined command, like Suppose you did I think to make it all work well, you've have to introduce combined commands, so you could introduce On a technical note, the |
The help of
Only for the help of
First, I don't think we have these conflicts right now, so this is not relevant to this PR. Second, I think that when this happens, the "run" could ignore the |
It's not clear to me how you're suggesting it would work. Does I think what is closer to what you're looking for is an option Could you tell me what's the exact scenario in which you're looking to do a translate-build-run? You're doing a run, so apparently it's a standalone Dafny application, not a library. I can imagine you also want to emit the binary, since you might decide the |
FTR, link to GCC's developer's options (including |
Fixes #2036 Fixes #2360 # Changes - Introduce three commands for the Dafny CLI: `verify`, `integrate`, `run`, as defined in #2036 - When commands are used, use a redesigned UI for the CLI - Use proper GNU options - (`-` and `--` for short and long names, instead of `-` and `/` for long names) - Use `=` instead of `:` for specifying the value of an option in a single term - boolean options take true and false instead of 1 and 0 as arguments. - `--<option>` will mean the same as `--<option>:true` for boolean options - Boogie options can only be specified through the option `--boogie="/loopUnroll:3 /overlookTypeErrors"` - Some Boogie options are exposed at the Dafny level: - `vscCores` is exposed as `cores` - `useBaseNameForFileName` is exposed - `timeLimit` is exposed as `verificationTimeLimit` - Rename several options - `compileTarget` is renamed to `target` - `dprint` is renamed to `print` - `print` is renamed to `bprint` - `compileVerbose` has been inverted and renamed to `quiet` - Some options have been hidden, so they don't show up in help: - `print` (previously named dprint), `rprint`, `bprint`, `printMode`, `useBaseNameForFileName` - There is a new mechanism for adding options, that allows adding options to both the new and old CLI UI. `showSnippets` is an existing option that has been refactored to make use of this new mechanism. - Disable the use of `compile`, `spillTargetCode` and `dafnyVerify` when using commands. - `dafny <command> --help` shows which options there are for that specific command. - Many existing options are still missing in the new commands. The plan is to add them gradually while we convert our usage over to these commands, and to at the same time refactor some of these options. Output from `dafny --help`: ``` Description: The Dafny CLI enables working with Dafny, a verification-aware programming language. Usage: Dafny [command] [options] Options: --version Show version information -?, -h, --help Show help and usage information Commands: verify <file> Verify the program. run <file> Run the program. build <file> Produce an executable binary. integrate <file> Generate source and build files in a specified target language. ``` Output from `dafny verify --help`: ``` Description: Verify the program. Usage: Dafny verify [<file>...] [options] Arguments: <file> input files Options: --cores <count> Run the Dafny CLI using <n> cores. Defaults to 1. [default: 1] --verificationTimeLimit <seconds> Limit the number of seconds spent trying to verify each procedure [default: 0] --showSnippets 0 (default) - don't show source code snippets for Dafny messages 1 - show a source code snippet for each Dafny message [default: False] --plugin <path to one assembly> (experimental) One path to an assembly that contains at least one instantiatable class extending Microsoft.Dafny.Plugin.Rewriter. It can also extend Microsoft.Dafny.Plugins.PluginConfiguration to receive arguments More information about what plugins do and how define them: https://github.com/dafny-lang/dafny/blob/master/Source/DafnyLanguageServer/README.md#about-plugins [] --boogie <boogie> arguments to boogie --prelude <file> choose Dafny prelude file -?, -h, --help Show help and usage information ``` Output from `dafny run --help` ``` Description: Run the program. Usage: Dafny run [<file>...] [options] Arguments: <file> input files Options: -t, --target <language> cs (default) - Compilation to .NET via C# go - Compilation to Go js - Compilation to JavaScript java - Compilation to Java py - Compilation to Python cpp - Compilation to C++ Note that the C++ backend has various limitations (see Docs/Compilation/Cpp.md). This includes lack of support for BigIntegers (aka int), most higher order functions, and advanced features like traits or co-inductive types. [default: cs] --noVerify Skip verification [default: False] --cores <count> Run the Dafny CLI using <n> cores. Defaults to 1. [default: 1] --verificationTimeLimit <seconds> Limit the number of seconds spent trying to verify each procedure [default: 0] --showSnippets 0 (default) - don't show source code snippets for Dafny messages 1 - show a source code snippet for each Dafny message [default: False] --plugin <path to one assembly> (experimental) One path to an assembly that contains at least one instantiatable class extending Microsoft.Dafny.Plugin.Rewriter. It can also extend Microsoft.Dafny.Plugins.PluginConfiguration to receive arguments More information about what plugins do and how define them: https://github.com/dafny-lang/dafny/blob/master/Source/DafnyLanguageServer/README.md#about-plugins [] --boogie <boogie> arguments to boogie --prelude <file> choose Dafny prelude file -?, -h, --help Show help and usage information ``` ### Future work - Expose `--boogie="/print=<file"` as `dafny build --target=boogie` - Expose more Boogie options as first class Dafny options, so they don't require using `--boogie` - Change `--noVerify` so it does not translate to and invoke Boogie. ### Testing - `comp/separateCompilation/usesTimesTwo.dfy` and `git-issues/github-issue-305.dfy` use `dafny build` - `comp/Arrays.dfy` and `comp/AsIs-Compile` use `dafny verify` and `dafny run` - Most of the tests using commands use longname options, and `comp/AsIs-Compile` also uses shortname options - `dafny0/AssumptionVariables1` uses boogie options through `--boogie-<optionName>` - `git-issue-2197.dfy` tests the boolean option `showSnippets` without explicit truthy value, while `ShowSnippets.dfy` tests it with explicit thruthy value. <small>By submitting this pull request, I confirm that my contribution is made under the terms of the [MIT license](https://github.com/dafny-lang/dafny/blob/master/LICENSE.txt).</small> Co-authored-by: Clément Pit-Claudel <[email protected]>
Related discussion in: #1322 (comment)
Goal
Update the Dafny CLI so it can accept as its first argument a "command". When no command is passed, the CLI remains unchanged. Commands correspond to use-cases. When a command is used, other options may no longer be available since the command specifies them. The options
/compile
and/spillTargetCode
are not available when using commands.dafny verify <inputs>
, runs verification, but does not emit anything. Useful in CI and when developing without an IDE.dafny /compile:0
dafny run <inputs>
, runs the Dafny program. Useful for running Dafny applications during development.dafny /compile:3
.dafny run --no-verify
runs the program without verifying it, similar todafny /noVerify /compile:4
--debug=<port>
will start a Debug server protocol server that listens at the specified port..cs
,.dll
,.java
,.jar
, these may be used to implement methods annotated with{:extern}
in the Dafny sources. Only input files that use the same back-end type may be used. The option--target
may be used to force using a particular back-end.dafny build [--os] [--arch] <inputs>
, creates a binary that can either be executed directly on the specified platform and architecture, or usingdafny run
when a platform and architecture independent build is made. Useful when creating a Dafny-only application or library.dafny build --os=win --arch=x64 <sourceFile>
, will create a.exe
binary that can be executed on a 64 bit Windows machine.dafny build <sourceFile>
will create a file that can be executed on any machine usingdafny run <builtFile>
. We leave the format of the built file unspecified for now.dafny /compile:1
.dafny build --no-verify
builds the program without verifying it, similar todafny /noVerify /compile:2
--target
dafny translate <target> <inputs>
, compiles to target language source and build files. The end result can immediately be invoked by a target language build tool. Useful for creating libraries to be used by an application written in another language.dafny /compile:0 /spillTargetCode:2
.dafny translate --no-verify
skips verification and produces target source code, similar todafny /noVerify /compile:0 /spillTargetCode:3
.translate
, and as such may define additional options and arguments. For example,java
may take an additional argument[gradle|maven]
to specify for which build system to generate files for, so a user could invokedafny translate java gradle <inputFile>
. Since targets are subcommands, help can be shown for them usingdafny translate <target> --help
..csproj
file that references the Dafny Runtime NuGet package and the required .NET version.package.json
that specifies a Dafny Runtime NPM package as a dependency, and possibly ajsconfig.json
to specify which ECMAScript version is required.pyproject.toml
that specifies the required python version and the Python Dafny Runtime as a dependency.Alternatives
A translate option that doesn't require a package manager
The current
dafny translate
produces files that rely on a package manager in the target language. For users who don't want to use a package system, Dafny could provide an option to produce sources that can be easily included as generated source in another project. This would mean the Dafny runtime is emitted as source, and possibly it would be good to package all the sources together in a single large source file for easy inclusion.Combined commands
Users who want to get the output of different Dafny commands together, can do so by running several commands separately. For example, a customer who wants .cs sources, a .dll, and to run that .dll, can do:
Alternatively, Dafny could offer combined commands, like
translate-build-run
.Out of scope
dafny package/publish
, commands related to publishing build artifacts.dafny [test|check]
runs tests. Useful when developing and in CI.dafny /compile:0
--no-verify
will skip verificationImplementation hints
We expect a straightforward implementation
The text was updated successfully, but these errors were encountered: