Imported Upstream version 5.0.0.42

Former-commit-id: fd56571888259555122d8a0f58c68838229cea2b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2017-04-10 11:41:01 +00:00
parent 1190d13a04
commit 6bdd276d05
19939 changed files with 3099680 additions and 93811 deletions

View File

@@ -0,0 +1,140 @@
Recommended reading to better understand this document:
[.NET Standard](https://github.com/dotnet/standard/blob/master/docs/faq.md)
| [Project-Guidelines](https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/project-guidelines.md)
| [Package-Projects](https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/package-projects.md)
#Add APIs
- [Determining versions and targets](#determining-versions-and-targets)
- [Making the changes in repo](#making-the-changes-in-repo)
- [FAQ](#faq)
##Determining versions and targets
1. [Determine what library](#determine-what-library) the API goes into.
2. [Determine the target framework](#determine-target-framework) for the library that will contain the API.
3. [Determine the version](#determine-library-version) for the library that will contain the API.
###Determine what library
- Propose a library for exposing it as part of the [API review process](http://aka.ms/apireview).
- Keep in mind the API might be exposed in a reference assembly that
doesn't match the identity of the implementation. There are many reasons for this but
the primary reason is to abstract the runtime assembly identities across
different platforms while sharing a common API surface and allowing us to refactor
the implementation without compat concerns in future releases.
###Determine target framework
`<latest>` is the target framework version currently under development. Currently netcoreapp1.1 and netstandard1.7 (note netstandard1.7 is a placeholder for netstandard2.0).
- If the library is [part of netstandard](#isnetstandard)
- Your target framework should be `netstandard<latest>`
- If it is a new API only available on .NET Core then it will be added to `netcoreapp<latest>`
- If the library is not part of netstandard
- If package dependencies are changed then your target framework should be the minimum target framework that supports all your package dependencies.
- If your package depends directly on runtime changes or library changes that ship with the runtime
(i.e. System.Private.CoreLib) then your target framework should be `netstandard<latest>` (hint: usually indicated by needing the latest Microsoft.TargetingPack.Private.* package)
- If your package depends on changes in a native shim package then your target framework should be
`netstandard<latest>`. (ex: something under https://github.com/dotnet/corefx/tree/master/src/Native)
- When targeting `netstandardX` your new API must be supported by all target frameworks that
map to that netstandard version (see [mapping table](https://github.com/dotnet/corefx/blob/master/Documentation/architecture/net-platform-standard.md#mapping-the-net-platform-standard-to-platforms)). If not bump the version to the minimum netstandard version that supports this API on all frameworks that map to that netstandard version.
- If the library is not part of netstandard and not building against netstandard
- All the rules for a library that is not part of netstandard apply but instead of having a target framework of
`netstandard<latest>` it will have a target framework of `<framework><latest>`. Example `net<latest>` for desktop or `netcoreapp<latest>` for .NET Core.
- It is not uncommon for a library to target the latest versions of multipe frameworks when adding new APIs (ex: https://github.com/dotnet/corefx/blob/master/src/System.Runtime/ref/System.Runtime.builds)
###Determine library version
- If targeting netstandard
- Ensure minor version of the assembly is bumped since last stable package release
- If targeting netcoreapp
- No assembly version bump necessary
##Making the changes in repo
**If changing the library version**
- Update the `AssemblyVersion` property in `<Library>\dir.props` (ex: [System.Runtime\dir.props](https://github.com/dotnet/corefx/blob/master/src/System.Runtime/dir.props#L4)) to the version determined above.
**Update ref**
- If changing target framework
- Update the `NugetTargetMoniker` property in `<Library>\ref\<Library>.csproj` (ex: [ref\System.Runtime.csproj](https://github.com/dotnet/corefx/blob/master/src/System.Runtime/ref/System.Runtime.csproj#L8))
- Update frameworks section in `<Library>\ref\project.json` to add a new target framework or replace an existing one (ex: [System.Runtime\ref\project.json](https://github.com/dotnet/corefx/blob/master/src/System.Runtime/ref/project.json#L4))
- Add your API to `<Library>\ref\<Library>.cs`. Use GenAPI to normalize the file.
- If adding an additional target framework for the ref (ex: adding a .NET Core specific API) you may need
to add a `<Library>\ref\<Library>.builds` for the new configuration (ex: [ref/System.Runtime.Extensions.builds](https://github.com/dotnet/corefx/blob/master/src/System.Runtime.Extensions/ref/System.Runtime.Extensions.builds#L6)).
**Update src**
- If changing target framework
- Update the `NugetTargetMoniker` property in `<Library>\src\<Library>.csproj` (ex: [src\System.Runtime.csproj](https://github.com/dotnet/corefx/blob/master/src/System.Runtime/src/System.Runtime.csproj#L12))
- Update frameworks section in `<Library>\src\project.json` to add a new target framework or replace an existing one (ex: [System.Runtime\src\project.json](https://github.com/dotnet/corefx/blob/master/src/System.Runtime/src/project.json#L3))
- Update build configurations in `<Library>\src\<Library>.builds` if necessary (see [Project configuration conventions](https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/project-guidelines.md#project-configuration-conventions))
- The default build configuration(i.e. TargetGroup excluded) should build the latest version
- If you need a live build of the older versions they need to be added as a new configuration
- Typically only done for libraries not in netstandard that have larger amounts of code
that we want to update outside of servicing events. For any configurations that are removed
we will still harvest the old assets from the last stable package an reship them again.
- Make your code changes.
**Update pkg**
- If changing the target framework
- Update `SupportedFramework` metadata on the ref ProjectReference to declare the set of
concrete of platforms you expect your library to support. (see [Specific platform mappings](https://github.com/dotnet/corefx/blob/master/Documentation/architecture/net-platform-standard.md#nuget)). Generally
will be a combination of netcoreapp1.x, netfx46x, uap10.x, and/or `$(AllXamarinFrameworks)`.
- If package is not split (i.e. only one pkgproj, ex [pkg\System.Diagnostics.Process.pkgproj](https://github.com/dotnet/corefx/blob/master/src/System.Diagnostics.Process/pkg/System.Diagnostics.Process.pkgproj)) then it should already have a `ProjectReference` the `<Library>\src\<Library>.builds` file and so there is no additional changes needed in the pkgproj.
- If package is RID split (i.e. has multple pkgprojs, ex: [pkg\any\System.Runtime.pkgproj](https://github.com/dotnet/corefx/blob/master/src/System.Runtime/pkg/any/System.Runtime.pkgproj) and [pkg\aot\System.Runtime](https://github.com/dotnet/corefx/blob/master/src/System.Runtime/pkg/aot/System.Runtime.pkgproj))
- Update the ProjectReferences in the respective pkgproj's to align with the build configurations in the
`<Library>\src\<Library>.builds` file. This may entail adding new references or removing references according to whatever changes were made to the .builds file.
- If assembly or package version is updated the package index needs to be updated by running
`msbuild <Library>/pkg/<Library>.pkgproj /t:UpdatePackageIndex`
**Update tests**
- If changing target framework
- Update the `NugetTargetMoniker` property in `<Library>\tests\<Library>.csproj` (ex: [tests\System.Runtime.csproj](https://github.com/dotnet/corefx/blob/master/src/System.Runtime/tests/System.Runtime.Tests.csproj#L13)). Add a `'$(TargetGroup)' == ''` condition if missing.
- Update frameworks section in `<Library>\tests\project.json` to add a new target framework or replace an existing one (ex: [System.Runtime\tests\project.json](https://github.com/dotnet/corefx/blob/master/src/System.Runtime/tests/project.json#L30))
- Add new build configuration in `<Library>\tests\<Library>.builds` (ex: [tests\System.Runtime.builds](https://github.com/dotnet/corefx/blob/master/src/System.Runtime/tests/System.Runtime.Tests.builds#L6))
- Set `TargetGroup` which will generally match the `TargetGroup` in the src library build configruation. (ex: [tests\System.Runtime.builds](https://github.com/dotnet/corefx/blob/master/src/System.Runtime/tests/System.Runtime.Tests.builds#L7))
- Set `TestTFMs` metadata to a list of target frameworks to run on, will generally match the `SupportedFramework` metadata in the pkgproj (ex: [tests\System.Runtime.builds](https://github.com/dotnet/corefx/blob/master/src/System.Runtime/tests/System.Runtime.Tests.builds#L8))
- If `TestTFMs` is empty it defaults to [netcoreapp1.0](https://github.com/dotnet/corefx/commit/57af41ef1439ad2e443e42d03d55d41613e4c02e#diff-cd0fc5e0bad8102e1a45aa7575bdd102R155)
- Add new test code following [conventions](https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/project-guidelines.md#code-file-naming-conventions) for new files to that are specific to the new target framework.
- To run just the new test configuration run `msbuild <Library>.csproj /t:RebuildAndTest /p:TargetGroup=<TargetGroup>`
##FAQ
_**<a name="isnetstandard">Is your API part of netstandard?</a>**_
- For netstandard2.0 refer to https://github.com/dotnet/standard/tree/master/netstandard/ref, and if any Type is included in any of the *.cs files then it is part of netstandard.
- For earlier netstandard versions refer to list at https://github.com/dotnet/corefx/blob/master/pkg/NETStandard.Library/NETStandard.Library.packages.targets. If the assembly is part of that list then it is in netstandard.
_**What is the difference between being part of netstandard and building against netstandard?**_
Things that are part of netstandard can only change when we release a new version of a platform
that supports the higher version of netstandard. Whereas things that build against netstandard and
ship in independent packages can be changed without an update to the platform that it is running on.
That gives more flexibility to add API to things that build against netstandard because it does not
require a platform update to consume.
_**What changes require me to update my target framework in my library package?**_
*Target framework of dependencies*
- If any changes (ref or src) require a higher target framework of one of the dependencies then your library package target framework must be increased to match the new minimum version that supports all package dependencies.
*Independently shipped dependencies*
- If any changes (ref or src) requires a newer runtime/platform change that ships independently(this should generally only apply to libraries that are part of netstandard). Some example dependencies include:
- Runtime (aka RID) split package dependencies
- Dependencies on runtime changes
- Dependencies on runtime libraries (i.e. in Microsoft.TargetingPack.Private.* packages)
- Dependencies on new native shim changes
- .NET Native Shared Library
_**How do I consume APIs from another package that aren't yet published?**_
If you are adding APIs across multiple packages at the same time. You can temporarily add a direct
ProjectReference from the ref\csproj to the ref\csproj, src\csproj to the ref\csproj, and/or tests\csproj to pkg\pkgproj. Once a new set of packages have been published these ProjectReferences should be removed.
_**What to do if you are moving types down into a lower contract?**_
If you are moving types down you need to version both contracts at the same time and temporarily use
project references across the projects. You also need to be sure to leave type-forwards in the places
where you removed types in order to maintain back-compat.
###Potential clean-up work that can be done
- Remove old build configurations - The older build configurations will automatically be harvested from
the last stable packages and thus can be removed.
- Remove import statements - If not referencing any pre-netstandard stable packages the [imports of dotnet5.x](https://github.com/dotnet/corefx/blob/master/src/System.Diagnostics.Process/src/project.json#L28) are no longer needed and can be removed. We should also remove any dead target frameworks sections.
- Remove all non-conditionsed `<AssemblyVersion>` properties from csproj's as it should be defined in library\dir.props.

View File

@@ -0,0 +1,38 @@
Breaking Change Definitions
===========================
Behavioral Change
-----------------
A behavioral change represents changes to the behavior of a member. A behavioral change may including throwing a new exception, adding or removing internal method calls, or alternating the way in which a return value is calculated. Behavioral changes can be the hardest type of change to categorize as acceptable or not - they can be severe in impact, or relatively innocuous.
Binary Compatibility
--------------------
Refers to the ability of existing consumers of an API to be able to use a newer version without recompilation. By definition, if an assembly's public signatures have been removed, or altered so that consumers cannot no longer access the same interface exposed by the assembly, the change is said to be a _binary incompatible change_.
Source Compatibility
--------------------
Refers to the ability of existing consumers of an API to recompile against a newer version without any source changes. By definition, if a consumer needs to make changes to its code in order to for it build successfully against a newer version of an API, the change is said to be a _source incompatible change_.
Design-Time Compatibility
-------------------------
_Design-time compatibility_ refers to preserving the design-time experience across versions of Visual Studio and other design-time environments. This can involve details around the UI of the designer, but by far the most interesting design-time compatibility is project compatibility. A potential project (or solution), must be able to be opened, and used on a newer version of a designer.
Backwards Compatibility
-----------------------
_Backwards compatibility_ refers to the ability of an existing consumer of an API to run against, and behave in the same way against a newer version. By definition, if a consumer is not able to run, or behaves differently against the newer version of the API, then the API is said to be _backwards incompatible_.
Changes that affect backwards compatibility are strongly discouraged. All alternates should be actively considered, since developers will, by default, expect backwards compatibility in newer versions of an API.
Forwards Compatibility
----------------------
_Forwards compatibility_ is the exact reverse of backwards compatibility; it refers to the ability of an existing consumer of an API to run against, and behave in the way against a _older_ version. By definition, if a consumer is not able to run, or behaves differently against an older version of the API, then the API is said to be _forwards incompatible_.
Changes that affect forwards compatibility are generally less pervasive, and there is not as stringent a demand to ensure that such changes are not introduced. Customers accept that a consumer which relies upon a newer API, may not function correctly against the older API.
This document does not attempt to detail forwards incompatibilities.

View File

@@ -0,0 +1,220 @@
Breaking Change Rules
=====================
* [Behavioral Changes](#behavioral-changes)
* [Property, Field, Parameter and Return Values](#property-field-parameter-and-return-values)
* [Exceptions](#exceptions)
* [Platform Support](#platform-support)
* [Code](#code)
* [Source and Binary Compatibility Changes](#source-and-binary-compatibility-changes)
* [Assemblies](#assemblies)
* [Types](#types)
* [Members](#members)
* [Signatures](#signatures)
* [Attributes](#attributes)
## Behavioral Changes
### Property, Field, Parameter and Return Values
&#10003; **Allowed**
* Increasing the range of accepted values for a property or parameter if the member _is not_ `virtual`
> Note that the range can only increase to the extent that it does not impact the static type. e.g. it is OK to remove `if (x > 10) throw new ArgumentOutOfRangeException("x")`, but it is not OK to change the type of `x` from `int` to `long`.
* Returning a value of a more derived type for a property, field, return or `out` value
> Note, again, that the static type cannot change. e.g. it is OK to return a `string` instance where an `object` was returned previously, but it is not OK to change the return type from `object` to `string`.
&#10007; **Disallowed**
* Increasing the range of accepted values for a property or parameter if the member _is_ `virtual`
> This is breaking because any existing overridden members will now not function correctly for the extended range of values.
* Decreasing the range of accepted values for a property or parameter, such as a change in parsing of input and throwing new errors (even if parsing behavior is not specified in the docs)
* Increasing the range of returned values for a property, field, return or `out` value
* Changing the returned values for a property, field, return or 'out' value, such as the value returned from `ToString`
> If you had an API which returned a value from 0-10, but actually intended to divide the value by two and forgot (return only 0-5) then changing the return to now give the correct value is a breaking.
* Changing the default value for a property, field or parameter (either via an overload or default value)
* Changing the value of an enum member
* Changing the precision of a numerical return value
### Exceptions
&#10003; **Allowed**
* Throwing a more derived exception than an existing exception
> For example, `CultureInfo.GetCultureInfo(String)` used to throw `ArgumentException` in .NET Framework 3.5. In .NET Framework 4.0, this was changed to throw `CultureNotFoundException` which derives from `ArgumentException`, and therefore is an acceptable change.
* Throwing a more specific exception than `NotSupportedException`, `NotImplementedException`, `NullReferenceException` or an exception that is considered unrecoverable
> Unrecoverable exceptions should not be getting caught and will be dealt with on a broad level by a high-level catch-all handler. Therefore, users are not expected to have code that catches these explicit exceptions. The list of unrecoverable exceptions are:
* `StackOverflowException`
* `SEHException`
* `ExecutionEngineException`
* `AccessViolationException`
* Throwing a new exception that only applies to a code-path which can only be observed with new parameter values, or state (that couldn't hit by existing code targeting the previous version)
* Removing an exception that was being thrown when the API allows more robust behavior or enables new scenarios
> For example, a Divide method which only worked on positive values, but threw an exception otherwise, can be changed to support all values and the exception is no longer thrown.
&#10007; **Disallowed**
* Throwing a new exception in any other case not listed above
* Removing an exception in any other case not listed above
### Platform Support
&#10003; **Allowed**
* An operation previously not supported on a specific platform, is now supported
&#10007; **Disallowed**
* An operation previously supported on a specific platform is no longer supported, or now requires a specific service-pack
### Code
&#10003; **Allowed**
* A change which is directly intended to increase performance of an operation
> The ability to modify the performance of an operation is essential in order to ensure we stay competitive, and we continue to give users operational benefits. This can break anything which relies upon the current speed of an operation, sometimes visible in badly built code relying upon asynchronous operations. Note that the performance change should have no affect on other behavior of the API in question, otherwise the change will be breaking.
* A change which indirectly, and often adversely, affects performance
> Assuming the change in question is not categorized as breaking for some other reason, this is acceptable. Often, actions need to be taken which may include extra operation calls, or new functionality. This will almost always affect performance, but may be essential to make the API in question function as expected.
* Changing the text of an error message
> Not only should users not rely on these text messages, but they change anyways based on culture
* Calling a brand new event that wasn't previously defined.
&#10007; **Disallowed**
* Adding the `checked` keyword to a code-block
> This may cause code in a block to to begin to throwing exceptions, an unacceptable change.
* Changing the order in which events are fired
> Developers can reasonably expect events to fire in the same order.
* Removing the raising of an event on a given action
* Changing a synchronous API to asynchronous (and vice versa)
* Firing an existing event when it was never fired before
* Changing the number of times given events are called
## Source and Binary Compatibility Changes
### Assemblies
&#10003; **Allowed**
* Making an assembly portable when the same platforms are still supported
&#10007; **Disallowed**
* Changing the name of an assembly
* Changing the public key of an assembly
### Types
&#10003; **Allowed**
* Adding the `sealed` or `abstract` keyword to a type when there are _no accessible_ (public or protected) constructors
* Increasing the visibility of a type
* Introducing a new base class
> So long as it does not introduce any new abstract members or change the semantics or behavior of existing members, a type can be introduced into a hierarchy between two existing types. For example, between .NET Framework 1.1 and .NET Framework 2.0, we introduced `DbConnection` as a new base class for `SqlConnection` which previously derived from `Component`.
* Adding an interface implementation to a type
> This is acceptable because it will not adversely affect existing clients. Any changes which could be made to the type being changed in this situation, will have to work within the boundaries of acceptable changes defined here, in order for the new implementation to remain acceptable.
> Extreme caution is urged when adding interfaces that directly affect the ability of the designer or serializer to generate code or data, that cannot be consumed down-level. An example is the `ISerializable` interface.
* Removing an interface implementation from a type when the interface is already implemented lower in the hierarchy
* Moving a type from one assembly into another assembly
> The old assembly must be marked with `TypeForwardedToAttribute` pointing to the new location
&#10007; **Disallowed**
* Adding the `sealed` or `abstract` keyword to a type when there _are accessible_ (public or protected) constructors
* Decreasing the visibility of a type
* Removing the implementation of an interface on a type
> It is not breaking when you added the implementation of an interface which derives from the removed interface. For example, you removed `IDisposable`, but implemented `IComponent`, which derives from `IDisposable`.
* Removing one or more base classes for a type, including changing `struct` to `class` and vice versa
* Changing the namespace or name of a type
### Members
&#10003; **Allowed**
* Adding an abstract member to a public type when there are _no accessible_ (`public` or `protected`) constructors, or the type is `sealed`
* Moving a member onto a class higher in the hierarchy tree of the type from which it was removed
* Increasing the visibility of a member that is not `virtual`
* Decreasing the visibility of a `protected` member when there are _no accessible_ (`public` or `protected`) constructors or the type is `sealed`
* Changing a member from `abstract` to `virtual`
* Adding `virtual` to a member
> Make note, that marking a member virtual might cause previous consumers to still call the member non-virtually.
* Introducing or removing an override
> Make note, that introducing an override might cause previous consumers to skip over the override when calling `base`.
&#10007; **Disallowed**
* Adding an member to an interface
* Adding an abstract member to a type when there _are accessible_ (`public` or `protected`) constructors and the type is not `sealed`
* Adding a constructor to a class which previously had no constructor, without also adding the default constructor
* Adding an overload that precludes an existing overload, and defines different behavior
> This will break existing clients that were bound to the previous overload. For example, if you have a class that has a single version of a method that accepts a `uint`, an existing consumer will
successfully bind to that overload, if simply passing an `int` value. However, if you add an overload that accepts an `int`, recompiling or via late-binding the application will now bind to the new overload. If different behavior results, then this is a breaking change.
* Removing or renaming a member, including a getter or setter from a property or enum members
* Decreasing the visibility of a `protected` member when there _are accessible_ (`public` or `protected`) constructors and the type is not `sealed`
* Adding or removing `abstract` from a member
* Removing the `virtual` keyword from a member
* Adding or removing `static` keyword from a member
### Signatures
&#10003; **Allowed**
* Adding `params` to a parameter
* Removing `readonly` from a field, unless the static type of the field is a mutable value type
&#10007; **Disallowed**
* Adding `readonly` to a field
* Adding the `FlagsAttribute` to an enum
* Changing the type of a property, field, parameter or return value
* Adding, removing or changing the order of parameters
* Removing `params` from a parameter
* Adding or removing `out` or `ref` keywords from a parameter
* Renaming a parameter (including case)
> This is considered breaking for two reasons:
* It breaks late-bound scenarios, such as Visual Basic's late-binding feature and C#'s `dynamic`
* It breaks source compatibility when developers use [named parameters](http://msdn.microsoft.com/en-us/library/dd264739.aspx).
* Changing a parameter modifier from `ref` to `out`, or vice versa
### Attributes
&#10003; **Allowed**
* Changing the value of an attribute that is _not observable_
&#10007; **Disallowed**
* Removing an attribute
> Although this item can be addressed on a case to case basis, removing an attribute will often be breaking. For example, `NonSerializedAttribute`
* Changing values of an attribute that _is observable_

View File

@@ -0,0 +1,112 @@
# Breaking Changes
We take compatibility in .NET Framework and .NET Core extremely seriously.
Although .NET Core can be deployed app local, we are engineering it such that
portable libraries can target it and still run on .NET Framework as well. This
means that the behavior of .NET Framework can constrain the implementation of
any overlapping APIs in .NET Core.
Below is a summary of some documentation we have internally about what kinds of
things constitute breaking changes, how we categorize them, and how we decide
what we're willing to take.
Note that these rules only apply to APIs that have shipped in a previous RTM
release. New APIs still under development can be modified but we are still
cautious not to disrupt the ecosystem unnecessarily when prerelease APIs change.
To help triage breaking changes, we classify them in to four buckets:
1. Public Contract
2. Reasonable Grey Area
3. Unlikely Grey Area
4. Clearly Non-Public
## Bucket 1: Public Contract
*Clear [violation of public contract][breaking-change].*
Examples:
* Renaming or removing of a public type, member, or parameter
* Changing the value of a public constant or enum member
* Sealing a type that wasn't sealed
* Making a virtual member abstract
* Adding an interface to the set of base types of an interface
* Removing a type or interface from the set of base types
* Changing the return type of a member
* ...or any other [incompatible change][breaking-change] to the shape of an API
[breaking-change]: breaking-change-rules.md#source-and-binary-compatibility-changes
## Bucket 2: Reasonable Grey Area
*[Change of behavior][behavioral-changes] that customers would have reasonably
depended on.*
Examples:
* Throwing a new/different exception type in an existing common scenario
* An exception is no longer thrown
* A different behavior is observed after the change for an input
* decreasing the range of accepted values within a given parameter
* A new instance field is added to a type (impacts serialization)
* Change in timing/order of events (even when not specified in docs)
* Change in parsing of input and throwing new errors (even if parsing behavior
is not specified in the docs)
These require judgment: how predictable, obvious, consistent was the behavior?
[behavioral-changes]: breaking-change-rules.md#behavioral-changes
## Bucket 3: Unlikely Grey Area
*Change of behavior that customers could have depended on, but probably
wouldn't.*
Examples:
* Correcting behavior in a subtle corner case
As with changes in bucket 2, these require judgment: what is reasonable and
what's not?
## Bucket 4: Clearly Non-Public
*Changes to surface area or behavior that is clearly internal or non-breaking
in theory, but breaks an app.*
Examples:
* Changes to internal API that break private reflection
It is impossible to evolve a code base without making such changes, so we don't
require up-front approval for these, but we will sometimes have to go back and
revisit such change if there's too much pain inflicted on the ecosystem through
a popular app or library.
This bucket is painful for the machine-wide .NET Framework, but we do have much
more latitude here in .NET Core.
## What This Means for Contributors
* All bucket 1, 2, and 3 breaking changes require talking to the repo owners
first:
- We generally **don't accept** change proposals that are in bucket #1.
- We **might accept** change proposals that are in #2 and #3 after a
risk-benefit analysis. See below for more details.
- We **usually accept** changes that are in bucket #4
* If you're not sure which bucket applies to a given change, contact us.
### Risk-Benefit Analysis
For buckets #2 and #3 we apply a risk-benefit analysis. It doesn't matter if the
old behavior is "wrong", we still need to think through the implications. This
can result in one of the following outcomes:
* **Accepted with compat switch**. Depending on the estimated customer impact,
we may decide to add a compat switch that allows consumers to bring back the
old behavior if necessary.
* **Accepted**. In some minor cases, we may decide to accept the change if the
benefit is large and the risk is super low or if the risk is moderate and a
compat switch isn't viable.
* **Rejected**. If the risk is too high and/or the improvement too minor, we may
decide not to accept the change proposal at all. We can help identify
alternatives such as introducing a new API and obsoleting the old one.

View File

@@ -0,0 +1,132 @@
C# Coding Style
===============
For C++ files (*.cpp and *.h), we use clang-format (version 3.6+) to ensure code styling. After changing any Cpp or H file and before merging, be sure to run src/Native/format-code.sh; this script will ensure that all native code files adhere to the coding style guidelines.
For non code files (xml etc) our current best guidance is consistency. When editing files, keep new code and changes consistent with the style in the files. For new files, it should conform to the style for that component. Last, if there's a completely new component, anything that is reasonably broadly accepted is fine.
The general rule we follow is "use Visual Studio defaults".
1. We use [Allman style](http://en.wikipedia.org/wiki/Indent_style#Allman_style) braces, where each brace begins on a new line. A single line statement block can go without braces but the block must be properly indented on its own line and it must not be nested in other statement blocks that use braces (See issue [381](https://github.com/dotnet/corefx/issues/381) for examples).
2. We use four spaces of indentation (no tabs).
3. We use `_camelCase` for internal and private fields and use `readonly` where possible. Prefix instance fields with `_`, static fields with `s_` and thread static fields with `t_`. When used on static fields, `readonly` should come after `static` (i.e. `static readonly` not `readonly static`).
4. We avoid `this.` unless absolutely necessary.
5. We always specify the visibility, even if it's the default (i.e.
`private string _foo` not `string _foo`). Visibility should be the first modifier (i.e.
`public abstract` not `abstract public`).
6. Namespace imports should be specified at the top of the file, *outside* of
`namespace` declarations and should be sorted alphabetically.
7. Avoid more than one empty line at any time. For example, do not have two
blank lines between members of a type.
8. Avoid spurious free spaces.
For example avoid `if (someVar == 0)...`, where the dots mark the spurious free spaces.
Consider enabling "View White Space (Ctrl+E, S)" if using Visual Studio, to aid detection.
9. If a file happens to differ in style from these guidelines (e.g. private members are named `m_member`
rather than `_member`), the existing style in that file takes precedence.
10. We only use `var` when it's obvious what the variable type is (i.e. `var stream = new FileStream(...)` not `var stream = OpenStandardInput()`).
11. We use language keywords instead of BCL types (i.e. `int, string, float` instead of `Int32, String, Single`, etc) for both type references as well as method calls (i.e. `int.Parse` instead of `Int32.Parse`). See issue [391](https://github.com/dotnet/corefx/issues/391) for examples.
12. We use PascalCasing to name all our constant local variables and fields. The only exception is for interop code where the constant value should exactly match the name and value of the code you are calling via interop.
13. We use ```nameof(...)``` instead of ```"..."``` whenever possible and relevant.
14. Fields should be specified at the top within type declarations.
15. When including non-ASCII characters in the source code use Unicode escape sequences (\uXXXX) instead of literal characters. Literal non-ASCII characters occasionally get garbled by a tool or editor.
We have provided a Visual Studio 2013 vssettings file (`corefx.vssettings`) at the root of the corefx repository, enabling C# auto-formatting conforming to the above guidelines. Note that rules 7 and 8 are not covered by the vssettings, since these are not rules currently supported by VS formatting.
We also use the [.NET Codeformatter Tool](https://github.com/dotnet/codeformatter) to ensure the code base maintains a consistent style over time, the tool automatically fixes the code base to conform to the guidelines outlined above.
### Example File:
``ObservableLinkedList`1.cs:``
```C#
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using Microsoft.Win32;
namespace System.Collections.Generic
{
public partial class ObservableLinkedList<T> : INotifyCollectionChanged, INotifyPropertyChanged
{
private ObservableLinkedListNode<T> _head;
private int _count;
public ObservableLinkedList(IEnumerable<T> items)
{
if (items == null)
throw new ArgumentNullException(nameof(items));
foreach (T item in items)
{
AddLast(item);
}
}
public event NotifyCollectionChangedEventHandler CollectionChanged;
public int Count
{
get { return _count; }
}
public ObservableLinkedListNode AddLast(T value)
{
var newNode = new LinkedListNode<T>(this, value);
InsertNodeBefore(_head, node);
}
protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
NotifyCollectionChangedEventHandler handler = CollectionChanged;
if (handler != null)
{
handler(this, e);
}
}
private void InsertNodeBefore(LinkedListNode<T> node, LinkedListNode<T> newNode)
{
...
}
...
}
}
```
``ObservableLinkedList`1.ObservableLinkedListNode.cs:``
```C#
using System;
namespace System.Collections.Generics
{
partial class ObservableLinkedList<T>
{
public class ObservableLinkedListNode
{
private readonly ObservableLinkedList<T> _parent;
private readonly T _value;
internal ObservableLinkedListNode(ObservableLinkedList<T> parent, T value)
{
Debug.Assert(parent != null);
_parent = parent;
_value = value;
}
public T Value
{
get { return _value; }
}
}
...
}
}
```

View File

@@ -0,0 +1,28 @@
Cross-Platform Guidelines
=========================
This page provides a FAQ for how we handle cross-platform code in CoreFX. (For structuring of interop code, see [interop guidelines](interop-guidelines.md).)
#### Should assemblies be binary-compatible across platforms (e.g. exact same System.IO.dll on Windows, Linux, and Mac)?
Our expectation is that the majority (estimating around 70%) of CoreFX assemblies will have no platform-specific code. These assemblies should be binary-compatible across platforms.
In some cases, the managed binary will be used across all platforms, but it'll come with its own native library that'll be compiled once per platform.
In a few dozen cases, the managed code itself will have differing implementations based on whether you're building for Windows, Linux, etc., and in such cases, the binary will not work from one platform to the next. Which binary gets used will be handled by the NuGet package delivering the libraries.
#### When should an existing platform-specific .NET API be deprecated or removed in favor of a new approach?
It's a case-by-case basis. In some cases, entire contracts that are platform-specific just won't be available on other platforms, as they don't make sense by their very nature (e.g. Microsoft.Win32.Registry.dll). In other cases, a contract will be available, but some members here and there that are platform-specific may throw PlatformNotSupportedException (e.g. Console.get_ForegroundColor on Unix). In general, though, we want to strive for having any APIs that exist on a platform (i.e. the contract is available) actually working on that platform.
#### When should partial classes be used to layer in platform-specific functionality?
Partial classes is the approach we're currently taking when the managed code needs to diverge based on underlying platform. There are a few cases where we've decided to go a different route, but even in some of those cases we may move back towards partial classes.
#### How should the platform-specific files be named (e.g. FileStream.Windows.cs? Win32FileStream.cs?)
When the whole type is for a particular platform, we've been using the prefix, e.g. PlatformFileStream.cs. When the file contains a partial class specialized for a particular platform, we've been using the *.Platform.cs suffix.
#### When should define statements be used rather than including different source files in the build environment?
We're striving to avoid defines whenever possible, instead preferring to include just the source files that are relevant.

View File

@@ -0,0 +1,311 @@
Framework Design Guidelines - Digest
====================================
This page is a distillation and a simplification of the most basic
guidelines described in detail in a book titled
[Framework Design Guidelines][FDG] by Krzysztof Cwalina and Brad Abrams.
Framework Design Guidelines were created in the early days of .NET Framework
development. They started as a small set of naming and design conventions but
have been enhanced, scrutinized, and refined to a point where they are generally
considered the canonical way to design frameworks at Microsoft. They carry the
experience and cumulative wisdom of thousands of developer hours over several
versions of the .NET Framework.
[FDG]: http://amazon.com/dp/0321545613
# General Design Principles
## Scenario Driven Design
Start the design process of your public API by defining the top scenarios for
each feature area. Write code you would like the end users to write when they
implement these scenarios using your API. Design your API based on the sample
code you wrote. For example, when designing API to measure elapsed time, you may
write the following scenario code samples:
```CSharp
// scenario #1 : measure time elapsed
Stopwatch watch = Stopwatch.StartNew();
DoSomething();
Console.WriteLine(watch.Elapsed);
// scenario #2 : reuse stopwatch
Dim watch As Stopwatch = Stopwatch.StartNew()
DoSomething();
Console.WriteLine(watch.ElapsedMilliseconds)
watch.Reset() watch.Start() DoSomething()
Console.WriteLine(watch.Elapsed)
// scenario #3: ...
```
## Usability Studies
Test usability of your API. Choose developers who are not familiar with your API
and have them implement the main scenarios. Try to identify which parts of your
API are not intuitive.
## Self Documenting API
Developers using your API should be able to implement main scenarios without
reading the documentation. Help users to discover what types they need to use in
main scenarios and what the semantics of the main methods are by choosing
intuitive names for most used types and members. Talk about naming choices
during specification reviews.
## Understand Your Customer
Realize that the majority of your customers are not like you. You should design
the API for your customer, not for developers working in your close working
group, who unlike majority of your customers are experts in the technology you
are trying to expose.
# Naming Guidelines
Casing and naming guidelines apply only to public and protected identifiers, and
privately implemented interface members. Teams are free to choose their own
guidelines for internal and private identifiers.
&#10003; **DO** use PascalCasing (capitalize the first letter of each word) for
all identifiers except parameter names. For example, use `TextColor` rather than
`Textcolor` or `Text_Color`.
&#10003; **DO** use camelCasing (capitalize first letters of each word except
for the first word) for all member parameter names. prefix descriptive type
parameter names with `T`.
```CSharp
public interface ISessionChannel<TSession>
where TSession : ISession
{
TSession Session { get; }
}
```
&#10003; **CONSIDER** using `T` as the type parameter name for types with one
single letter type parameter.
&#10003; **DO** use PascalCasing or camelCasing for any acronyms over two
characters long. For example, use `HtmlButton` rather than `HTMLButton`, but
`System.IO` instead of `System.Io`.
&#10007; **DO NOT** use acronyms that are not generally accepted in the field.
&#10003; **DO** use well-known acronyms only when absolutely necessary. For
example, use `UI` for User Interface and `Html` for Hyper-Text Markup Language.
&#10007; **DO NOT** use of shortenings or contractions as parts of identifier
names. For example, use `GetWindow` rather than `GetWin`.
&#10007; **DO NOT** use underscores, hyphens, or any other non-alphanumeric
characters.
&#10007; **DO NOT** use the Hungarian notation.
&#10003; **DO** name types and properties with nouns or noun phrases.
&#10003; **DO** name methods and events with verbs or verb phrases. Always give
events names that have a concept of before and after using the present particle
and simple past tense. For example, an event that is raised before a `Form`
closes should be named `Closing`. An event raised after a `Form` is closed
should be named `Closed`.
&#10007; **DO NOT** use the `Before` or `After` prefixes to indicate pre and
post events.
&#10003; **DO** use the following prefixes:
* `I` for interfaces.
* `T` for generic type parameters (except single letter parameters).
&#10003; **DO** use the following postfixes:
* `Exception` for types inheriting from `System.Exception`.
* `Collection` for types implementing `IEnumerable`.
* `Dictionary` for types implementing `IDictionary` or `IDictionary<K,V>`.
* `EventArgs` for types inheriting from `System.EventArgs`.
* `EventHandler` for types inheriting from `System.Delegate`.
* `Attribute` for types inheriting from `System.Attribute`.
&#10007; **DO NOT** use the postfixes listed above for any other types.
&#10007; **DO NOT** postfix type names with `Flags` or `Enum`.
&#10003; **DO** use plural noun phrases for flag enums (enums with values that
support bitwise operations) and singular noun phrases for non-flag enums.
&#10003; **DO** use the following template for naming namespaces:
<Company>.<Technology>[.<Feature>].
For example, `Microsoft.Office.ClipGallery`. Operating System components should
use System namespaces instead for the <Company> namespaces.
&#10007; **DO NOT** use organizational hierarchies as the basis for namespace
hierarchies. Namespaces should correspond to scenarios regardless of what teams
contribute APIs for those scenarios.
# General Design Guidelines
&#10003; **DO** use the most derived type for return values and the least
derived type for input parameters. For example take `IEnumerable` as an input
parameter but return `Collection<string>` as the return type. Provide a clear
API entry point for every scenario. Every feature area should have preferably
one, but sometimes more, types that are the starting points for exploring given
technology. We call such types Aggregate Components. Implementation of large
majority of scenarios in given technology area should start with one of the
Aggregate Components.
&#10003; **DO** write sample code for your top scenarios. The first type used in
all these samples should be an Aggregate Component and the sample code should be
straightforward. If the code gets longer than several lines, you need to
redesign. Writing to an event log in Win32 API was around 100 lines of code.
Writing to .NET Framework EventLog takes one line of code.
&#10003; **DO** model higher level concepts (physical objects) rather than
system level tasks with Aggregate Components. For example `File`, `Directory`,
`Drive` are easier to understand than `Stream`, `Formatter`, `Comparer`.
&#10007; **DO NOT** require users of your APIs to instantiate multiple objects
in main scenarios. Simple tasks should be done with new statement.
&#10003; **DO** support so called ”Create-Set-Call” programming style in all
Aggregate Components. It should be possible to instantiate every component with
the default constructor, set one or more properties, and call simple methods or
respond to events.
```CSharp
var applicationLog = new EventLog();
applicationLog.Source = "MySource";
applicationLog.WriteEntry(exception.Message);
```
&#10007; **DO NOT** require extensive initialization before Aggregate Components
can be used. If some initialization is necessary, the exception resulting from
not having the component initialized should clearly explain what needs to be
done.
&#10003; **DO** carefully choose names for your types, methods, and parameters.
Think hard about the first name people will try typing in the code editor when
they explore the feature area. Reserve and use this name for the Aggregate
Component. A common mistake is to use the ”best” name for a base type. Run FxCop
on your libraries.
&#10003; **DO** ensure your library is CLS compliant. Apply `CLSCompliantAttribute`
to your assembly.
&#10003; **DO** prefer classes over interfaces.
&#10007; **DO NOT** seal types unless you have a strong reason to do it.
&#10007; **DO NOT** create mutable value types.
&#10007; **DO NOT** ship abstractions (interfaces or abstract classes) without
providing at least one concrete type implementing each abstraction. This helps
to validate the interface design.
&#10007; **DO NOT** ship interfaces without providing at least one API consuming
the interface (a method taking the interface as a parameter). This helps to
validate the interface design.
&#10007; **AVOID** public nested types.
&#10003; **DO** apply `FlagsAttribute` to flag enums.
&#10003; **DO** strongly prefer collections over arrays in public API.
&#10007; **DO NOT** use `ArrayList`, `List<T>`, `Hashtable`, or `Dictionary<K,V>`
in public APIs. Use `Collection<T>`, `ReadOnlyCollection<T>`,
`KeyedCollection<K,V>`, or `CollectionBase` subtypes instead. Note that the
generic collections are only supported in the Framework version 2.0 and above.
&#10007; **DO NOT** use error codes to report failures. Use Exceptions instead.
&#10007; **DO NOT** throw `Exception` or `SystemException`.
&#10007; **AVOID** catching the `Exception` base type.
&#10003; **DO** prefer throwing existing common general purpose exceptions like
`ArgumentNullException`, `ArgumentOutOfRangeException`,
`InvalidOperationException` instead of defining custom exceptions. throw the
most specific exception possible.
&#10003; **DO** ensure that exception messages are clear and actionable.
&#10003; **DO** use `EventHandler<T>` for events, instead of manually defining
event handler delegates.
&#10003; **DO** prefer event based APIs over delegate based APIs.
&#10003; **DO** prefer constructors over factory methods.
&#10007; **DO NOT** expose public fields. Use properties instead.
&#10003; **DO** prefer properties for concepts with logical backing store but
use methods in the following cases:
* The operation is a conversion (such as `Object.ToString()`)
* The operation is expensive (orders of magnitude slower than a field set would
be)
* Obtaining a property value using the Get accessor has an observable side
effect
* Calling the member twice in succession results in different results
* The member returns an array. Note: Members returning arrays should return
copies of an internal master array, not a reference to the internal array.
&#10003; **DO** allow properties to be set in any order. Properties should be
stateless with respect to other properties.
&#10007; **DO NOT** make members virtual unless you have a strong reason to do
it.
&#10007; **AVOID** finalizers.
&#10003; **DO** implement `IDisposable` on all types acquiring native resources
and those that provide finalizers.
&#10003; **DO** be consistent in the ordering and naming of method parameters.
It is common to have a set of overloaded methods with an increasing number of
parameters to allow the developer to specify a desired level of information.
&#10003; **DO** make sure all the related overloads have a consistent parameter
order (same parameter shows in the same place in the signature) and naming
pattern. The only method in such a group that should be virtual is the one that
has the most parameters and only when extensibility is needed.
```CSharp
public class Foo
{
private readonly string _defaultForA = "default value for a";
private readonly int _defaultForB = 42;
public void Bar()
{
Bar(_defaultForA, _defaultForB);
}
public void Bar(string a)
{
Bar(a, _defaultForB);
}
public void Bar(string a, int b)
{
// core implementation here
}
}
```
&#10007; **AVOID** `out` and `ref` parameters.
# Resources
## FxCop
[FxCop](https://msdn.microsoft.com/en-us/library/bb429476.aspx) is a code analysis tool that checks managed code assemblies for
conformance to the [Framework Design Guidelines][FDG] (also see [MSDN](https://msdn.microsoft.com/en-us/library/ms229042.aspx)).
## Presentations
* [Overview of the Framework Design Guidelines](http://blogs.msdn.com/kcwalina/archive/2007/03/29/1989896.aspx)
* [TechEd 2007 Presentation about framework engineering](http://blogs.msdn.com/kcwalina/archive/2008/01/08/FrameworkEngineering.aspx)

View File

@@ -0,0 +1,300 @@
Interop Guidelines
==================
## Goals
We have the following goals related to interop code being used in CoreFX:
- Minimize code duplication for interop.
- We should only define a given interop signature in a single place.
This stuff is tricky, and we shouldn't be copy-and-pasting it.
- Minimize unnecessary IL in assemblies.
- Interop signatures should only be compiled into the assemblies that
actually consume them. Having extra signatures bloats assemblies and
makes it more difficult to do static analysis over assemblies to
understand what they actually use. It also leads to problems when such
static verification is used as a gate, e.g. if a store verifies that
only certain APIs are used by apps in the store.
- Keep interop code isolated and consolidated.
- This is both for good hygiene and to help keep platform-specific code
separated from platform-neutral code, which is important for maximizing
reusable code above PAL layers.
- Ensure maximal managed code reuse across different OS flavors which have
the same API but not the same ABI.
- This is the case for UNIX and addressing it is a work-in-progress (see issue
#2137 and section on "shims" below.)
## Approach
### Interop type
- All code related to interop signatures (DllImports, interop structs
used in DllImports, constants that map to native values, etc.) should
live in a partial, static, and internal “Interop” class in the root
namespace, e.g.
```C#
internal static partial class Interop { ... }
```
- Declarations shouldn't be in Interop directly, but rather within a
partial, static, internal nested type named for a given library or set
of libraries, e.g.
```C#
internal static partial class Interop
{
internal static partial class libc { ... }
}
...
internal static partial class Interop
{
internal static partial class mincore { ... }
}
```
- With few exceptions, the only methods that should be defined in these
interop types are DllImports.
- Exceptions are limited to times when most or every consumer of a
particular DllImport will need to wrap its invocation in a helper, e.g.
to provide additional marshaling support, to hide thread-safety issues
in the underlying OS implementation, to do any required manipulation of
safe handles, etc. In such cases, the DllImport should be private
whenever possible rather than internal, with the helper code exposed to
consumers rather than having the DllImport exposed directly.
### File organization
- The Interop partial class definitions should live in Interop.*.cs
files. These Interop.*.cs files should all live under Common rather than
within a given assembly's folder.
- The only exception to this should be when an assembly P/Invokes to its
own native library that isn't available to or consumed by anyone else,
e.g. System.IO.Compression P/Invoking to clrcompression.dll. In such
cases, System.IO.Compression should have its own Interop folder which
follows a similar scheme as outlined in this proposal, but just for
these private P/Invokes.
- Under Common\src\Interop, we'll have a folder for each target
platform, and within each platform, for each library from which
functionality is being consumed. The Interop.*.cs files will live within
those library folders, e.g.
```
\Common\src\Interop
\Windows
\mincore
... interop files
\Unix
\libc
... interop files
\Linux
\libc
... interop files
```
As shown above, platforms may be additive, in that an assembly may use functionality from multiple folders, e.g. System.IO.FileSystem's Linux build will use functionality both from Unix (common across all Unix systems) and from Linux (specific to Linux and not available across non-Linux Unix systems).
 
- Interop.*.cs files are created in a way such that every assembly
consuming the file will need every DllImport it contains.
- If multiple related DllImports will all be needed by every consumer,
they may be declared in the same file, named for the functionality
grouping, e.g. Interop.IOErrors.cs.
- Otherwise, in the limit (and the expected case for most situations)
each Interop.*.cs file will contain a single DllImport and associated
interop types (e.g. the structs used with that signature) and helper
wrappers, e.g. Interop.strerror.cs.
```
\Common\src\Interop
\Unix
\libc
\Interop.strerror.cs
\Windows
\mincore
\Interop.OutputDebugString.cs
```
- If structs/constants will be used on their own without an associated
DllImport, or if they may be used with multiple DllImports not in the
same file, they should be declared in a separate file.
- In the case of multiple overloads of the same DllImport (e.g. some
overloads taking a SafeHandle and others taking an IntPtr, or overloads
taking different kinds of SafeHandles), if they can't all be declared in
the same file (because they won't all be consumed by all consumers), the
file should be qualified with the key differentiator, e.g.
```
\Common\src\Interop
\Windows
\mincore
\Interop.DuplicateHandle_SafeTokenHandle.cs
\Interop.DuplicateHandle_IntPtr.cs
```
- The library names used per-platform are stored in internal constants
in the Interop class in a private Libraries class in a per-platform file
named Interop.Libraries.cs. These constants are then used for all
DllImports to that library, rather than having the string duplicated
each time, e.g.
```C#
internal static partial class Interop // contents of Common\src\Interop\Windows\Interop.Libraries.cs
{
private static class Libraries
{
internal const string Kernel32 = "kernel32.dll";
internal const string Localization = "api-ms-win-core-localization-l1-2-0.dll";
internal const string Handle = "api-ms-win-core-handle-l1-1-0.dll";
internal const string ProcessThreads = "api-ms-win-core-processthreads-l1-1-0.dll";
internal const string File = "api-ms-win-core-file-l1-1-0.dll";
internal const string NamedPipe = "api-ms-win-core-namedpipe-l1-1-0.dll";
internal const string IO = "api-ms-win-core-io-l1-1-0.dll";
...
}
}
```
(Note that this will likely result in some extra constants defined in
each assembly that uses interop, which minimally violates one of the
goals, but it's very minimal.)
 
- .csproj project files then include the interop code they need, e.g.
```XML
<ItemGroup Condition=" '$(TargetsUnix)' == 'true' ">
<Compile Include="Interop\Unix\Interop.Libraries.cs" />
<Compile Include="Interop\Unix\libc\Interop.strerror.cs" />
<Compile Include="Interop\Unix\libc\Interop.getenv.cs" />
<Compile Include="Interop\Unix\libc\Interop.getenv.cs" />
<Compile Include="Interop\Unix\libc\Interop.open64.cs" />
<Compile Include="Interop\Unix\libc\Interop.close.cs" />
<Compile Include="Interop\Unix\libc\Interop.snprintf.cs" />
...
</ItemGroup>
```
### Build System
When building CoreFx, we use the "OSGroup" property to control what
target platform we are building for. The valid values for this property
are Windows_NT (which is the default value from MSBuild when running on
Windows), Linux and OSX.
The build system sets a few MSBuild properties, depending on the OSGroup
setting:
* TargetsWindows
* TargetsLinux
* TargetsOSX
* TargetsUnix
TargetsUnix is true for both OSX and Linux builds and can be used to
include code that can be used on both Linux and OSX (e.g. it is written
against a POSIX API that is present on both platforms).
You should not test the value of the OSGroup property directly, instead
use one of the values above.
#### Project Files
Whenever possible, a single .csproj should be used per assembly,
spanning all target platforms, e.g. System.Console.csproj includes
conditional entries for when targeting Windows vs when targeting Linux.
A property can be passed to msbuild to control which flavor is built,
e.g. msbuild /p:OSGroup=OSX System.Console.csproj.
### Constants
- Wherever possible, constants should be defined as "const". Only if the
data type doesn't support this (e.g. IntPtr) should they instead be
static readonly fields.
- Related constants should be grouped under a partial, static, internal
type, e.g. for error codes they'd be grouped under an Errors type:
```C#
internal static partial class Interop
{
internal static partial class libc
{
internal static partial class Errors
{
internal const int ENOENT = 2;
internal const int EINTR = 4;
internal const int EWOULDBLOCK = 11;
internal const int EACCES = 13;
internal const int EEXIST = 17;
internal const int EXDEV = 18;
internal const int EISDIR = 21;
internal const int EINVAL = 22;
internal const int EFBIG = 27;
internal const int ENAMETOOLONG = 36;
internal const int ECANCELED = 125;
...
}
}
}
```
Using enums instead of partial, static classes can lead to needing lots
of casts at call sites and can cause problems if such a type needs to be
split across multiple files (enums can't currently be partial). However,
enums can be valuable in making it clear in a DllImport signature what
values are permissible. Enums may be used in limited circumstances where
these aren't concerns: the full set of values can be represented in the
enum, and the interop signature can be defined to use the enum type
rather than the underlying integral type.
## Naming
- Interop signatures / structs / constants should be defined using the
same name / capitalization / etc. that's used in the corresponding
native code.
- We should not rename any of these based on managed coding guidelines.
The only exception to this is for the constant grouping type, which
should be named with the most discoverable name possible; if that name
is a concept (e.g. Errors), it can be named using managed naming
guidelines.
## UNIX shims
Often, various UNIX flavors offer the same API from the point-of-view of compatibility
with C/C++ source code, but they do not have the same ABI. e.g. Fields can be laid out
differently, constants can have different numeric values, exports can
be named differently, etc. There are not only differences between operating systems
(Mac OS X vs. Ubuntu vs. FreeBSD), but also differences related to the underlying
processor architecture (x64 vs. x86 vs. ARM).
This leaves us with a situation where we can't write portable P/Invoke declarations
that will work on all flavors, and writing separate declarations per flavor is quite
fragile and won't scale.
To address this, we're moving to a model where all UNIX interop from corefx starts with
a P/Invoke to a C++ lib written specifically for corefx. These libs -- System.*.Native.so
(aka "shims") -- are intended to be very thin layers over underlying platform libraries.
Generally, they are not there to add any significant abstraction, but to create a
stable ABI such that the same IL assembly can work across UNIX flavors.
Guidelines for shim C++ API:
- Keep them as "thin"/1:1 as possible.
- We want to write the majority of code in C#.
- Never skip the shim and P/Invoke directly to the underlying platform API. It's
easy to assume something is safe/guaranteed when it isn't.
- Don't cheat and take advantage of coincidental agreement between
one flavor's ABI and the shim's ABI.
- Use PascalCase in a style closer to Win32 than libc.
- If an export point has a 1:1 correspondence to the platform API, then name
it after the platform API in PascalCase (e.g. stat -> Stat, fstat -> FStat).
- If an export is not 1:1, then spell things out as we typically would in
CoreFX code (i.e. don't use abbreviations unless they come from the underlying
API.
- At first, it seemed that we'd want to use 1:1 names throughout, but it
turns out there are many cases where being strictly 1:1 isn't practical.
- In order to reduce the chance of collisions when linking with CoreRT, all
exports should have a prefix that corresponds to the Libraries' name, e.g.
"SystemNative_" or "CryptoNative_" to make the method name more unique.
See https://github.com/dotnet/corefx/issues/4818.
- Stick to data types which are guaranteed not to vary in size across flavors.
- Use int32_t, int64_t, etc. from stdint.h and not int, long, etc.
- Use char* for ASCII or UTF-8 strings and uint8_t* for byte buffers.
- Note that sizeof(char) == 1 is guaranteed.
- Do not use size_t in shim API. Always pick a fixed size. Often, it is most
convenient to line up with the managed int as int32_t (e.g. scratch buffer
size for read/write), but sometimes we need to handle huge sizes (e.g.
memory mapped files) and therefore use uint64_t.
- Use int64_t for native off_t values.

View File

@@ -0,0 +1,96 @@
##dotnet/CoreFx
###Libraries in NETStandard
- ref
- Default targetgroup should be NETCoreApp build
- P2P references to other reference assembly CSProjs.
- System.Runtime core assembly.
- Cross-compiles for concrete frameworks (if different)
- EG: exposes types/members not in NETStandard on NETCoreApp, but not on UWP
- src
- Default targetgroup should be NETCoreApp build
- depends on System.Runtime?
- Yes: P2P to ref CSProjs
- No: P2P to implementation projects
- **Issue:** what if dependency is not in NETStandard? EG: Buffers
- P2P reference to pkgproj
- Reference to NETStandard.dll facade for NETCoreApp
- pkg
- No individual package builds.
- We will have a single package for all of NETCore.App's netstandard.library implementation. Below TBD.
- framework split packages
- ref\netcoreappN - all refs for NETCoreApp,Version=vN
- runtime split packages
- runtime\{RID}\lib\netcoreappN - all impl for NETCoreApp,Version=vN, cross-gen'ed for RID
- tests
- By default get all of NETStandard.Library for a specific version that they target (auto-referenced by targets)
- Use P2P references to pkgproj for things not in NETStandard.Library
- Implementation is automatically injected by targets.
###Libraries above NETStandard
- ref
- Only required if component is inbox somewhere or has multiple implementations for same NETStandard version.
- Build against NETStandard.Library package
- P2P references to pkgproj for things not in NETStandard.Library
- For builds that support older platforms (eg: netstandard1.0-1.6) we'll be building against the older contract-based NETStandard, we will need a story for this for build-from-source.
- src
- Build against NETStandard.Library package
- P2P references to pkgproj for things not in NETStandard.Library
- For builds that support older platforms (eg: netstandard1.0-1.6) we'll be building against the older contract-based NETStandard, we will need a story for this for build-from-source.
- pkg
- Not in NETCore.App: as today
- In NETCore.App: package in NETCore.App package as above
- If the library also ships in a package, it will also build a package as today. This package may or may-not include the same binaries as are used by NETCore.App, for instance if the library builds against older NETStandard versions.
- tests
- By default get all of NETStandard.Library for a specific version that they target (auto-referenced by targets)
- Use P2P references for things not in NETStandard.Library
- Implementation is automatically injected by targets.
###NETStandard compatibility facade
Provides compatibility between NETCore.App and libraries built against NETStandard.
- ref
- Should adapt supported NETStandard.dll to contract reference assemblies.
- EG: `GenFacades -contracts:<netstandard.dll> -seeds:<allNetCoreAppReferenceAssemblies>`
- src
- Should adapt supported NETStandard.dll to implementation assemblies.
- EG: `GenFacades -contracts:<netstandard.dll> -seeds:<allNetCoreAppImplementationAssemblies>`
- pkg
- No individual package builds.
- Should be included in NETCoreApp package as above
###Desktop compatibility facades
- ref
- Should adapt latest desktop surface to contract reference assemblies for anything that has type-overlap with desktop, including assemblies like Microsoft.Win32.Registry which are not in NETStandard.Library.
- EG: `GenFacades -contracts:<desktopReferenceAssemblies> -seeds:<allNetCoreAppReferenceAssemblies>`
- src
- Should adapt latest desktop surface to netcore app implementation for anything that has type-overlap with desktop, including assemblies like Microsoft.Win32.Registry which are not in NETStandard.Library.
- EG: `GenFacades -contracts:<desktopReferenceAssemblies> -seeds:<allNetCoreAppImplementationAssemblies>`
- pkg
- No individual package builds.
- Should be included in NETCoreApp package as above
###Native shims
- pkg
- No individual package builds.
- As with libraries in NETStandard the shims will be included in the runtime specific packages for NETCoreApp
##Transition
###End goal
- CoreFx does not build any reference assemblies for NETStandard.
- For every library in NETStandard.Library, the only configurations in CoreFx are framework-specific. EG: NETCoreApp1.2, UAP10.1
- For every library in NETCore.App but not in NETStandard.Library there must be a framework-specific configuration for NETCoreApp1.2. Other configurations may exist to ship in a package, but those will not be built by folks building just NETCore.App.
###Getting there (WIP)
Folks still consume our current packages so we need to keep building those until we transition.
1. Create a new NETCore.App package: Microsoft.Private.CoreFx.NETCore.App. This will be an identity package with every ref that targets NETCore.App and runtime-specific packages that have all runtime impl's that apply to NETCore.App.
2. Filter the content of Microsoft.Private.CoreFx.NETCore.App to just the things that are part of NETCore, and their closure.
3. Transition tests to use Microsoft.Private.CoreFx.NETCore.App.
4. Delete packages for things that are only part of Microsoft.Private.CoreFx.NETCore.App and don't ship independently.
- Delete configurations for libraries that are no longer used
- As packages are deleted we'll need to opt-in to Microsoft.Private.CoreFx.NETCore.App in some way.
- proposal:
- each CSProj is evaluated for layout path in the context of all of its build configurations.
- We'll determine applicability similar to how we do for pkgprojs to idenitify which config to binplace.

View File

@@ -0,0 +1,326 @@
# Package projects
Package projects bring together all the assemblies that make up a library on different platforms into a set of NuGet packages.
## Package hierarchy
All libraries should have at least one package if they represent public surface area. This is called the *reference package* and is named the same as the library's assembly, EG: System.Collections.Immutable.
Packages may have platform specific implementation packages. These are referred to as *runtime packages* and follow the naming convention of runtime.{rid}.{assemblyName}, EG: runtime.unix.System.IO.FileSystem.
In either case the file name of the `.pkgproj` is just {assemblyName}.pkgproj and package names are derived from the contents of the project.
## Package samples
### Simple portable library
This is the simplest case. The package project need only reference the single project that implements the portable libary.
Sample `System.Text.Encodings.Web.pkgproj`
```
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<ProjectReference Include="..\src\System.Text.Encodings.Web.csproj">
<SupportedFramework>net45;netcore45;wp8;wpa81;netcoreapp1.0</SupportedFramework>
</ProjectReference>
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
```
### Portable library, inbox on some platforms
These packages need to include placeholders for inbox platforms. They should also include reference assemblies for representing the fixed API that is inbox in old platforms.
Sample `System.Collections.Concurrent.pkgproj`
```
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<ProjectReference Include="..\ref\4.0.0\System.Collections.Concurrent.depproj">
<SupportedFramework>net45;netcore45;wpa81</SupportedFramework>
</ProjectReference>
<ProjectReference Include="..\ref\System.Collections.Concurrent.csproj">
<SupportedFramework>net46;netcore50;netcoreapp1.0</SupportedFramework>
</ProjectReference>
<ProjectReference Include="..\src\System.Collections.Concurrent.csproj"/>
<InboxOnTargetFramework Include="MonoAndroid10" />
<InboxOnTargetFramework Include="MonoTouch10" />
<InboxOnTargetFramework Include="net45" />
<InboxOnTargetFramework Include="win8" />
<InboxOnTargetFramework Include="wpa81" />
<InboxOnTargetFramework Include="xamarinios10" />
<InboxOnTargetFramework Include="xamarinmac20" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
```
### Framework-specific library
Framework specific libraries are effectively the same as the previous example. The difference is that the src project reference **must** refer to the `.builds` file which will provide multiple assets from multiple projects.
Sample System.Net.Security.pkgproj
```
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<ProjectReference Include="..\ref\System.Net.Security.builds">
<SupportedFramework>net463;netcoreapp1.1;$(AllXamarinFrameworks)</SupportedFramework>
</ProjectReference>
<ProjectReference Include="..\src\System.Net.Security.builds" />
</ItemGroup>
<ItemGroup>
<InboxOnTargetFramework Include="MonoAndroid10" />
<InboxOnTargetFramework Include="MonoTouch10" />
<InboxOnTargetFramework Include="xamarinios10" />
<InboxOnTargetFramework Include="xamarinmac20" />
<InboxOnTargetFramework Include="xamarintvos10" />
<InboxOnTargetFramework Include="xamarinwatchos10" />
<NotSupportedOnTargetFramework Include="netcore50">
<PackageTargetRuntime>win7</PackageTargetRuntime>
</NotSupportedOnTargetFramework>
</ItemGroup>
<ItemGroup>
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
```
Sample \ref .builds file defining a constant used to filter API that were added on top of the netstandard1.7 ones and are available only in netcoreapp1.1:
```
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
<OutputType>Library</OutputType>
<NuGetTargetMoniker>.NETStandard,Version=v1.7</NuGetTargetMoniker>
<DefineConstants Condition="'$(TargetGroup)' == 'netcoreapp1.1'">$(DefineConstants);netcoreapp11</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Compile Include="System.Net.Security.cs" />
<Compile Include="System.Net.Security.Manual.cs" />
</ItemGroup>
<ItemGroup>
<None Include="project.json" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
```
Conditional compilation using the above-mentioned constant (from `ref\System.Net.Security.cs`):
```
#if netcoreapp11
public virtual void AuthenticateAsClient(string targetHost, System.Security.Cryptography.X509Certificates.X509CertificateCollection clientCertificates, bool checkCertificateRevocation) { }
#endif
```
Sample \src .builds file (in this case the implementation is the same in both netcoreapp1.1 and netstandard1.7):
```
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<Project Include="System.Net.Security.csproj">
<OSGroup>Unix</OSGroup>
</Project>
<Project Include="System.Net.Security.csproj">
<OSGroup>Windows_NT</OSGroup>
</Project>
<Project Include="System.Net.Security.csproj">
<TargetGroup>net463</TargetGroup>
</Project>
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.traversal.targets))\dir.traversal.targets" />
</Project>
```
Tests can be similarly filtered grouping the compilation directives under:
```
<ItemGroup Condition="'$(TargetGroup)'=='netcoreapp1.1'">
```
(from `\tests\FunctionalTests\System.Net.Security.Tests.csproj`)
### Platform-specific library
These packages need to provide a different platform specific implementation on each platform. They do this by splitting the implementations into seperate packages and associating those platform specific packages with the primary reference package. Each platform specific package sets `PackageTargetRuntime` to the specific platform RID that it applies.
Sample `System.IO.FileSystem.pkgproj`
```
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<ProjectReference Include="..\ref\System.IO.FileSystem.csproj">
<SupportedFramework>net46;netcore50;netcoreapp1.0</SupportedFramework>
</ProjectReference>
<ProjectReference Include="..\src\Facade\System.IO.FileSystem.csproj" />
<ProjectReference Include="win\System.IO.FileSystem.pkgproj" />
<ProjectReference Include="unix\System.IO.FileSystem.pkgproj" />
<InboxOnTargetFramework Include="MonoAndroid10" />
<InboxOnTargetFramework Include="MonoTouch10" />
<InboxOnTargetFramework Include="xamarinios10" />
<InboxOnTargetFramework Include="xamarinmac20" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
```
`win/System.IO.FileSystem.pkgproj`
```
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
<PackageTargetRuntime>win7</PackageTargetRuntime>
<PreventImplementationReference>true</PreventImplementationReference>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\System.IO.FileSystem.builds">
<AdditionalProperties>OSGroup=Windows_NT</AdditionalProperties>
</ProjectReference>
<!-- No implementation on platforms where our P-Invokes are not allowed -->
<NotSupportedOnTargetFramework Include="win8" />
<NotSupportedOnTargetFramework Include="wp8" />
<NotSupportedOnTargetFramework Include="wpa81" />
<!-- don't use the dotnet implementation for any version of desktop, it's implementation comes from the reference package -->
<ExternalOnTargetFramework Include="net" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
```
`unix/System.IO.FileSystem.pkgproj`
```
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
<PackageTargetRuntime>unix</PackageTargetRuntime>
<PreventImplementationReference>true</PreventImplementationReference>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\System.IO.FileSystem.builds">
<AdditionalProperties>OSGroup=Linux</AdditionalProperties>
</ProjectReference>
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
```
## Asset selection
The makeup of a package folder is primarily a grouping of project references to the projects that compose that package. Settings within each referenced project determines where that asset will be placed in the package. For example, reference assembly projects will be placed under the `ref/{targetMoniker}` folder in the package and implementations will be under either `lib/{targetMoniker}` or `runtimes/{rid}/lib/{targetMoniker}`. Whenever NuGet evaulates a package in the context of a referencing project it will choose the best compile time asset (preferring `ref`, then falling back to `lib`) and runtime asset (preffering `runtimes/{rid}/lib` and falling back to `lib`) for every package that is referenced. For more information see http://docs.nuget.org/.
Asset projects (`.csproj`, `.vbproj`, or `.depproj`) can control their `{targetMoniker}` using the `PackageTargetFramework` property in the project file. Similarly `{rid}` is controlled using the `PackageTargetRuntime` property. In the corefx repo we automatically select default values for these properties based on the [Build pivots](#build-pivots). These can be overridden in the project reference using metadata of the same name, but this is rarely needed.
The primary thing that the library author needs to do in order to ensure the correct asset selection is:
1. Configure the correct projects in your library's `.builds` file.
2. Reference the `.builds` file from the package project.
3. Provide a default PackageTargetFramework for empty-TargetGroup builds in the library's `.csproj` or `.vbproj`.
```
<PackageTargetFramework Condition="'$(PackageTargetFramework)' == ''">dotnet5.4</PackageTargetFramework>
```
### Which version of dotnet/netstandard should I select?
TL;DR - choose the lowest version that doesn't result in build errors for both the library projects and package project.
NETStandard/DotNet are *open* ended portable identifiers. They allow a package to place an asset in a folder and that asset can be reused on any framework that supports that version of NETStandard/DotNet. This is in contrast to the previous *closed* set portable-a+b+c identifiers which only applied to the frameworks listed in the set. For more information see [.NET Standard](https://github.com/dotnet/standard/blob/master/docs/faq.md).
Libraries should select a version of DotNet/NETStandard that supports the most frameworks. This means the library should choose the lowest version that provides all the API needed to implement their functionality. Eventually this will be the same moniker used for package resolution in the library project, AKA in `frameworks` section for the libraries project.json.
In CoreFx we don't always use the package resolution for dependencies, sometimes we must use project references. Additionally we aren't building all projects with the NETStandard/DotNet identifier. This issue is tracked with https://github.com/dotnet/corefx/issues/2427. As a result we calculate the version as an added safegaurd based on seeds. These seeds are listed in [Generations.json](https://github.com/dotnet/buildtools/blob/master/src/Microsoft.DotNet.Build.Tasks.Packaging/src/PackageFiles/Generations.json) and rarely change. They are a record of what libraries shipped in-box and are unchangeable for a particular framework supporting a generation. Occasionally an API change can be made even to these in-box libraries and shipped out-of-band, for example by adding a new type and putting that type in a hybrid facade. This is the only case when it is permitted to update Generations.json.
In addition to the minimum API version required by implementation, reference assemblies should only claim the NETStandard/DotNet version of the minimum implementation assembly. Just because a reference assembly only depends on API in NETStandard1.0, if its implementations only apply to frameworks supporting NETStandard1.4, it should use NETStandard1.4.
### .NET Framework facades
.NET Framework facades must be part of the reference package. This is because if we were to use the reference assembly on desktop it would have type collisions with whatever types already exist in the desktop reference assemblies. Since we include the desktop reference facade in the reference package we also include the runtime facade in the same package for compression savings.
## Applicability validation
Part of package build is to ensure that a package is applicable on all platforms it supports and not applicable on platforms it does not support. We do this validation for a set of targets established in the packaging tools (see [DefaultValidateFramework](https://github.com/dotnet/buildtools/blob/9f4ddda1cb021c9bd25f606bc4e74b92e4b82869/src/Microsoft.DotNet.Build.Tasks.Packaging/src/PackageFiles/Packaging.targets#L709)). Package projects identify the targets supported in one of two ways.
1. **Preferred:** Through `SupportedFramework` metadata on the project reference. The metadata will associate the API version of that project reference with the frameworks listed.
```
<ProjectReference Include="..\ref\4.0.0\System.Collections.Concurrent.depproj">
<SupportedFramework>net45;netcore45;wpa81</SupportedFramework>
</ProjectReference>
<ProjectReference Include="..\ref\System.Collections.Concurrent.csproj">
<SupportedFramework>net46;netcore50;netcoreapp1.0</SupportedFramework>
</ProjectReference>
```
2. Through SupportedFramework items with Version metdata.
```
<!-- no version indicates latest is supported -->
<SupportedFramework Include="net46;netcore50;netcoreapp1.0" />
<!-- specific version indicates that version is supported -->
<SupportedFramework Include="net45;netcore45;wpa81">
<Version>4.0.0.0</Version>
</SupportedFramework>
```
###Inbox assets
Some libraries are supported inbox on particular frameworks. For these frameworks the package should not present any assets for (ref or lib) for that framework, but instead permit installation and provide no assets. We do this in the package by using placeholders ref and lib folders for that framework. In the package project one can use `InboxOnTargetFramework` items. The following is an example from the System.Linq.Expressions package.
```
<InboxOnTargetFramework Include="net45" />
<InboxOnTargetFramework Include="win8" />
<InboxOnTargetFramework Include="wp80" />
<InboxOnTargetFramework Include="wpa81" />
```
If the library is also a "classic" reference assembly, not referenced by default, then adding the `AsFrameworkReference` metadata will instruct that the package include a `frameworkReference` element in the nuspec. The following is the an example from the Microsoft.CSharp package.
```
<InboxOnTargetFramework Include="net45">
<AsFrameworkReference>true</AsFrameworkReference>
</InboxOnTargetFramework>
<InboxOnTargetFramework Include="win8" />
<InboxOnTargetFramework Include="wp80" />
<InboxOnTargetFramework Include="wpa81" />
```
Package validation will catch a case where we know a library is supported inbox but a package is using an asset from the package. This data is driven by framework lists from previously-shipped targeting packs. The error will appear as: *Framework net45 should support Microsoft.CSharp inbox but {explanation of problem}. You may need to add <InboxOnTargetFramework Include="net45" /> to your project.*
###External assets
Runtime specific packages are used to break apart implementations into seperate packages and enable "pay-for-play". For example: don't download the Windows implementation if we're only building/deploying for linux. In most cases we can completely seperate implementations into seperate packages such that they easily translate. For example:
```
runtimes/win/lib/dotnet5.4/System.Banana.dll
runtimes/unix/lib/dotnet5.4/System.Banana.dll
```
This can easily be split into a `win` and `unix` package. If someone happens to install both packages into a project they'll still get a single implementation.
Consider the following:
```
runtimes/win/lib/dotnet5.4/System.Banana.dll
runtimes/win/lib/net46/System.Banana.dll
```
Suppose we wanted to split the desktop (`net46`) implementation into a seperate package than the portable implementation. Doing so would cause both the `dotnet5.4` asset and the `net46` asset to be applicable and result in a bin-clash. This is because in a single package the `net46` asset is preferred over the `dotnet5.4` asset, but in seperate packages both are in view. The packaging validation will catch this problem and display an error such as
*System.Banana includes both package1/runtimes/win/lib/net46/System.Banana.dll and package2/runtimes/win/lib/dotnet5.4/System.Banana.dll an on net46 which have the same name and will clash when both packages are used.*
The fix for the error is to put a placeholder in the package that contains the asset we want to prevent applying. This can be done with the following syntax.
```
<ExternalOnTargetFramework Include="net46" />
```
###Not supported
In rare cases a particular library might represent itself as targeting a specific portable moniker (eg: `dotnet5.4`) but it cannot be supported on a particular target framework that is included in that portable moniker for other reasons. One example of this is System.Diagnostics.Process. The surface area of this API is portable to dotnet5.4 and could technically run in UWP based on its managed dependencies. The native API, however, is not supported in app container. To prevent this package and packages which depend on from installing in UWP projects, only to fail at runtime, we can block the package from being installed.
To do this we create a placeholder in the lib folder with the following syntax. The resulting combination will be an applicable ref asset with no applicable lib and NuGet's compat check will fail.
```
<NotSupportedOnTargetFramework Include="net46" />
```
The packaging validation will catch this problem and display an error such as
*System.Diagnostics.Process should not be supported on netcore50 but has both compile and runtime assets.*

View File

@@ -0,0 +1,16 @@
Managed Code Performance Guidelines
===================================
Different applications have different needs when it comes to performance. For libraries that may be used in any of them and potentially on critical paths, however, it is of the utmost importance that code is as efficient as possible. The code in CoreFX should strive to be high-performing, including minimizing the number and size of allocations, minimizing the number of branches involved in code, and overall minimizing the amount of work that must be done to perform any given operation.
Much has been written about writing high-performance code in C#. This page provides links to some of that material and will expand over time as additional resources are found and identified as being relevant and useful.
You can read [CoreCLR Performance Requirements](https://github.com/dotnet/coreclr/blob/master/Documentation/project-docs/performance-guidelines.md) to learn more.
# Memory Management
* **Avoiding delegate and closure allocations for lambdas**. The code generated by the C# compiler for anonymous methods and lambdas may involve one or more allocations. Certain patterns in APIs can help to avoid these allocations. See [Know Thine Implicit Allocations](http://blogs.msdn.com/b/pfxteam/archive/2012/02/03/10263921.aspx) for more information.
# Asynchrony
* **Best practices for async/await performance**. The C# async/await feature makes it easy to write asynchronous code in the same manner that you'd write synchronous code, but it comes with its own set of costs, and understanding these costs can help you to avoid them. This [presentation from Build](http://channel9.msdn.com/Events/BUILD/BUILD2011/TOOL-829T) and this [MSDN Magazine article](http://msdn.microsoft.com/en-us/magazine/hh456402.aspx) outline some best practices.

View File

@@ -0,0 +1,245 @@
#Build Project Guidelines
In order to work in corefx repo you must first run build.cmd/sh from the root of the repo at least
once before you can iterate and work on a given library project.
##Behind the scenes with build.cmd/sh
- Setup tools (currently done in init-tools but will later be a boot-strap script in run.cmd/sh)
- Restore external dependencies
- CoreCLR - Copy to `bin\runtime\$(BuildConfiguration)`
- Netstandard Library - Copy to `bin\ref\netstandard`
- UAP - Copy to `bin\runtime\$(BuildConfiguration)`
- NetFx targeting pack - Copy to `bin\ref\netfx`
- Build targeting pack
- Build src\ref.builds which builds all references assembly projects. For reference assembly project information see [ref](#ref)
- Build product
- Build src\src.builds which builds all the source library projects. For source library project information see [src](#src).
- Sign product
- Build src\sign.builds
//**CONSIDER**: We should make this as part of the src.builds file instead of a separate .builds file.
##Behind the scenes with build-test.cmd/sh
- build-test.cmd cannot be ran successfully until build.cmd has been ran at least once for a `BuildConfiguration`.
- Build src\tests.builds which builds all applicable test projects. For test project information see [tests](#tests).
- The build pass will happen twice. Once for the specific `$(BuildConfiguration)` and once for netstandard. That way we run both sets of applicable tests against for the given `$(BuildConfiguration)`.
- TODO: Currently as part of src/post.builds we call CloudBuild.targets which sets up our test runs. This needs to be moved to be part of build-test.cmd now.
##Behind the scenes with build-packages.cmd/sh
- build-packages.cmd cannot be run successfully until build.cmd has been ran at least once for a BuildConfiguration.
- Build src\packages.builds which will build only the packages it has the context to build which will generally be only the ones for the given `BuildConfiguration`. If a package requires assets from multiple `BuildConfigurations` it will require that all `BuildConfigurations` are built first.
#Build Pivots
Below is a list of all the various options we pivot the project builds on:
- **Target Frameworks:** NetFx (aka Desktop), netstandard (aka dotnet/Portable), NETCoreApp (aka .NET Core), UAP (aka UWP/Store/netcore50)
- **Platform Runtimes:** NetFx (aka CLR/Desktop), CoreCLR, CoreRT (aka NetNative/AOT/MRT)
- **OS:** Windows_NT, Linux, OSX, FreeBSD, AnyOS
- **Flavor:** Debug, Release
- **Architecture:** x86, x64, arm, arm64, AnyCPU
##Individual build properties
The following are the properties associated with each build pivot
- `$(TargetGroup) -> netstandard | netcoreapp | netcoreappcorert | netfx | uap | uapaot`
//**CONSIDER**: naming netcoreappcorert something shorter maybe just corert.
- `$(OSGroup) -> Windows | Linux | OSX | FreeBSD | [defaults to running OS when empty]`
- `$(ConfigurationGroup) -> Release | [defaults to Debug when empty]`
- `$(ArchGroup) - x86 | x64 | arm | arm64 | [defaults to x64 when empty]`
- `$(RuntimeOS) - win7 | osx10.10 | ubuntu.14.04 | [any other RID OS+version] | [defaults to runnning OS when empty]` See [RIDs](https://github.com/dotnet/corefx/tree/master/pkg/Microsoft.NETCore.Platforms) for more info.
For more information on various targets see also [.NET Standard](https://github.com/dotnet/standard/blob/master/docs/versions.md)
##Aggregate build properties
Each project will define a set of supported build configurations
```
<PropertyGroup>
<BuildConfigurations>
[BuildConfiguration1];
[BuildConfiguration2];
...
</BuildConfigurations>
<PropertyGroup>
```
- `$(BuildConfiguration) -> $(TargetGroup)[-$(OSGroup)][-$(ConfigurationGroup)][-$(ArchGroup)]`
- Note this property should be file path safe and thus can be used in file names or directories that need to a unique path for a project configuration.
- The only required configuration value is the `$(TargetGroup)` the others are optional.
Example:
Pure netstandard configuration:
```
<PropertyGroup>
<BuildConfigurations>
netstandard;
</BuildConfigurations>
<PropertyGroup>
```
All supported targets with unique windows/unix build for netcoreapp:
```
<PropertyGroup>
<BuildConfigurations>
netcoreapp-Windows_NT;
netcoreapp-Unix;
netfx-Windows_NT;
uap-Windows_NT;
</BuildConfigurations>
<PropertyGroup>
```
##Options for building
A full or individual project build is centered around BuildConfiguration and will be setup in one of the following ways:
1. `$(BuildConfiguration)` can directly be passed to the build.
2. `$(Configuration)` can be passed to the build and `$(BuildConfiguration)` will be set to `$(Configuration)-$(ArchGroup)`. This is a convinence mechanism primarily to help with VS support because VS uses the `Configuration` property for switching between various configurations in the UI. NOTE: this only works well for individual projects and not the root builds.
3. `$(TargetGroup), $(OSGroup), $(ConfigurationGroup), $(ArchGroup)` can individually be passed in to change the default value for just part of the `BuildConfiguration`.
4. If nothing is passed to the build then we will default `BuildConfiguration` from the environment. Example: `netcoreapp-[OSGroup Running On]-Debug-x64`.
On top of the `BuildConfiguration` we also have `RuntimeOS` which can be passed to customize the specific OS and version needed for native package builds as well as package restoration. If not passed it will default based on the OS you are running on.
Any of the mentioned properties can be set via `/p:<Property>=<Value>` at the command line. When building using our run tool or any of the wrapper scripts around it (i.e. build.cmd) a number of these properties have aliases which make them easier to pass (run build.cmd/sh -? for the aliases).
##Selecting the correct build configuration
When building an individual project the `BuildConfiguation` will be used to select the closest matching configuration listed in the projects `BuildConfigurations` property. The rules used to select the configuration will consider compatible target frameworks and OS fallbacks.
TODO: Link to the target framework and OS fallbacks when they are available.
Temporary versions are at https://github.com/dotnet/corefx/blob/dev/eng/src/Tools/GenerateProps/osgroups.props and https://github.com/dotnet/corefx/blob/dev/eng/src/Tools/GenerateProps/targetgroups.props
##Supported full build configurations
- .NET Core latest on current OS (default) -> `netcoreapp-[RunningOS]`
- .NET Core CoreRT -> `netcoreappcorert-[RunningOS]`
- .NET Framework latest -> `netfx-Windows_NT`
- UWP -> `uapaot-Windows_NT`
- UAP F5 -> `uap-Windows_NT`
##Project configurations for VS
For each unique configuration needed for a given library project a configuration property group should be added to the project so it can be selected and built in VS and also clearly identify the various configurations.<BR/>
`<PropertyGroup Condition="'$(Configuration)|$(Platform)' == '$(OSGroup)-$(TargetGroup)-$(ConfigurationGroup)|$(Platform)'">`
- Note that the majority of managed projects, currently all in corefx, $(Platform) is overridden to be AnyCPU.
####*Examples*
Project configurations for a pure IL library project which targets the defaults.
```xml
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'" />
```
Project configurations with a unique implementation on Unix and Windows
```xml
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Unix-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Unix-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Windows_NT-Release|AnyCPU'" />
```
Project configurations that are unique for a few different target frameworks and runtimes
```xml
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap101aot-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap101aot-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap101-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap101-Release|AnyCPU'" />
```
#Library project guidelines
Library projects should use the following directory layout.
```
src\<Library Name>\src - Contains the source code for the library.
src\<Library Name>\ref - Contains any reference assembly projects for the library
src\<Library Name>\pkg - Contains package projects for the library.
src\<Library Name>\tests - Contains the test code for a library
```
##ref
Reference assemblies are required for any library that has more than one implementation or uses a facade. A reference assembly is a surface-area-only assembly that represents the public API of the library. To generate a reference assembly source file you can use the [GenAPI tool](https://www.nuget.org/packages/Microsoft.DotNet.BuildTools.GenAPI). If a library is a pure portable library with a single implementation it need not use a reference assembly at all.
In the ref directory for the library there should be at most **one** `.csproj` that contains the latest API for the reference assembly for the library. That project can contain multiple entries in its `BuildConfigurations` property.
There are two types of reference assembly projects:
1. Libraries that are contain APIs in netstandard
- `BuildConfigurations` should contain non-netstandard configurations for the platforms they support.
- Should use a relative path `<ProjectReference>` to the dependencies it has. Those depedencies should only be libraries with similar build configurations and be part of netstandard.
<BR/>//**CONSIDER**: just using Reference with a custom task to pull from TP or turn to ProjectReference
2. Libraries that are built on top of netstandard
- `BuildConfigurations` should contain only netstandard configurations.
- Should contain `<Reference Include='netstandard'>`
- Anything outside of netstandard should use a relative path `<ProjectReference>` to its dependencies it has. Those depdencies should only be libraries that are built against netstandard as well.
###ref output
The output for the ref project build will be a flat targeting pack folder in the following directory:
`bin\ref\$(TargetGroup)`
<BR/>//**CONSIDER**: Do we need a specific BuildConfiguration version of TargetGroup for this output path to ensure all projects output to same targeting path?
##src
In the src directory for a library there should be only **one** `.csproj` file that contains any information necessary to build the library in various configurations. All supported configurations should be listed in the `BuildConfigurations` property.
All libraries should use `<Reference Include="..." />` for all their project references. That will cause them to be resolved against a targeting pack (i.e. `bin\ref\netcoreapp` or `\bin\ref\netstanard`) based on the project configuration. There should not be any direct project references to other libraries. The only exception to that rule right now is for partial facades which directly reference System.Private.CoreLib and thus need to directly reference other partial facades to avoid type conflicts.
<BR>//**CONSIDER**: just using Reference and use a reference to System.Private.CoreLib as a trigger to turn the other References into a ProjectReference automatically. That will allow us to have consistency where all projects just use Reference.
###src output
The output for the src product build will be a flat runtime folder into the following directory:
`bin\runtime\$(BuildConfiguration)`
Note: The `BuildConfiguration` is the global property and not the project configuration because we need all projects to output to the same runtime directory no matter which compatible configuration we select and build the project with.
##pkg
In the pkg directory for the library there should be only **one** `.pkgproj` for the primary package for the library. If the library has platform-specific implementations those should be split into platform specific projects in a subfolder for each platform. (see [Package projects](./package-projects.md))
TODO: Outline changes needed for pkgprojs
##tests
Similar to the src projects tests projects will define a `BuildConfigurations` property so they can list out the set of build configurations they support.
Tests should not have any `<Reference>` or `<ProjectReference>` items in their project because they will automatically reference everything in the targeting pack based on the configuration they are building in. The only exception to this is a `<ProjectReference>` can be used to reference other test helper libraries or assets.
In order to build and run a test project in a given configuration a root level build.cmd/sh must have been completed for that configuration first. Tests will run on the live built runtime at `bin\runtime\$(BuildConfiguration)`.
TODO: We need update our test host so that it can run from the shared runtime directory as well as resolve assemblies from the test output directory.
###tests output
All test outputs should be under
`bin\tests\$(MSBuildProjectName)\$(BuildConfiguration)` or
`bin\tests\$(MSBuildProjectName)\netstandard`
##Facades
Facade are unique in that they don't have any code and instead are generated by finding a contract reference assembly with the matching identity and generating type forwards for all the types to where they live in the implementation assemblies (aka facade seeds). There are also partial facades which contain some type forwards as well as some code definitions. All the various build configurations should be contained in the one csproj file per library.
TODO: Fill in more information about the required properties for creatng a facade project.
# Conventions for forked code
While our goal is to have the exact code for every configuration there is always reasons why that is not realistic so we need to have a set of conventions for dealing with places where we fork code. In order of preference, here are the strategies we employ:
1. Using different code files with partial classes to implement individual methods different on different configurations
2. Using entirely different code files for cases were the entire class (or perhaps static class) needs to be unique in a given configuration.
3. Using `#ifdef`'s directly in a shared code file.
In general we prefer different code files over `#ifdef`'s because it forces us to better factor the code which leads to easier maintenance over time.
## Code file naming conventions
Each source file should use the following guidelines
- The source code file should contain only one class. The only exception is small supporting structs, enums, nested classes, or delegates that only apply to the class can also be contained in the source file.
- The source code file should be named `<class>.cs` and should be placed in a directory structure that matches its namespace relative to its project directory. Ex. `System\IO\Stream.cs`
- Larger nested classes should be factored out into their own source files using a partial class and the file name should be `<class>.<nested class>.cs`.
- Classes that are forked based on configuration should have file names `<class>.<configuration>.cs`.
- Where `<configuration>` is one of `$(OSGroup)`, `$(TargetGroup)`, `$(ConfigurationGroup)`, or `$(Platform)`, matching exactly by case to ensure consistency.
- Classes that are forked based on a feature set should have file names `<class>.<feature>.cs`.
- Where `<feature>` is the name of something that causes a fork in code that isn't a single configuration. Examples:
- `.CoreCLR.cs` - implementation specific to CoreCLR runtime
- `.CoreRT.cs` - implementation specific to CoreRT runtime
- `.Win32.cs` - implementation based on [Win32](https://en.wikipedia.org/wiki/Windows_API)
- `.WinRT.cs` - implementation based on [WinRT](https://en.wikipedia.org/wiki/Windows_Runtime)
- `.Uap.cs` - implementation specific to UAP, also known as [UWP](https://en.wikipedia.org/wiki/Universal_Windows_Platform)
## Define naming convention
As mentioned in [Conventions for forked code](conventions-for-forked-code) `#ifdef`ing the code is the last resort as it makes code harder to maintain overtime. If we do need to use `#ifdef`'s we should use the following conventions:
- Defines based on conventions should be one of `$(OSGroup)`, `$(TargetGroup)`, `$(ConfigurationGroup)`, or `$(Platform)`, matching exactly by case to ensure consistency.
- Examples: `<DefineConstants>$(DefineConstants),net46</DefineContants>`
- Defines based on convention should match the pattern `FEATURE_<feature name>`. These can unique to a given library project or potentially shared (via name) across multiple projects.