Skip to content
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

Create nuget package (without native libs) #744

Closed
wants to merge 1 commit into from

Conversation

acco32
Copy link
Contributor

@acco32 acco32 commented Jul 6, 2018

@Mizux I am unsure how you plan to package the native libraries for each operating system. This target will create the package for dotnet only. Once the native library installation is decided we can add it as a dependency to this package.

@Mizux
Copy link
Collaborator

Mizux commented Jul 6, 2018

thx for this PR.
I think we can integrate it as a first step for the OrTools nuget package, here what I have in mind for the futur (no deadline yet)

Roadmap

Release

On the longterm I would like to provide a nuget package with native libs for all supported platforms (like we do for python package). But this is more a requirement for doing a release from my side...
issue: While on python you build a package on each platform then upload them with the same name so package name is "universal" and python package manager retrieve the correct one according to your current host. On the other hand for windows you have to create one nuget package which embed the three targets (linux, win, macos).
Maybe two step process:

User

For customer we should also provide the possibility to create/generate a package from its build directory only containing its platform kind of local custom package build.
make dotnet_package -> profit

so maybe we'll need two .nuspec file one for user i.e. single platform package and one for multi-platforms release package

Open to any feedback !!!!
note: for the 6.8 I think we will continue to provide an zip/tar archive with all the necessary
cf my working in progress on it https://github.com/google/or-tools/commits/mizux/dev

Misc

It seems there is also dotnet pack which only use the csproj and not the nuspec to create the package.
I need to dig a little...
Feedback from a dev trying to do it ->
https://stackoverflow.com/questions/49162127/how-to-include-native-assets-in-nuget-on-multiple-platforms-only-64-bit
related issue: NuGet/Home#2372
related issue: NuGet/Home#6645

Documentation

Here my wish list of RIDs (Runtime IDentifier) target
win-x64;linux-x64;osx-x64
src: https://docs.microsoft.com/en-us/dotnet/core/rid-catalog#using-rids

@Mizux Mizux self-assigned this Jul 6, 2018
@Mizux Mizux added Feature Request Missing Feature/Wrapper OS: Windows Windows OS OS: Linux GNU/Linux OS OS: Mac MacOS Lang: .NET .Net wrapper issue labels Jul 6, 2018
@Mizux Mizux added this to the v6.9 milestone Jul 6, 2018
@Mizux Mizux self-requested a review July 6, 2018 23:35
@acco32
Copy link
Contributor Author

acco32 commented Jul 21, 2018

@Mizux For the native libraries, I think it would be cleaner to have a separate installer (with the destination being the system folders). This way, the dotnet package is truly platform independent.

@Mizux
Copy link
Collaborator

Mizux commented Jul 24, 2018

if I understand you we should have several nuget packages:

  • Google.OrTools: only contains the csharp/fsharp dll and conditionally depends on one of the following one.

note: let's call it frontend.

  • runtime.linux-x64.Google.OrTools: native linux-x64 ortools i.e. Google.OrTools.import.so
  • runtime.osx-x64.Google.OrTools: native osx-x64 ortools i.e. Google.OrTools.import.dylib
  • runtime.win-x64.Google.OrTools: native win-x64 ortools i.e. Google.OrTools.import.dll

note: let's call them backends.
this follow the windows naming convention of Microsoft.NETCore.App

  • Google.OrTools.Examples: package containing all examples, not sure how to make it usable...

note: let's call it examples.

Question: since we pass the name of the native library when generating cs wrapper (e.g. here) does it means that wrappers should also belong to each native packages ?

I think to do it in several steps:

  1. make a full fat one package one RID only working (i.e. create one package per platform and maybe only publish the win-x64 one on nuget.org first)
  2. move all native code to runtimes/RID/.. and keep it working
  3. split the package in two part
  4. Use condition in the "frontend" package to retrieve the good native backend.
  • move example in their own package
  • make/add support for the last netfx framework net70 if needed

@acco32
Copy link
Contributor Author

acco32 commented Jul 28, 2018

@Mizux I like the proposal with a few modifications.

Yes, the native libraries and wrappers would need to be packaged together which reduces the platform build to a small wrapper module that only has the dotnet/C++ binding. That module would then be referenced from the remaining dotnet library without any knowledge of the underlying binding module.

*nix:
Google.OrTools.Import.so
Google.OrTools.Import.dll

MacOS:
Google.OrTools.dylib
Google.OrTools.Import.dll

Windows:
Google.OrTools.Import.dll

Each of the above would be a separate package that would be installed in the GAC (to avoid location issues). Afterward the nuget package would be the top level libraries that only search for Google.OrTools.Import.dll from the GAC (where the developer would need to import it into their project)

Google.OrTools.dll
Google.OrTools.FSharp.dll

I would personally like to avoid platform information in nuget and essentially avoid the branching in some top level library.

As we are tageting netstandardXX, net70 would come from whether the next version of the metaframework targets it (for instance if netstandard21 includes it we get it for free by upgrading the metaframework).

As for examples, have a separate github project that people can checkout with a small subset of the examples used for development. I don't think a separate package is needed.

@mwpowellhtx
Copy link
Contributor

mwpowellhtx commented Aug 6, 2018

@acco32 @Mizux Would you consider separating the examples into a separate Google.OrTools.Examples.nupkg? For starters, I am eager to get my hands on at least an RC package that I can start migrating my own assemblies depending on it. Second, this package could carry with it a dependency on the core Google.OrTools.nupkg itself, and clears the deck to push forward with earnest. Thanks!

@jonwagner
Copy link

The proposal above seems to match the standard convention for packaging native apps.

  • Google.OrTools package
    • Contains .NET library (Google.OrTools.dll)
    • Reference to platform-specific package (e.g. Google.OrTools.linux-x64)
  • Google.OrTools.(platform) package (e.g. Google.OrTools.linux-x64)
    • Contains the platform-specific import library (Google.OrTools.Import.dll)
    • Contains platform-specific implementations and dependencies (e.g. Google.OrTools.dylib)

Some notes:

  • Don't put anything in the GAC. It's a cause of numerous compatibility issues and is generally unnecessary if you are using nuget packaging.
  • I was able to build OSX and Windows versions of the package with the latest code, making small changes to the nupkg file similar to this PR and building them separately. The only issue I saw was including all of the files in the temp_dotnet file brings in a lot of unnecessary files.

@mwpowellhtx
Copy link
Contributor

@jonwagner Good point re: GAC. I wasn't aware OR-tools was deploying there? Perhaps I missed something? Anyway, that should be something left to the applications guy(s), per se, minimum integrating OR-tools, if at all. But then again, with the advent of netcore, netstandard, way of doing things, of whole platform/application containers, your run-time, per se, pretty much gets deployed to a well contained sandbox, so it isn't a concern any more.

@jonwagner
Copy link

OR-tools isn't currently in the GAC, but it was a suggested solution above.

@Mizux
Copy link
Collaborator

Mizux commented Aug 9, 2018

@jonwagner do you know a public working example of this architecture ?

note: I'm testing on pet project there https://github.com/Mizux/dotnet but still have some difficulties...

@jonwagner
Copy link

@Mizux here's an article on how to do multi-runtimes as a single package:

https://natemcmaster.com/blog/2016/05/19/nuget3-rid-graph/

The downside is that you get a large package with multiple sets of binaries, but it's really easy to do as a single package.

I'm pretty sure that the large system-level packages split them somehow. Let me poke around and see if I can find an example.

@jonwagner
Copy link

jonwagner commented Aug 9, 2018

@Mizux I spent the last half hour looking for documentation and examples for packaging native libraries. They all seem to use the single-package approach.

You build one package with files in a structure like this:

/lib/<framework>/*
/runtimes/<runtimeid>/lib/<framework>/*
/runtimes/<runtimeid>/native/*

The link I posted above has pretty good instructions.

It will make a large package, but then consumers of the package will always have the files it needs. Now that I've looked at it I'd recommend going with the single-package approach.

@Mizux
Copy link
Collaborator

Mizux commented Aug 28, 2018

@jonwagner thanks for the link unfortunately in our case we must use the several-packages
approach which is documented nowhere...
Since or-tools is a C++ library it's nearly impossible to build from source for windows,mac,linux on one platform...

Fortunately after few weeks of effort I manage to do it cf my dev branch...
doc here for details: https://github.com/google/or-tools/blob/mizux/dev/ortools/dotnet/README.md
@ALL (@mwpowellhtx) I'll try to upload beta package here so you can test it a give me ome feeback if you want...

ToDo before pushing:

  • Fix Google.FSharp build (currently disabled)
  • Fix Xunit project (currently disabled)
  • Move all examples to examples/csharp and generate a .csproj for each of them.

Copy link
Collaborator

@Mizux Mizux left a comment

Choose a reason for hiding this comment

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

I think this PR will be replaced by the branch mizux/dev

@mwpowellhtx
Copy link
Contributor

@Mizux Blazing the trail. I like it; looking forward to seeing the path you forge.

@jonwagner
Copy link

The mizux/dev branch looks good. Great work!

@acco32
Copy link
Contributor Author

acco32 commented Sep 9, 2018

@Mizux the dev branch looks good.

@Mizux
Copy link
Collaborator

Mizux commented Sep 10, 2018

Here a preview if you want to test on Windows only:
Windows-preview-6.8.704.zip

i.e. Google.OrTools only depends on runtime.win-x64.Google.OrTools

@mwpowellhtx
Copy link
Contributor

@Mizux To be clear, I think we got our wires cross. When I think of Google.OrTools building for netstandard, I expect the same Google.OrTools.$(version).nupkg. The only difference being the targets. Google.OrTools.dll, perhaps a Google.OrTools.xml, etc, should still be there. I do not see there being any value added introducing yet another package runtime.win-x64.Google.OrTools.$(version).nupkg whatsoever. Within which Google.OrTools.$(version).nupkg may contain bitness specifics, as far as I know, but which target is netstandard.

@Mizux
Copy link
Collaborator

Mizux commented Sep 11, 2018

@mwpowellhtx As I said before I can't build one big package for the three OS targeted (win, linux, osx) on one machine so I create a "backend" package for each OS let's call them runtime packages. And one meta package the "frontend" depending on each of them and containing the Reference assembly.

  • nuget (like maven) package manager contrary to pypi, nix, bintray/conan (and any smart package mamager) only want ONE archive (i.e. one .nupkg) per version i.e. you can upload one package for each native OS targeted so that's why I had to create a package tree.
  • You'll only need to depends on Google.OrTools which transitively depends on runtime packages.
  • Since Google.OrTools is a meta package it only contains the reference assembly in ref/netstandard2.0/Google.OrTools.dll you can see it as an empty library only containing a list of "undefined symbol" (if I can make an analogy with the language C) and runtime.* contains the implementation in runtime/<rid>-x64/Google.OrTools.dll

Please take a look at https://github.com/google/or-tools/tree/master/ortools/dotnet (feedback/PR welcome)

@Mizux
Copy link
Collaborator

Mizux commented Sep 11, 2018

@acco32 Since Google.OrTools is a meta package, I can't compile any file in it thus F# files are in a separate package (i.e. Google.OrTools.FSharp).
Maybe later (v6.10) I will rename the current project Google.OrTools to Google.OrTools.CSharp then reuse Google.OrTools as empty package depending on Google.OrTools.FSharp and Google.OrTools.CSharp so customer only need to depends to Google.OrTools to get C# and F# which is OK since .Net Core SDK can build both languages (contrary to previous mono/.NetFramework which require an extra package for F# (VisualStudio and brew package if I recall well not sure if mono package integrate the F# compiler))

@mwpowellhtx
Copy link
Contributor

mwpowellhtx commented Sep 11, 2018

@Mizux I'm not sure what your sentence means means, "cannot compile any file in it, thus..." ? As far as I know, to OrTools build process, FSharp has always been a separate thing over and above and depending upon OrTools.

You've got your dependencies mixed up. Open the packages as ZIP files; you don't even have to rename the extension. You will find FSharp depending on the now empty package Google.OrTools, which now depends on the zero value added "run time". Maybe I am oversimplifying, however, I'd suggest if this is the case that it is time to reconsider how OrTools builds.

Given the cross platform nature of netstandard, it is easy to include the necessary binaries in the lib or even native directories, as far as I know. Case in point, let's say someone does want to run OrTools in .NET across platforms? Or even embedded? Then what?

Hopefully on the other side of the Core/Standard dust settling things will be smoother, but for now, the effort is what it is. But having an entirely separate "runtime" package adds no value IMO but to confuse matters.

I don't know about Mono, as I haven't followed it that closely. However, now that things are on the Core/Standard track, I don't see anything gained by dwelling there apart from a historical learning perspective.

Thoughts?

@Mizux
Copy link
Collaborator

Mizux commented Sep 11, 2018

@mwpowellhtx

  • zip file need to be extracted..., github only allow upload of images and zip archive (10Mo max).
    So I only zip it to be able to provide an all in one on nugets preview test archive. We will upload each one on nuget.org so it won't be a problem anymore. I means you will depends on Google.OrTools few package are downloaded and it will just work wherever you work on windows, osx or linux host.
  • If you build a C# wrapper on native library by hand you can have one cs file which "dll import" the correct native library according to your current runtime OS but here these wrapper are auto generated by SWIG i.e. we have three time the same wrapper with the dll import which differ leading to three Google.OrTools.dll specific to one rid -> multiple definition if you don't take into account the <rid>.
  • dotnet run ignore <rid> option on linux so it just not work and dotnet bin/x64/...../foo.dll is not what I call "just working" ;)
  • .Net is only an end of the Makefile based build process which start with the C++ build of the dependencies and there is not cross-toolchain for osx, win and linux which run on a single host so we build osx on osx, linuxs on linux (docker for several distro) and windows on windows (plus think of all dependencies to build etc...). (i.e. we don't have support for cross-compilation yet (arm cross compilation using CMake-Toolchain in the pipe))
    note: I'll try to create an up-to-date schema of the build pipeline...
  • Take a look at https://www.nuget.org/packages?q=Microsoft.NETCore.App (e.d. here they use a "runtime.json" to download the relevant runtime that's why you can't see directly dependencies on runtime packages, it avoids consumers to download all runtime but it has some boring side effect e.g. dotnet build won't download it so dotnet bin/.../*.dll will fail and transitive dependency doesn't work anymore...)
    Todo: need to cleanup a little runtime for linux and osx to remove unneeded .so/.dylib (~30Mo while windows which use static lib is ~7Mo).
  • Also splitting in several packages means I can upload one runtime package while keeping the same meta package and/or having each host uploading their runtime package e.g. uploading the runtime.osx-x64.Google.OrTools.XXX.nupkg from my macOS build runner and the linux package from my linux one

@Mizux
Copy link
Collaborator

Mizux commented Sep 11, 2018

I'm closing this pull request since mizux/dev has been integrated to master...

@Mizux Mizux closed this Sep 11, 2018
@mwpowellhtx
Copy link
Contributor

@Mizux In the context of NuGet packages, right? Come on, for Christ's sake, don't insult my intelligence here. You can open those, extract them, etc, like you would any ZIP file. From there look at the dependencies for yourself in the actual nuspec that got packaged. You can see clearly what the dependencies are.

Re: the Core packages: Ah, I see, good point! 👍

Sorry if I came off a bit raw there. This whole netstandard thing is a mess and I'm trying to sort some things out by it myself. I do not think my experience therein thus far is too far from being on par with the rest of the industry to date.

Once it is settled and behind us it will be much smoother I'm sure.

Thanks for clarifying.

@mwpowellhtx
Copy link
Contributor

mwpowellhtx commented Sep 18, 2018

One other thing I noticed. Can't wait to see the package finally published to NuGet. Approaching that, remember Google.Protobuf also needs to be potentially repackaged targeting netstandard2. I see that it is, but that it is targeting netstandard 1.6.1+. It is probably fine, but fingers crossed.

Mizux added a commit that referenced this pull request Oct 5, 2018
Change runtime.{rid}.Google.OrTools -> Google.OrTools.runtime.{rid}

note: nuget support team didn't want to give us runtime.{rid}.Google* reserved prefix
beside the fact they use this naming convention in the dotnetframework and give it to
"quamotion" company too
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Feature Request Missing Feature/Wrapper Lang: .NET .Net wrapper issue OS: Linux GNU/Linux OS OS: Mac MacOS OS: Windows Windows OS
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants