I have a chrome packaged app that also includes a PNaCl/NaCl C++ module, as well as some data files which the NaCl module needs to read in. However, I am not able to get it to read in the files.
I set it up according to all the documentation and official examples that I could find, as well as the answer to: How to include a data file in a chrome app for a native client module to read
The nacl_io demo that comes with the SDK is able to do this, but it is in C, not C++.
I came up with a simple example, which I'll post below. When you press the button on the page, the NaCl module should load the first character of test.txt and show it. As of now, it always just responds with "-100" (the error value I put in), meaning that it could not open the file, rather than with the first character of the file.
Can anyone suggest some changes that would allow it to work correctly and load the file?
In order to run it, on the Mac at least, I use this command, with all the files in the ./file-test dir: /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --load-and-launch-app=./file-test
Note that if you try to use this, you will most likely need to change the NACL_SDK_ROOT path in the makefile.
#include "ppapi/cpp/instance.h"
#include "ppapi/cpp/module.h"
#include "ppapi/cpp/var.h"
#include "nacl_io/nacl_io.h"
#include "sys/mount.h"
class FileTestInstance : public pp::Instance {
public:
explicit FileTestInstance(PP_Instance instance) : pp::Instance(instance)
{
// initialize nacl file system
nacl_io_init_ppapi(instance, pp::Module::Get()->get_browser_interface());
// mount the http root at /http
mount("", "/http", "httpfs", 0, "");
}
virtual ~FileTestInstance() {}
// Receive message from javascript
virtual void HandleMessage(const pp::Var& var_message) {
// Open and load from the file
int c;
FILE *file;
file = fopen("/http/test.txt", "r");
if (file) {
c = getc(file);
fclose(file);
} else {
c = -100;
}
// Send message to JavaScript
pp::Var var_reply(c);
PostMessage(var_reply);
}
};
class FileTestModule : public pp::Module {
public:
FileTestModule() : pp::Module() {}
virtual ~FileTestModule() {}
virtual pp::Instance* CreateInstance(PP_Instance instance) {
return new FileTestInstance(instance);
}
};
namespace pp {
Module* CreateModule() {
return new FileTestModule();
}
} // namespace pp
<!DOCTYPE html>
<html>
<head>
<title>File Test</title>
<script type="text/javascript" src="script.js"></script>
</head>
<body>
<h1>File Test</h1>
<input type="button" id="test" name="test" value="Test" />
<p><b>Output:</b><p>
<div id="output">
</div>
<p>
<div id="listener">
<embed id="file_test" width=0 height=0 src="file_test.nmf" type="application/x-pnacl" />
</div>
</p>
</body>
</html>
// outgoing messages
function postMessage(message) {
var nacl_module = document.getElementById('file_test')
nacl_module.postMessage(message);
}
// incoming messages
function handleMessage(message_event) {
var outputDiv = document.getElementById('output');
outputDiv.textContent = message_event.data;
}
// button action
function buttonClicked() {
postMessage("file");
}
// set up
function init() {
// add listener to nacl module
var listener = document.getElementById('listener');
listener.addEventListener('message', handleMessage, true);
// add action to button
document.getElementById("test").onclick = buttonClicked;
}
window.onload = init;
/**
* Listens for the app launching then creates the window
*/
chrome.app.runtime.onLaunched.addListener(function() {
// Center window on screen.
var screenWidth = screen.availWidth;
var screenHeight = screen.availHeight;
var width = 600;
var height = 600;
chrome.app.window.create('index.html', {
id: "File-TestID",
bounds: {
width: width,
height: height,
left: Math.round((screenWidth-width)/2),
top: Math.round((screenHeight-height)/2)
}
});
});
{
"program": {
"portable": {
"pnacl-translate": {
"url": "file_test.pexe"
}
}
}
}
#
# Get pepper directory for toolchain and includes.
#
# If NACL_SDK_ROOT is not set, then assume where it can be found.
#
THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST)))
NACL_SDK_ROOT ?= $(abspath $(dir $(THIS_MAKEFILE))../../nacl_sdk/pepper_33)
# Project Build flags
WARNINGS := -Wno-long-long -Wall -Wswitch-enum -pedantic -Werror
CXXFLAGS := -pthread -std=gnu++98 $(WARNINGS)
#
# Compute tool paths
#
GETOS := python $(NACL_SDK_ROOT)/tools/getos.py
OSHELPERS = python $(NACL_SDK_ROOT)/tools/oshelpers.py
OSNAME := $(shell $(GETOS))
RM := $(OSHELPERS) rm
PNACL_TC_PATH := $(abspath $(NACL_SDK_ROOT)/toolchain/$(OSNAME)_pnacl)
PNACL_CXX := $(PNACL_TC_PATH)/bin/pnacl-clang++
PNACL_FINALIZE := $(PNACL_TC_PATH)/bin/pnacl-finalize
CXXFLAGS := -I$(NACL_SDK_ROOT)/include -I$(NACL_SDK_ROOT)/include/pnacl
LDFLAGS := -L$(NACL_SDK_ROOT)/lib/pnacl/Release -lppapi_cpp -lppapi -lnacl_io
#
# Disable DOS PATH warning when using Cygwin based tools Windows
#
CYGWIN ?= nodosfilewarning
export CYGWIN
# Declare the ALL target first, to make the 'all' target the default build
all: file_test.pexe
clean:
$(RM) file_test.pexe file_test.bc
file_test.bc: file_test.cc
$(PNACL_CXX) -o $@ $< -O2 $(CXXFLAGS) $(LDFLAGS)
file_test.pexe: file_test.bc
$(PNACL_FINALIZE) -o $@ $<
AAAA
From Sam Clegg on the native-client-discuss list:
"I think the main problem you have is that you are trying to use nacl_io on the main thread. nacl_io, like the blocking PPAPI interfaces on which it is mostly based, will only work on background threads where blocking calls are allowed. See: https://developer.chrome.com/native-client/devguide/coding/nacl_io."
"Try running your code on a separate thread. One easy way to do this is to use the ppapi_simple library."
Using this advice, and also looking at the examples using_ppapi_simple, flock, and earth, that are included with the SDK, I was able to make a working version:
#include <stdio.h>
#include "sys/mount.h"
#include <ppapi/cpp/var.h>
#include "ppapi_simple/ps_main.h"
#include "ppapi_simple/ps_event.h"
#include "ppapi_simple/ps_interface.h"
int file_test_main(int argc, char* argv[]) {
PSEventSetFilter(PSE_ALL);
// mount the http root at /http
mount("", "/http", "httpfs", 0, "");
while (true) {
PSEvent* ps_event;
// Consume all available events
while ((ps_event = PSEventWaitAcquire()) != NULL) {
// handle messages from javascript
if (ps_event->type == PSE_INSTANCE_HANDLEMESSAGE) {
// Convert Pepper Simple message to PPAPI C++ vars
pp::Var var_message(ps_event->as_var);
// process the message if it is a string
if (var_message.is_string()) {
// get the string message
std::string message = var_message.AsString();
// handle message
if (message == "file") {
// Open and load from the file
int c;
FILE *file;
file = fopen("/http/test.txt", "r");
if (file) {
c = getc(file);
fclose(file);
} else {
c = -100;
}
// Send response back to JavaScript
pp::Var var_reply(c);
PSInterfaceMessaging()->PostMessage(PSGetInstanceId(), var_reply.pp_var());
}
}
}
PSEventRelease(ps_event);
}
}
return 0;
}
/*
* Register the function to call once the Instance Object is initialized.
* see: pappi_simple/ps_main.h
*/
PPAPI_SIMPLE_REGISTER_MAIN(file_test_main)
In addition, it is necessary to add -lppapi_simple to LDFLAGS in Makefile.
It would also be possible to do this handling the threads oneself, rather than using ppapi_simple, which can be seen in nacl_io_demo which is included with the SDK.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With