Skip to content

Commit

Permalink
Onboarding new build infrastructure (dotnet#473)
Browse files Browse the repository at this point in the history
This PR onboards a new shared build infrastrucutre - primarily props + targets - that are shared between this repo and WPF's internal build.
  • Loading branch information
vatsan-madhavan authored Mar 28, 2019
1 parent 8eab750 commit 031b79d
Show file tree
Hide file tree
Showing 102 changed files with 9,009 additions and 139 deletions.
162 changes: 162 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
# editorconfig.org

# This file should be kept in sync across https://www.github.com/dotnet/wpf and dotnet-wpf-int repos.

# top-most EditorConfig file
root = true

# Default settings:
# A newline ending every file
# Use 4 spaces as indentation
[*]
insert_final_newline = true
indent_style = space
indent_size = 4

[project.json]
indent_size = 2

# C# files
[*.cs]
# New line preferences
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true

# Indentation preferences
csharp_indent_block_contents = true
csharp_indent_braces = false
csharp_indent_case_contents = true
csharp_indent_switch_labels = true
csharp_indent_labels = one_less_than_current

# avoid this. unless absolutely necessary
dotnet_style_qualification_for_field = false:suggestion
dotnet_style_qualification_for_property = false:suggestion
dotnet_style_qualification_for_method = false:suggestion
dotnet_style_qualification_for_event = false:suggestion

# only use var when it's obvious what the variable type is
csharp_style_var_for_built_in_types = false:none
csharp_style_var_when_type_is_apparent = false:none
csharp_style_var_elsewhere = false:suggestion

# use language keywords instead of BCL types
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
dotnet_style_predefined_type_for_member_access = true:suggestion

# name all constant fields using PascalCase
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style

dotnet_naming_symbols.constant_fields.applicable_kinds = field
dotnet_naming_symbols.constant_fields.required_modifiers = const

dotnet_naming_style.pascal_case_style.capitalization = pascal_case

# static fields should have s_ prefix
dotnet_naming_rule.static_fields_should_have_prefix.severity = suggestion
dotnet_naming_rule.static_fields_should_have_prefix.symbols = static_fields
dotnet_naming_rule.static_fields_should_have_prefix.style = static_prefix_style

dotnet_naming_symbols.static_fields.applicable_kinds = field
dotnet_naming_symbols.static_fields.required_modifiers = static

dotnet_naming_style.static_prefix_style.required_prefix = s_
dotnet_naming_style.static_prefix_style.capitalization = camel_case

# internal and private fields should be _camelCase
dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion
dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields
dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style

dotnet_naming_symbols.private_internal_fields.applicable_kinds = field
dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal

dotnet_naming_style.camel_case_underscore_style.required_prefix = _
dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case

# Code style defaults
dotnet_sort_system_directives_first = true
csharp_preserve_single_line_blocks = true
csharp_preserve_single_line_statements = false

# Expression-level preferences
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_null_propagation = true:suggestion

# Expression-bodied members
csharp_style_expression_bodied_methods = false:none
csharp_style_expression_bodied_constructors = false:none
csharp_style_expression_bodied_operators = false:none
csharp_style_expression_bodied_properties = true:none
csharp_style_expression_bodied_indexers = true:none
csharp_style_expression_bodied_accessors = true:none

# Pattern matching
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion

# Null checking preferences
csharp_style_throw_expression = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion

# Space preferences
csharp_space_after_cast = false
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_after_comma = true
csharp_space_after_dot = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_after_semicolon_in_for_statement = true
csharp_space_around_binary_operators = before_and_after
csharp_space_around_declaration_statements = do_not_ignore
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_before_comma = false
csharp_space_before_dot = false
csharp_space_before_open_square_brackets = false
csharp_space_before_semicolon_in_for_statement = false
csharp_space_between_empty_square_brackets = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_declaration_name_and_open_parenthesis = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_between_square_brackets = false

# C++ Files
[*.{cpp,h,in}]
curly_bracket_next_line = true
indent_brace_style = Allman

# Xml project files
[*.{csproj,vcxproj,vcxproj.filters,proj,nativeproj,locproj}]
indent_size = 2

# Xml build files
[*.builds]
indent_size = 2

# Xml files
[*.{xml,stylecop,resx,ruleset}]
indent_size = 2

# Xml config files
[*.{props,targets,config,nuspec}]
indent_size = 2

# Shell scripts
[*.sh]
end_of_line = lf
[*.{cmd, bat}]
end_of_line = crlf
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ bld/

# Visual Studio 2015/2017 cache/options directory
.vs/
.vscode/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/

Expand Down
30 changes: 20 additions & 10 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<Import Project="Sdk.props" Sdk="Microsoft.DotNet.Arcade.Sdk" />
<Import Project="SystemResources.props"/>
<!-- Normalize $(TestWpfArcadeSdkPath) by appending a '\' to it if one is missing -->
<PropertyGroup Condition="'$(TestWpfArcadeSdkPath)'!=''">
<WpfArcadeSdkPath>$(TestWpfArcadeSdkPath)</WpfArcadeSdkPath>
<WpfArcadeSdkPath Condition="!$(WpfArcadeSdkPath.EndsWith('\'))">$(TestWpfArcadeSdkPath)\</WpfArcadeSdkPath>
</PropertyGroup>

<PropertyGroup Condition="'$(CopyrightNetFoundation)' != ''">
<Copyright>$(CopyrightNetFoundation)</Copyright>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PropertyGroup Condition="'$(TestWpfArcadeSdkPath)'=='' And Exists('$(MSBuildThisFileDirectory)eng\WpfArcadeSdk\')">
<WpfArcadeSdkPath>$(MSBuildThisFileDirectory)eng\WpfArcadeSdk\</WpfArcadeSdkPath>
</PropertyGroup>

<PropertyGroup>
<PublishWindowsPdb>true</PublishWindowsPdb>
<DebugType>full</DebugType>
<!-- Select Sdk.props from test location or eng\WpfArcadeSdk\. If neither exists, then fall back to the use of one
obtained using MSBuild's Sdk resolver -->
<PropertyGroup Condition="Exists('$(WpfArcadeSdkPath)')">
<WpfArcadeSdkProps>$(WpfArcadeSdkPath)Sdk\Sdk.props</WpfArcadeSdkProps>
<WpfArcadeSdkTargets>$(WpfArcadeSdkPath)Sdk\Sdk.targets</WpfArcadeSdkTargets>
</PropertyGroup>


<Import Project="$(WpfArcadeSdkProps)"
Condition="Exists('$(WpfArcadeSdkProps)') And Exists('$(WpfArcadeSdkTargets)')"/>

<Import Sdk="Microsoft.DotNet.Arcade.Wpf.Sdk"
Project="Sdk.props"
Condition="!Exists('$(WpfArcadeSdkProps)') Or !Exists('$(WpfArcadeSdkTargets)')"/>
</Project>
11 changes: 7 additions & 4 deletions Directory.Build.targets
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<Import Project="Sdk.targets" Sdk="Microsoft.DotNet.Arcade.Sdk" />
<Import Project="$(MSBuildThisFileDirectory)Packaging.targets" />
<Import Project="$(MSBuildThisFileDirectory)Publishing.targets" />

<Import Project="$(WpfArcadeSdkTargets)"
Condition="Exists('$(WpfArcadeSdkProps)') And Exists('$(WpfArcadeSdkTargets)')"/>

<Import Sdk="Microsoft.DotNet.Arcade.Wpf.Sdk"
Project="Sdk.targets"
Condition="!Exists('$(WpfArcadeSdkProps)') Or !Exists('$(WpfArcadeSdkTargets)')"/>
</Project>
Binary file added Documentation/images/configurations.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
71 changes: 71 additions & 0 deletions Documentation/packaging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Packaging

Packaging is implemented in the following files:

```
$(WpfArcadeSdkToolsDir)\Packaging.props
$(WpfArcadeSdkToolsDir)\Packaging.targets
$(RepoRoot)\packaging\**\*
├───Microsoft.DotNet.Arcade.Wpf.Sdk
│ Microsoft.DotNet.Arcade.Wpf.Sdk.ArchNeutral.csproj
├───Microsoft.DotNet.Wpf.DncEng
│ Microsoft.DotNet.Wpf.DncEng.ArchNeutral.csproj
│ Microsoft.DotNet.Wpf.DncEng.csproj
└───Microsoft.DotNet.Wpf.GitHub
Microsoft.DotNet.Wpf.GitHub.ArchNeutral.csproj
Microsoft.DotNet.Wpf.GitHub.csproj
```

- The `ArchNeutral` packages are built only during the `x86` (i.e., `AnyCPU`) build phase
- Normally, the `ArchNeutral` packages will contain a `runtime.json` file that incorporates the *Bait & Switch* technique for referencing RID-specific packages automatically.
- `runtime.json` functionality is turned off when a packaging project requests so by setting `$(PlatformIndependentPackage)=true`.
- See [Improve documentation - bait and switch pattern, other #1282 ](https://github.com/NuGet/docs.microsoft.com-nuget/issues/1282)


- The packages that are not `ArchNeutral` are architecture-specific, and will produce packages containing the RID (`win-x86`, `win-x64`) as a prefix
- The arch-specific packages are produced in each of the build phases.

#### Package Names

There are two packages produced out of this repo, a *transport* package and an *MsBuild Sdk* package:

- `Microsoft.DotNet.Wpf.Github`
- This contains assemblies and corresponding reference binaries that are currently built out of this repo ([https://www.github.com/dotnet/wpf](https://www.github.com/dotnet/wpf)).
- `Microsoft.DotNet.Arcade.Wpf.Sdk`
- This is an *MsBuild Sdk*, and is and extension to [Microsoft.DotNet.Arcade.Sdk](https://www.github.com/dotnet/arcade).
- This Sdk contains all the build props, targets and scripts needed to build WPF.
- Since WPF's build is split across two repos, we build this Sdk out of one repo, and consume it as an *MsBuild Sdk* in the other repo.

#### Opting into a package

- An assembly opts-into a package in `$(WpfArcadeSdkToolsDir)\Packaging.props` by simply setting the `PackageName` property, for e.g., like this:

`<PackageName Condition="'$(MSBuildProjectName)'=='WpfGfx'">$(DncEngTransportPackageName)</PackageName>`

In practice, this is not needed. *Shipping* assemblies are already enumerated in detail within `$(WpfArcadeSdkToolsDir)ShippingProjects.props`, and each one of them is marked for packaging correctly within `Packaging.props` based on its `$(RepoLocation)` value (possible values are `{Internal, External}`)

- These package names that various assembly projects can opt to be packaged into are defined in `$(WpfArcadeSdkToolsDir)\Packaging.props`. The project names under `$(RepoRoot)\packaging\` must match these.

#### How Packaging Works

##### Preparing Package Assets (*`PreparePackageAssets`* target)

- *`PreparePackageAssets`* target is defined in `$(WpfArcadeSdkToolsDir)Packaging.targets`
- It runs after *`Build`*, and copies all project outputs, symbols, reference assemblies, satellite assemblies, and content files (defined in *`@(PackageContent)`* `ItemGroup`) to `$(ArtifactsPackagingDir)$(PackageName)\lib\$(TargetFrameworkOrRuntimeIdentifier)\`
- If `@(PackagingAssemblyContent)` is populated, then only those files from `$(OutDir)` would be copied and packaged further - and none others would be included.
- At the end of this target, all files that need to be packed would have been laid out in the right folder hierarchy, and ready to be packed.

##### Populate the `@(Content)` itemgroup with custom lsit of package-assets (*`CreateContentFolder`* target)

- *`CreateContentFolder`* is defined in `$(WpfArcadeSdkToolsDir)Packaging.targets`
- It runs just before *`GenerateNuspec`* target, and populates `@(Content)` with files that were copied during *`PreparePackageAssets`*
- This is consume by NuGet `PackTask` to create the package.

##### Create a Nuget Package

- The projects under `$(RepoRoot)\packaging` are the only ones with `$(IsPackable)=true`
- The layout of the generated package is identical to the layout under `$(ArtifactsPackagindir)$(PackageName)\`
53 changes: 53 additions & 0 deletions Documentation/solution-and-project-configurations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Solution and Project Configuration

Solutions configurations are mapped to Project configurations in the following manner.

<font face="consolas">
<table>
<tr>
<th>Solution</th>
<th>Managed Projects</th>
<th>Native Projects</th>
</tr>
<tr>
<td>Debug|AnyCPU</td>
<td>Debug|AnyCPU</td>
<td>Debug|<font color="red">Win32</font></td>
</tr>
<tr>
<td>Debug|x86</td>
<td>Debug|<font color="red">AnyCPU</font></td>
<td>Debug|<font color="blue">Win32</font></td>
</tr>
<tr>
<td>Debug|x64</td>
<td>Debug|x64</td>
<td>Debug|x64</td>
</tr>
<tr>
<td>Release|AnyCPU</td>
<td>Release|AnyCPU</td>
<td>Release|<font color="red">Win32</font></td>
</tr>
<tr>
<td>Release|x86</td>
<td>Release|<font color="red">AnyCPU</red></td>
<td>Release|<font color="blue">Win32</font></td>
</tr>
<tr>
<td>Release|x64</td>
<td>Release|x64</td>
<td>Release|x64</td>
</tr>
</table>
</font>


- `AnyCPU` **solution** configuration is intended for developer-builds only.
- Official build would *always* specify `x86` or `x64` solution configurations explicitly.
- Native projects should map `AnyCPU` solution-configuration to `x86` project configuration
- Managed projects should map `x86` solution-configuration to `AnyCPU` project configuration
- Use Solution->Properties->Configuration view to ensure that the mapping between solution-configuration and project configuration is consistent for every possible configuration.
- Note that packaging projects under `nupkg` folder have only one (`AnyCPU`) configuration

![](images/configurations.png)
Loading

0 comments on commit 031b79d

Please sign in to comment.