google / or-tools

Google's Operations Research tools:
https://developers.google.com/optimization/
Apache License 2.0
11.12k stars 2.11k forks source link

Missing support for .NET Framework in latest Nuget packages #3503

Closed anders9ustafsson closed 1 year ago

anders9ustafsson commented 1 year ago

What language and solver does this apply to? C#

Describe the problem you are trying to solve. Use Google.OrTools Nuget package, versions 9.3 and later, in a .NET Framework 4.8 project.

Describe the solution you'd like Being able to use the latest Nuget pacakge in .NET Framework.

Describe alternatives you've considered

Additional context With version 9.2 and earlier, .NET Framework was supported. Why was .NET Framework support dropped?

lperron commented 1 year ago

because .NET6 is out and is supposed to merge the two branches (dotnet code and dotnet framework).

anders9ustafsson commented 1 year ago

because .NET6 is out and is supposed to merge the two branches (dotnet code and dotnet framework).

Please elaborate. As far as I know, you cannot reference a .NET 6 DLL from a .NET Framework 4.x assembly.

CervEdin commented 1 year ago

Please elaborate. As far as I know, you cannot reference a .NET 6 DLL from a .NET Framework 4.x assembly.

@anders9ustafsson Well, you can but it's likely to crash.

because .NET6 is out and is supposed to merge the two branches (dotnet code and dotnet framework).

@lperron dotnet 6 does not merge dotnet core (typo?) and dotnet framework. Tbh it's really just a rebrand of dotnet core. Dotnet standard is used as a compatibility framework to bridge the two.

anders9ustafsson commented 1 year ago

@CervEdin Yes, it will definitely crash. First of all, you cannot include the Nuget package due to frameworks not matching. Second, if you try to reference the 9.4 Google.OrTools DLL directly, the project will indeed build, but the app will crash due to missing/mismatching DLLs.

I would like to use the PDLP linear solver, but as far as I have been able to find out it is only available in version 9.3 and onwards. The latest OR Tools Nuget package that supports .NET Framework is 9.2.

I have tested to build the stable branch of the Google.OrTools project from source with target framework set to net48. It does build, so as far as I understand it should be possible to re-introduce .NET Framework support in the Nuget package.

Mizux commented 1 year ago

My 2 cents.

Context

  1. .Net Framework [2.0-4.6.1] are deprecated src: https://learn.microsoft.com/en-us/lifecycle/products/microsoft-net-framework
  2. .Net Framework 4.6.2 and 4.8 still seems to be used BUT are not backed by Microsoft on Linux and MacOS... note: Mono is not well supported by dotnet cli and build ecosytem AFAIK
  3. SWIG should generate .Net 4.0 compatible code but in our samples we use some "advanced" C# languages (e.g. string literal, lambda, for each) so porting code to C++17/Java/.Net are barely identical with minor syntax change. ref: https://www.swig.org/Doc4.0/CSharp.html
anders9ustafsson commented 1 year ago

@Mizux Many thanks for your input. Regarding the points you list:

  1. Not an issue, I think most .NET Framework users have no problem if you limit support to version 4.6.2 and later.
  2. For .NET Framework users, Linux and MacOS support is a non-issue. For the .NET Framework target, you would not even need to make Linux and MacOS native packages a dependency, .NET Framework applications will only ever run on Windows.
  3. Not sure what your concern is here, but .NET Framework 4.6.2 and later does support up to C# 7.3 and even C# 8. So language level should hardly be an issue for SWIG generated C# code.

As I pointed out above, I have no problems manually building the Google.OrTools C# project for .NET Framework (4.8), but I would definitely prefer being able to reference an official Nuget package rather than having to rely on locally built DLLs. I am not sure why, but the locally built DLL has terrible performance compared with the 9.2 Nuget version, so I would feel so much more confident being able to use an up-to-date Nuget package instead.

linzeqipku commented 1 year ago

Hi guys, I'm developing a visual studio extension based on or-tools. As VS runs on .NET framework, it would be great if the newest version of or-tools could support net472. Thanks!

anders9ustafsson commented 1 year ago

@Mizux This feature request was added by you to the 9.5 milestone a few weeks ago, but the issue remains closed and I fail to see any development activity related to the issue. Will v9.5 be available for .NET Framework?

lperron commented 1 year ago

Most likely not. We already have a lot to merge in 9.5 Laurent Perron | Operations Research | @.*** | (33) 1 42 68 53 00

Le ven. 4 nov. 2022 à 16:06, Anders Gustafsson @.***> a écrit :

@Mizux https://github.com/Mizux This feature request was added by you to the 9.5 milestone a few weeks ago, but the issue remains closed and I fail to see any development activity related to the issue. Will v9.5 be available for .NET Framework?

— Reply to this email directly, view it on GitHub https://github.com/google/or-tools/issues/3503#issuecomment-1303705321, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACUPL3JMRBDNRDWLNB44PSTWGUQ7PANCNFSM6AAAAAARIFW25U . You are receiving this because you were mentioned.Message ID: @.***>

Mizux commented 1 year ago

to be honest for v9.5, I fear it won't be possible, we already postponed v9.5 for too long IMHO... Maybe for next release v9.6 (around December ?) we (I) may study it depending of my bandwidth...

2 points need to be addressed (before or-tools integration): 1) how in cmake you can count how many options are on or off among a set... in csproj tag is <TargetFramework> for one but <TargetFrameworks> for several (notice the s) also need to deal with the separator ; to build the DOTNET_TFM var for two options (net3.1 net6.0) we can unroll it but if we need few more tfm... https://github.com/google/or-tools/blob/efc089e8b578014a5ce6571e765e79e63e022427/cmake/dotnet.cmake#L77-L86

Pseudo CMake code to test and wrap in a cmake function?:

# In CMakeLists.txt
option(A "" ON)
option(B "" ON)
option(C "" ON)
option(D  "" ON)

# Inside util.cmake
function(generate_tfm OUT OPTIONS...)
  if(A + B + C + D + ... == 0)
    message(FATAL "at least one Target Framework Moniker must be selected")
  endif()

  # open tag
  set(DOTNET_TFM "")
  if(A + B + C + D = 1)
   set(DOTNET_TFM "<TFM>")
  else()
   set(DOTNET_TFM "<TFMS>")
  endif()

  # feed TFM
  set(FIRST ON)
  foreach(T IN LIST A B C D ...)
    if(NOT T)
     continue()
    endif()
    if (FIRST)
      set(FIRST OFF)
    else()
       set(DOTNET_TFM "${TFM};")
    endif()
    set(DOTNET_TFM "${TFM}T")
  endforeach()

  # closing tag
  if(A + B + C + D = 1)
   set(DOTNET_TFM "${TFM}</TFM>")
  else
   set(DOTNET_TFM "${TFM}</TFMS>")
  endif()
endfunction()

# inside dotnet.cmake
...
generate_tfm(DOTNET_TFM A B C D ...)

few possible outputs to ${TFM}: <TFM>B</TFM> or <TFMS>A;B;D<TFMS>

2) How .net48 app behave if we only provide net46 native package will it fallback at runtime to load the net46 native library OR

So pain point are identified just need to find time to test and implement it ;)

ref: https://learn.microsoft.com/en-us/dotnet/standard/frameworks#supported-target-frameworks

CADBIMDeveloper commented 1 year ago

@Mizux , maybe a single NetStandard 2.0 ?

.NET Framework: 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8 ref: https://learn.microsoft.com/en-us/dotnet/standard/net-standard?tabs=net-standard-2-0

NET Standard is a formal specification of .NET APIs that are available on multiple .NET implementations. The motivation behind .NET Standard was to establish greater uniformity in the .NET ecosystem. .NET 5 and later versions adopt a different approach to establishing uniformity that eliminates the need for .NET Standard in most scenarios. However, if you want to share code between .NET Framework and any other .NET implementation, such as .NET Core, your library should target .NET Standard 2.0. No new versions of .NET Standard will be released, but .NET 5, .NET 6, and all future versions will continue to support .NET Standard 2.1 and earlier.

Mizux commented 1 year ago

@CADBIMDeveloper yes something to test and document too. Thx for the suggestion...

anders9ustafsson commented 1 year ago

@Mizux @lperron Many thanks for reopening this request!

Regarding the version of .NET Framework, I would recommend that you target .NET 4.6.1 or 4.6.2. That would definitely be enough for most .NET Framework users, and it is forward compatible up to .NET Framework 4.8.

I understand your concern on the <TargetFrameworks> issue, although I believe you have some kind of solution for it? Anyway, targeting .NET Framework 4.6.1 (2), .NET Core 3.1 and .NET 6 will probably suffice for quite a while forward.

Regarding .NET Standard 2.0, that would of course be a tempting solution, but I am not sure about accessing the native x64 libraries directly from a .NET Standard assembly? It will probably be less extra work if you stick with the approach you have chosen now for .NET.

CADBIMDeveloper commented 1 year ago

@anders9ustafsson , https://github.com/dotnet/standard/issues/584

there is no .NETCore or .NET Standard specific documentation about it because there is nothing special compared to Desktop. If you have a managed .NETStandard library, you should be able to just add DllImports and PInvoke into them as you would in traditional .NET Framework

anders9ustafsson commented 1 year ago

FYI.

When manually building the Google.OrTools.csproj project for .NET Framework, I noticed that C# language version was set to 9.0 in the project file. Officially, .NET Framework is only expected to support C# up to language version 8, but I got no compilation errors when building, at least for .NET Framework 4.8.

When changing language version to 8.0 in the project file, I get the following compilation errors:

\or-tools\ortools\sat\csharp\CpModel.cs(145,33): error CS8400: Feature 'or pattern' is not available in C# 8.0. Please use language version 9.0 or greater. [\or-tools\build\dotnet\Google.OrTools\Google.OrTools.csproj] \or-tools\ortools\util\csharp\NestedArrayHelper.cs(61,27): error CS8400: Feature 'not pattern' is not available in C# 8.0. Please use language version 9.0 or greater. [\or-tools\build\dotnet\Google.OrTools\Google.OrTools.csproj] \or-tools\ortools\sat\csharp\CpModel.cs(146,33): error CS8400: Feature 'or pattern' is not available in C# 8.0. Please use language version 9.0 or greater. [\or-tools\build\dotnet\Google.OrTools\Google.OrTools.csproj] \or-tools\ortools\sat\csharp\CpModel.cs(165,40): error CS8400: Feature 'or pattern' is not available in C# 8.0. Please use language version 9.0 or greater. [\or-tools\build\dotnet\Google.OrTools\Google.OrTools.csproj] \or-tools\ortools\sat\csharp\CpModel.cs(1015,36): error CS8400: Feature 'not pattern' is not available in C# 8.0. Please use language version 9.0 or greater. [\or-tools\build\dotnet\Google.OrTools\Google.OrTools.csproj] \or-tools\ortools\sat\csharp\CpModel.cs(1015,81): error CS8400: Feature 'not pattern' is not available in C# 8.0. Please use language version 9.0 or greater. [\or-tools\build\dotnet\Google.OrTools\Google.OrTools.csproj] \or-tools\ortools\sat\csharp\CpSolver.cs(36,35): error CS8400: Feature 'not pattern' is not available in C# 8.0. Please use language version 9.0 or greater. [\or-tools\build\dotnet\Google.OrTools\Google.OrTools.csproj] \or-tools\ortools\sat\csharp\CpSolver.cs(40,30): error CS8400: Feature 'not pattern' is not available in C# 8.0. Please use language version 9.0 or greater. [\or-tools\build\dotnet\Google.OrTools\Google.OrTools.csproj] \or-tools\ortools\sat\csharp\CpSolver.cs(44,19): error CS8400: Feature 'not pattern' is not available in C# 8.0. Please use language version 9.0 or greater. [\or-tools\build\dotnet\Google.OrTools\Google.OrTools.csproj] \or-tools\ortools\sat\csharp\CpSolver.cs(52,19): error CS8400: Feature 'not pattern' is not available in C# 8.0. Please use language version 9.0 or greater. [\or-tools\build\dotnet\Google.OrTools\Google.OrTools.csproj] \or-tools\ortools\sat\csharp\CpSolver.cs(84,31): error CS8400: Feature 'not pattern' is not available in C# 8.0. Please use language version 9.0 or greater. [\or-tools\build\dotnet\Google.OrTools\Google.OrTools.csproj]

Mizux commented 1 year ago

https://github.com/google/or-tools/blob/1f36b82559cbcc93ddff3c349d59a962c5530bab/ortools/sat/csharp/CpModel.cs#L145-L146

anders9ustafsson commented 1 year ago

@Mizux Thanks, yes, I noticed. I suppose it should be fairly easy to "downgrade" this limited number of statements to C# 8.0. Did I understand correctly that these C# files were auto-generated? Are you able to control the C# version level in the generator in that case?

CADBIMDeveloper commented 1 year ago

@Mizux , @anders9ustafsson, I still believe that .Net standard 2.0 is a better option: you don't need to publish separate nuget packages or target a nuget package for both .Net and .NetFramework.

But it requires a bit more downgrade to C# 7.3: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/configure-language-version

Seems this downgrade doesn't require a lot of work to do

lperron commented 1 year ago

No. These are hand written and optimized. Laurent Perron | Operations Research | @.*** | (33) 1 42 68 53 00

Le mar. 8 nov. 2022 à 11:23, Anders Gustafsson @.***> a écrit :

@Mizux https://github.com/Mizux Thanks, yes, I noticed. I suppose it should be fairly easy to "downgrade" this limited number of statements to C# 8.0. Did I understand correctly that these C# files werer auto-generated? Are you able to control the C# version level in the generator in that case?

— Reply to this email directly, view it on GitHub https://github.com/google/or-tools/issues/3503#issuecomment-1306976534, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACUPL3OC7N7PLT5OAELP253WHISZFANCNFSM6AAAAAARIFW25U . You are receiving this because you were mentioned.Message ID: @.***>

anders9ustafsson commented 1 year ago

No. These are hand written and optimized.

Would you be interested if I provided a pull request where I used C# pre-version 9 constructs to overcome the above compiler errors? As far as I can see the patterns used are only "syntactic sugar", it should be very easy to replace them with backwards compatible code.

