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

[RFC] Detecting current OS #539

Closed
radical opened this Issue Mar 22, 2016 · 18 comments

Comments

Projects
None yet
@radical
Copy link
Member

radical commented Mar 22, 2016

MSBuild sets the $(OS) property to OSX/Unix/Windows at runtime, which can be used in targets to determine the current OS. But xbuild has been using $(OS)==Unix on OSX and Linux, because of an old mono bug. And it continues to do so for compatibility reasons.

It makes sense for MSBuild to follow the same, since users would want to use it with existing targets. PR #538 reverts back to that behavior. So, for non-windows case, $(OS) property is effectively acting as a IsUnixLike. Considering it like that, $(OS) should probably have only two values now - Windows_NT and Unix.

Now, I think it might be useful to be able to differentiate between OSX and other specific unices. But maybe we should use some other (new) property for that? $(OSName) ? I am not sure how the CoreCLR case is affected by this, but AFAIU, it would be in the same boat.

Thoughts?

@akoeplinger

This comment has been minimized.

Copy link
Member

akoeplinger commented Mar 22, 2016

We just discussed this in Xamarin and we came to the conclusion that MSBuild changing $(OS) to OSX is too much of a breaking change for us, so when we adopt MSBuild we need to quirk this to return Unix again to prevent breaking existing code. This has the unfortunate side effect of creating a behavior difference based on the runtime.

@rainersigwald you said in #446 (comment) that you think it's reasonable to update conditions when moving to MSBuild, but is there a chance we can revisit this decision?

@jonpryor

This comment has been minimized.

Copy link
Member

jonpryor commented Mar 22, 2016

For bad added context, there are 140 matches on github for .targets files which contain both OS and Unix (my possibly futile effort at capturing constructs similar to Condition="'$(OS)' == 'Unix'").

There are 1,653 matches when targeting .csproj files.

This isn't necessarily "a lot" -- or even accurate? -- but it does show that plenty of existing code files use $(OS) in one form or another, and adding a new value has the potential to break all of these existing files.

Changing $(OS) to be OSX instead of Unix is at minimum a possible compatibility break, and I believe shows that the "abstraction" isn't abstract enough. Users would likely be better served with an alternate mechanism that was more conducive to supporting new platforms without requiring auditing all existing use of e.g. $(OS), though I'm not sure what such an abstraction would resemble.

@AndyGerlicher

This comment has been minimized.

Copy link
Member

AndyGerlicher commented Mar 28, 2016

We discussed this a bit today in our team meeting. This is a tricky one because msbuild isn't exactly the same as xbuild. So if we're migrating users from xbuild to msbuild, while we want it to be as easy as possible we definitely don't want to implement "bugs" in msbuild to match xbuild behavior (to the largest extent possible). "Bug" is a stretch here, but it's definitely not behavior we would choose (at least in hindsight).

Few options we talked about:

  1. Keep $(OS) as is: Windows_NT, OSX, Unix
    1. OS override in the xbuild targets fork (if possible).
    2. Breaking change for xbuild -> msbuild.
  2. Match xbuild behavior for $(OS): Windows_NT, Unix
    1. Rename the current $(OS) to something else and keep OSX in that one.
    2. Add $(OSPlatform) property, match OSPlatform Linux, Windows, OS. Document to prefer $(OSPlatform) for .NET Core.
  3. Diverge the #if code between Mono and Core and keep both implementations.

Personally I think this should not be done in MSBuild but passed off to the Runtime. The closest thing I know of there would be to use OSPlatform. Unfortunately that a) doesn't include Unix at all, b) Windows_NT is changed to Windows, and c) sadly because of the way that's implemented MSBuild would have to change to add another value. What I don't really want to do is keep $(OS) as legacy for xbuild compat and add a 2nd way that's again custom to MSBuild (which is basically 2.i) for those who do want to distinguish.

Also for the statistics @jonpryor mentioned, most of those 1600+ hits are '$(OS)' != 'Windows_NT' so those would not break. Not that it makes it much better since there are exceptions, but it is much smaller than 1600.

Thoughts? We will discuss this again during our team triage tomorrow.

@dsplaisted

This comment has been minimized.

Copy link
Member

dsplaisted commented Mar 28, 2016

I would lean towards option 2, matching the xbuild behavior, as right now it has a lot more adoption than .NET Core MSBuild and it is better to keep this behavior consistent if possible.

The OSPlatform APIs don't allow you to get the name (by design), they only allow you to check to see if you are on a specified OS. So if we want to expose this functionality, I think we should do so as an intrinsic function instead of a property, ie IsOSPlatform('OSX').

@AndyGerlicher

This comment has been minimized.

Copy link
Member

AndyGerlicher commented Mar 29, 2016

Team Triage: Marking as up-for-grabs. We would like to make $(OS) follow the xbuild behavior (Windows_NT, Unix) and implement what @dsplaisted mentioned (IsOSPlatform('OSX')).

@rainersigwald

This comment has been minimized.

Copy link
Contributor

rainersigwald commented Mar 29, 2016

We talked about this a bit more. It's unfortunate that IsOSPlatform is CoreCLR-only, so we might need to have a special case for running on the full framework that returns false for anything that's not Windows.

@akoeplinger

This comment has been minimized.

Copy link
Member

akoeplinger commented Mar 29, 2016

@rainersigwald afaik you can use the System.Runtime.InteropServices.RuntimeInformation package which has these new APIs on full framework too, but @ericstj can confirm.

radical added a commit to radical/msbuild that referenced this issue Apr 6, 2016

$(OS) should return only two values - `Windows_NT` and `Unix` .
Based on the discussion in issue Microsoft#539, $(OS) property will return
`Windows_NT` whenever running on windows and `Unix` for any other OS.

NativeMethodsShared.OSName is used to set that property, hence this is
being changed.

radical added a commit to radical/msbuild that referenced this issue Apr 11, 2016

Add instrinsic property function `IsOSPlatform(string os)`
Usage:
    $([MSBuild]::IsOSPlatform(Windows))

Based on @dsplaisted's suggestion in issue Microsoft#539 .

radical added a commit to radical/msbuild that referenced this issue Apr 11, 2016

Add intrinsic property function `IsOSPlatform(string os)`
Usage:
    $([MSBuild]::IsOSPlatform(Windows))

Based on @dsplaisted's suggestion in issue Microsoft#539 .

radical added a commit to radical/msbuild that referenced this issue Apr 11, 2016

Add intrinsic property function `IsOSPlatform(string os)`
Usage:
    $([MSBuild]::IsOSPlatform(Windows))

Based on @dsplaisted's suggestion in issue Microsoft#539 .

radical added a commit to radical/msbuild that referenced this issue Apr 12, 2016

Add intrinsic property function `IsOSPlatform(string os)`
Usage:
    $([MSBuild]::IsOSPlatform(Windows))

Based on @dsplaisted's suggestion in issue Microsoft#539 .
@am11

This comment has been minimized.

Copy link

am11 commented Jan 19, 2017

Hello, just wanted to chime in with the detection task I have added today using RuntimeInformation in one of our projects:
https://github.com/am11/libsass-net/blob/68861f8/LibSass.NET/LibSass.NET.csproj#L75-L107

I saw @jeffkl's pull request #1486, which will probably allow us to get rid of the reflection calls and make code look decent, but is there a way to get the list of all dependencies that are in closure of S.R.IS.RuntimeInformation, that we would need to specify?

Regardless, it would be nice to get this information using RuntimeInformation type (which provides xplat OS description and architectures beyond X86/X64 ; ARM and ARM64 etc.) intrinsically from MSBuild. :)

Note that the project is targeting Framework 4.0 at the moment, while S.R.IS.RuntimeInformation v4.3.0 only provides support for Framework v4.5+, so I added the entry in packages.config, restored package and load it using Assembly.LoadFrom in our inline task and it worked! Is it some sort of a false-positive behavior?

(cc: @nschonni, @darrenkopp for visibility)

@jeffkl

This comment has been minimized.

Copy link
Contributor

jeffkl commented Jan 19, 2017

@am11 I made a sample based on your needs that doesn't use reflection: https://github.com/jeffkl/MSBuild-NetCore/tree/master/src/UsingTaskWithReference

I only needed to add a reference to System.Runtime to make it work.

@am11

This comment has been minimized.

Copy link

am11 commented Jan 19, 2017

@jeffkl, thanks a lot! 🎉 Running into few issues with MSBuild v14.0, I have started a thread in your repo: jeffkl/MSBuild-NetCore#1. :)

@natemcmaster natemcmaster referenced this issue Jan 20, 2017

Merged

Upgrade to RC.3 #1314

2 of 2 tasks complete

@cdmihai cdmihai changed the title [RFC] Detecting current OS in targets [RFC] Detecting current OS Mar 14, 2017

@eerhardt

This comment has been minimized.

Copy link
Member

eerhardt commented Mar 28, 2017

So I wanted to figure out "am I building on OSX or not?" and came across this issue. I want to know whether I am building on Windows, OSX, or Linux, and I want to know it statically (so I can set some other properties statically).

I've figured out that if I'm running MSBuild on .NET Core, I can call RuntimeInformation:

  <PropertyGroup>
    <IsWindows Condition="'$(OS)' == 'Windows_NT'">true</IsWindows>
  </PropertyGroup>
  
  <PropertyGroup Condition="'$(MSBuildRuntimeType)' == 'Core'">
    <IsOSX Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX)))' == 'true'">true</IsOSX>
    <IsLinux Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))' == 'true'">true</IsLinux>
  </PropertyGroup>

  <Target Name="PrintRID" BeforeTargets="Build">
    <Message Text="IsWindows $(IsWindows)" Importance="high" />
    <Message Text="IsOSX $(IsOSX)" Importance="high" />
    <Message Text="IsLinux $(IsLinux)" Importance="high" />
  </Target>

The above works in Visual Studio and when using dotnet build. However, there is another case I need to consider: what if my project is building using MSBuild running on Mono? @radical - do you know how I can tell statically whether I am on OSX or Linux in MSBuild on Mono?

@akoeplinger

This comment has been minimized.

Copy link
Member

akoeplinger commented Mar 28, 2017

@eerhardt the above should work on Mono MSBuild as well since (recent) Mono ships with System.Runtime.InteropServices.RuntimeInformation. You'll need to change the MSBuildRuntimeType check of course.

@eerhardt

This comment has been minimized.

Copy link
Member

eerhardt commented Mar 28, 2017

Perfect! That's exactly what I wanted to hear.

And since RuntimeInformation is available on netstandard1.1, I think MSBuild could even support these checks on Full MSBuild, if they shipped with System.Runtime.InteropServices.RuntimeInformation as well. That would completely eliminate the need for the $(MSBuildRuntimeType) check all together.

@akoeplinger

This comment has been minimized.

Copy link
Member

akoeplinger commented Mar 28, 2017

Hmm, seems we're missing the FEATURE_RUNTIMEINFORMATION in dir.props in our Mono MSBuild build so it might not be available at runtime. @radical I don't see a reason why this shouldn't work, could you look into enabling it?

@cdmihai

This comment has been minimized.

Copy link
Member

cdmihai commented Mar 31, 2017

Enabled cross-platform in #1926

@cdmihai cdmihai closed this Mar 31, 2017

@migueldeicaza

This comment has been minimized.

Copy link
Member

migueldeicaza commented May 21, 2017

The above trick does not work with regular .NET on VS 2017. What incarnation should someone use to detect Mac/Linux/Windows platforms?

@cdmihai

This comment has been minimized.

Copy link
Member

cdmihai commented May 23, 2017

@migueldeicaza It should be there with the next big Visual Studio update. Daily CLI builds should also have it. It brings the following new stuff: MicrosoftDocs/visualstudio-docs#111

@bhanu1989

This comment has been minimized.

Copy link

bhanu1989 commented Nov 28, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment