Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UAP - platform specific binaries not picked up from runtimes #1221

Closed
furmek opened this issue Aug 20, 2015 · 13 comments
Closed

UAP - platform specific binaries not picked up from runtimes #1221

furmek opened this issue Aug 20, 2015 · 13 comments
Milestone

Comments

@furmek
Copy link

furmek commented Aug 20, 2015

My NuGet package contains .dll files that are build for specific platforms (arm, x86 and x64).
The project.lock.json file seems to be updating just fine but the project will build only in x86.
When trying to build in x64 or arm the runtimes/win10-[platform] is ignored - VS will complain about lib arhitecture:

There was a mismatch between the processor architecture of the project being 
built "AMD64" and the processor architecture of the reference 
"C:\Users\Daniel\.nuget\packages\MySDK\2.1.0\runtimes\win10-x86\lib\uap10.0\MySDK.dll", "x86". 

The nupkg structure goes like this:

"MySDK/2.1.0": {
      "type": "Package",
      "files": [
        ...
        "runtimes/win10-arm/lib/uap10.0/MySDK.dll",
        "runtimes/win10-x64/lib/uap10.0/MySDK.dll",
        "runtimes/win10-x86/lib/uap10.0/MySDK.dll",
        ...
      ]
    }

After installing my project.lock.json gets updated with following data:

"targets": {
    "UAP,Version=v10.0": {
      "MySDK/2.1.0": {
        "compile": {
          "runtimes/win10-x86/lib/uap10.0/MySDK.dll": {},
        },
        "runtime": {
          "runtimes/win10-x86/lib/uap10.0/MySDK.dll": {},
        }
      }
    },
    "UAP,Version=v10.0/win10-arm": {
      "MySDK/2.1.0": {
        "compile": {
          "runtimes/win10-arm/lib/uap10.0/MySDK.dll": {},
        },
        "runtime": {
          "runtimes/win10-arm/lib/uap10.0/MySDK.dll": {},
        }
      }
    },
    "UAP,Version=v10.0/win10-x64": {
      "MySDK/2.1.0": {
        "compile": {
          "runtimes/win10-x64/lib/uap10.0/MySDK.dll": {},
        },
        "runtime": {
          "runtimes/win10-x64/lib/uap10.0/MySDK.dll": {},
        }
     ....

I have tried to remove compile and runtime from "UAP,Version=v10.0" but after doing so, VS no longer can see namespaces in those libraries.

MySDK does not have AnyCPU version and it is compiled specifically for UWP (former UAP).
Am I doing something wrong or is this a bug ?

@yishaigalatzer
Copy link

You need a ref library or anycpu (in your case you don't). I would probably use ref in your case with the x86 dll

@furmek
Copy link
Author

furmek commented Aug 24, 2015

I've tried adding x86 dll in a following ways:

  1. lib\MySDK.dll
  2. lib\uap10.0\MySDK.dll
  3. ref\MySDK.dll
  4. ref\uap10.0\MySDK.dll
  5. runtimes\win10-anycpu\lib\uap10.0\MySDK.dll

None of them worked for me.
Interestingly enough, when I add anycpu (line 5) and build project that consumes MySDK with x64 selected as a target platform, VS output suggests that anycpu folder was used during the build.

Would you mind posting an example showing me how should I add my x86 as a ref.

@ericstj
Copy link

ericstj commented Aug 24, 2015

There isn't any point in having a lib folder if you also have a win10-anycpu/lib folder. If that is all you need just put it in lib.

If you need architecture specific implementation you can put that in a runtimes/win10-x86/lib/uap10.0 folder.

So here are the two scenarios.

  1. Any CPU dll:
lib/uap10.0/MySDK.dll
  1. Architecture specific dll, requires a reference assembly since the "runtime" section is not used during compile.
ref/uap10.0/MySDK.dll
runtimes/win10-x86/lib/uap10.0/MySDK.dll
runtimes/win10-x64/lib/uap10.0/MySDK.dll
runtimes/win10-arm/lib/uap10.0/MySDK.dll

@furmek
Copy link
Author

furmek commented Aug 24, 2015

My dll will not compile as a anycpu so the scenario 1 won't work.

As for scenario 2:
that reference assembly will be used in build process so its architecture must match architecture that the project is currently being build for (eg.: x64)?
If so, do I have to provide a 'mock' assembly that can be used to build for all supported by me platforms: x86, x64 and ARM, or is there a way similar to what I used in NuGet 2.x - MySDK.targets file.

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="InjectReference" BeforeTargets="ResolveAssemblyReferences">
    <ItemGroup Condition=" '$(Platform)' == 'x86' or '$(Platform)' == 'x64' or '$(Platform)' == 'ARM'">
      <Reference Include="MySDK">
        <HintPath>$(MSBuildThisFileDirectory)$(Platform)\MySDK.dll</HintPath>
      </Reference>
    </ItemGroup>
  </Target>
</Project>

I have tried adding x86 as a ref/uap10.0/MySDK.dll but this enables me only to build for x86. When I build for x64 or ARM I get error about architecture mismatch - mentioned in first post.

@ericstj
Copy link

ericstj commented Aug 24, 2015

that reference assembly will be used in build process so its architecture must match architecture that the project is currently being build for (eg.: x64 )?

The architecture is ignored by the compiler when creating an assembly reference. It's a load time concept. The loader will prefer an architecture specific reference if it exists.

One trick you can use to produce an AnyCPU assembly is to use corflags to remove the architecture from your x86 assembly. EG: corflags /32BITREQ- MySDK.dll. Corflags is part of the .NET SDK and can be found in VS's developer command prompt.

We produce stripped down reference assemblies for all of the .NET framework assemblies. You can see some examples of those in one my recent changes in corefx: dotnet/corefx@40723b7.

We have numerous internal tools that can produce reference assemblies from implementation. @weshaggard @nguerrera do we have any public tools for creating reference assemblies or reference assembly source?

@yishaigalatzer
Copy link

I'm moving this issue to the discussions milestone, as there is no bug fix to be done here.

@ericstj it would be nice to show this as one of our samples.

@yishaigalatzer yishaigalatzer added this to the Discussions milestone Aug 25, 2015
@ericstj
Copy link

ericstj commented Aug 25, 2015

@furmek the roslyn team is planning on adding support for reference assembly generation to the compiler. dotnet/roslyn#2184

@furmek
Copy link
Author

furmek commented Aug 27, 2015

@ericstj thank you, the corflags did help me.

I think at this point I'll describe my final solution so it can help someone else.

First, description of MySDK:
I have two projects,
one MySDKNative is written in c++/cx and can't be compiled as a AnyCPU,
the other project (MySDKManaged) is written in C# and provides just couple of controls that couldn't be put in c++/cx projects (reason: all public ref classes must be sealed). It consumes MySDKNative so it also can't be compiled as AnyCPU.

After building my solution I'm left with few files:
for MySDKNative I get: MySDKNative.dll (three versions: x86, x64 and ARM) and MySDKNative.winmd (seems to be the same for all platforms)
MySDKManaged produces MySDKManaged.dll (three versions: x86, x64 and ARM)

NuGet package creation:
I start with running corflags /32BITREQ- MySDKManaged.dll on copy of x86 version.

next I pack my NuGet using following nuspec

<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
    <metadata>
        <id>MySDK.UWP</id>
       ...
    </metadata>
    <files>
        <file src="MySDKManaged.dll" target="lib\uap10.0\MySDKManaged.dll" /><!-- this one is changed by corflags command -->
        <file src="..\SDK\bin\Debug\Win32\SDK.UAP\MySDKNative.winmd" target="lib\uap10.0\MySDKNative.winmd" />

        <!-- x86 -->        
        <file src="..\SDK.UAP\bin\x86\Debug\MySDKManaged.dll" target="runtimes\win10-x86\lib\uap10.0\MySDKManaged.UAP.dll" />  
        <file src="..\SDK\bin\Debug\Win32\SDK\MySDKNative.winmd" target="runtimes\win10-x86\lib\uap10.0\MySDKNative.winmd" />
        <file src="..\SDK\bin\Debug\Win32\SDK\MySDKNative.dll" target="runtimes\win10-x86\native\MySDKNative.dll" />
        <file src="..\SDK\bin\Debug\Win32\SDK\MySDKNative.pri" target="runtimes\win10-x86\native\MySDKNative.pri" />

        <!-- x64 -->        
        <file src="..\SDK.UAP\bin\x64\Debug\MySDKManaged.dll" target="runtimes\win10-x64\lib\uap10.0\MySDKManaged.UAP.dll" />  
        <file src="..\SDK\bin\Debug\x64\SDK\MySDKNative.winmd" target="runtimes\win10-x64\lib\uap10.0\MySDKNative.winmd" />
        <file src="..\SDK\bin\Debug\x64\SDK\MySDKNative.dll" target="runtimes\win10-x64\native\MySDKNative.dll" />
        <file src="..\SDK\bin\Debug\x64\SDK\MySDKNative.pri" target="runtimes\win10-x64\native\MySDKNative.pri" />

        <!-- ARM -->        
        <file src="..\SDK.UAP\bin\ARM\Debug\MySDKManaged.dll" target="runtimes\win10-arm\lib\uap10.0\MySDKManaged.UAP.dll" />  
        <file src="..\SDK\bin\Debug\arm\SDK\MySDKNative.winmd" target="runtimes\win10-arm\lib\uap10.0\MySDKNative.winmd" />
        <file src="..\SDK\bin\Debug\arm\SDK\MySDKNative.dll" target="runtimes\win10-arm\native\MySDKNative.dll" />
        <file src="..\SDK\bin\Debug\arm\SDK\MySDKNative.pri" target="runtimes\win10-arm\native\MySDKNative.pri" />
    </files>
</package>

Package created like this can be added to UWP c# project and compiled for x86, x64 or ARM. I don't think it is possible to compile dor AnyCPU.

@furmek furmek closed this as completed Aug 27, 2015
@ericstj
Copy link

ericstj commented Aug 27, 2015

@furmek folks can compile UAP class libraries or windows runtime components for AnyCPU. Your solution will still work fine for those projects since they don't require implementation assets as they are not directly runnable. If someone were to build such a component, consuming your package, they could do so, then when they referenced that component from an application it would deploy the write bit-specific implementation for the app.

One thing I notice about your package that you may or may not care about is consumption in C++ and JavaScript applications. I hadn't brought this up previously since we'd just been talking about dlls and not winmd. Since C++ and JS don't support project.json yet nuget won't use your runtime specific assets. Additionally JS will complain about the DLL being referenced.

For the first problem I've been recommending that folks write targets files to address the issue. For the later the only solution I've come up with is to split the packages. It seems to be a shortcoming in the JS project system / inflexibility of nuget to provide language specific references.

I'm actually working on some docs around these scenarios here: https://github.com/ericstj/nugetdocs/tree/ericstj/nuget3samples. Let's move the discussion over here. I hope to have a PR for nuget shortly.

@billyzkid
Copy link

It doesn't seem possible at the moment to create a single nuget package that works across all UAP application languages (C#, VB, C++, JS) containing a WinRT component with x86, x64, and ARM binaries.

The problem is caused by C# and VB using project.json while C++ and JS use packages.config. There seems to be no way (in a single package) to add build file(s) targeting the C++ and JS specifically (in order to add the necessary platform references). I've tried adding a "native" build file which works for C++, but there's no equivalent for JS. I've tried adding a uap10.0 build file with conditions for JS, but these seem to be ignored.

Am I missing something?

@ericstj
Copy link

ericstj commented Aug 15, 2016

I believe you can create targets/props in the root build folder and then just condition the content of them to only apply for UWP apps.

@clairernovotny
Copy link

For anyone looking at this old thread, I've just added support for creating these kinds of advanced packages in my MSBuild.Sdk.Extras package:

https://github.com/onovotny/MSBuildSdkExtras#per-runtimeidentifier

@alex4998
Copy link

Can anybody explain this to me "Architecture specific dll, requires a reference assembly since the "runtime" section is not used during compile."? I noticed that if I put assemblies only into runtimes section I cannot consume the package and build. What those assemblies are used for in this case? I expect when I reference a NuGet package with platform specific assemblies, those assemblies are used in compilation and in the result I would have a project built for particular platform. If they are not used this way how it would work? Will it use one set of assemblies for build and another for runtime? How it will use another set for runtime? Where it will take them from? I'm totally lost.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants