1 # This file is part of NIT ( http://www.nitlanguage.org )
3 # Copyright 2014 Johan Kayser <kayser.johan@gmail.com>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # Compile program for the PNaCl platform
21 import abstract_compiler
23 redef class ToolContext
24 redef fun platform_from_name
(name
)
26 if name
== "pnacl" then return new PnaclPlatform
34 redef fun toolchain
(toolcontext
) do return new PnaclToolchain(toolcontext
)
38 super MakefileToolchain
40 var pnacl_project_root
: String
44 var normal_compile_dir
= super
45 pnacl_project_root
= "{normal_compile_dir}/pnacl/"
46 return "{normal_compile_dir}/pnacl/src/"
49 redef fun write_files
(compiler
, compile_dir
, cfiles
)
51 var app_name
= compiler
.mainmodule
.name
54 var dir
= pnacl_project_root
55 if not dir
.file_exists
then dir
.mkdir
58 if not dir
.file_exists
then dir
.mkdir
60 # compile normal C files
61 super(compiler
, compile_dir
, cfiles
)
63 # Gather extra C files generated elsewhere than in super
64 for f
in compiler
.extern_bodies
do
65 if f
isa ExternCFile then cfiles
.add
(f
.filename
.basename
(""))
69 var outname
= toolcontext
.opt_output
.value
70 if outname
== null then outname
= "{compiler.mainmodule.name}"
73 dir
= pnacl_project_root
74 if not dir
.file_exists
then dir
.mkdir
75 var file
= "{dir}/Makefile"
77 # This file was generated by Nit, any modification will be lost.
79 # Get pepper directory for toolchain and includes.
81 # If NACL_SDK_ROOT is not set, then assume it can be found five directories up.
83 THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST)))
84 NACL_SDK_ROOT ?= $(abspath $(dir $(THIS_MAKEFILE))../../../..)
87 WARNINGS := -Wno-long-long -Wall -Wswitch-enum -pedantic -Werror
88 CXXFLAGS := -pthread -std=gnu++98 $(WARNINGS)
93 GETOS := python $(NACL_SDK_ROOT)/tools/getos.py
94 OSHELPERS = python $(NACL_SDK_ROOT)/tools/oshelpers.py
95 OSNAME := $(shell $(GETOS))
98 PNACL_TC_PATH := $(abspath $(NACL_SDK_ROOT)/toolchain/$(OSNAME)_pnacl)
99 PNACL_CXX := $(PNACL_TC_PATH)/bin/pnacl-clang
100 PNACL_FINALIZE := $(PNACL_TC_PATH)/bin/pnacl-finalize
101 CXXFLAGS := -I$(NACL_SDK_ROOT)/include
102 LDFLAGS := -L$(NACL_SDK_ROOT)/lib/pnacl/Release -lppapi_cpp -lppapi
105 # Disable DOS PATH warning when using Cygwin based tools Windows
107 CYGWIN ?= nodosfilewarning
111 # Declare the ALL target first, to make the 'all' target the default build
112 all: ../../{{{outname}}}/{{{app_name}}}.pexe
115 $(RM) {{{app_name}}}.pexe
117 {{{app_name}}}.pexe: src/{{{cfiles.join(" src/")}}}
118 $(PNACL_CXX) -o $@ $^ -g -O0 $(CXXFLAGS) $(LDFLAGS) # For Debug
119 # $(PNACL_CXX) -o $@ $^ -O3 $(CXXFLAGS) $(LDFLAGS) # For Release
121 ../../{{{outname}}}/{{{app_name}}}.pexe: {{{app_name}}}.pexe
122 $(PNACL_FINALIZE) -o $@ $<
125 # Makefile target to run the SDK's simple HTTP server and serve this example.
127 HTTPD_PY := python $(NACL_SDK_ROOT)/tools/httpd.py
131 $(HTTPD_PY) -C $(CURDIR)
132 """.write_to_file
(file
)
134 ### generate the minimal index.html
135 if not outname
.file_exists
then outname
.mkdir
136 file
= "{outname}/index.html"
137 if not file
.file_exists
then
142 This file was generated by Nit, any modification will be lost.
145 <title>{{{app_name}}}</title>
146 <script src="js/pnacl_js.js"></script>
148 <body onload="pageDidLoad()">
149 <h1>PNaCl : Minimal HTML for {{{app_name}}}</h1>
152 Load the published pexe.
153 Note: Since this module does not use any real-estate in the browser, its
154 width and height are set to 0.
156 Note: The <embed> element is wrapped inside a <div>, which has both a 'load'
157 and a 'message' event listener attached. This wrapping method is used
158 instead of attaching the event listeners directly to the <embed> element to
159 ensure that the listeners are active before the NaCl module 'load' event
160 fires. This also allows you to use PPB_Messaging.PostMessage() (in C) or
161 pp::Instance.PostMessage() (in C++) from within the initialization code in
165 <script type="text/javascript">
166 var listener = document.getElementById('listener');
167 listener.addEventListener('load', moduleDidLoad, true);
168 listener.addEventListener('message', handleMessage, true);
171 <embed id="{{{app_name}}}"
173 src="{{{app_name}}}.nmf"
174 type="application/x-pnacl" />
177 <h2>Status <code id="statusField">NO-STATUS</code></h2>
180 """.write_to_file
(file
)
183 ### generate pnacl_js.js in a folder named 'js'
184 dir
= "{outname}/js/"
185 if not dir
.file_exists
then dir
.mkdir
186 file
= "{dir}/pnacl_js.js"
187 if not file
.file_exists
then
189 // This file was generated by Nit, any modification will be lost.
191 {{{app_name}}}Module = null; // Global application object.
192 statusText = 'NO-STATUS';
194 // Indicate load success.
195 function moduleDidLoad() {
196 {{{app_name}}}Module = document.getElementById('{{{app_name}}}');
197 updateStatus('SUCCESS');
198 // Send a message to the Native Client module like that
199 //{{{app_name}}}Module.postMessage('Hello World');
202 // The 'message' event handler. This handler is fired when the NaCl module
203 // posts a message to the browser by calling PPB_Messaging.PostMessage()
204 // (in C) or pp::Instance.PostMessage() (in C++). This implementation
205 // simply displays the content of the message in an alert panel.
206 function handleMessage(message_event) {
207 console.log(message_event.data);
210 // If the page loads before the Native Client module loads, then set the
211 // status message indicating that the module is still loading. Otherwise,
212 // do not change the status message.
213 function pageDidLoad() {
214 if ({{{app_name}}}Module == null) {
215 updateStatus('LOADING...');
217 // It's possible that the Native Client module onload event fired
218 // before the page's onload event. In this case, the status message
219 // will reflect 'SUCCESS', but won't be displayed. This call will
220 // display the current message.
225 // Set the global status message. If the element with id 'statusField'
226 // exists, then set its HTML to the status message as well.
227 // opt_message The message test. If this is null or undefined, then
228 // attempt to set the element with id 'statusField' to the value of
230 function updateStatus(opt_message) {
232 statusText = opt_message;
233 var statusField = document.getElementById('statusField');
235 statusField.innerHTML = statusText;
238 """.write_to_file
(file
)
241 ### generate the manifest file : app_name.nmf
242 # used to point the HTML to the Native Client module
243 # and optionally provide additional commands to the PNaCl translator in Chrome
244 file
= "{outname}/{app_name}.nmf"
250 "url": "{{{app_name}}}.pexe"
255 """.write_to_file
(file
)
258 redef fun write_makefile
(compiler
, compile_dir
, cfiles
)
260 # Do nothing, already done in `write_files`
263 redef fun compile_c_code
(compiler
, compile_dir
)
266 toolcontext
.exec_and_check
(["make", "-C", pnacl_project_root
], "PNaCl project error")