# This file is part of NIT ( http://www.nitlanguage.org ) # # Copyright 2014 Johan Kayser # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Compile program for the PNaCl platform module pnacl import platform import compiler::abstract_compiler redef class ToolContext redef fun platform_from_name(name) do if name == "pnacl" then return new PnaclPlatform return super end end class PnaclPlatform super Platform redef fun name do return "pnacl" redef fun supports_libunwind do return false redef fun no_main do return true redef fun toolchain(toolcontext, compiler) do return new PnaclToolchain(toolcontext, compiler) end class PnaclToolchain super MakefileToolchain redef fun write_files(compile_dir, cfiles) do var app_name = compiler.mainmodule.name # create compile_dir var dir = compile_dir if not dir.file_exists then dir.mkdir # compile normal C files super # Gather extra C files generated elsewhere than in super for f in compiler.extern_bodies do if f isa ExternCFile then cfiles.add(f.filename.basename("")) end # Outname var outname = toolcontext.opt_output.value if outname == null then outname = "{compiler.mainmodule.name}" var ofiles = new Array[String] for cfile in cfiles do ofiles.add(cfile.substring(0, cfile.length-2) + ".o") ## Generate makefile var file = "{dir}/Makefile" """ # This file was generated by Nit, any modification will be lost. # Get pepper directory for toolchain and includes. # # If NACL_SDK_ROOT is not set, then assume it can be found five directories up. # THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) NACL_SDK_ROOT ?= $(abspath $(dir $(THIS_MAKEFILE))../../../..) # Project Build flags WARNINGS := -Wno-long-long -Wno-unused-value -Wno-unused-label -Wno-duplicate-decl-specifier -Wno-switch -Wno-embedded-directive CXXFLAGS := -pthread $(WARNINGS) CXXFLAGS += -g -O0 # Debug # CXXFLAGS += -O3 # Release # # Compute tool paths # GETOS := python $(NACL_SDK_ROOT)/tools/getos.py OSHELPERS = python $(NACL_SDK_ROOT)/tools/oshelpers.py OSNAME := $(shell $(GETOS)) 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 -lm # # 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: ../{{{outname}}}/{{{app_name}}}.pexe .c.o: $(PNACL_CXX) -c $< -g -O0 $(CXXFLAGS) {{{app_name}}}.pexe: {{{ofiles.join(" ")}}} $(PNACL_CXX) -o $@ $^ $(LDFLAGS) ../{{{outname}}}/{{{app_name}}}.pexe: {{{app_name}}}.pexe $(PNACL_FINALIZE) -o $@ $< """.write_to_file(file) ### generate the minimal index.html if not outname.file_exists then outname.mkdir file = "{outname}/index.html" if not file.file_exists then """ {{{app_name}}}

PNaCl : Minimal HTML for {{{app_name}}}

Status NO-STATUS

""".write_to_file(file) ### generate pnacl_js.js in a folder named 'js' dir = "{outname}/js/" if not dir.file_exists then dir.mkdir file = "{dir}/pnacl_js.js" if not file.file_exists then """ // This file was generated by Nit, any modification will be lost. {{{app_name}}}Module = null; // Global application object. statusText = 'NO-STATUS'; // Indicate load success. function moduleDidLoad() { {{{app_name}}}Module = document.getElementById('{{{app_name}}}'); updateStatus('SUCCESS'); // Send a message to the Native Client module like that //{{{app_name}}}Module.postMessage('Hello World'); } // 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) { console.log(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 ({{{app_name}}}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('statusField'); if (statusField) { statusField.innerHTML = statusText; } } """.write_to_file(file) ### generate the manifest file : app_name.nmf # used to point the HTML to the Native Client module # and optionally provide additional commands to the PNaCl translator in Chrome file = "{outname}/{app_name}.nmf" """ { "program": { "portable": { "pnacl-translate": { "url": "{{{app_name}}}.pexe" } } } } """.write_to_file(file) end redef fun write_makefile(compile_dir, cfiles) do # Do nothing, already done in `write_files` end redef fun compile_c_code(compile_dir) do # Generate the pexe toolcontext.exec_and_check(["make", "-C", compile_dir, "-j", "4"], "PNaCl project error") end end