Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Share static lib in Win8 and WP8 apps

I have a static library written in C++ that I want to make available to Windows 8 and Windows Phone 8 applications written in .NET.

I'd like to minimize the number of separate projects to maintain by setting up my solution something like the following:

Attempt #1: Only UI projects are platform-specific

MySolution.sln
|
+- Library                    (virtual folder to group projects below)
|  |
|  +- LegacyLib.vcxproj       Static Library project - Platform-independant, native C++ code using STL & CRT. Just enough C++/CX to make some types available to .NET and expose a few static methods.
|  |
|  +- LegacyPcl.csproj        Portable Class Library project - References LegacyLib, adds some types, wrappers, interfaces, etc. written in C#.
|
+- SampleApp                  (virtual folder to group projects below)
   |
   +- CommonAppSrc            Platform-independant C# source code (e.g. MVVM classes for Model and ViewModel).
   |
   +- SampleApp_Win8.csproj   Platform-specific App project - References LegacyPcl, includes files from CommonAppSrc using "Add as Link".
   |
   +- SampleApp_Wp8.csproj    Platform-specific App project - References LegacyPcl, includes files from CommonAppSrc using "Add as Link".

Problem: It seems that Portable Class Libraries don't support the inclusion of native C++ code in any form.

One suggested way of including native C++ in your Windows 8 and Windows Phone 8 apps is by creating a Windows Runtime Component. Unfortunately, WRC projects targeting Win8 and Wp8 are different project types; there is no option to create a Windows Runtime Component that targets multiple platforms.

So, creating a Windows Runtime Component project for each target platform yields the following:

Attempt #2 - UI projects are platform-specific, and so is LegacyLib wrapper

MySolution.sln
|
+- Library                    (virtual folder to group projects below)
|  |
|  +- LegacyLib.vcxproj       Static Library project - Platform-independant, native C++ code using STL & CRT. Just enough C++/CX to make some types available to .NET and expose a few static methods.
|  |
|  +- LegacyWrc_Win8.csproj   Platform-specific Windows Runtime Component project - References LegacyLib, adds some types, wrappers, interfaces, etc. written in C#.
|  |
|  +- LegacyWrc_Wp8.csproj    Platform-specific Windows Runtime Component project - References LegacyLib, adds some types, wrappers, interfaces, etc. written in C#.
|
+- SampleApp                  (virtual folder to group projects below)
   |
   +- CommonAppSrc            C# source code (e.g. Model and ViewModel classes).
   |
   +- SampleApp_Win8.csproj   Platform-specific App project - References LegacyWrc_Win8, includes files from CommonAppSrc using "Add as Link".
   |
   +- SampleApp_Wp8.csproj    Platform-specific App project - References LegacyWrc_Wp8, includes files from CommonAppSrc using "Add as Link".

Problem: When I try to reference LegacyLib from the LegacyWrc_Win8 project; I see the following warning:

Adding reference to 'LegacyLib' is not recommended because it is not compatible with Windows Store Apps.

The build environment is saying that to make the LegacyLib static library compatible with my Win8 Windows Runtime Component, I must enable Windows Store App Support in the LegacyLib project configuration (ignoring the warning only results in an error later on):

  • Project Properties > Configuration Properties > General > Project Defaults
  • Set Windows Store App Support to Yes

Next, when I try to do the same thing with the LegacyWrc_Wp8 project, I get the following error:

A reference to 'LegacyLib' cannot be added because the two projects target different platforms.

So, making the static library compatible with Windows 8 made it incompatible with Windows 8 Phone.

Looks like it's simply not possible to build a single static library that can be consumed by these two different platforms, even though the library itself contains no platform-specific code.

I don't necessarily have to maintain parallel versions of the source code, but I have to create/maintain two separate projects that each build a platform-specific version of the static library.

My solution now has a platform-specific version of every project:

Attempt #3 - EVERY PROJECT is platform-specific

MySolution.sln
|
+- Library                        (virtual folder to group projects below)
|  |
|  +- NativeCode                  (virtual folder to group projects below)
|  |  |
|  |  +- CommonLibSrc             Native C++ source code using STL & CRT. Just enough C++/CX to make some types available to .NET and expose a few static methods.
|  |  |
|  |  +- LegacyLib_Win8.vcxproj   Platform-specific Static Library project - Includes files from CommonLibSrc using "Add as Link".
|  |  |
|  |  +- LegacyLib_Wp8.vcxproj    Platform-specific Static Library project - Includes files from CommonLibSrc using "Add as Link".
|  |
|  +- DotNetWrapper               (virtual folder to group projects below)
|     |
|     +- CommonWrcSrc             Platform-independant C# source code (types, wrappers, interfaces, etc. for LegacyLib support) for the Windows Runtime Component projects.
|     |
|     +- LegacyWrc_Win8.csproj    Platform-specific Windows Runtime Component project - References LegacyLib_Win8, includes files from CommonWrcSrc using "Add as Link".
|     |
|     +- LegacyWrc_Wp8.csproj     Platform-specific Windows Runtime Component project - References LegacyLib_Wp8, includes files from CommonWrcSrc using "Add as Link".
|
+- SampleApp                      (virtual folder to group projects below)
   |
   +- CommonAppSrc                Platform-independant C# source code (e.g. Model, ViewModel).
   |
   +- SampleApp_Win8.csproj       Platform-specific App project - References LegacyWrc_Win8, includes files from CommonAppSrc using "Add as Link".
   |
   +- SampleApp_Wp8.csproj        Platform-specific App project - References LegacyWrc_Wp8, includes files from CommonAppSrc using "Add as Link".

Problem: None that I can see so far (other than the fact that this is ugly and higher-maintenance).

BTW, I did look into the possibility of using Build Configurations, but they're already being used for combinations of Debug/Release and x86/ARM. Adding Win8/Wp8 into the mix just doubles the configurations again, and you've shifted, rather than reduced the maintenance burden.

Am I missing something? It seems like this is a common thing to want to do. Has anyone else gone through this and come up with alternate/better ways of doing this?

EDIT FOR COMPLETENESS

Here's what I ended up doing...

MySolution.sln
|
+- LegacyApiLib               (virtual folder to group projects below)
|  |
|  +- CommonCppSource         Common C++ source code used by LegacyWrc_*.vcxproj projects
|  |                          below
|  |
|  +- LegacyPcl.csproj        Portable class library with C# API interfaces only; no
|  |                          implementation classes.
|  |
|  +- LegacyWrc_Win8.vcxproj  Platform-specific Windows Runtime Component project - includes
|  |                          legacy C++ files, and uses C++/CX to expose static methods and
|  |                          classes to .NET in Win8.
|  |
|  +- LegacyWrc_Wp8.vcxproj   Platform-specific Windows Runtime Component project - includes
|                             legacy C++ files, and uses C++/CX to expose static methods and
|                             classes to .NET in WP8.
|
+- SampleApp                  (virtual folder to group projects below)
   |
   +- SampleAppBL.csproj      Portable class library containing the app's business logic.
   |                          References LegacyPcl.csproj for legacy API interface definitions.
   |                          Business logic is written against those interfaces; never against
   |                          specific classes. The Win8 or WP8 apps will reference the
   |                          appropriate Windows Runtime Component project, create or register
   |                          the concrete classes that implement the legacy API interface, and
   |                          either pass it into the BL or register it with IOC mechanism. In
   |                          this way, SampleAppBL.csproj never has to know about (or
   |                          reference) any of the WRC projects. 
   |
   +- SampleAppUI_Win8.csproj Platform-specific App project - References LegacyWrc_Win8.vcxproj
   |                          and SampleAppBL. Contains minimal platform-specific Win8 UI code.
   |
   +- SampleAppUI_Wp8.csproj  Platform-specific App project - References LegacyWrc_Wp8.vcxproj
                              and SampleAppBL. Contains minimal platform-specific WP8 UI code.

I realized that the few helper classes that LegacyApiLib exports could be written in managed C++ instead of C#. This meant that I could just bundle them with the WRC projects, which simplified things a bit.

like image 308
Scott Smith Avatar asked Nov 03 '22 19:11

Scott Smith


1 Answers

As you've found, the native library needs to be compiled separately for each platform, so it can't be directly referenced from a Portable Class Library.

I'd suggest using the abstraction pattern to allow you to share most of your .NET code (ie models and view models) via a Portable Class Library. In a PCL, create interfaces or abstract classes for the functionality that you are exposing in the native library. Then implement those in platform-specific projects that forward the calls onto the native library. Finally use dependency injection to hook up the implementations of those interfaces so you can call them from your shared PCL.

Here are a few blog posts that cover this:

  • Using Target-Specific Code in a Portable Library
  • How to Make Portable Class Libraries Work for You
like image 129
Daniel Plaisted Avatar answered Nov 08 '22 05:11

Daniel Plaisted