这是indexloc提供的服务,不要输入任何密码
Skip to content

Conversation

@KevinRansom
Copy link
Contributor

@KevinRansom KevinRansom commented Nov 6, 2019

Update @jonsequitur 's PR to probe for cross platform native .dlls

Other changes are Jon's.

{
public class NativeAssemblyLoadHelper : INativeAssemblyLoadHelper
{
private static readonly HashSet<DirectoryInfo> globalProbingPaths = new HashSet<DirectoryInfo>();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are several instances of NativeAssemblyLoadHelper created. The globalProbingPaths is the union of all of the located probing paths.

}
}

private IEnumerable<string> ProbingFilenames(string name)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the name passed in here is the value specified with the DllAttribute. by convention, the dll may have:

  1. A full path
  2. A relativepath
  3. lib prepended
  4. on windows .dll or .exe as a suffix.
  5. on linux .so as a suffix
  6. on macos .dynlib as a suffix

This function enumerates the possibilities.

}
}

private IEnumerable<string> ProbingPaths(string probingPath, string name)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function combines the probing root directory with the runtimes/rid/native to produce a list of dll's

(libraryName, assembly, searchPath) =>
{
var ptr = IntPtr.Zero;
if (_resolvers.TryGetValue(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use calling assembly path to limit probes to _probepaths.

return ptr;
});

IntPtr nativeLoader(string dll)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we can't load it, just return a Zero intptr

foreach (var pname in ProbingFilenames(name))
{
var p = Path.Combine(path, pname);
if (File.Exists(p))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we are probing for a file, don't return it if it isn't actually there.

NuGet.config Outdated
<add key="dotnet-try" value="https://dotnet.myget.org/F/dotnet-try/api/v3/index.json" />
<add key="roslyn" value="https://dotnet.myget.org/F/roslyn/api/v3/index.json" />
<add key="dotnet-corefxlab" value="https://dotnet.myget.org/F/dotnet-corefxlab/api/v3/index.json" />
<add key="dotnet-corefxlab" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/MachineLearning/nuget/v3/index.json" />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to include this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this file should not use azure package source

void Configure(string v);
void Handle(ResolvedNugetPackageReference reference);

void SetNativeDllProbingPaths(IReadOnlyList<DirectoryInfo> nativeDllProbingPaths);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(nit) NativeDll may not be the best name here since .dll is a Windows concept/extension.

How about NativeLibrary?


// Computer valid dotnet-rids for this environment: https://docs.microsoft.com/en-us/dotnet/core/rid-catalog
// Where rid is: win, win-x64, win-x86, osx-x64, linux-x64 etc ...
IEnumerable<string> ProbingRids()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we doing this ourselves? This is exactly what AssemblyDependencyResolver is meant to solve. It reads the .deps.json files and handles any RID fallbacks.

Copy link
Contributor

@jonsequitur jonsequitur Nov 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have a .deps.json. We're doing a restore but not a build in order to avoid copying so many files out of the NuGet caches.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should be generating a .deps.json file then. The logic being added here is super fragile and will not work in many cases.

For example, the proposed code won't handle the same scenario I just fixed in Azure Functions - Azure/azure-functions-host#5187. In that case, the native library is located at runtimes\{RID}\nativeassets\{TFM}. You won't be able to guess at this path, unless you are planning on knowing how to fall back through TFMs. The current RID support here is also problematic because it won't allow for things like alpine to work.

The more we try to hard-code what the current system does, the more we are going to get it wrong. We should be using as much of the current systems as possible.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should be generating a .deps.json file then.

Do you mean by doing a build or do you have another approach in mind?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You wouldn't need to do a full build to generate a .deps.json file. We have a few levels of places we can get at the current code.

  1. Call into the MSBuild Task directly.
  2. Invoke the MSBuild Target

Maybe @dsplaisted or @nguerrera have other ideas on how to generate a .deps.json file without doing a full build.

Another potential route would be to inspect NuGet's project.assets.json file and read all of the native asset paths from it. However, we would still need to know how to do RID fallback which the AssemblyDependencyResolver solves for us. But that is a solvable problem by reading the shared frameworks .deps.json file, which will give you the RID fallback graph for the current machine. (Assuming we are always running on a shared framework in dotnet-try.)

Also - another route is that if you just want to avoid "copying so many files out of the NuGet cache", you can set MSBuild properties to disable that. See dotnet/sdk@1936ebd.

The CopyLocalLockFileAssemblies property can be set to false to revert to
the previous behavior for dotnet build.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with Eric that you should try to reuse as much of the existing build logic as possible. I would avoid calling the GenerateDepsFile task directly, as a lot of the logic of what flows into that happens in targets files. Running the GenerateDepsFile target is probably the right thing to do.

NativeLibrary.SetDllImportResolver(args.LoadedAssembly, Resolve);
ptr = NativeLibrary.Load(dll);
Logger.Log.Info("NativeLibrary.Load({dll})", args.LoadedAssembly.Location);
Console.WriteLine($"NativeLibrary.Load({dll})");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this going to show up in the user's notebook output?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. The Console.WriteLine needs to be removed.

"#r \"nuget:Microsoft.ML,1.4.0-preview\"\n",
"#r \"nuget:Microsoft.ML.AutoML,0.16.0-preview\"\n",
"#r \"nuget:Microsoft.Data.DataFrame,0.1.1-e190920-1\""
"#r \"nuget:Microsoft.Data.DataFrame,1.0.0-e190910-1\""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately we messed up some versions on our myget feed. The 1.0.0- versions are older than the 0.1.1- versions. If you are looking at the feed, note the date it was published.

The good news is that we have renamed the package to Microsoft.Data.Analysis and so all the versioning issues went away.

I can send a separate update to fix this to the latest package name and version, and fixing any code that needs updating.

Copy link
Contributor

@jonsequitur jonsequitur Nov 7, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@KevinRansom, please revert the notebook changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jonsequitur, I had already reverted them on my machine. Eric, updated the version, and have updated it to the newer version.

The tests were failing because there was no way to specify the custom feed, with the new location for the project file. I have added support for #r "nuget:restoresources=http://blah".

Unlike the F# repo, this needs to be specified before the #r nugets that rely on it. So … first I suppose.

I am going to spend some time seeing if I can wire up the F# #r nuget processor, wich would enable me to rip out some of the code.

@eerhardt --- the primary benefit of reading the assets.json file, will be that there is less guesswork about where to find the file is, and so it should perform better in the resolution stage. My main gripe, is there is no decent way to find the nuget root directory.

I will try to incorporate asset.json probing in the F# probing algorithm and thus the C# probing if I can successfully incorporate it. However, using #I to specified probing roots for assemblies, has always been a thing in F# and we will want to continue with that including native probing, it's a nice developer scenario.

Copy link
Member

@eerhardt eerhardt Nov 8, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My main gripe, is there is no decent way to find the nuget root directory.

I believe that is what the FallbackPackagePathResolver in NuGet is for. It will locate where a NuGet package is for a given context.

See https://github.com/dotnet/sdk/blob/51a0655dea6d6e4f56c235191aec6c2f9d62c07b/src/Tasks/Microsoft.NET.Build.Tasks/NuGetPackageResolver.cs#L17 for the usage in the .NET SDK.

However, doesn't the Interactive Kernel control where the nuget root directory is?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per our discussions yesterday, I'd prefer to merge this PR and then revisit the approach, since there a number of different bugs being fixed here, not just the native dependency resolution.

@colombod colombod merged commit 1f0e3e9 into dotnet:master Nov 8, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants