summaryrefslogtreecommitdiffstats
path: root/native_client_sdk/src/project_templates
diff options
context:
space:
mode:
authorbradnelson@google.com <bradnelson@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-19 02:46:32 +0000
committerbradnelson@google.com <bradnelson@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-19 02:46:32 +0000
commit745945afe8e9fbfad7bb9ed442143172bf690073 (patch)
tree770e9c5f61e1204221fb4c2887cb863ad8b6688f /native_client_sdk/src/project_templates
parentf0953ccbeb01a7a4ed1daa3cb84c2bc42adbed1f (diff)
downloadchromium_src-745945afe8e9fbfad7bb9ed442143172bf690073.zip
chromium_src-745945afe8e9fbfad7bb9ed442143172bf690073.tar.gz
chromium_src-745945afe8e9fbfad7bb9ed442143172bf690073.tar.bz2
Adding reduced version of sdk at 1387 to chrome tree.
BUG=None TEST=None R=noelallen@google.com TBR git-svn-id: svn://svn.chromium.org/chrome/trunk/src@110822 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'native_client_sdk/src/project_templates')
-rw-r--r--native_client_sdk/src/project_templates/README45
-rw-r--r--native_client_sdk/src/project_templates/c/build.scons15
-rw-r--r--native_client_sdk/src/project_templates/c/project_file.c227
-rw-r--r--native_client_sdk/src/project_templates/cc/build.scons16
-rw-r--r--native_client_sdk/src/project_templates/cc/project_file.cc87
-rw-r--r--native_client_sdk/src/project_templates/html/project_file.html95
-rwxr-xr-xnative_client_sdk/src/project_templates/init_project.py502
-rwxr-xr-xnative_client_sdk/src/project_templates/init_project_test.py256
-rwxr-xr-xnative_client_sdk/src/project_templates/scons32
-rwxr-xr-xnative_client_sdk/src/project_templates/scons.bat31
-rw-r--r--native_client_sdk/src/project_templates/test.scons26
-rw-r--r--native_client_sdk/src/project_templates/vs/project_file.sln20
-rw-r--r--native_client_sdk/src/project_templates/vs/project_file.vcproj184
13 files changed, 1536 insertions, 0 deletions
diff --git a/native_client_sdk/src/project_templates/README b/native_client_sdk/src/project_templates/README
new file mode 100644
index 0000000..5aca398
--- /dev/null
+++ b/native_client_sdk/src/project_templates/README
@@ -0,0 +1,45 @@
+Welcome to the Native Client SDK project_templates directory.
+
+Currently, this directory contains a mechanism to allow a developer to
+bootstrap a native client project and write a lot of the NaCl-specific code
+automatically, so the developer can add her own functionality quickly. The
+projects created are designed to be self-contained, meaning that they have
+everything they need to run, except a server.
+
+To start a project, run "./init_project.py" or "python init_project.py"
+depending on your system configuration. The script will give you usage
+information when run with -h or when insufficient or malformed arguments are
+provided.
+
+The result of the script is a project with the name you provide at a location
+of your choice. If you have your own server, you may create the project in
+a location it serves. Otherwise, you may create a project under the SDK
+examples directory and examples/httpd.py to serve your project quickly - at
+least temporarily.
+
+In the future, this directory is intended as a repository for useful stub code,
+code snippets, and code generators that can be used to facilitate rapid
+development. For now we support initial project setup via init_project.py, but
+any generically useful code can be added here if it follows a reasonable
+organization. The organization is as follows:
+
+project_templates:
+ Contains any top-level scripting elements that apply or may come in useful
+ for the generation of all NaCl/Pepper2 projects, common Makefile sections,
+ and this README.
+project_templates/[language]:
+ For any given language there should be a directory with a name that is
+ commonly associated with that language.
+project_templates/[topic]
+project_templates/[language]/[topic]
+ For any given programming topic, such as audio, 2d, or 3d programming, there
+ should be a directory at the root level for any components that are not
+ language specific and that may apply to that topic. For corresponding
+ components that are language specific, a sub-directory for the topic may
+ also be created under the language directory.
+
+Note that the layout in this directory does not reflect the layout of the
+projects that are created. It is merely a set of simple guidelines to help
+organize generic code and utilities so they can be managed here. How
+generated projects are laid out is left up to the design of the particular
+code-generator.
diff --git a/native_client_sdk/src/project_templates/c/build.scons b/native_client_sdk/src/project_templates/c/build.scons
new file mode 100644
index 0000000..fcfcf0e
--- /dev/null
+++ b/native_client_sdk/src/project_templates/c/build.scons
@@ -0,0 +1,15 @@
+#! -*- python -*-
+#
+# Copyright (c) 2011 The Native Client Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import make_nacl_env
+import os
+
+nacl_env = make_nacl_env.NaClEnvironment(
+ nacl_platform=os.getenv('NACL_TARGET_PLATFORM'))
+
+sources = ['<PROJECT_NAME>.c']
+
+nacl_env.AllNaClModules(sources, '<PROJECT_NAME>')
diff --git a/native_client_sdk/src/project_templates/c/project_file.c b/native_client_sdk/src/project_templates/c/project_file.c
new file mode 100644
index 0000000..7f25bd6
--- /dev/null
+++ b/native_client_sdk/src/project_templates/c/project_file.c
@@ -0,0 +1,227 @@
+/** @file <PROJECT_NAME>.c
+ * This example demonstrates loading, running and scripting a very simple
+ * NaCl module.
+ */
+#include <stdlib.h>
+#include <string.h>
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/c/pp_module.h"
+#include "ppapi/c/pp_var.h"
+#include "ppapi/c/ppb.h"
+#include "ppapi/c/ppb_instance.h"
+#include "ppapi/c/ppb_messaging.h"
+#include "ppapi/c/ppb_var.h"
+#include "ppapi/c/ppp.h"
+#include "ppapi/c/ppp_instance.h"
+#include "ppapi/c/ppp_messaging.h"
+
+static PP_Module module_id = 0;
+static struct PPB_Messaging* messaging_interface = NULL;
+static struct PPB_Var* var_interface = NULL;
+
+/**
+ * Returns a mutable C string contained in the @a var or NULL if @a var is not
+ * string. This makes a copy of the string in the @a var and adds a NULL
+ * terminator. Note that VarToUtf8() does not guarantee the NULL terminator on
+ * the returned string. See the comments for VarToUtf8() in ppapi/c/ppb_var.h
+ * for more info. The caller is responsible for freeing the returned memory.
+ * @param[in] var PP_Var containing string.
+ * @return a mutable C string representation of @a var.
+ * @note The caller is responsible for freeing the returned string.
+ */
+/* TODO(sdk_user): 2. Uncomment this when you need it. It is commented out so
+ * that the compiler doesn't complain about unused functions.
+ */
+#if 0
+static char* AllocateCStrFromVar(struct PP_Var var) {
+ uint32_t len = 0;
+ if (var_interface != NULL) {
+ const char* var_c_str = var_interface->VarToUtf8(var, &len);
+ if (len > 0) {
+ char* c_str = (char*)malloc(len + 1);
+ memcpy(c_str, var_c_str, len);
+ c_str[len] = '\0';
+ return c_str;
+ }
+ }
+ return NULL;
+}
+#endif
+
+/**
+ * Creates a new string PP_Var from C string. The resulting object will be a
+ * refcounted string object. It will be AddRef()ed for the caller. When the
+ * caller is done with it, it should be Release()d.
+ * @param[in] str C string to be converted to PP_Var
+ * @return PP_Var containing string.
+ */
+/* TODO(sdk_user): 3. Uncomment this when you need it. It is commented out so
+ * that the compiler doesn't complain about unused functions.
+ */
+#if 0
+static struct PP_Var AllocateVarFromCStr(const char* str) {
+ if (var_interface != NULL)
+ return var_interface->VarFromUtf8(module_id, str, strlen(str));
+ return PP_MakeUndefined();
+}
+#endif
+
+/**
+ * Called when the NaCl module is instantiated on the web page. The identifier
+ * of the new instance will be passed in as the first argument (this value is
+ * generated by the browser and is an opaque handle). This is called for each
+ * instantiation of the NaCl module, which is each time the <embed> tag for
+ * this module is encountered.
+ *
+ * If this function reports a failure (by returning @a PP_FALSE), the NaCl
+ * module will be deleted and DidDestroy will be called.
+ * @param[in] instance The identifier of the new instance representing this
+ * NaCl module.
+ * @param[in] argc The number of arguments contained in @a argn and @a argv.
+ * @param[in] argn An array of argument names. These argument names are
+ * supplied in the <embed> tag, for example:
+ * <embed id="nacl_module" dimensions="2">
+ * will produce two arguments, one named "id" and one named "dimensions".
+ * @param[in] argv An array of argument values. These are the values of the
+ * arguments listed in the <embed> tag. In the above example, there will
+ * be two elements in this array, "nacl_module" and "2". The indices of
+ * these values match the indices of the corresponding names in @a argn.
+ * @return @a PP_TRUE on success.
+ */
+static PP_Bool Instance_DidCreate(PP_Instance instance,
+ uint32_t argc,
+ const char* argn[],
+ const char* argv[]) {
+ return PP_TRUE;
+}
+
+/**
+ * Called when the NaCl module is destroyed. This will always be called,
+ * even if DidCreate returned failure. This routine should deallocate any data
+ * associated with the instance.
+ * @param[in] instance The identifier of the instance representing this NaCl
+ * module.
+ */
+static void Instance_DidDestroy(PP_Instance instance) {
+}
+
+/**
+ * Called when the position, the size, or the clip rect of the element in the
+ * browser that corresponds to this NaCl module has changed.
+ * @param[in] instance The identifier of the instance representing this NaCl
+ * module.
+ * @param[in] position The location on the page of this NaCl module. This is
+ * relative to the top left corner of the viewport, which changes as the
+ * page is scrolled.
+ * @param[in] clip The visible region of the NaCl module. This is relative to
+ * the top left of the plugin's coordinate system (not the page). If the
+ * plugin is invisible, @a clip will be (0, 0, 0, 0).
+ */
+static void Instance_DidChangeView(PP_Instance instance,
+ const struct PP_Rect* position,
+ const struct PP_Rect* clip) {
+}
+
+/**
+ * Notification that the given NaCl module has gained or lost focus.
+ * Having focus means that keyboard events will be sent to the NaCl module
+ * represented by @a instance. A NaCl module's default condition is that it
+ * will not have focus.
+ *
+ * Note: clicks on NaCl modules will give focus only if you handle the
+ * click event. You signal if you handled it by returning @a true from
+ * HandleInputEvent. Otherwise the browser will bubble the event and give
+ * focus to the element on the page that actually did end up consuming it.
+ * If you're not getting focus, check to make sure you're returning true from
+ * the mouse click in HandleInputEvent.
+ * @param[in] instance The identifier of the instance representing this NaCl
+ * module.
+ * @param[in] has_focus Indicates whether this NaCl module gained or lost
+ * event focus.
+ */
+static void Instance_DidChangeFocus(PP_Instance instance,
+ PP_Bool has_focus) {
+}
+
+/**
+ * Handler that gets called after a full-frame module is instantiated based on
+ * registered MIME types. This function is not called on NaCl modules. This
+ * function is essentially a place-holder for the required function pointer in
+ * the PPP_Instance structure.
+ * @param[in] instance The identifier of the instance representing this NaCl
+ * module.
+ * @param[in] url_loader A PP_Resource an open PPB_URLLoader instance.
+ * @return PP_FALSE.
+ */
+static PP_Bool Instance_HandleDocumentLoad(PP_Instance instance,
+ PP_Resource url_loader) {
+ /* NaCl modules do not need to handle the document load function. */
+ return PP_FALSE;
+}
+
+
+/**
+ * Handler for messages coming in from the browser via postMessage. The
+ * @a var_message can contain anything: a JSON string; a string that encodes
+ * method names and arguments; etc. For example, you could use JSON.stringify
+ * in the browser to create a message that contains a method name and some
+ * parameters, something like this:
+ * var json_message = JSON.stringify({ "myMethod" : "3.14159" });
+ * nacl_module.postMessage(json_message);
+ * On receipt of this message in @a var_message, you could parse the JSON to
+ * retrieve the method name, match it to a function call, and then call it with
+ * the parameter.
+ * @param[in] instance The instance ID.
+ * @param[in] message The contents, copied by value, of the message sent from
+ * browser via postMessage.
+ */
+void Messaging_HandleMessage(PP_Instance instance, struct PP_Var var_message) {
+ /* TODO(sdk_user): 1. Make this function handle the incoming message. */
+}
+
+/**
+ * Entry points for the module.
+ * Initialize instance interface and scriptable object class.
+ * @param[in] a_module_id Module ID
+ * @param[in] get_browser_interface Pointer to PPB_GetInterface
+ * @return PP_OK on success, any other value on failure.
+ */
+PP_EXPORT int32_t PPP_InitializeModule(PP_Module a_module_id,
+ PPB_GetInterface get_browser_interface) {
+ module_id = a_module_id;
+ var_interface = (struct PPB_Var*)(get_browser_interface(PPB_VAR_INTERFACE));
+ messaging_interface =
+ (struct PPB_Messaging*)(get_browser_interface(PPB_MESSAGING_INTERFACE));
+ return PP_OK;
+}
+
+/**
+ * Returns an interface pointer for the interface of the given name, or NULL
+ * if the interface is not supported.
+ * @param[in] interface_name name of the interface
+ * @return pointer to the interface
+ */
+PP_EXPORT const void* PPP_GetInterface(const char* interface_name) {
+ if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) {
+ static struct PPP_Instance instance_interface = {
+ &Instance_DidCreate,
+ &Instance_DidDestroy,
+ &Instance_DidChangeView,
+ &Instance_DidChangeFocus,
+ &Instance_HandleDocumentLoad
+ };
+ return &instance_interface;
+ } else if (strcmp(interface_name, PPP_MESSAGING_INTERFACE) == 0) {
+ static struct PPP_Messaging messaging_interface = {
+ &Messaging_HandleMessage
+ };
+ return &messaging_interface;
+ }
+ return NULL;
+}
+
+/**
+ * Called before the plugin module is unloaded.
+ */
+PP_EXPORT void PPP_ShutdownModule() {
+}
diff --git a/native_client_sdk/src/project_templates/cc/build.scons b/native_client_sdk/src/project_templates/cc/build.scons
new file mode 100644
index 0000000..537d17b
--- /dev/null
+++ b/native_client_sdk/src/project_templates/cc/build.scons
@@ -0,0 +1,16 @@
+#! -*- python -*-
+#
+# Copyright (c) 2011 The Native Client Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import make_nacl_env
+import nacl_utils
+import os
+
+nacl_env = make_nacl_env.NaClEnvironment(
+ use_c_plus_plus_libs=True, nacl_platform=os.getenv('NACL_TARGET_PLATFORM'))
+
+sources = ['<PROJECT_NAME>.cc']
+
+nacl_env.AllNaClModules(sources, '<PROJECT_NAME>')
diff --git a/native_client_sdk/src/project_templates/cc/project_file.cc b/native_client_sdk/src/project_templates/cc/project_file.cc
new file mode 100644
index 0000000..c0123fe
--- /dev/null
+++ b/native_client_sdk/src/project_templates/cc/project_file.cc
@@ -0,0 +1,87 @@
+/// @file <PROJECT_NAME>.cc
+/// This example demonstrates loading, running and scripting a very simple NaCl
+/// module. To load the NaCl module, the browser first looks for the
+/// CreateModule() factory method (at the end of this file). It calls
+/// CreateModule() once to load the module code from your .nexe. After the
+/// .nexe code is loaded, CreateModule() is not called again.
+///
+/// Once the .nexe code is loaded, the browser than calls the CreateInstance()
+/// method on the object returned by CreateModule(). It calls CreateInstance()
+/// each time it encounters an <embed> tag that references your NaCl module.
+///
+/// The browser can talk to your NaCl module via the postMessage() Javascript
+/// function. When you call postMessage() on your NaCl module from the browser,
+/// this becomes a call to the HandleMessage() method of your pp::Instance
+/// subclass. You can send messages back to the browser by calling the
+/// PostMessage() method on your pp::Instance. Note that these two methods
+/// (postMessage() in Javascript and PostMessage() in C++) are asynchronous.
+/// This means they return immediately - there is no waiting for the message
+/// to be handled. This has implications in your program design, particularly
+/// when mutating property values that are exposed to both the browser and the
+/// NaCl module.
+
+#include <cstdio>
+#include <string>
+#include "ppapi/cpp/instance.h"
+#include "ppapi/cpp/module.h"
+#include "ppapi/cpp/var.h"
+
+/// The Instance class. One of these exists for each instance of your NaCl
+/// module on the web page. The browser will ask the Module object to create
+/// a new Instance for each occurence of the <embed> tag that has these
+/// attributes:
+/// type="application/x-nacl"
+/// src="<PROJECT_NAME>.nmf"
+/// To communicate with the browser, you must override HandleMessage() for
+/// receiving messages from the borwser, and use PostMessage() to send messages
+/// back to the browser. Note that this interface is entirely asynchronous.
+class <ProjectName>Instance : public pp::Instance {
+ public:
+ /// The constructor creates the plugin-side instance.
+ /// @param[in] instance the handle to the browser-side plugin instance.
+ explicit <ProjectName>Instance(PP_Instance instance) : pp::Instance(instance)
+ {}
+ virtual ~<ProjectName>Instance() {}
+
+ /// Handler for messages coming in from the browser via postMessage(). The
+ /// @a var_message can contain anything: a JSON string; a string that encodes
+ /// method names and arguments; etc. For example, you could use
+ /// JSON.stringify in the browser to create a message that contains a method
+ /// name and some parameters, something like this:
+ /// var json_message = JSON.stringify({ "myMethod" : "3.14159" });
+ /// nacl_module.postMessage(json_message);
+ /// On receipt of this message in @a var_message, you could parse the JSON to
+ /// retrieve the method name, match it to a function call, and then call it
+ /// with the parameter.
+ /// @param[in] var_message The message posted by the browser.
+ virtual void HandleMessage(const pp::Var& var_message) {
+ // TODO(sdk_user): 1. Make this function handle the incoming message.
+ }
+};
+
+/// The Module class. The browser calls the CreateInstance() method to create
+/// an instance of your NaCl module on the web page. The browser creates a new
+/// instance for each <embed> tag with type="application/x-nacl".
+class <ProjectName>Module : public pp::Module {
+ public:
+ <ProjectName>Module() : pp::Module() {}
+ virtual ~<ProjectName>Module() {}
+
+ /// Create and return a <ProjectName>Instance object.
+ /// @param[in] instance The browser-side instance.
+ /// @return the plugin-side instance.
+ virtual pp::Instance* CreateInstance(PP_Instance instance) {
+ return new <ProjectName>Instance(instance);
+ }
+};
+
+namespace pp {
+/// Factory function called by the browser when the module is first loaded.
+/// The browser keeps a singleton of this module. It calls the
+/// CreateInstance() method on the object you return to make instances. There
+/// is one instance per <embed> tag on the page. This is the main binding
+/// point for your NaCl module with the browser.
+Module* CreateModule() {
+ return new <ProjectName>Module();
+}
+} // namespace pp
diff --git a/native_client_sdk/src/project_templates/html/project_file.html b/native_client_sdk/src/project_templates/html/project_file.html
new file mode 100644
index 0000000..0b21ad9
--- /dev/null
+++ b/native_client_sdk/src/project_templates/html/project_file.html
@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title><ProjectName>!</title>
+
+ <script type="text/javascript">
+ <ProjectName>Module = null; // Global application object.
+ statusText = 'NO-STATUS';
+
+ // Indicate load success.
+ function moduleDidLoad() {
+ <ProjectName>Module = document.getElementById('<PROJECT_NAME>');
+ updateStatus('SUCCESS');
+ }
+
+ // The 'message' event handler. This handler is fired when the NaCl module
+ // posts a message to the browser by calling PPB_Messaging.PostMessage()
+ // (in C) or pp::Instance.PostMessage() (in C++). This implementation
+ // simply displays the content of the message in an alert panel.
+ function handleMessage(message_event) {
+ alert(message_event.data);
+ }
+
+ // If the page loads before the Native Client module loads, then set the
+ // status message indicating that the module is still loading. Otherwise,
+ // do not change the status message.
+ function pageDidLoad() {
+ if (<ProjectName>Module == null) {
+ updateStatus('LOADING...');
+ } else {
+ // It's possible that the Native Client module onload event fired
+ // before the page's onload event. In this case, the status message
+ // will reflect 'SUCCESS', but won't be displayed. This call will
+ // display the current message.
+ updateStatus();
+ }
+ }
+
+ // Set the global status message. If the element with id 'statusField'
+ // exists, then set its HTML to the status message as well.
+ // opt_message The message test. If this is null or undefined, then
+ // attempt to set the element with id 'statusField' to the value of
+ // |statusText|.
+ function updateStatus(opt_message) {
+ if (opt_message)
+ statusText = opt_message;
+ var statusField = document.getElementById('status_field');
+ if (statusField) {
+ statusField.innerHTML = statusText;
+ }
+ }
+ </script>
+</head>
+<body onload="pageDidLoad()">
+
+<h1>Native Client Module <ProjectName></h1>
+<p>
+ <!-- Load the published .nexe. This includes the 'nacl' attribute which
+ shows how to load multi-architecture modules. Each entry in the "nexes"
+ object in the .nmf manifest file is a key-value pair: the key is the
+ instruction set architecture ('x86-32', 'x86-64', etc.); the value is a URL
+ for the desired NaCl module.
+ To load the debug versions of your .nexes, set the 'nacl' attribute to the
+ _dbg.nmf version of the manifest file.
+
+ Note: Since this NaCl module does not use any real-estate in the browser,
+ it's width and height are set to 0.
+
+ Note: The <EMBED> element is wrapped inside a <DIV>, which has both a 'load'
+ and a 'message' event listener attached. This wrapping method is used
+ instead of attaching the event listeners directly to the <EMBED> element to
+ ensure that the listeners are active before the NaCl module 'load' event
+ fires. This also allows you to use PPB_Messaging.PostMessage() (in C) or
+ pp::Instance.PostMessage() (in C++) from within the initialization code in
+ your NaCl module.
+ -->
+ <div id="listener">
+ <script type="text/javascript">
+ var listener = document.getElementById('listener');
+ listener.addEventListener('load', moduleDidLoad, true);
+ listener.addEventListener('message', handleMessage, true);
+ </script>
+
+ <embed name="nacl_module"
+ id="<PROJECT_NAME>"
+ width=0 height=0
+ src="<PROJECT_NAME>.nmf"
+ type="application/x-nacl" />
+ </div>
+</p>
+
+<h2>Status</h2>
+<div id="status_field">NO-STATUS</div>
+</body>
+</html>
diff --git a/native_client_sdk/src/project_templates/init_project.py b/native_client_sdk/src/project_templates/init_project.py
new file mode 100755
index 0000000..4b5bad2
--- /dev/null
+++ b/native_client_sdk/src/project_templates/init_project.py
@@ -0,0 +1,502 @@
+#!/usr/bin/python2.6
+#
+# Copyright (c) 2011 The Native Client Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""A simple project generator for Native Client projects written in C or C++.
+
+This script accepts a few argument which it uses as a description of a new NaCl
+project. It sets up a project with a given name and a given primary language
+(default: C++, optionally, C) using the appropriate files from this area.
+This script does not handle setup for complex applications, just the basic
+necessities to get a functional native client application stub. When this
+script terminates a compileable project stub will exist with the specified
+name, at the specified location.
+
+GetCamelCaseName(): Converts an underscore name to a camel case name.
+GetCodeDirectory(): Decides what directory to pull source code from.
+GetCodeSoureFiles(): Decides what source files to pull into the stub.
+GetCommonSourceFiles(): Gives list of files needed by all project types.
+GetHTMLDirectory(): Decides what directory to pull HTML stub from.
+GetHTMLSourceFiles(): Gives HTML files to be included in project stub.
+GetTargetFileName(): Converts a source file name into a project file name.
+ParseArguments(): Parses the arguments provided by the user.
+ReplaceInFile(): Replaces a given string with another in a given file.
+ProjectInitializer: Maintains some state applicable to setting up a project.
+main(): Executes the script.
+"""
+
+__author__ = 'mlinck@google.com (Michael Linck)'
+
+import fileinput
+import optparse
+import os.path
+import shutil
+import sys
+import uuid
+
+# A list of all platforms that should have make.cmd.
+WINDOWS_BUILD_PLATFORMS = ['cygwin', 'win32']
+
+# Tags that will be replaced in our the new project's source files.
+PROJECT_NAME_TAG = '<PROJECT_NAME>'
+PROJECT_NAME_CAMEL_CASE_TAG = '<ProjectName>'
+SDK_ROOT_TAG = '<NACL_SDK_ROOT>'
+NACL_PLATFORM_TAG = '<NACL_PLATFORM>'
+VS_PROJECT_UUID_TAG = '<VS_PROJECT_UUID>'
+VS_SOURCE_UUID_TAG = '<VS_SOURCE_UUID>'
+VS_HEADER_UUID_TAG = '<VS_HEADER_UUID>'
+VS_RESOURCE_UUID_TAG = '<VS_RESOURCE_UUID>'
+
+# This string is the part of the file name that will be replaced.
+PROJECT_FILE_NAME = 'project_file'
+
+# Lists of source files that will be used for the new project.
+COMMON_PROJECT_FILES = ['scons']
+C_SOURCE_FILES = ['build.scons', '%s.c' % PROJECT_FILE_NAME]
+CC_SOURCE_FILES = ['build.scons', '%s.cc' % PROJECT_FILE_NAME]
+HTML_FILES = ['%s.html' % PROJECT_FILE_NAME]
+VS_FILES = ['%s.sln' % PROJECT_FILE_NAME, '%s.vcproj' % PROJECT_FILE_NAME]
+
+# Error needs to be a class, since we 'raise' it in several places.
+class Error(Exception):
+ pass
+
+
+def GetCamelCaseName(lower_case_name):
+ """Converts an underscore name to a camel case name.
+
+ Args:
+ lower_case_name: The name in underscore-delimited lower case format.
+
+ Returns:
+ The name in camel case format.
+ """
+ camel_case_name = ''
+ name_parts = lower_case_name.split('_')
+ for part in name_parts:
+ if part:
+ camel_case_name += part.capitalize()
+ return camel_case_name
+
+
+def GetCodeDirectory(is_c_project, project_templates_dir):
+ """Decides what directory to pull source code from.
+
+ Args:
+ is_c_project: A boolean indicating whether this project is in C or not.
+ project_templates_dir: The path to the project_templates directory.
+
+ Returns:
+ The code directory for the given project type.
+ """
+ stub_directory = ''
+ if is_c_project:
+ stub_directory = os.path.join(project_templates_dir, 'c')
+ else:
+ stub_directory = os.path.join(project_templates_dir, 'cc')
+ return stub_directory
+
+
+def GetCodeSourceFiles(is_c_project):
+ """Decides what source files to pull into the stub.
+
+ Args:
+ is_c_project: A boolean indicating whether this project is in C or not.
+
+ Returns:
+ The files that are specific to the requested type of project and live in its
+ directory.
+ """
+ project_files = []
+ if is_c_project:
+ project_files = C_SOURCE_FILES
+ else:
+ project_files = CC_SOURCE_FILES
+ return project_files
+
+
+def GetCommonSourceFiles():
+ """Gives list of files needed by all project types.
+
+ Returns:
+ The files C and C++ projects have in common. These are the files that live
+ in the top level project_templates directory.
+ """
+ project_files = COMMON_PROJECT_FILES
+ if sys.platform in WINDOWS_BUILD_PLATFORMS:
+ project_files.extend(['scons.bat'])
+ return project_files
+
+
+def GetVsDirectory(project_templates_dir):
+ """Decides what directory to pull Visual Studio stub from.
+
+ Args:
+ project_templates_dir: The path to the project_templates directory.
+
+ Returns:
+ The directory where the HTML stub is to be found.
+ """
+ return os.path.join(project_templates_dir, 'vs')
+
+
+def GetVsProjectFiles():
+ """Gives VisualStudio files to be included in project stub.
+
+ Returns:
+ The VisualStudio files needed for the project.
+ """
+ return VS_FILES
+
+
+def GetHTMLDirectory(project_templates_dir):
+ """Decides what directory to pull HTML stub from.
+
+ Args:
+ project_templates_dir: The path to the project_templates directory.
+
+ Returns:
+ The directory where the HTML stub is to be found.
+ """
+ return os.path.join(project_templates_dir, 'html')
+
+
+def GetHTMLSourceFiles():
+ """Gives HTML files to be included in project stub.
+
+ Returns:
+ The HTML files needed for the project.
+ """
+ return HTML_FILES
+
+
+def GetTargetFileName(source_file_name, project_name):
+ """Converts a source file name into a project file name.
+
+ Args:
+ source_file_name: The name of a file that is to be included in the project
+ stub, as it appears at the source location.
+ project_name: The name of the project that is being generated.
+
+ Returns:
+ The target file name for a given source file. All project files are run
+ through this filter and it modifies them as needed.
+ """
+ target_file_name = ''
+ if source_file_name.startswith(PROJECT_FILE_NAME):
+ target_file_name = source_file_name.replace(PROJECT_FILE_NAME,
+ project_name)
+ else:
+ target_file_name = source_file_name
+ return target_file_name
+
+
+def GetDefaultProjectDir():
+ """Determines the default project directory.
+
+ The default directory root for new projects is called 'nacl_projects' under
+ the user's home directory. There are two ways to override this: you can set
+ the NACL_PROJECT_ROOT environment variable, or use the --directory option.
+
+ Returns:
+ An os-specific path to the default project directory, which is called
+ 'nacl_projects' under the user's home directory.
+ """
+ return os.getenv('NACL_PROJECT_ROOT',
+ os.path.join(os.path.expanduser('~'), 'nacl_projects'))
+
+
+def ParseArguments(argv):
+ """Parses the arguments provided by the user.
+
+ Parses the command line options and makes sure the script errors when it is
+ supposed to.
+
+ Args:
+ argv: The argument array.
+
+ Returns:
+ The options structure that represents the arguments after they have been
+ parsed.
+ """
+ parser = optparse.OptionParser()
+ parser.add_option(
+ '-n', '--name', dest='project_name',
+ default='',
+ help=('Required: the name of the new project to be stubbed out.\n'
+ 'Please use lower case names with underscore, i.e. hello_world.'))
+ parser.add_option(
+ '-d', '--directory', dest='project_directory',
+ default=GetDefaultProjectDir(),
+ help=('Optional: If set, the new project will be created under this '
+ 'directory and the directory created if necessary.'))
+ parser.add_option(
+ '-c', action='store_true', dest='is_c_project',
+ default=False,
+ help=('Optional: If set, this will generate a C project. Default '
+ 'is C++.'))
+ parser.add_option(
+ '-p', '--nacl-platform', dest='nacl_platform',
+ default='pepper_17',
+ help=('Optional: if set, the new project will target the given nacl\n'
+ 'platform. Default is the most current platform. e.g. pepper_17'))
+ parser.add_option(
+ '--vsproj', action='store_true', dest='is_vs_project',
+ default=False,
+ help=('Optional: If set, generate Visual Studio project files.'))
+ result = parser.parse_args(argv)
+ options = result[0]
+ args = result[1]
+ #options, args) = parser.parse_args(argv)
+ if args:
+ parser.print_help()
+ sys.exit(1)
+ elif not options.project_name.islower():
+ print('--name missing or in incorrect format. Please use -h for '
+ 'instructions.')
+ sys.exit(1)
+ return options
+
+
+class ProjectInitializer(object):
+ """Maintains the state of the project that is being created."""
+
+ def __init__(self, is_c_project, is_vs_project, project_name,
+ project_location, nacl_platform, project_templates_dir,
+ os_resource=os):
+ """Initializes all the fields that are known after parsing the parameters.
+
+ Args:
+ is_c_project: A boolean indicating whether this project is in C or not.
+ is_vs_project: A boolean indicating whether this project has Visual
+ Studio support.
+ project_name: A string containing the name of the project to be created.
+ project_location: A path indicating where the new project is to be placed.
+ project_templates_dir: The path to the project_templates directory.
+ os_resource: A resource to be used as os. Provided for unit testing.
+ """
+ self.__is_c_project = is_c_project
+ self.__is_vs_project = is_vs_project
+ self.__project_files = []
+ self.__project_name = project_name
+ self.__project_location = project_location
+ self.__nacl_platform = nacl_platform
+ self.__project_templates_dir = project_templates_dir
+ # System resources are properties so mocks can be inserted.
+ self.__fileinput = fileinput
+ self.__os = os_resource
+ self.__shutil = shutil
+ self.__sys = sys
+ self.__CreateProjectDirectory()
+
+ def CopyAndRenameFiles(self, source_dir, file_names):
+ """Places files in the new project's directory and renames them as needed.
+
+ Copies the given files from the given source directory into the new
+ project's directory, renaming them as necessary. Each file that is created
+ in the project directory is also added to self.__project_files.
+
+ Args:
+ source_dir: A path indicating where the files are to be copied from.
+ file_names: The list of files that is to be copied out of source_dir.
+ """
+ for source_file_name in file_names:
+ target_file_name = GetTargetFileName(source_file_name,
+ self.__project_name)
+ copy_source_file = self.os.path.join(source_dir, source_file_name)
+ copy_target_file = self.os.path.join(self.__project_dir, target_file_name)
+ self.shutil.copy(copy_source_file, copy_target_file)
+ self.__project_files += [copy_target_file]
+
+ def __CreateProjectDirectory(self):
+ """Creates the project's directory and any parents as necessary."""
+ self.__project_dir = self.os.path.join(self.__project_location,
+ self.__project_name)
+ if self.os.path.exists(self.__project_dir):
+ raise Error("Error: directory '%s' already exists" % self.__project_dir)
+ self.os.makedirs(self.__project_dir)
+
+ def PrepareDirectoryContent(self):
+ """Prepares the directory for the new project.
+
+ This function's job is to know what directories need to be used and what
+ files need to be copied and renamed. It uses several tiny helper functions
+ to do this.
+ There are three locations from which files are copied to create a project.
+ That number may change in the future.
+ """
+ code_source_dir = GetCodeDirectory(self.__is_c_project,
+ self.__project_templates_dir)
+ code_source_files = GetCodeSourceFiles(self.__is_c_project)
+ html_source_dir = GetHTMLDirectory(self.__project_templates_dir)
+ html_source_files = GetHTMLSourceFiles()
+ common_source_files = GetCommonSourceFiles()
+ self.CopyAndRenameFiles(code_source_dir, code_source_files)
+ self.CopyAndRenameFiles(html_source_dir, html_source_files)
+ self.CopyAndRenameFiles(self.__project_templates_dir,
+ common_source_files)
+ if self.__is_vs_project:
+ vs_source_dir = GetVsDirectory(self.__project_templates_dir)
+ vs_files = GetVsProjectFiles()
+ self.CopyAndRenameFiles(vs_source_dir, vs_files)
+ print('init_project has copied the appropriate files to: %s' %
+ self.__project_dir)
+
+ def PrepareFileContent(self):
+ """Changes contents of files in the new project as needed.
+
+ Goes through each file in the project that is being created and replaces
+ contents as necessary.
+ """
+ camel_case_name = GetCamelCaseName(self.__project_name)
+ sdk_root_dir = os.getenv('NACL_SDK_ROOT', None)
+ if not sdk_root_dir:
+ raise Error("Error: NACL_SDK_ROOT is not set")
+ sdk_root_dir = self.os.path.abspath(sdk_root_dir)
+ if self.__is_vs_project:
+ project_uuid = str(uuid.uuid4()).upper()
+ vs_source_uuid = str(uuid.uuid4()).upper()
+ vs_header_uuid = str(uuid.uuid4()).upper()
+ vs_resource_uuid = str(uuid.uuid4()).upper()
+ for project_file in self.__project_files:
+ self.ReplaceInFile(project_file, PROJECT_NAME_TAG, self.__project_name)
+ self.ReplaceInFile(project_file,
+ PROJECT_NAME_CAMEL_CASE_TAG,
+ camel_case_name)
+ self.ReplaceInFile(project_file, SDK_ROOT_TAG, sdk_root_dir)
+ self.ReplaceInFile(project_file, NACL_PLATFORM_TAG, self.__nacl_platform)
+ if self.__is_vs_project:
+ self.ReplaceInFile(project_file, VS_PROJECT_UUID_TAG, project_uuid)
+ self.ReplaceInFile(project_file, VS_SOURCE_UUID_TAG, vs_source_uuid)
+ self.ReplaceInFile(project_file, VS_HEADER_UUID_TAG, vs_header_uuid)
+ self.ReplaceInFile(project_file, VS_RESOURCE_UUID_TAG, vs_resource_uuid)
+
+ def ReplaceInFile(self, file_path, old_text, new_text):
+ """Replaces a given string with another in a given file.
+
+ Args:
+ file_path: The path to the file that is to be modified.
+ old_text: The text that is to be removed.
+ new_text: The text that is to be added in place of old_text.
+ """
+ for line in self.fileinput.input(file_path, inplace=1, mode='U'):
+ self.sys.stdout.write(line.replace(old_text, new_text))
+
+ # The following properties exist to make unit testing possible.
+
+ def _GetFileinput(self):
+ """Accessor for Fileinput property."""
+ return self.__fileinput
+
+ def __GetFileinput(self):
+ """Indirect Accessor for _GetFileinput."""
+ return self._GetFileinput()
+
+ def _SetFileinput(self, fileinput_resource):
+ """Accessor for Fileinput property."""
+ self.__fileinput = fileinput_resource
+
+ def __SetFileinput(self, fileinput_resource):
+ """Indirect Accessor for _SetFileinput."""
+ return self._SetFileinput(fileinput_resource)
+
+ fileinput = property(
+ __GetFileinput, __SetFileinput,
+ doc="""Gets and sets the resource to use as fileinput.""")
+
+ def _GetOS(self):
+ """Accessor for os property."""
+ return self.__os
+
+ def __GetOS(self):
+ """Indirect Accessor for _GetOS."""
+ return self._GetOS()
+
+ def _SetOS(self, os_resource):
+ """Accessor for os property."""
+ self.__os = os_resource
+
+ def __SetOS(self, os_resource):
+ """Indirect Accessor for _SetOS."""
+ return self._SetOS(os_resource)
+
+ os = property(__GetOS, __SetOS,
+ doc="""Gets and sets the resource to use as os.""")
+
+ def _GetShutil(self):
+ """Accessor for shutil property."""
+ return self.__shutil
+
+ def __GetShutil(self):
+ """Indirect Accessor for _GetShutil."""
+ return self._GetShutil()
+
+ def _SetShutil(self, shutil_resource):
+ """Accessor for shutil property."""
+ self.__shutil = shutil_resource
+
+ def __SetShutil(self, shutil_resource):
+ """Indirect Accessor for _SetShutil."""
+ return self._SetShutil(shutil_resource)
+
+ shutil = property(__GetShutil, __SetShutil,
+ doc="""Gets and sets the resource to use as shutil.""")
+
+ def _GetSys(self):
+ """Accessor for sys property."""
+ return self.__sys
+
+ def __GetSys(self):
+ """Indirect Accessor for _GetSys."""
+ return self._GetSys()
+
+ def _SetSys(self, sys_resource):
+ """Accessor for sys property."""
+ self.__sys = sys_resource
+
+ def __SetSys(self, sys_resource):
+ """Indirect Accessor for _SetSys."""
+ return self._SetSys(sys_resource)
+
+ sys = property(__GetSys, __SetSys,
+ doc="""Gets and sets the resource to use as sys.""")
+
+
+def main(argv):
+ """Prepares the new project.
+
+ Args:
+ argv: The arguments passed to the script by the shell.
+ """
+ print 'init_project parsing its arguments.'
+ script_dir = os.path.abspath(os.path.dirname(__file__))
+ options = ParseArguments(argv)
+ print 'init_project is preparing your project.'
+ # Check to see if the project is going into the SDK bundle. If so, issue a
+ # warning.
+ sdk_root_dir = os.getenv('NACL_SDK_ROOT', None)
+ if sdk_root_dir:
+ if os.path.normpath(options.project_directory).count(
+ os.path.normpath(sdk_root_dir)) > 0:
+ print('WARNING: It looks like you are creating projects in the NaCl SDK '
+ 'directory %s.\nThese might be removed at the next update.' %
+ sdk_root_dir)
+ project_initializer = ProjectInitializer(options.is_c_project,
+ options.is_vs_project,
+ options.project_name,
+ options.project_directory,
+ options.nacl_platform,
+ script_dir)
+ project_initializer.PrepareDirectoryContent()
+ project_initializer.PrepareFileContent()
+ return 0
+
+
+if __name__ == '__main__':
+ try:
+ sys.exit(main(sys.argv[1:]))
+ except Exception as error:
+ print error
+ sys.exit(1)
diff --git a/native_client_sdk/src/project_templates/init_project_test.py b/native_client_sdk/src/project_templates/init_project_test.py
new file mode 100755
index 0000000..681916f
--- /dev/null
+++ b/native_client_sdk/src/project_templates/init_project_test.py
@@ -0,0 +1,256 @@
+#!/usr/bin/python2.6
+#
+# Copyright (c) 2011 The Native Client Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Unit tests for init_project.py."""
+
+__author__ = 'mlinck@google.com (Michael Linck)'
+
+import fileinput
+import os
+import shutil
+import sys
+import unittest
+import mox
+import init_project
+
+
+def TestMock(file_path, open_func):
+ temp_file = open_func(file_path)
+ temp_file.close()
+
+
+class TestGlobalFunctions(unittest.TestCase):
+ """Class for test cases to cover globally declared helper functions."""
+
+ def testGetCamelCaseName(self):
+ output = init_project.GetCamelCaseName('camel_case_name')
+ self.assertEqual(output, 'CamelCaseName')
+ output = init_project.GetCamelCaseName('print_42')
+ self.assertEqual(output, 'Print42')
+
+ def testGetCodeDirectory(self):
+ output = init_project.GetCodeDirectory(True, '')
+ self.assertEqual(output, 'c')
+ output = init_project.GetCodeDirectory(False, '')
+ self.assertEqual(output, 'cc')
+ output = init_project.GetCodeDirectory(True, 'test')
+ self.assertEqual(output, 'test/c')
+ output = init_project.GetCodeDirectory(False, 'test')
+ self.assertEqual(output, 'test/cc')
+
+ def testGetCodeSourceFiles(self):
+ output = init_project.GetCodeSourceFiles(False)
+ self.assertEqual(output, init_project.CC_SOURCE_FILES)
+ output = init_project.GetCodeSourceFiles(True)
+ self.assertEqual(output, init_project.C_SOURCE_FILES)
+
+ def testGetCommonSourceFiles(self):
+ output = init_project.GetCommonSourceFiles()
+ expected_output_linux = init_project.COMMON_PROJECT_FILES
+ expected_output_windows = init_project.COMMON_PROJECT_FILES
+ expected_output_windows.extend(['scons.bat'])
+ linux_match = (output == expected_output_linux)
+ windows_match = (output == expected_output_windows)
+ passed = (linux_match | windows_match)
+ self.assertTrue(passed)
+
+ def testGetHTMLDirectory(self):
+ output = init_project.GetHTMLDirectory('')
+ self.assertEqual(output, 'html')
+ output = init_project.GetHTMLDirectory('test')
+ self.assertEqual(output, 'test/html')
+
+ def testGetHTMLSourceFiles(self):
+ output = init_project.GetHTMLSourceFiles()
+ self.assertEqual(output, init_project.HTML_FILES)
+
+ def testGetTargetFileName(self):
+ output = init_project.GetTargetFileName('project_file.cc', 'bonkers')
+ self.assertEqual(output, 'bonkers.cc')
+ output = init_project.GetTargetFileName('constant.html', 'bonkers')
+ self.assertEqual(output, 'constant.html')
+
+ def testParseArguments(self):
+ output = init_project.ParseArguments(['-n', 'test_name', '-d', 'test/dir'])
+ self.assertEqual(output.is_c_project, False)
+ self.assertEqual(output.project_name, 'test_name')
+ self.assertEqual(output.project_directory, 'test/dir')
+ output = init_project.ParseArguments(['-n', 'test_name_2', '-c'])
+ self.assertEqual(output.is_c_project, True)
+ self.assertEqual(output.project_name, 'test_name_2')
+ self.assertEqual(output.project_directory,
+ init_project.GetDefaultProjectDir())
+
+
+class TestProjectInitializer(unittest.TestCase):
+ """Class for test cases to cover public interface of ProjectInitializer."""
+
+ def setUp(self):
+ self.script_dir = os.path.abspath(os.path.dirname(__file__))
+ self.nacl_src_dir = os.getenv('NACL_SDK_ROOT', None)
+ self.mock_factory = mox.Mox()
+ # This mock is only valid for initialization and will be overwritten
+ # after ward by self.os_mock.
+ init_path_mock = self.mock_factory.CreateMock(os.path)
+ init_path_mock.join('test/dir', 'test_project').AndReturn(
+ 'test/dir/test_project')
+ init_path_mock.exists('test/dir/test_project').AndReturn(False)
+ init_os_mock = self.mock_factory.CreateMock(os)
+ init_os_mock.path = init_path_mock
+ init_os_mock.makedirs('test/dir/test_project')
+ self.mock_factory.ReplayAll()
+ self.test_subject = init_project.ProjectInitializer(
+ # True => is C project, False => is vs project
+ True, False, 'test_project', 'test/dir', 'pepper_14', self.script_dir,
+ init_os_mock)
+ self.mock_factory.VerifyAll()
+ self.InitializeResourceMocks()
+
+ def InitializeResourceMocks(self):
+ """Can be called multiple times if multiple functions need to be tested."""
+ self.fileinput_mock = self.mock_factory.CreateMock(fileinput)
+ self.test_subject.fileinput = self.fileinput_mock
+ self.os_mock = self.mock_factory.CreateMock(os)
+ self.test_subject.os = self.os_mock
+ self.shutil_mock = self.mock_factory.CreateMock(shutil)
+ self.test_subject.shutil = self.shutil_mock
+ self.sys_mock = self.mock_factory.CreateMock(sys)
+ self.test_subject.sys = self.sys_mock
+
+ def testCopyAndRenameFiles(self):
+ self.shutil_mock.copy('source/dir/normal_name.txt',
+ 'test/dir/test_project/normal_name.txt')
+ self.shutil_mock.copy('source/dir/project_file.txt',
+ 'test/dir/test_project/test_project.txt')
+ self.os_mock.path = os.path
+ self.mock_factory.ReplayAll()
+ self.test_subject.CopyAndRenameFiles(
+ 'source/dir', ['normal_name.txt', 'project_file.txt'])
+ self.mock_factory.VerifyAll()
+
+ def testPrepareDirectoryContent(self):
+ self.shutil_mock.copy(
+ '%s/c/build.scons' % self.script_dir,
+ 'test/dir/test_project/build.scons')
+ self.shutil_mock.copy(
+ '%s/c/project_file.c' % self.script_dir,
+ 'test/dir/test_project/test_project.c')
+ self.shutil_mock.copy(
+ '%s/html/project_file.html' % self.script_dir,
+ 'test/dir/test_project/test_project.html')
+ self.shutil_mock.copy(
+ '%s/scons' % self.script_dir,
+ 'test/dir/test_project/scons')
+ self.shutil_mock.copy(
+ '%s/scons.bat' % self.script_dir,
+ 'test/dir/test_project/scons.bat')
+ self.os_mock.path = os.path
+ self.mock_factory.ReplayAll()
+ self.test_subject.PrepareDirectoryContent()
+ self.mock_factory.VerifyAll()
+
+ def testPrepareFileContent(self):
+ self.testCopyAndRenameFiles()
+ # We need a new set of resource mocks since the old ones have already been
+ # used.
+ self.InitializeResourceMocks()
+ path_mock = self.mock_factory.CreateMock(os.path)
+ stdout_mock = self.mock_factory.CreateMock(sys.stdout)
+ self.os_mock.path = path_mock
+ path_mock.abspath(self.nacl_src_dir).AndReturn(self.nacl_src_dir)
+ self.fileinput_mock.input(
+ 'test/dir/test_project/normal_name.txt',
+ inplace=1, mode='U').AndReturn(
+ ['A line with <PROJECT_NAME>.',
+ 'A line with <ProjectName>.',
+ 'A line with <NACL_SDK_ROOT>.',
+ 'A line with <NACL_PLATFORM>.'])
+ stdout_mock.write('A line with test_project.')
+ stdout_mock.write('A line with <ProjectName>.')
+ stdout_mock.write('A line with <NACL_SDK_ROOT>.')
+ stdout_mock.write('A line with <NACL_PLATFORM>.')
+ self.fileinput_mock.input(
+ 'test/dir/test_project/normal_name.txt',
+ inplace=1, mode='U').AndReturn(
+ ['A line with test_project.',
+ 'A line with <ProjectName>.',
+ 'A line with <NACL_SDK_ROOT>.',
+ 'A line with <NACL_PLATFORM>.'])
+ stdout_mock.write('A line with test_project.')
+ stdout_mock.write('A line with TestProject.')
+ stdout_mock.write('A line with <NACL_SDK_ROOT>.')
+ stdout_mock.write('A line with <NACL_PLATFORM>.')
+ self.fileinput_mock.input(
+ 'test/dir/test_project/normal_name.txt',
+ inplace=1, mode='U').AndReturn(
+ ['A line with test_project.',
+ 'A line with TestProject.',
+ 'A line with <NACL_SDK_ROOT>.',
+ 'A line with <NACL_PLATFORM>.'])
+ stdout_mock.write('A line with test_project.')
+ stdout_mock.write('A line with TestProject.')
+ stdout_mock.write('A line with %s.' % self.nacl_src_dir)
+ stdout_mock.write('A line with <NACL_PLATFORM>.')
+ self.fileinput_mock.input(
+ 'test/dir/test_project/normal_name.txt',
+ inplace=1, mode='U').AndReturn(
+ ['A line with test_project.',
+ 'A line with TestProject.',
+ 'A line with some/dir.',
+ 'A line with <NACL_PLATFORM>.'])
+ stdout_mock.write('A line with test_project.')
+ stdout_mock.write('A line with TestProject.')
+ stdout_mock.write('A line with some/dir.')
+ stdout_mock.write('A line with pepper_14.')
+ # One multi-line file with different replacements has already been mocked
+ # so we make this next test simpler.
+ self.fileinput_mock.input(
+ 'test/dir/test_project/test_project.txt',
+ inplace=1, mode='U').AndReturn(['A line with no replaceable text.'])
+ stdout_mock.write('A line with no replaceable text.')
+ self.fileinput_mock.input(
+ 'test/dir/test_project/test_project.txt',
+ inplace=1, mode='U').AndReturn(['A line with no replaceable text.'])
+ stdout_mock.write('A line with no replaceable text.')
+ self.fileinput_mock.input(
+ 'test/dir/test_project/test_project.txt',
+ inplace=1, mode='U').AndReturn(['A line with no replaceable text.'])
+ stdout_mock.write('A line with no replaceable text.')
+ self.fileinput_mock.input(
+ 'test/dir/test_project/test_project.txt',
+ inplace=1, mode='U').AndReturn(['A line with no replaceable text.'])
+ stdout_mock.write('A line with no replaceable text.')
+ self.sys_mock.stdout = stdout_mock
+ self.mock_factory.ReplayAll()
+ self.test_subject.PrepareFileContent()
+ self.mock_factory.VerifyAll()
+
+ def testReplaceInFile(self):
+ self.fileinput_mock.input('test/path', inplace=1, mode='U').AndReturn(
+ ['A sentence replace_me.'])
+ stdout_mock = self.mock_factory.CreateMock(sys.stdout)
+ stdout_mock.write('A sentence with_this.')
+ self.sys_mock.stdout = stdout_mock
+ self.mock_factory.ReplayAll()
+ self.test_subject.ReplaceInFile('test/path', 'replace_me', 'with_this')
+ self.mock_factory.VerifyAll()
+
+
+def RunTests():
+ # It's possible to do this with one suite instead of two, but then it's
+ # harder to read the test output.
+ return_value = 1
+ suite_one = unittest.TestLoader().loadTestsFromTestCase(TestGlobalFunctions)
+ result_one = unittest.TextTestRunner(verbosity=2).run(suite_one)
+ suite_two = unittest.TestLoader().loadTestsFromTestCase(
+ TestProjectInitializer)
+ result_two = unittest.TextTestRunner(verbosity=2).run(suite_two)
+ if result_one.wasSuccessful() and result_two.wasSuccessful():
+ return_value = 0
+ return return_value
+
+if __name__ == '__main__':
+ sys.exit(RunTests())
diff --git a/native_client_sdk/src/project_templates/scons b/native_client_sdk/src/project_templates/scons
new file mode 100755
index 0000000..2b7e0d3
--- /dev/null
+++ b/native_client_sdk/src/project_templates/scons
@@ -0,0 +1,32 @@
+#!/bin/bash
+#
+# Copyright (c) 2011 The Native Client Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+readonly SCRIPT_DIR="$(dirname "$0")"
+readonly SCRIPT_DIR_ABS="$(cd "${SCRIPT_DIR}" ; pwd -P)"
+
+export NACL_SDK_ROOT=<NACL_SDK_ROOT>
+# NACL_TARGET_PLATFORM is really the name of a folder with the base dir -
+# usually NACL_SDK_ROOT - within which the toolchain for the target platform
+# are found.
+# Replace the platform with the name of your target platform. For example, to
+# build applications that target the pepper_17 API, set
+# NACL_TARGET_PLATFORM="pepper_17"
+export NACL_TARGET_PLATFORM="<NACL_PLATFORM>"
+
+readonly NACL_PLATFORM_DIR="${NACL_SDK_ROOT}/${NACL_TARGET_PLATFORM}"
+readonly BASE_SCRIPT="${NACL_PLATFORM_DIR}/third_party/scons-2.0.1/script/scons"
+
+export SCONS_LIB_DIR="${NACL_PLATFORM_DIR}/third_party/scons-2.0.1/engine"
+export PYTHONPATH="${NACL_PLATFORM_DIR}/third_party/scons-2.0.1/engine"
+# We have to do this because scons overrides PYTHONPATH and does not preserve
+# what is provided by the OS. The custom variable name won't be overwritten.
+export PYMOX="${NACL_PLATFORM_DIR}/third_party/pymox"
+
+"${BASE_SCRIPT}" --file=build.scons \
+ --site-dir="${NACL_PLATFORM_DIR}/build_tools/nacl_sdk_scons" \
+ $*
+
diff --git a/native_client_sdk/src/project_templates/scons.bat b/native_client_sdk/src/project_templates/scons.bat
new file mode 100755
index 0000000..f487e28
--- /dev/null
+++ b/native_client_sdk/src/project_templates/scons.bat
@@ -0,0 +1,31 @@
+@echo off
+
+:: Copyright (c) 2011 The Native Client Authors. All rights reserved.
+:: Use of this source code is governed by a BSD-style license that can be
+:: found in the LICENSE file.
+
+setlocal
+
+set NACL_SDK_ROOT=<NACL_SDK_ROOT>
+:: NACL_TARGET_PLATFORM is really the name of a folder with the base dir -
+:: usually NACL_SDK_ROOT - within which the toolchain for the target platform
+:: are found.
+:: Replace the platform with the name of your target platform. For example, to
+:: build applications that target the pepper_17 API, set
+:: NACL_TARGET_PLATFORM=pepper_17
+set NACL_TARGET_PLATFORM=<NACL_PLATFORM>
+
+set NACL_PLATFORM_DIR=%NACL_SDK_ROOT%\%NACL_TARGET_PLATFORM%
+
+:: Set the PYTHONPATH and SCONS_LIB_DIR so we can import SCons modules
+set SCONS_LIB_DIR=%NACL_PLATFORM_DIR%\third_party\scons-2.0.1\engine
+set PYTHONPATH=%NACL_PLATFORM_DIR%\third_party\scons-2.0.1\engine
+
+:: We have to do this because scons overrides PYTHONPATH and does not preserve
+:: what is provided by the OS. The custom variable name won't be overwritten.
+set PYMOX=%NACL_PLATFORM_DIR%\third_party\pymox
+
+:: Run the included copy of scons.
+python -O -OO "%NACL_PLATFORM_DIR%\third_party\scons-2.0.1\script\scons" ^
+--file=build.scons ^
+--site-dir="%NACL_PLATFORM_DIR%\build_tools\nacl_sdk_scons" %*
diff --git a/native_client_sdk/src/project_templates/test.scons b/native_client_sdk/src/project_templates/test.scons
new file mode 100644
index 0000000..c00e2a8
--- /dev/null
+++ b/native_client_sdk/src/project_templates/test.scons
@@ -0,0 +1,26 @@
+#! -*- python -*-
+#
+# Copyright (c) 2010 The Native Client Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Build file for tests of init_project interface.
+
+Adapted from scons documentation: http://www.scons.org/wiki/UnitTests
+
+RunUnitTests(): Runs a comment and uses the return code to determine success.
+"""
+
+__author__ = 'mlinck@google.com (Michael Linck)'
+
+import os
+import sys
+
+Import('env')
+
+#TODO(mlinck) Enable this test again when it works on Windows
+cmd = env.CreatePythonUnitTest(filename='init_project_test.py',
+ dependencies=['init_project.py'],
+ disabled=env['IS_WINDOWS'])
+
+env.AddNodeToTestSuite(cmd, ['bot'], 'run_init_project_test', 'small')
diff --git a/native_client_sdk/src/project_templates/vs/project_file.sln b/native_client_sdk/src/project_templates/vs/project_file.sln
new file mode 100644
index 0000000..05f5169
--- /dev/null
+++ b/native_client_sdk/src/project_templates/vs/project_file.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "<PROJECT_NAME>", "<PROJECT_NAME>.vcproj", "{<VS_PROJECT_UUID>}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {<VS_PROJECT_UUID>}.Debug|Win32.ActiveCfg = Debug|Win32
+ {<VS_PROJECT_UUID>}.Debug|Win32.Build.0 = Debug|Win32
+ {<VS_PROJECT_UUID>}.Release|Win32.ActiveCfg = Release|Win32
+ {<VS_PROJECT_UUID>}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/native_client_sdk/src/project_templates/vs/project_file.vcproj b/native_client_sdk/src/project_templates/vs/project_file.vcproj
new file mode 100644
index 0000000..d2b0f25
--- /dev/null
+++ b/native_client_sdk/src/project_templates/vs/project_file.vcproj
@@ -0,0 +1,184 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="<PROJECT_NAME>"
+ ProjectGUID="{<VS_PROJECT_UUID>"
+ RootNamespace="<PROJECT_NAME>"
+ Keyword="MakeFileProj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="0"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ BuildCommandLine="$(NACL_SDK_ROOT)\<NACL_PLATFORM>\examples\scons"
+ ReBuildCommandLine="$(NACL_SDK_ROOT)\<NACL_PLATFORM>\examples\scons -c &amp;&amp; $(NACL_SDK_ROOT)\<NACL_PLATFORM>\examples\scons"
+ CleanCommandLine="$(NACL_SDK_ROOT)\<NACL_PLATFORM>\examples\scons -c"
+ Output="<PROJECT_NAME>_x86_64_dbg.nexe"
+ PreprocessorDefinitions="WIN32;_DEBUG"
+ IncludeSearchPath=""
+ ForcedIncludes=""
+ AssemblySearchPath=""
+ ForcedUsingAssemblies=""
+ CompileAsManaged=""
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="0"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ BuildCommandLine=""
+ ReBuildCommandLine=""
+ CleanCommandLine=""
+ Output="<PROJECT_NAME>.exe"
+ PreprocessorDefinitions="WIN32;NDEBUG"
+ IncludeSearchPath=""
+ ForcedIncludes=""
+ AssemblySearchPath=""
+ ForcedUsingAssemblies=""
+ CompileAsManaged=""
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{<VS_SOURCE_UUID>}"
+ >
+ <File
+ RelativePath=".\build.scons"
+ >
+ </File>
+ <File
+ RelativePath=".\<PROJECT_NAME>.cc"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{<VS_HEADER_UUID>}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{<VS_RESOURCE_UUID>}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="<PROJECT_NAME>"
+ ProjectGUID="{<VS_PROJECT_UUID>"
+ RootNamespace="<PROJECT_NAME>"
+ Keyword="MakeFileProj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="0"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ BuildCommandLine="$(NACL_SDK_ROOT)\<NACL_PLATFORM>\examples\scons"
+ ReBuildCommandLine="$(NACL_SDK_ROOT)\<NACL_PLATFORM>\examples\scons -c &amp;&amp; $(NACL_SDK_ROOT)\<NACL_PLATFORM>\examples\scons"
+ CleanCommandLine="$(NACL_SDK_ROOT)\<NACL_PLATFORM>\examples\scons -c"
+ Output="<PROJECT_NAME>_x86_64_dbg.nexe"
+ PreprocessorDefinitions="WIN32;_DEBUG"
+ IncludeSearchPath=""
+ ForcedIncludes=""
+ AssemblySearchPath=""
+ ForcedUsingAssemblies=""
+ CompileAsManaged=""
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="0"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ BuildCommandLine=""
+ ReBuildCommandLine=""
+ CleanCommandLine=""
+ Output="<PROJECT_NAME>.exe"
+ PreprocessorDefinitions="WIN32;NDEBUG"
+ IncludeSearchPath=""
+ ForcedIncludes=""
+ AssemblySearchPath=""
+ ForcedUsingAssemblies=""
+ CompileAsManaged=""
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{<VS_SOURCE_UUID>}"
+ >
+ <File
+ RelativePath=".\build.scons"
+ >
+ </File>
+ <File
+ RelativePath=".\<PROJECT_NAME>.cc"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{<VS_HEADER_UUID>}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{<VS_RESOURCE_UUID>}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>