Mizux commented 1 year ago
  1. Did I understand correctly that these C# files were auto-generated ?

    no, generated cs file are done by swig which should generate net452 compatible code but we also have to add few custom complementary cs files like this one and here we use relatively modern language version (open to discussion if you have strong argument like a PR)

  2. Doing some tests using TFM:net48/netstandard2.0 lang:C#8 seems to be some good candidates to add... see: https://github.com/Mizux/dotnet-native/actions/runs/3430397056 (note: this PoC don't use C#8/9 features AFAIK) note: here dotnet build didn't complain to have a csproj targeting netstandard2.0 and C# lang 8.0 but the source didn't use it so the issue is compile only ?

  3. I just bricked my macbook air INTEL so release may be postponed until next week (to grab a new one) -> I may have time to integrate at least net48/netstandard2.0 in v9.5 (again need to check if we could stick to C#9.0) see: https://github.com/Mizux/dotnet-native/commit/5cddfbff5247311e33713646b4dc8df4dbab601e

  4. You can provide a C#8/C#7.3 fix but usually our line is open to integrate change to extend or-tools IFF it doesn't block us to move forward and use latest features and maintaining cost is minimal. So rolling back to pre C#9 seems to be a backward move IMHO but you can convince us of the contrary and/or send us a quick PR ;)

    note for myself to be able to switch lang easily: https://github.com/Mizux/dotnet-native/commit/54dc9f45a9ccfa072241f0d42c595a156261b488

anders9ustafsson commented 1 year ago

@Mizux @lperron Now I have provided two PR:s for you to consider.

The first, #3542, concerns replacing a few C# 9 patterns with C# 8 compatible code. Changes are very small, so I hope you will have no problems accepting this PR.

The second PR, #3543, emanated when I tried to build the C# managed project for .NET Standard 2.0. It then turned out that the API for .NET Standard 2.0 did not contain the method Queue.TryDequeue. Where relevant, I have refactored the code to make the project successfully build for .NET Standard 2.0. If you plan to target .NET Standard 2.0 (which is out-of-the-box compatible e.g. with .NET Framework 4.6.1 and later), this PR needs to be considered.

Regarding item 1 in your list above, @Mizux , I am not quite sure I follow? Maybe the concerns you raise there are addressed in my PR:s?

lperron commented 1 year ago

The code improvements were a result of a contribution where the user spent a lot of time profiling, improving, and optimizing the code. I am not happy to throw away his code.

4.5.2, 4.6, and 4.6.1 are EOL. We will not target them. .NET core 3.1 is ending in one month. We should probably drop it now. .NET standard 2.0 is messy. I would stay away from if possible.

Now, the code needs vs2019 to compile (in C++). I would like to see if we can compile targeting 4.6.2 or later with some C#9 code inside with vs2019. That would solve a lot of problems. See https://sergiopedri.medium.com/enabling-and-using-c-9-features-on-older-and-unsupported-runtimes-ce384d8debb Laurent Perron | Operations Research | @.*** | (33) 1 42 68 53 00

Le jeu. 10 nov. 2022 à 17:11, Anders Gustafsson @.***> a écrit :

@Mizux https://github.com/Mizux @lperron https://github.com/lperron Now I have provided two PR:s for you to consider.

The first, #3542 https://github.com/google/or-tools/pull/3542, concerns replacing a few C# 9 patterns with C# 8 compatible code. Changes are very small, so I hope you will have no problems accepting this PR.

The second PR, #3543 https://github.com/google/or-tools/pull/3543, emanated when I tried to build the C# managed project for .NET Standard 2.0. It then turned out that the API for .NET Standard 2.0 did not contain the method Queue.TryDequeue, only Queue.Dequeue. Where relevant, I have modified the code to make the project successfully build for .NET Standard 2.0. If you plan to target .NET Standard 2.0 (which is out-of-the-box compatible e.g. with .NET Framework 4.6.1 and later), this PR needs to be considered.

Regarding item 1 in your list above, @Mizux https://github.com/Mizux , I am not quite sure I follow? Maybe the concerns you raise there are addressed in my PR:s?

— Reply to this email directly, view it on GitHub https://github.com/google/or-tools/issues/3503#issuecomment-1310534054, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACUPL3KGLTYH5GDVB7NSKUDWHUNCVANCNFSM6AAAAAARIFW25U . You are receiving this because you were mentioned.Message ID: @.***>

anders9ustafsson commented 1 year ago

The code improvements were a result of a contribution where the user spent a lot of time profiling, improving, and optimizing the code. I am not happy to throw away his code.

@lperron The code changes I have made in PR #3542 are not in any way related to code optimization. I have only reverted the use of some C# 9 syntactic sugar. Code functions exactly the same as before, it is just a change of expressing the patterns in code.

I would like to see if we can compile targeting 4.6.2 or later with some C#9 code inside with vs2019. That would solve a lot of problems.

The changes I have made have no negative impact on the ability to build on VS 2019, quite the opposite, since I would expect that C# 8 is more reliably supported on VS 2019 than is C# 9.

And yes, although not officially supported it looks like the current code builds for .NET Framework 4.6.1 and forward with language version set to 9. As a .NET Framework user I would still be concerned that the code could misbehave in scenarios not captured in compilation, but at this point I have yet no indication that it will not work.

CervEdin commented 1 year ago

@CADBIMDeveloper @anders9ustafsson dotnet standard and dotnet framework can use (some?) newer features of csharp 7.3+, it's just not supported

@lperron wrote

Now, the code needs vs2019 to compile (in C++). I would like to see if we can compile targeting 4.6.2 or later with some C#9 code inside with vs2019. That would solve a lot of problems.

As you note, this is often totally doable. It's just "unsupported".

@anders9ustafsson wrote

The second PR, https://github.com/google/or-tools/pull/3543, emanated when I tried to build the C# managed project for .NET Standard 2.0. It then turned out that the API for .NET Standard 2.0 did not contain the method Queue.TryDequeue. Where relevant, I have refactored the code to make the project successfully build for .NET Standard 2.0. If you plan to target .NET Standard 2.0 (which is out-of-the-box compatible e.g. with .NET Framework 4.6.1 and later), this PR needs to be considered.

As Anders noted earlier, there are some other API incompatibilities between dotnet 6 and dotnet framework, namely in System.Collections. In this case it's Queue (and it's sibling ConcurrentQueue). But there are also other collections, like PriorityQueue (maybe not currently used in this project?), that isn't available in dotnet framework. It's understandable if the maintainers feel this hinders the evolution of the project and no longer wish to support it.

On the other hand, lot's of the dotnet world is stuck in dotnet framework and oftentimes in situations were migrating is a demanding task. So I personally sympathize with the situation. That said, it's always possible for whomever to maintain a fork of the project that suits their own compatibility needs.

I don't really have any skin in the game here. I just happen to be interested both in OR-Tools and dotnet.

lperron commented 1 year ago

What is the maximum .NET framework supported? I would prefer target 4.7 or better 4.8 instead of 4.6.2? Laurent Perron | Operations Research | @.*** | (33) 1 42 68 53 00

Le ven. 11 nov. 2022 à 13:10, Erik Cervin Edin @.***> a écrit :

@CADBIMDeveloper https://github.com/CADBIMDeveloper @anders9ustafsson https://github.com/anders9ustafsson dotnet standard and dotnet framework can use (some?) newer features of csharp 7.3+, it's just not supported

@lperron https://github.com/lperron wrote

Now, the code needs vs2019 to compile (in C++). I would like to see if we can compile targeting 4.6.2 or later with some C#9 code inside with vs2019. That would solve a lot of problems.

As you note, this is often totally doable. It's just "unsupported".

@anders9ustafsson https://github.com/anders9ustafsson wrote

The second PR, #3543 https://github.com/google/or-tools/pull/3543, emanated when I tried to build the C# managed project for .NET Standard 2.0. It then turned out that the API for .NET Standard 2.0 did not contain the method Queue.TryDequeue. Where relevant, I have refactored the code to make the project successfully build for .NET Standard 2.0. If you plan to target .NET Standard 2.0 (which is out-of-the-box compatible e.g. with .NET Framework 4.6.1 and later), this PR needs to be considered.

As Anders noted earlier, there are some other API incompatibilities between dotnet 6 and dotnet framework, namely in System.Collections. In this case it's Queue (and it's sibling ConcurrentQueue). But there are also other collections, like PriorityQueue (maybe not currently used in this project?), that isn't available in dotnet framework. It's understandable if the maintainers feel this hinders the evolution of the project and no longer wish to support it.

On the other hand, lot's of the dotnet world is stuck in dotnet framework and oftentimes in situations were migrating is a demanding task. So I personally sympathize with the situation. That said, it's always possible for whomever to maintain a fork of the project that suits their own compatibility needs.

I don't really have any skin in the game here. I just happen to be interested both in OR-Tools and dotnet.

— Reply to this email directly, view it on GitHub https://github.com/google/or-tools/issues/3503#issuecomment-1311620114, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACUPL3NLSTHEBF2D7FLULRDWHYZSBANCNFSM6AAAAAARIFW25U . You are receiving this because you were mentioned.Message ID: @.***>

anders9ustafsson commented 1 year ago

What is the maximum .NET framework supported? I would prefer target 4.7 or better 4.8 instead of 4.6.2?

Latest .NET Framework release is 4.8.1, but given its new features list, I do not expect that very many have bothered to update to this version.

What is your concern with targeting 4.6.2? Limiting support to 4.7 or 4.8 will most likely prevent many .NET Framework users from taking advantage of Google's OR Tools.

lperron commented 1 year ago

OR-Tools 9.5 is built on windows for .NET framework 4.6 (alongside .NET core 3.1 and .NET 6.0).

Closing the bug. Please reopen if something is broken.