diff options
author | binji@chromium.org <binji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-07 00:02:13 +0000 |
---|---|---|
committer | binji@chromium.org <binji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-07 00:02:13 +0000 |
commit | 531e2a2678f1969150c0019e07e34825e2fe4bd9 (patch) | |
tree | e6ad15ce96663659fa12f49bc972e397c8108a4a /native_client_sdk | |
parent | 37f6454a0c30fce52459105db2f837da4f51e4d3 (diff) | |
download | chromium_src-531e2a2678f1969150c0019e07e34825e2fe4bd9.zip chromium_src-531e2a2678f1969150c0019e07e34825e2fe4bd9.tar.gz chromium_src-531e2a2678f1969150c0019e07e34825e2fe4bd9.tar.bz2 |
[NaCl SDK] nacl-mounts example.
BUG=122229
NOTRY=true
Review URL: https://chromiumcodereview.appspot.com/11190066
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@166309 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'native_client_sdk')
9 files changed, 750 insertions, 2 deletions
diff --git a/native_client_sdk/src/build_tools/build_sdk.py b/native_client_sdk/src/build_tools/build_sdk.py index e00b51e..9fd82f8 100755 --- a/native_client_sdk/src/build_tools/build_sdk.py +++ b/native_client_sdk/src/build_tools/build_sdk.py @@ -566,6 +566,7 @@ EXAMPLE_LIST = [ 'fullscreen_tumbler', 'gamepad', 'geturl', + 'hello_nacl_mounts', 'hello_world_interactive', 'hello_world', 'hello_world_gles', diff --git a/native_client_sdk/src/examples/hello_nacl_mounts/example.dsc b/native_client_sdk/src/examples/hello_nacl_mounts/example.dsc new file mode 100644 index 0000000..41e5587 --- /dev/null +++ b/native_client_sdk/src/examples/hello_nacl_mounts/example.dsc @@ -0,0 +1,17 @@ +{ + 'TOOLS': ['newlib', 'glibc', 'win'], + 'TARGETS': [ + { + 'NAME' : 'hello_nacl_mounts', + 'TYPE' : 'main', + 'SOURCES' : ['hello_nacl_mounts.c'], + 'LIBS': ['ppapi', 'pthread', 'nacl_mounts'] + } + ], + 'DATA': [ + 'example.js' + ], + 'DEST': 'examples', + 'NAME': 'hello_nacl_mounts', + 'TITLE': 'Hello, Nacl Mounts!', +} diff --git a/native_client_sdk/src/examples/hello_nacl_mounts/example.js b/native_client_sdk/src/examples/hello_nacl_mounts/example.js new file mode 100644 index 0000000..3d1206b --- /dev/null +++ b/native_client_sdk/src/examples/hello_nacl_mounts/example.js @@ -0,0 +1,164 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Start up the paint timer when the NaCl module has loaded. +function moduleDidLoad() { + common.hideModule(); +} + +// Called by the common.js module. +function attachListeners() { + var radioEls = document.querySelectorAll('input[type="radio"]'); + for (var i = 0; i < radioEls.length; ++i) { + radioEls[i].addEventListener('click', onRadioClicked); + } + + document.getElementById('fopenExecute').addEventListener('click', fopen); + document.getElementById('fcloseExecute').addEventListener('click', fclose); + document.getElementById('freadExecute').addEventListener('click', fread); + document.getElementById('fwriteExecute').addEventListener('click', fwrite); + document.getElementById('fseekExecute').addEventListener('click', fseek); +} + +function onRadioClicked(e) { + var divId = this.id.slice(5); // skip "radio" + var functionEls = document.querySelectorAll('.function'); + for (var i = 0; i < functionEls.length; ++i) { + var visible = functionEls[i].id === divId; + if (functionEls[i].id === divId) + functionEls[i].removeAttribute('hidden'); + else + functionEls[i].setAttribute('hidden'); + } +} + +function addFilenameToSelectElements(filehandle, filename) { + var text = '[' + filehandle + '] ' + filename; + var selectEls = document.querySelectorAll('select.file-handle'); + for (var i = 0; i < selectEls.length; ++i) { + var optionEl = document.createElement('option'); + optionEl.setAttribute('value', filehandle); + optionEl.appendChild(document.createTextNode(text)); + selectEls[i].appendChild(optionEl); + } +} + +function removeFilenameFromSelectElements(filehandle) { + var optionEls = document.querySelectorAll('select.file-handle > option'); + for (var i = 0; i < optionEls.length; ++i) { + var optionEl = optionEls[i]; + if (optionEl.value == filehandle) { + var selectEl = optionEl.parentNode; + selectEl.removeChild(optionEl); + } + } +} + +var filehandle_map = {}; + +function fopen(e) { + var filename = document.getElementById('fopenFilename').value; + + var access = ''; + if (document.getElementById('fopenWrite').checked) + access += 'w'; + if (document.getElementById('fopenRead').checked) + access += 'r'; + + nacl_module.postMessage(makeCall('fopen', filename, access)); +} + +function fopen_result(filename, filehandle) { + filehandle_map[filehandle] = filename; + + addFilenameToSelectElements(filehandle, filename) + logMessage('File ' + filename + ' opened successfully.'); +} + +function fclose(e) { + var filehandle = document.getElementById('fcloseHandle').value; + nacl_module.postMessage(makeCall('fclose', filehandle)); +} + +function fclose_result(filehandle) { + var filename = filehandle_map[filehandle]; + removeFilenameFromSelectElements(filehandle, filename); + logMessage('File ' + filename + ' closed successfully.'); +} + +function fread(e) { + var filehandle = document.getElementById('freadHandle').value; + var numBytes = document.getElementById('freadBytes').value; + nacl_module.postMessage(makeCall('fread', filehandle, numBytes)); +} + +function fread_result(filehandle, data) { + var filename = filehandle_map[filehandle]; + logMessage('Read "' + data + '" from file ' + filename + '.'); +} + +function fwrite(e) { + var filehandle = document.getElementById('fwriteHandle').value; + var data = document.getElementById('fwriteData').value; + nacl_module.postMessage(makeCall('fwrite', filehandle, data)); +} + +function fwrite_result(filehandle, bytes_written) { + var filename = filehandle_map[filehandle]; + logMessage('Wrote ' + bytes_written + ' bytes to file ' + filename + '.'); +} + +function fseek(e) { + var filehandle = document.getElementById('fseekHandle').value; + var offset = document.getElementById('fseekOffset').value; + var whence = document.getElementById('fseekWhence').value; + nacl_module.postMessage(makeCall('fseek', filehandle, offset, whence)); +} + +/** + * Return true when |s| starts with the string |prefix|. + * + * @param {string} s The string to search. + * @param {string} prefix The prefix to search for in |s|. + */ +function startsWith(s, prefix) { + // indexOf would search the entire string, lastIndexOf(p, 0) only checks at + // the first index. See: http://stackoverflow.com/a/4579228 + return s.lastIndexOf(prefix, 0) === 0; +} + +function logMessage(msg) { + var logEl = document.getElementById('log'); + logEl.innerHTML += msg + '<br>'; +} + +function makeCall(func) { + var message = func; + for (var i = 1; i < arguments.length; ++i) { + message += '\1' + arguments[i]; + } + + return message; +} + +// Called by the common.js module. +function handleMessage(message_event) { + var msg = message_event.data; + if (startsWith(msg, 'Error:')) { + logMessage(msg); + } else { + // Result from a function call. + var params = msg.split('\1'); + var func_name = params[0]; + var func_result_name = func_name + '_result'; + var result_func = window[func_result_name]; + + if (!result_func) { + logMessage('Error: Bad message received from NaCl module.'); + return; + } + + result_func.apply(null, params.slice(1)); + } +} diff --git a/native_client_sdk/src/examples/hello_nacl_mounts/hello_nacl_mounts.c b/native_client_sdk/src/examples/hello_nacl_mounts/hello_nacl_mounts.c new file mode 100644 index 0000000..5536614 --- /dev/null +++ b/native_client_sdk/src/examples/hello_nacl_mounts/hello_nacl_mounts.c @@ -0,0 +1,464 @@ +/* Copyright (c) 2012 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include <assert.h> +#include <stdarg.h> +#include <stdio.h> +#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" +#include "nacl_mounts/kernel_intercept.h" + + +#define MAX_OPEN_FILES 10 +#define MAX_PARAMS 4 +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +#if defined(WIN32) +#define va_copy(d, s) ((d) = (s)) +#endif + + +typedef int (*HandleFunc)(int num_params, char** params, char** output); +typedef struct { + const char* name; + HandleFunc function; +} FuncNameMapping; + + +int HandleFopen(int num_params, char** params, char** output); +int HandleFwrite(int num_params, char** params, char** output); +int HandleFread(int num_params, char** params, char** output); +int HandleFseek(int num_params, char** params, char** output); +int HandleFclose(int num_params, char** params, char** output); + + +static PPB_Messaging* ppb_messaging_interface = NULL; +static PPB_Var* ppb_var_interface = NULL; +static FILE* g_OpenFiles[MAX_OPEN_FILES]; +static FuncNameMapping g_FunctionMap[] = { + { "fopen", HandleFopen }, + { "fwrite", HandleFwrite }, + { "fread", HandleFread }, + { "fseek", HandleFseek }, + { "fclose", HandleFclose }, + { NULL, NULL }, +}; + + +static struct PP_Var CStrToVar(const char* str) { + if (ppb_var_interface != NULL) { + return ppb_var_interface->VarFromUtf8(str, strlen(str)); + } + return PP_MakeUndefined(); +} + +static char* VprintfToNewString(const char* format, va_list args) { + va_list args_copy; + int length; + char* buffer; + int result; + + va_copy(args_copy, args); + length = vsnprintf(NULL, 0, format, args); + buffer = (char*)malloc(length + 1); /* +1 for NULL-terminator. */ + result = vsnprintf(&buffer[0], length + 1, format, args_copy); + assert(result == length); + return buffer; +} + +static char* PrintfToNewString(const char* format, ...) { + va_list args; + char* result; + va_start(args, format); + result = VprintfToNewString(format, args); + va_end(args); + return result; +} + +static struct PP_Var PrintfToVar(const char* format, ...) { + if (ppb_var_interface != NULL) { + char* string; + va_list args; + struct PP_Var var; + + va_start(args, format); + string = VprintfToNewString(format, args); + va_end(args); + + var = ppb_var_interface->VarFromUtf8(string, strlen(string)); + free(string); + + return var; + } + + return PP_MakeUndefined(); +} + +static uint32_t VarToCStr(struct PP_Var var, char* buffer, uint32_t length) { + if (ppb_var_interface != NULL) { + uint32_t var_length; + const char* str = ppb_var_interface->VarToUtf8(var, &var_length); + /* str is NOT NULL-terminated. Copy using memcpy. */ + uint32_t min_length = MIN(var_length, length - 1); + memcpy(buffer, str, min_length); + buffer[min_length] = 0; + + return min_length; + } + + return 0; +} + +static int AddFileToMap(FILE* file) { + int i; + assert(file != NULL); + for (i = 0; i < MAX_OPEN_FILES; ++i) { + if (g_OpenFiles[i] == NULL) { + g_OpenFiles[i] = file; + return i; + } + } + + return -1; +} + +static void RemoveFileFromMap(int i) { + assert(i >= 0 && i < MAX_OPEN_FILES); + g_OpenFiles[i] = NULL; +} + +static FILE* GetFileFromMap(int i) { + assert(i >= 0 && i < MAX_OPEN_FILES); + return g_OpenFiles[i]; +} + +static FILE* GetFileFromIndexString(const char* s, int* file_index) { + char* endptr; + int result = strtol(s, &endptr, 10); + if (endptr != s + strlen(s)) { + /* Garbage at the end of the number...? */ + return NULL; + } + + if (file_index) + *file_index = result; + + return GetFileFromMap(result); +} + +int HandleFopen(int num_params, char** params, char** output) { + FILE* file; + int file_index; + const char* filename; + const char* mode; + + if (num_params != 2) { + *output = PrintfToNewString("Error: fopen takes 2 parameters."); + return 1; + } + + filename = params[0]; + mode = params[1]; + + file = fopen(filename, mode); + if (!file) { + *output = PrintfToNewString("Error: fopen returned a NULL FILE*."); + return 2; + } + + file_index = AddFileToMap(file); + if (file_index == -1) { + *output = PrintfToNewString( + "Error: Example only allows %d open file handles.", MAX_OPEN_FILES); + return 3; + } + + *output = PrintfToNewString("fopen\1%s\1%d", filename, file_index); + return 0; +} + +int HandleFwrite(int num_params, char** params, char** output) { + FILE* file; + const char* file_index_string; + const char* data; + size_t data_len; + size_t bytes_written; + + if (num_params != 2) { + *output = PrintfToNewString("Error: fwrite takes 2 parameters."); + return 1; + } + + file_index_string = params[0]; + file = GetFileFromIndexString(file_index_string, NULL); + data = params[1]; + data_len = strlen(data); + + if (!file) { + *output = PrintfToNewString("Error: Unknown file handle %s.", + file_index_string); + return 2; + } + + bytes_written = fwrite(data, 1, data_len, file); + + *output = PrintfToNewString("fwrite\1%s\1%d", file_index_string, + bytes_written); + return 0; +} + +int HandleFread(int num_params, char** params, char** output) { + FILE* file; + const char* file_index_string; + char* buffer; + size_t data_len; + size_t bytes_read; + + if (num_params != 2) { + *output = PrintfToNewString("Error: fread takes 2 parameters."); + return 1; + } + + file_index_string = params[0]; + file = GetFileFromIndexString(file_index_string, NULL); + data_len = strtol(params[1], NULL, 10); + + if (!file) { + *output = PrintfToNewString("Error: Unknown file handle %s.", + file_index_string); + return 2; + } + + buffer = (char*)malloc(data_len + 1); + bytes_read = fread(buffer, 1, data_len, file); + buffer[bytes_read] = 0; + + *output = PrintfToNewString("fread\1%s\1%s", file_index_string, buffer); + free(buffer); + return 0; +} + +int HandleFseek(int num_params, char** params, char** output) { + FILE* file; + const char* file_index_string; + long offset; + int whence; + int result; + + if (num_params != 3) { + *output = PrintfToNewString("Error: fseek takes 3 parameters."); + return 1; + } + + file_index_string = params[0]; + file = GetFileFromIndexString(file_index_string, NULL); + offset = strtol(params[1], NULL, 10); + whence = strtol(params[2], NULL, 10); + + if (!file) { + *output = PrintfToNewString("Error: Unknown file handle %s.", + file_index_string); + return 2; + } + + result = fseek(file, offset, whence); + if (result) { + *output = PrintfToNewString("Error: fseek returned error %d.", result); + return 3; + } + + *output = PrintfToNewString("fseek\1%d", file_index_string); + return 0; +} + +int HandleFclose(int num_params, char** params, char** output) { + FILE* file; + int file_index; + const char* file_index_string; + int result; + + if (num_params != 1) { + *output = PrintfToNewString("Error: fclose takes 1 parameters."); + return 1; + } + + file_index_string = params[0]; + file = GetFileFromIndexString(file_index_string, &file_index); + if (!file) { + *output = PrintfToNewString("Error: Unknown file handle %s.", + file_index_string); + return 2; + } + + result = fclose(file); + if (result) { + *output = PrintfToNewString("Error: fclose returned error %d.", result); + return 3; + } + + RemoveFileFromMap(file_index); + + *output = PrintfToNewString("fclose\1%s", file_index_string); + return 0; +} + +static size_t ParseMessage(char* message, + char** out_function, + char** out_params, + size_t max_params) { + char* separator; + char* param_start; + size_t num_params = 0; + + /* Parse the message: function\1param1\1param2\1param3,... */ + *out_function = &message[0]; + + separator = strchr(message, 1); + if (!separator) { + return num_params; + } + + *separator = 0; /* NULL-terminate function. */ + + while (separator && num_params < max_params) { + param_start = separator + 1; + separator = strchr(param_start, 1); + if (separator) { + *separator = 0; + out_params[num_params++] = param_start; + } + } + + out_params[num_params++] = param_start; + + return num_params; +} + +static HandleFunc GetFunctionByName(const char* function_name) { + FuncNameMapping* map_iter = g_FunctionMap; + for (; map_iter->name; ++map_iter) { + if (strcmp(map_iter->name, function_name) == 0) { + return map_iter->function; + } + } + + return NULL; +} + + +static PP_Bool Instance_DidCreate(PP_Instance instance, + uint32_t argc, + const char* argn[], + const char* argv[]) { + + ki_init(NULL); + return PP_TRUE; +} + + +static void Instance_DidDestroy(PP_Instance instance) { +} + +static void Instance_DidChangeView(PP_Instance instance, + PP_Resource view_resource) { +} + +static void Instance_DidChangeFocus(PP_Instance instance, + PP_Bool has_focus) { +} + +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; +} + +static void Messaging_HandleMessage(PP_Instance instance, + struct PP_Var message) { + char buffer[1024]; + char* function_name; + char* params[MAX_PARAMS]; + size_t num_params; + char* output = NULL; + int result; + HandleFunc function; + + VarToCStr(message, &buffer[0], 1024); + + num_params = ParseMessage(buffer, &function_name, ¶ms[0], MAX_PARAMS); + + function = GetFunctionByName(function_name); + if (!function) { + /* Function name wasn't found. Error. */ + ppb_messaging_interface->PostMessage( + instance, PrintfToVar("Error: Unknown function \"%s\"", function)); + } + + result = (*function)(num_params, ¶ms[0], &output); + if (result != 0) { + /* Error. */ + struct PP_Var var; + if (output != NULL) { + var = PrintfToVar( + "Error: Function \"%s\" returned error %d. " + "Additional output: %s", function_name, result, output); + } else { + var = PrintfToVar("Error: Function \"%s\" returned error %d.", + function_name, result); + } + + ppb_messaging_interface->PostMessage(instance, var); + return; + } + + if (output != NULL) { + /* Function returned an output string. Send it to JavaScript. */ + ppb_messaging_interface->PostMessage(instance, CStrToVar(output)); + free(output); + } +} + +PP_EXPORT int32_t PPP_InitializeModule(PP_Module a_module_id, + PPB_GetInterface get_browser) { + ppb_messaging_interface = + (PPB_Messaging*)(get_browser(PPB_MESSAGING_INTERFACE)); + ppb_var_interface = (PPB_Var*)(get_browser(PPB_VAR_INTERFACE)); + return PP_OK; +} + + +PP_EXPORT const void* PPP_GetInterface(const char* interface_name) { + if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) { + static 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 PPP_Messaging messaging_interface = { + &Messaging_HandleMessage, + }; + return &messaging_interface; + } + return NULL; +} + + +PP_EXPORT void PPP_ShutdownModule() { +} diff --git a/native_client_sdk/src/examples/hello_nacl_mounts/index.html b/native_client_sdk/src/examples/hello_nacl_mounts/index.html new file mode 100644 index 0000000..4116316 --- /dev/null +++ b/native_client_sdk/src/examples/hello_nacl_mounts/index.html @@ -0,0 +1,79 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright (c) 2012 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> +<head> + <meta http-equiv="Pragma" content="no-cache"> + <meta http-equiv="Expires" content="-1"> + <title><TITLE></title> + <script type="text/javascript" src="common.js"></script> + <script type="text/javascript" src="example.js"></script> +</head> +<body data-name="<NAME>" data-tc="<tc>" data-path="<path>"> + <h1><TITLE></h1> + <h2>Status: <code id="statusField">NO-STATUS</code></h2> + <div> + <span> + <input type="radio" id="radiofopen" name="group" checked="checked">fopen + <input type="radio" id="radiofclose" name="group">fclose + <input type="radio" id="radiofread" name="group">fread + <input type="radio" id="radiofwrite" name="group">fwrite + <input type="radio" id="radiofseek" name="group">fseek + </span> + </div> + <div class="function" id="fopen"> + <span> + Filename: + <input type="text" id="fopenFilename"> + Write: + <input type="checkbox" id="fopenWrite"> + Read: + <input type="checkbox" id="fopenRead"> + <button id="fopenExecute">fopen</button> + </span> + </div> + <div class="function" id="fclose" hidden> + <span> + <select class="file-handle" id="fcloseHandle"></select> + <button id="fcloseExecute">fclose</button> + </span> + </div> + <div class="function" id="fread" hidden> + <span> + <select class="file-handle" id="freadHandle"></select> + Count: + <input type="text" id="freadBytes"> + <button id="freadExecute">fread</button> + </span> + </div> + <div class="function" id="fwrite" hidden> + <span> + <select class="file-handle" id="fwriteHandle"></select> + Data: + <input type="text" id="fwriteData"> + <button id="fwriteExecute">fwrite</button> + </span> + </div> + <div class="function" id="fseek" hidden> + <span> + <select class="file-handle" id="fseekHandle"></select> + Offset: + <input type="text" id="fseekOffset"> + Whence: + <select id="fseekWhence"> + <option value="SEEK_SET">SEEK_SET</option> + <option value="SEEK_CUR">SEEK_CUR</option> + <option value="SEEK_END">SEEK_END</option> + </select> + <button id="fseekExecute">fseek</button> + </span> + </div> + <!-- The NaCl plugin will be embedded inside the element with id "listener". + See common.js.--> + <div id="listener"></div> + <div id="log"></div> +</body> +</html> diff --git a/native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.cc b/native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.cc index f7af9e0..940f5b7 100644 --- a/native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.cc +++ b/native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.cc @@ -3,8 +3,10 @@ * found in the LICENSE file. */ #include "nacl_mounts/kernel_intercept.h" - #include "nacl_mounts/kernel_proxy.h" +#include "utils/macros.h" + +FORCE_LINK_THAT(kernel_wrap) static KernelProxy* s_kp; diff --git a/native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.h b/native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.h index e4a472c..a966c4d 100644 --- a/native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.h +++ b/native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.h @@ -46,3 +46,4 @@ int ki_access(const char* path, int amode); EXTERN_C_END #endif // LIBRARIES_NACL_MOUNTS_KERNEL_INTERCEPT_H_ + diff --git a/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap.cc b/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap.cc index 0dd5021..c3d0581 100644 --- a/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap.cc +++ b/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap.cc @@ -4,6 +4,9 @@ */ #include <sys/types.h> // Include something that will define __GLIBC__. +#include "utils/macros.h" + +FORCE_LINK_THIS(kernel_wrap) #if defined(__native_client__) # if defined(__GLIBC__) diff --git a/native_client_sdk/src/libraries/utils/macros.h b/native_client_sdk/src/libraries/utils/macros.h index 97602b3..8731e25 100644 --- a/native_client_sdk/src/libraries/utils/macros.h +++ b/native_client_sdk/src/libraries/utils/macros.h @@ -25,8 +25,25 @@ # define EXTERN_C_END } #else # define EXTERN_C_BEGIN -# define EXEERN_C_END +# define EXTERN_C_END #endif /* __cplusplus */ +/** + * Macros to help force linkage of symbols that otherwise would not be + * included. + * + * // In a source file that you want to force linkage (file scope): + * FORCE_LINK_THIS(myfilename); + * + * // In a source file that you are sure will be linked (file scope): + * FORCE_LINK_THAT(myfilename) + * + */ +#define FORCE_LINK_THIS(x) int force_link_##x = 0; +#define FORCE_LINK_THAT(x) \ + void force_link_function_##x() { \ + extern int force_link_##x; \ + force_link_##x = 1; \ + } #endif /* LIBRARIES_UTILS_MACROS_H_ */ |