-
Notifications
You must be signed in to change notification settings - Fork 262
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
chore: Factor out projects without runtimes #2568
chore: Factor out projects without runtimes #2568
Conversation
* Rename Dafny folder/DafnyPipeline project to DafnyCore, remove reference to DafnyRuntime and DafnyRuntime.* embedded resources * Create new DafnyPipeline folder/project, referencing DafnyCore and adding DafnyRuntime.* embedded resources * Relabel DafnyDriver as DafnyDriver.dll instead of Dafny.dll, remove reference to DafnyRuntime * Create new Dafny folder/project, referencing DafnyDriver and DafnyPipeline (and hence pulling in embedded runtimes)
…projects-without-runtimes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a very nice improvement. :) I noticed a few tiny things that could be fixed (which should fix at least one of the test failures) but it otherwise seems great.
Makefile
Outdated
@@ -29,12 +29,12 @@ z3-ubuntu: | |||
mv z3-4.8.5-x64-ubuntu-16.04 ${DIR}/Binaries/z3 | |||
|
|||
format: | |||
dotnet tool run dotnet-format -w -s error Source/Dafny.sln --exclude Dafny/Scanner.cs --exclude Dafny/Parser.cs | |||
dotnet tool run dotnet-format -w -s error Source/Dafny.sln --exclude DafnyCore/Scanner.cs --exclude DafnyCore/Parser.cs | |||
|
|||
clean: | |||
(cd ${DIR}; cd Source; rm -rf Dafny/bin Dafny/obj DafnyDriver/bin DafnyDriver/obj DafnyRuntime/obj DafnyRuntime/bin DafnyServer/bin DafnyServer/obj DafnyPipeline/obj DafnyPipeline/bin ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line should perhaps be updated to include DafnyCore
, too?
Makefile
Outdated
|
||
clean: | ||
(cd ${DIR}; cd Source; rm -rf Dafny/bin Dafny/obj DafnyDriver/bin DafnyDriver/obj DafnyRuntime/obj DafnyRuntime/bin DafnyServer/bin DafnyServer/obj DafnyPipeline/obj DafnyPipeline/bin ) | ||
(cd ${DIR} ; dotnet build Source/Dafny.sln -v:q --nologo -target:clean ) | ||
make -C ${DIR}/Source/Dafny -f Makefile clean | ||
make -C ${DIR}/Source/DafnyCore -f Makefile clean | ||
(cd ${DIR}/Source/DafnyRuntime/DafnyRuntimeJava; ./gradlew clean) | ||
make -C ${DIR}/docs/DafnyRef clean | ||
(cd ${DIR}; cd Source; rm -rf Dafny/bin Dafny/obj DafnyDriver/bin DafnyDriver/obj DafnyRuntime/obj DafnyRuntime/bin DafnyServer/bin DafnyServer/obj DafnyPipeline/obj DafnyPipeline/bin ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as for the previous rm
line.
} | ||
var fullJarName = $"{targetDirectory}/{jarName}"; | ||
FileStream outStream = new FileStream(fullJarName, FileMode.Create, FileAccess.Write); | ||
stream!.CopyTo(outStream); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change has the side effect of creating an empty JavaRuntime.jar
if it's not found in the assembly, as opposed to doing nothing, which is perhaps better behavior? It might be even nicer to emit an error message in that case, but I didn't do that in the original code, either. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah my intention was just to cleanly make this an exception rather than a silent failure, but I can throw right away without that messy side effect.
Note that I'm going to make it an exception rather than an error message as SinglePassCompiler.ReadRuntimeSystem
does (and I intend to make that throw as well in the next PR). At least right now, the publicly released tools should always have the runtimes attached, so I'd rather crash loudly if we've made a publishing mistake.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact I'm touching SinglePassCompiler.ReadRuntimeSystem
already anyway, I'm going to make it throw in this PR after all - no time like the present!
@@ -1,18 +1,14 @@ | |||
<Project Sdk="Microsoft.NET.Sdk"> | |||
|
|||
<PropertyGroup> | |||
<OutputType>Exe</OutputType> | |||
<AssemblyName>Dafny</AssemblyName> | |||
<OutputType>Library</OutputType> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One nice impact of this is that a client can now get all of Dafny as a library (though only conveniently if we publish this library to NuGet).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, and I think I'm going to have to define an additional "DafnyWithoutRuntimes" Exe project that depends on this in order to run Dafny on my DafnyRuntime.dfy
code in the next PR. My intent remains to keep this and that project internal-only for now though.
@@ -21,8 +21,7 @@ | |||
</ItemGroup> | |||
|
|||
<ItemGroup> | |||
<ProjectReference Include="..\DafnyDriver\DafnyDriver.csproj" /> | |||
<ProjectReference Include="..\DafnyRuntime\DafnyRuntime.csproj" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on the test output, it seems that this project still depends dynamically on DafnyRuntime
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Specific tests are depending on linking to DafnyRuntime.dll
, yup. Unfortunately one of them reveals that DafnyMain
calls Assembly.LoadFile
on any dll
file passed to the CLI, in order to read the contents of any DafnySourceAttribute
: https://github.com/dafny-lang/dafny/blob/master/Source/Dafny/DafnyMain.cs#L67. This will fail if its dependencies are not available (DafnyRuntime.dll
or any other dependency!).
I originally fixed this by loading the assembly reflectively using Cecil, but unfortunately we lost that when switching to .NET Core: https://github.com/dafny-lang/dafny/pull/794/files#diff-0ba2e4842e187b0efcf6a6b5fd6fca73b546ece27e54074265eab734f826240dL45-R47. Even better, there's an Assembly.ReflectionOnlyLoad
method, but it turns out it always did a regular load instead, and now always throws an exception instead (which is definitely better, but still feels like a bait-and-switch :P )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eventually figured out the supported replacement for Assembly.ReflectionOnlyLoad
- see updated PR description and release note.
…projects-without-runtimes
@@ -30,36 +29,8 @@ | |||
<PackageReference Include="Boogie.ExecutionEngine" Version="2.15.7" /> | |||
</ItemGroup> | |||
|
|||
<ItemGroup> | |||
<ProjectReference Include="..\DafnyRuntime\DafnyRuntime.csproj" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine removing the reference to the DafnyRuntime, however, in one of my PRs, I am making use of the DafnyRuntime.cs which should then become a dependency of DafnyCore in your setting. Can we just add an external dependency to this file so that it's included at compile time?
That was we don't need a dependency of all the possible runtimes as you suggest but I have still it working for us.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your PR will actually work just fine after this change. Since you're not passing /useRuntimeLib
when compiling your Dafny code through dafny.msbuild
, the compiled output will have the embedded DafnyRuntime.cs
file prepended, and you won't need to depend on DafnyRuntime.dll
.
That means that the version of the runtime you build your part of DafnyCore
with doesn't affect the version that a dafny
end user will end up depending on in their compiled code. It's admittedly a little weird and confusing to have the C# runtime code embedded like that though. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I see, it's in the generated code. That's fine I think ^^
@@ -1,18 +1,14 @@ | |||
<Project Sdk="Microsoft.NET.Sdk"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the PR description:
Relabel DafnyDriver as DafnyDriver.dll instead of Dafny.dll, remove reference to DafnyRuntime
I'll be able to use this entry point to build Dafny source code into the runtimes when implementing #2390
Why do you need this project? Can't you use DafnyCore instead? Are you planning on setting the output type here to Exe again so you can run it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm planning on adding an empty Exe project that references DafnyDriver
, something like DafnyWithoutRuntimes
, so I can easily invoke the Dafny compiler from something like a Makefile. I don't know of any way to invoke logic in DafnyCore
directly, but I'd be happier if there was!
…projects-without-runtimes # Conflicts: # RELEASE_NOTES.md # Source/DafnyCore/DafnyCore.csproj # Source/DafnyDriver/DafnyDriver.csproj # Source/DafnyLanguageServer.Test/Various/PluginsTestBase.cs # Source/version.cs
…projects-without-runtimes
…projects-without-runtimes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good! I had a couple of questions that could lead to changes, but I'm approving it to avoid delay in the (likely) case where they don't require any.
|
||
<ItemGroup> | ||
<ProjectReference Include="..\DafnyDriver\DafnyDriver.csproj" /> | ||
<ProjectReference Include="..\DafnyPipeline\DafnyPipeline.csproj" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need DafnyPipeline
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Absolutely, since that's how the runtime files are included. I understand why you ask, because the minimal contents of Dafny
should just be DafnyDriver + runtimes
, but DafnyPipeline
is exactly the assembly that embeds the runtimes. Most importantly the compilers load them from the DafnyPipeline.dll
assembly explicitly rather than whatever the currently executing assembly is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, of course!
} | ||
|
||
private static string GetDafnySourceAttributeText(string dllPath) { | ||
using var dllFs = new FileStream(dllPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this result in a reasonable error if dllPath
is a non-existent file? Or does the earlier code in DafnyFile
ensure that it exists?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good callout! It's no worse than the old version that tried to Assembly.LoadFile
it: you still get a System.IO.FileNotFoundException
, just with a slightly different stack trace.
It's worth making that cleaner since it's a user error that shouldn't lead to a crash, but it may be non-trivial to fix. Throwing IllegalDafnyFile
will probably lead to a different less helpful error so it may need some refactoring. I cut #2719 as a follow up.
Factors out two new projects that don't depend on the
DafnyRuntime
project orDafnyRuntime.*
runtime artifacts, and removes the DLL-level dependencies onDafnyRuntime.dll
. It also has the happy side-effect of making directory, csproj, and assembly names consistent.The four main changes are:
Dafny
folder/DafnyPipeline
project toDafnyCore
, remove reference toDafnyRuntime
andDafnyRuntime.*
embedded resourcesDafnyPipeline
folder/project, referencingDafnyCore
and addingDafnyRuntime.*
embedded resourcesDafnyPipeline.dll
does NOT depend onDafnyRuntime.dll
, however! It has a project-level dependency to ensureDafnyRuntime
is built first, but only embeds the runtime artifacts.DafnyDriver
asDafnyDriver.dll
instead ofDafny.dll
, remove reference toDafnyRuntime
Dafny
folder/project, referencingDafnyDriver
andDafnyPipeline
(and hence pulling in embedded runtimes)Note that we are still only publishing
Dafny.dll
andDafnyPipeline.dll
as Nuget packages, and they still transitively contain the same content. We could publishDafnyDriver
and/orDafnyCore
in the future as well.Removing
DafnyRuntime
as a DLL dependency from all of these projects initially caused theTest/dafny0/DafnyLibClient.dfy
test to break. This is because the driver was attempting toAssembly.Load
each DLL passed to it, in order to read anyDafnySourceAttribute
value out of it if present. This has never been a good idea, since an arbitrary DLL will have dependencies not satisfied by the invoking context, and not findingDafnyRuntime.dll
was just one potential error this could cause. I had previously used Cecil to read DLL files without loading them, but this was lost when we moved to .NET Core v2 since that library was not supported. This time I've used the built-inSystem.Reflection.Metadata.MetadataReader
and related types to decode enough of the DLL to read this attribute.By submitting this pull request, I confirm that my contribution is made under the terms of the MIT license.