Pages

Apr 26, 2012

Porting to Native Client with Visual Studio pt.1


This article series shows you how to port to Native Client via a Chrome Trusted Plugin. This will allow you port your platform code over to Chrome's Pepper APIs while using Visual Studio for debugging. 


WARNING:
As of 10.1.2012, there's an official version of a Visual Studio 2010 plugin. Only some subset of this article series is accurate, please see the official documentation at gonacl.com for more.

Thus far, if you were a Native Client developer, your development process would look something like this:

  1. Compile your app against NaCl's GCC
    1. Curse at all the problems of using the GCC tools
  2. Modify your APIs to target the Pepper APIs
    1. Throw furniture across the room while trying to printf debug all the API issues, while at the same time overhauling your codebase to deal with the nuances of Pepper's Async APIs
  3. Debug any run time issues that come with running in a webpage
    1. Take up alcoholism as a professional sport because it makes your printf logs look 'perty'

But this stops today! Today we learn about using Visual Studio and Chrome Plugins to develop your Native Client application.
Crazy Harry, also known as the patron saint of plugin development.

Chrome, Plugins, and Native Client
Officially, you should read the Basics of Chrome, it's a great read that's eye-opening for non-web developers. If you don't have the time, here's a condensed version:

  1. Chrome is a web-browser
  2. Chrome provides the ability for developers to create Plugins to extend functionality
  3. Chrome provides a safe, secure API for plugins called Pepper (PPAPI). Plugins target the PPAPI to interact with Chrome, and the sandbox safely
  4. Native Client is a plugin that's built into Chrome, which loads external assemblies and allows them to interact with the Pepper APIs in a safe, secure fashion.
The important take-away from the list above is that Native Client is a Chrome Plugin, meaning that they both target the Pepper APIs.


What this article series talks about, is how to port to native client by first developing as a Chrome Plugin, so that you can gradually migrate over to the Pepper APIs.

Oh, and did I mention you get the full power of visual studio?


You can read the official documentation on developing trusted plugins, which, honestly, melts my brain; so I've condensed the process into the steps below.

Grab the chromium source code
Before you can compile your plugin, you'll need to get the latest source code of Chrome (called chromium) to compile against. The source code includes the specific header files that your plugin will need to link against in order to operate correctly. Note that when you pull down chromium, the root folder is "src" so it's best if you create a parent folder "chromium" to pull it into.

Using GIT you can grab the top of the tree here:
git clone http://git.chromium.org/chromium/src.git

If you're new to using GIT as your source control solution, I highly recommend using TortiseGit, it fits really well into the Windows IDE, and is free.

This is going to take a while, so you while that's working, continue forward with the next steps ;)

Grab the latest build of Chromium
To properly debug, you'll need a build of Chromium that matches the headers from the source repo. You can choose to build it yourself, if you've got a few hours and a high tolerance for pain.

If you'd like to skip that step (which I recommend), you can download the nighly builds from the chromium build repository.

Clicking on "builds: continuous" and choosing "win" as a sub-folder lists all the archived builds of chromium that you can use directly. (or you could click here for simplicity ;) Scrolling to the bottom of the page gives you the latest successful build folder, contained within is the binaries and symbols for that build.

You only need the chrome-win32-syms.zip (symbols) and chrome-32.zip (binaries) from this directory

I unzip the contents of these files in a folder named "chrome_build" so that it's easy for me to remember which build i'm running ;)

aside - Yes, for Windows, there's only a 32 bit version. That's a separate discussion; just download it, use it, and move on.

Grabbing the Native Client SDK
Visit gonacl.com and click on the 'sdk' link on the left hand side of the page. Follow the instructions to download and install the latest version of the sdk, and update to the latest version of pepper_*

Creating the windows project

  1. Start a new Visual Studio project
  2. Select Win32 Project
  3. When the win32 application wizard starts up, select "Application settings" and choose "DLL" with "Empty Project"


Continue on to create the project.

Adding the source files
Add a new "main.cpp" file to your solution, in this file, we'll write the base code for our Pepper plugin that will interact with Chrome. But rather than typing all that out by hand, we're going to cheat, and use some existing code from the Native Client SDK. Once it's downloaded and installed, copy-paste the contents of this example NaCl file into your new main.cpp

(NaCl_SDK_root)\pepper_18\examples\hello_world_newlib\hello_world.c

In addition, you'll also need an html file to host your NaCl module from.
Continue on and add a new "index.html" file to your solution. Note, depending on what version of visual studio you have, creating an html file will be under the 'web' subcategory of the 'add new item' dialog.
Copy-paste the contents of this example NaCl file into your new index.html

(NaCl_SDK_root)\pepper_18\examples\hello_world_newlib\hello_world.html

NOTE - For you advanced users out there, you most likely have noticed that you could have simply added the hello_world files to the project as remote references, rather than copy-pasting and all that jazz; I've presented the above method for the sake of conciseness; This makes it easier to hack on the files w/o ruining the files in your examples folder.

Setting the visual studio project properties
This is where the dark magic comes in. Right clicking on your project, select Properties, and fill in the following line-items.

C/C++ > General >Additional Include Directories :
(Some Path)\chromium\src\
This is the path where you downloaded your chromium source code to.

Debugging > Command:
(Some other Path)\chrome_build\chrome-win32\chrome.exe
This is the path to your downloaded build of Chromium.

Debugging > Command Arguments:
--single-process --register-pepper-plugins=$(TargetPath);application/x-nacl "localhost:5103/index.html"
this... requires some explanation...

  • --single-process - tells chrome to run the tabs in a single process. As the background document states, chrome is a multi-process browser, and each tab is opened in a separate process. Since our goal is to debug the open tab w/o going insane, we specify this command line argument so that we can properly attach to the running instance of Chromium to debug it. In addition, it's worth pointing out that this turns off the sand boxing in chrome. As such, I don't recommend running your main chrome.exe with this flag due to potential security issues.
  • --register-pepper-plugins=$(TargetPath);application/x-nacl - This is a debug flag that tells Chrome to load the specific plugin automatically. Normally a plugin would have to be distributed and installed through the Chrome Extensions UI, which would generally kill your productivity turnaround. In addition the application/x-nacl flag tells chrome to associate the usage of this plugin with any Mime type matching "application/x-nacl". So once the webpage find a mime object matching that string, it will invoke our plugin properly
  • localhost:5103/index.html - This ending parameter tells Chrome what URL to load when it launches. Why are we pointing it to localhost? let's chat about that a bit more.


The HTML and Web-service.

As noted before, we're working with a web-technology; that is, native client modules must be served from a web-server to operate correctly. This is generally a 'pick your poison' setup with tons of options to create web-servers on your windows desktop. For simplicity's sake, the Native Client SDK comes with some easy uses for this and provides a single-file python based web-server to use for showing off the examples. You can find this web-server here:

(NaCl_SDK_root)\pepper_18\examples\httpd.py

The httpd.py script will launch a webserver who's root is the directory it's launched from. As such, we need to copy the file to the same location as the index.html file you created above (or the location of your vcxproj, which should be the same)
Note, make sure python is properly added to your path, otherwise running httpd.py could be problematic.

Once placed, feel free to launch the webserver and minimize the window.



caveat
At the time of this writing, this python script contains a check to ensure that the webserver is running from the examples folder. This makes the script useless for our purposes, so I suggest that you remove this check by simply adding a 'return' at the beginning of the 'SanityCheckDirectory()' function.

Simply add a 'return' to this function, and you can use the httpd.py module anywhere as a quick, easy local web-server. Note, that if you're new to Python, make sure that you've indented 'return' in the proper tabs as the rest of the function.

Compiling and debugging.
In visual studio, Choose "Debug > Start Debugging" (or just hit F5). If all went well, Visual studio should fire up an instance of chromium; load the page, and pop up an alert.
Now, this is where the magic happens; If you place a break point inside visual studio in the Instance_DidCreate function (line 46ish) then it'll fire before the window pops up the alert box.  This function will send a message from the plugin to the HTML page to alert. Continue past the break-point to see the HTML page pope up the alert.
YES! A break point! My IDE color scheme is Zenburn, thanks to Jeff Atwood
Want to go deeper? If you pop open the Debugging Tools inside of chrome, you can set a break point in the HTML's handleMessage function (line 24ish) which is responsible for popping up the alert. If you haven't stopped visual studio yet, then simply hit "RELOAD" in the webpage and you'll hit the javascript break point.


Conclusion
AND that's all for now! You can now create a trusted plugin for chrome, and have it communicate back and forth with the html in the page. Note that what we haven't done here is talk about NaCl; All we've done is create a trusted plugin that targets the Pepper APIs

Also Mad props to NaCl SDK Lead Noel Allen for helping plot all the tricky bits out.

Note, you can download the source code for this series @ my github repo.

The rest of the series - 
Part 1 : Setting up visual studio
Part 2 : Using platform-specific code 
Part 3 : Porting to Pepper
Part 4 : Compile to NaCl






You can find me here:

  

~Main

1 comment:

  1. I have pepper_19. When running the web server from my new visual studio project folder, I had to add the environment variable NACL_SDK_ROOT pointing to where the SDK is installed. i.e. 'C:\nacl_sdk\pepper_19'.

    ReplyDelete