-
Notifications
You must be signed in to change notification settings - Fork 808
Packaging
This document discusses the way WinObjC is packaged and released to customers along with tips for contributors building and consuming their own packages.
WinObjC is shipping its code and build integration via NuGet. NuGet packages are .zip files that carry semantic versioning information and conventions for discovery and installation. More information about what a package is and the details of creating and consuming a NuGet package can be found here.
NuGet operates on the notion of feeds of packages where a package producer (the WinObjC team) uploads and hosts its packages. For WinObjC, we are choosing to host our packages on nuget.org, the default package feed location. Both Visual Studio's package manager and the NuGet commandline client (which can be downloaded here) have this feed enabled by default. To install a WinObjC package, a developer simply needs to declare a dependency (via either project.json or PackageReference) to one of our packages (see below), and run nuget restore
from the commandline or simply build the solution in Visual Studio. Updating is as simple as declaring a different version dependency. See the NuGet documentation for an in depth overview.
Command line tools / entry point into WinObjC. Includes vsimporter and Visual Studio Extensions
Objective-C language support. Includes the compiler (clang) and the runtime (libobjc2)
Common logging package shared between Language and Frameworks
Core Objective-C Frameworks (Foundation and things with Core in the name). Factored out to share between Frameworks UWP and Frameworks
Universal Windows Platform Frameworks like Cortana
All of the remaining Objective-C default Frameworks
Third Party Dependencies that WinObjC relies on
Meta package that aids in creation of other packages. Especially useful for Middleware.
WinObjC uses GitVersion with a few customizations (great documentation on all these options is found here) to automatically determine package versions based on the git repository tags and branching structure. The WinObjC release process follows a very similar workflow to GitFlow and thus the ground truth for our releases comes from the master branch tags. These tags are created during the release process to snapshot the state of the repository at that time. Our nightly builds and local development then start the cycle for the next release and thus get an incremented patch number along with a prerelease string indicating when they were created.
WinObjC.Frameworks.0.2.170229-pr-20170318003711
\----------------/\---------/\----------------/
| | |
(1) (2) (3)
- Package Name
- Latest Git Tag + 1 - Master builds don't get the + 1
- Pre-release string with timestamp - Master builds aren't pre-release
Add WinObjC.Frameworks and WinObjC.Language to your project. These are the "leaf nodes" and will cause most of the other packages to be included through their dependency chain.
If you are packaging your own code into a NuGet (for middleware as an example), please add WinObjC.Packaging to simplify the process.
If you are using a prebuilt SDK, download Visual Studio 2017, and re import your app using the latest winobjc-tools command line package (Instructions on README).
If you are building the SDK locally, please install Visual Studio 2017, the Nugetizer VSIX (either from the winobjc-tools package or directly as described below), and make sure any local/internal NuGet feeds are configured to pick up latest beta packages if desired. Please see the below for how to consume a new locally built SDK.
Simply build build.sln or tools.sln to produce the packages. WinObjC is leveraging Nugetizer in order to integrate package creation into the build. These are the .nuproj
projects that are now in the solution. This project works by leveraging MSBuild to walk project references, infer project output and ultimately create the packaged content.
Project output is automatically inferred from all projects that the .nuproj references. As long as the project mimics the other projects in the WinObjC repo, it should automatically add its contents to the package. If a project has "Extra" content that it needs to stick in the package, a custom MSBuild target that runs before GetPackageContents that adds PackageFile items can be used. See CoreFoundation.vcxproj's AddExtraPackageItems target as an example.
NuGet allows using a local directory as a package feed when restoring packages. In order to make this as seamless as possible, the output directories for WinObjC packages have been added to the nuget.config files where feasible (in the samples directory for instance). In cross repository scenarios, please set WINOBJC_SDK_ROOT
to your cloned directory and configure the nuget.config to use that.
In addition to finding packages, consuming a just produced package locally means updating the consumer to automatically pick up the new version. Luckily by adding winobjc.packagereference.override.targets
as an import to your project (an example can be found at bottom of WOCCatalog.vcxproj) the version that the consumer depends on can be swapped out on the fly. Again for cross repo scenarios, it advisable to set WINOBJC_SDK_ROOT
.
NOTE: Local packages are always preferred when using the override targets so make sure to not forget about locally produced packages on the machine that may be influencing builds.
When discussing how to find and use local packages it very useful to separate the package producer persona from that of the consumer. In the below example I will discuss a hypothetical scenario in which Alice and Bob work on an app together that uses WinObjC and, as advanced users, they wish to make local changes to WinObjC and share those changes with each other.
-
Alice clones WinObjC and makes changes to fix a small bug in UIKit. She sets an environment variable called WINOBJC_SDK_ROOT to where she cloned the repo so that her awesome app can easily point back to it.
-
Alice builds build.sln and sees new output packages at:
\build\OutputPackages\Debug
and
\build\OutputPackages\Release
(If Alice builds a change for the language or logging packages, these packages will be in \tools\OutputPackages\Release
and \tools\OutputPackages\Debug
)
- To try out her changes locally, Alice adds the following lines to the
nuget.config
next to her awesome app's visual studio solution (if she does not have she should consider adding one to control how nuget is configured for that solution):
<packageSources>
<add key="Local WinObjC Tools Packages" value="%WINOBJC_SDK_ROOT%\tools\OutputPackages\Release\" />
<add key="Local WinObjC Tools Packages - DEBUG" value="%WINOBJC_SDK_ROOT%\tools\OutputPackages\Debug\" />
<add key="Local WinObjC Frameworks Packages" value="%WINOBJC_SDK_ROOT%\build\OutputPackages\Release\" />
<add key="Local WinObjC Frameworks Packages - DEBUG" value="%WINOBJC_SDK_ROOT%\build\OutputPackages\Debug\" />
</packageSources>
The full nuget.config
would look like:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="Local WinObjC Tools Packages" value="%WINOBJC_SDK_ROOT%\tools\OutputPackages\Release\" />
<add key="Local WinObjC Tools Packages - DEBUG" value="%WINOBJC_SDK_ROOT%\tools\OutputPackages\Debug\" />
<add key="Local WinObjC Frameworks Packages" value="%WINOBJC_SDK_ROOT%\build\OutputPackages\Release\" />
<add key="Local WinObjC Frameworks Packages - DEBUG" value="%WINOBJC_SDK_ROOT%\build\OutputPackages\Debug\" />
</packageSources>
<activePackageSource>
<add key="All" value="(Aggregate source)" />
</activePackageSource>
<disabledPackageSources />
</configuration>
This way her app can locate the local packages based on the WINOBJC_SDK_ROOT variable. See here for more info on nuget.config
- Now that her app can find the locally built packages, Alice needs to update the awesome app to look for the new version of the packages. If she is using project.json, she changes the version of her dependencies to match what was just built. For instance she might change:
. . .
"dependencies": {
"WinObjC.Frameowrks": "*"
},
. . .
to be:
. . .
"dependencies": {
"WinObjC.Frameowrks": "0.2.170229-dev-20170318003711"
},
. . .
(the actual version should match what is in Alice's OutputPackages folder). A more in depth discussion of NuGet Version specifiers is here
If she is using <PackageReference>
she can instead choose to add the following to her app's .vcxproj:
<Import Project="$(WINOBJC_SDK_ROOT)\common\winobjc.packagereference.override.targets" Condition="Exists('$(WINOBJC_SDK_ROOT)\common\winobjc.packagereference.override.targets')"/>
This allows her project to dynamically pick up the just built versions from the output directory to make it a little easier to consume new packages.
-
Bob has not cloned WinObjC but wants to try out Alice's awesome changes.
-
Alice puts her packages on a file share, internal NuGet feed, or otherwise shares them with Bob.
-
Bob updates his nuget.config and project.json to look at these packages and tries out the changes.
-
When Alice and Bob are happy with the changes they submit a pull request so that the change can make its way to the packages on the official nuget feed.
NOTE: The above steps are already done for the sample apps in the WinObjC repo and the hope is that most consumers will be able to just use the official package feed without producing new packages themselves.
The short answer is that you don't. Packages are only built locally to allow a contributor or advanced developer to test out changes. Official packages hosted on nuget.org are built by our build machines and must go through release validation. If you require changes to a package in order to successfully use it, please submit a pull request so that other WinObjC consumers can benefit as well.
The Any CPU
build platform is used to indicate that both ARM and x86 builds should occur. This allows a single build to produce a full package (which is what our build machine uses). To speed up local development, build x86 or ARM will build a package that only works for that single platform.
NOTE: If you switch platforms, make sure to build a new package for that platform for any local packages previously made.
Packages are installed to the nuget cache. This is typically located at C:\Users\your_username\.nuget
The Visual Studio Package Manager has a Clear Cache button that can be used if you need to free up space.
2160 Clang Windows pop up all over the place.
Cause not known but closing and opening visual studio / restarting the machine seems to make it go away. Several devs hit this briefly but then did not encounter it again.
4307 Visual Studio Nuget Restore fails with
Error occurred while restoring NuGet packages: The operation failed as details for project SomeProjectName could not be loaded
Try turning on Lightweight Solution Load (it'll make loading our large build.sln solution faster anyway). This is an untested suggestion from the NuGet folks so your mileage may vary.
4633 Despite needing to restore, Visual Studio NuGet Restore shows:
Output window for Package Manager:
All packages are already installed and there is nothing to restore.
Time Elapsed: 00:00:00.5279550
========== Finished ==========
Try restoring from the commandline. Run init.ps1
from the repo root to get a copy of nuget in your .tools directory and then restore with:
.tools\nuget.exe restore .\build\build.sln
[N/A] Builds fail with Accelerate.lib is missing, can't find ErrorHandling.h or other errors that seem like packages are missing.
Make sure that packages are restored (Run .tools\nuget.exe restore .\build\build.sln
from the command line). Visual Studio 2017 has an issue where it sometimes claims projects are up to date even if they are not. see 4633 below for more information.
Make sure that you have winobjc-tools installed (see instructions on main README) or manually install the NuGetizer VSIX.
Make sure that you have selected MSBuild as an install step in VS 2017. The new PackageReference style of dependencies only work in MSBuild version 15 or greater. The first line of nuget restore will tell you which version of MSBuild is being used.
Several of our devs accidentally had MSBuild 14.0 in their PATH variable that was overriding the one nuget used.
Note that you can override the msbuild version used with:
-msbuildversion 15
[N/A] After pulling latest develop (with packaging) I can't seem to debug anymore. Where did my symbols go?
The symbols for each release should still be indexed nightly. Please file issues for anything the symbol server isn't finding for you.
Local symbol files have moved according to where they are packaged and can be found in either the build\
or tools\
sub directories in similar spots to where they were before (\deps\prebuilt\Universal Windows
for prebuilt binaries and Win32\Release\Universal Windows
for built frameworks). Please adjust your symbol search paths accordingly.
Make sure that you correctly have the version you want to use specified in your project.json, as a PackageReference, or in your packages.config. If you are building a sample app or the SDK itself, make sure you don't have an old locally built package preventing you from using the version from the feed.
Re-run package restore and you should have the desired package now installed.
2237 Build break when building "Any CPU" configuration
You can build individual CPUs instead. (x86 or ARM).
Project
Using the bridge
- Getting Started
- Using vsimporter
- Using the SDK
- Building From Source
- Adding Objective C to an Existing Project
- UI Guidance
- Changing the SDK Version of a Project
- Debugging
- Debugging Stack Traces from Crash Dumps
- Supported Third Party Libraries
- Creating and Linking Against C++ Static Libraries
- Packaging
Samples and Tutorials
- Quick Start Tutorial
- Building a To-Do List App
- Building a Calculator App
- Mixing and Matching UIKit and XAML
- IOS Bridge Samples Repo
Contributing
Links