aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmake/Modules/FindOpenAL.cmake26
-rw-r--r--cmake/Platform/Emscripten.cmake7
-rwxr-xr-xemcc15
-rw-r--r--tests/freealut/CMakeLists.txt55
-rwxr-xr-xtests/runner.py24
-rw-r--r--tests/test_browser.py101
-rw-r--r--third_party/lzma.js/doit.bat4
-rw-r--r--tools/settings_template_readonly.py2
-rw-r--r--tools/split.py34
9 files changed, 176 insertions, 92 deletions
diff --git a/cmake/Modules/FindOpenAL.cmake b/cmake/Modules/FindOpenAL.cmake
new file mode 100644
index 00000000..3170966d
--- /dev/null
+++ b/cmake/Modules/FindOpenAL.cmake
@@ -0,0 +1,26 @@
+# Locate OpenAL
+# This module defines
+# OPENAL_LIBRARY
+# OPENAL_FOUND, if false, do not try to link to OpenAL
+# OPENAL_INCLUDE_DIR, where to find the headers
+
+# The implementation is based on the standard FindOpenAL.cmake provided with CMake,
+# but customized for targeting Emscripten only.
+
+if (NOT OPENAL_FOUND)
+ SET(OPENAL_FOUND TRUE)
+
+ # For Emscripten-compiled apps in the test suite (test_alut), this is expected...
+ SET(OPENAL_INCLUDE_DIR "${EMSCRIPTEN_ROOT_PATH}/system/include")
+ # ... but the stock FindOpenAL.cmake would have returned this.
+ #SET(OPENAL_INCLUDE_DIR "${EMSCRIPTEN_ROOT_PATH}/system/include/AL")
+
+ # No library to link against for OpenAL, this is picked up automatically by library_openal.js,
+ # but need to report something, or CMake thinks we failed in the search.
+ SET(OPENAL_LIBRARY "nul")
+ SET(OPENAL_LIB "")
+
+ set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${EMSCRIPTEN_ROOT_PATH}/system/include" "${EMSCRIPTEN_ROOT_PATH}/system/include/AL")
+
+ MARK_AS_ADVANCED(OPENAL_LIBRARY OPENAL_INCLUDE_DIR)
+endif()
diff --git a/cmake/Platform/Emscripten.cmake b/cmake/Platform/Emscripten.cmake
index e1e54ccf..c30632ca 100644
--- a/cmake/Platform/Emscripten.cmake
+++ b/cmake/Platform/Emscripten.cmake
@@ -44,9 +44,10 @@ endif()
# Normalize, convert Windows backslashes to forward slashes or CMake will crash.
get_filename_component(EMSCRIPTEN_ROOT_PATH "${EMSCRIPTEN_ROOT_PATH}" ABSOLUTE)
-if ("${CMAKE_MODULE_PATH}" STREQUAL "")
- set(CMAKE_MODULE_PATH "${EMSCRIPTEN_ROOT_PATH}/cmake")
+if (NOT CMAKE_MODULE_PATH)
+ set(CMAKE_MODULE_PATH "")
endif()
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${EMSCRIPTEN_ROOT_PATH}/cmake/Modules")
set(CMAKE_FIND_ROOT_PATH "${EMSCRIPTEN_ROOT_PATH}/cmake")
@@ -82,6 +83,8 @@ set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
+set(CMAKE_SYSTEM_INCLUDE_PATH "${EMSCRIPTEN_ROOT_PATH}/system/include")
+
# We would prefer to specify a standard set of Clang+Emscripten-friendly common convention for suffix files, especially for CMake executable files,
# but if these are adjusted, ${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake will fail, since it depends on being able to compile output files with predefined names.
#SET(CMAKE_LINK_LIBRARY_SUFFIX "")
diff --git a/emcc b/emcc
index c3f9d862..008468a1 100755
--- a/emcc
+++ b/emcc
@@ -50,7 +50,7 @@ emcc can be influenced by a few environment variables:
import os, sys, shutil, tempfile, subprocess, shlex, time, re, logging
from subprocess import PIPE, STDOUT
from tools import shared, jsrun
-from tools.shared import Compression, execute, suffix, unsuffixed, unsuffixed_basename
+from tools.shared import Compression, execute, suffix, unsuffixed, unsuffixed_basename, WINDOWS
from tools.response_file import read_response_file
CXX_SUFFIXES = ('.cpp', '.cxx', '.cc')
@@ -887,8 +887,17 @@ try:
check_bad_eq(newargs[i])
parts = newargs[i+1].split(',')
assert len(parts) == 3, '--compression requires specifying native_encoder,js_decoder,js_name - see emcc --help. got: %s' % newargs[i+1]
- Compression.encoder = parts[0]
- Compression.decoder = parts[1]
+ def locate(tool):
+ if WINDOWS:
+ if os.path.exists(tool+'.exe'):
+ return tool+'.exe'
+ if os.path.exists(tool+'.bat'):
+ return tool+'.bat'
+ if os.path.exists(tool+'.cmd'):
+ return tool+'.cmd'
+ return tool
+ Compression.encoder = locate(parts[0])
+ Compression.decoder = locate(parts[1])
Compression.js_name = parts[2]
assert os.path.exists(Compression.encoder), 'native encoder %s does not exist' % Compression.encoder
assert os.path.exists(Compression.decoder), 'js decoder %s does not exist' % Compression.decoder
diff --git a/tests/freealut/CMakeLists.txt b/tests/freealut/CMakeLists.txt
index 640f35bf..c11680cd 100644
--- a/tests/freealut/CMakeLists.txt
+++ b/tests/freealut/CMakeLists.txt
@@ -72,20 +72,39 @@ ADD_DEFINE("__NO_CTYPE 1")
ADD_DEFINITIONS(-DHAVE_CONFIG_H)
ADD_DEFINITIONS(-DNDEBUG)
-FIND_LIBRARY(OPENAL_LIB NAMES openal openal32 PATHS /usr/lib /usr/local/lib ${OPENAL_LIB_DIR})
-IF(OPENAL_LIB MATCHES "NOTFOUND")
- MESSAGE(FATAL_ERROR "OpenAL not installed, cannot build alut - aborting.")
-ENDIF(OPENAL_LIB MATCHES "NOTFOUND")
-
-IF(UNIX)
- SET(ADD_LIBS ${ADD_LIBS} m)
-ENDIF(UNIX)
+if (EMSCRIPTEN)
+ # Emscripten cannot use FIND_LIBRARY, since that seaches for linkable library files, but Emscripten supports
+ # OpenAL in core and there are no library files to link against. Instead, use a custom OpenAL package finder
+ # provided by Emscripten.
+ FIND_PACKAGE(OpenAL)
+
+ # All the include file checks bloew are no-ops for Emscripten, so for that platform, just define the flags we support.
+ SET(HAVE_STDINT_H 1)
+ SET(HAVE_STAT 1)
+ SET(HAVE_NANOSLEEP 1)
+ SET(HAVE_TIME_H 1)
+ ADD_DEFINITIONS(-DHAVE_STDINT_H=1 -DHAVE_STAT=1 -DHAVE_NANOSLEEP=1 -DHAVE_TIME_H=1)
+ SET(CMAKE_EXECUTABLE_SUFFIX ".bc")
+else()
+ FIND_LIBRARY(OPENAL_LIB NAMES openal openal32 PATHS /usr/lib /usr/local/lib ${OPENAL_LIB_DIR})
+
+ IF(OPENAL_LIB MATCHES "NOTFOUND")
+ MESSAGE(FATAL_ERROR "OpenAL not installed, cannot build alut - aborting.")
+ ENDIF(OPENAL_LIB MATCHES "NOTFOUND")
+
+ IF(UNIX)
+ SET(ADD_LIBS ${ADD_LIBS} m)
+ ENDIF(UNIX)
+endif()
SET(CMAKE_REQUIRED_INCLUDES ${OPENAL_INCLUDE_DIR})
-CHECK_INCLUDE_FILES("AL/alc.h;AL/al.h" AL_HEADERS)
-IF(NOT AL_HEADERS)
- MESSAGE(FATAL_ERROR "OpenAL header files not found - aborting.")
-ENDIF(NOT AL_HEADERS)
+
+if (NOT EMSCRIPTEN) # Emscripten is a cross-compiler and cannot verify paths of include files with CHECK_INCLUDE_FILES, since that requires building native executables.
+ CHECK_INCLUDE_FILES("AL/alc.h;AL/al.h" AL_HEADERS)
+ IF(NOT AL_HEADERS)
+ MESSAGE(FATAL_ERROR "OpenAL header files not found - aborting.")
+ ENDIF(NOT AL_HEADERS)
+endif()
IF(DEFINED OPENAL_INCLUDE_DIR)
INCLUDE_DIRECTORIES(${OPENAL_INCLUDE_DIR})
@@ -178,10 +197,18 @@ INSTALL_FILES(/lib/pkgconfig FILES admin/pkgconfig/freealut.pc)
IF(BUILD_TESTS)
# examples
ADD_EXECUTABLE(hello_world examples/hello_world.c)
- TARGET_LINK_LIBRARIES(hello_world ${OPENAL_LIB} ${ADD_LIBS} alut)
+ if (EMSCRIPTEN)
+ TARGET_LINK_LIBRARIES(hello_world ${OPENAL_LIB} ${ADD_LIBS} alut_static)
+ else()
+ TARGET_LINK_LIBRARIES(hello_world ${OPENAL_LIB} ${ADD_LIBS} alut)
+ endif()
ADD_EXECUTABLE(playfile examples/playfile.c)
- TARGET_LINK_LIBRARIES(playfile ${OPENAL_LIB} ${ADD_LIBS} alut)
+ if (EMSCRIPTEN)
+ TARGET_LINK_LIBRARIES(playfile ${OPENAL_LIB} ${ADD_LIBS} alut_static)
+ else()
+ TARGET_LINK_LIBRARIES(playfile ${OPENAL_LIB} ${ADD_LIBS} alut)
+ endif()
SET(TESTS errorstuff
diff --git a/tests/runner.py b/tests/runner.py
index 7f513635..34435383 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -16,7 +16,7 @@ so you may prefer to use fewer cores here.
'''
from subprocess import Popen, PIPE, STDOUT
-import os, unittest, tempfile, shutil, time, inspect, sys, math, glob, re, difflib, webbrowser, hashlib, threading, platform, BaseHTTPServer, multiprocessing, functools, stat, string
+import os, unittest, tempfile, shutil, time, inspect, sys, math, glob, re, difflib, webbrowser, hashlib, threading, platform, BaseHTTPServer, SimpleHTTPServer, multiprocessing, functools, stat, string
# Setup
@@ -491,22 +491,14 @@ def harness_server_func(q):
httpd.serve_forever() # test runner will kill us
def server_func(dir, q):
- class TestServerHandler(BaseHTTPServer.BaseHTTPRequestHandler):
- def do_GET(s):
- if 'report_' in s.path:
- q.put(s.path)
+ class TestServerHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
+ def do_GET(self):
+ if 'report_' in self.path:
+ q.put(self.path)
else:
- filename = s.path.split('?')[0][1:]
- if os.path.exists(filename):
- s.send_response(200)
- s.send_header("Content-type", "text/html")
- s.end_headers()
- s.wfile.write(open(filename).read())
- s.wfile.close()
- else:
- s.send_response(500)
- s.send_header("Content-type", "text/html")
- s.end_headers()
+ # Use SimpleHTTPServer default file serving operation for GET.
+ SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
+
def log_request(code=0, size=0):
# don't log; too noisy
pass
diff --git a/tests/test_browser.py b/tests/test_browser.py
index 65bccb38..f2bcaa93 100644
--- a/tests/test_browser.py
+++ b/tests/test_browser.py
@@ -1,4 +1,4 @@
-import BaseHTTPServer, multiprocessing, os, shutil, subprocess, unittest
+import BaseHTTPServer, multiprocessing, os, shutil, subprocess, unittest, zlib
from runner import BrowserCore, path_from_root
from tools.shared import *
@@ -8,6 +8,45 @@ def run_in_other_browser(url):
webbrowser.open_new = run_in_other_browser
'''
+def test_chunked_synchronous_xhr_server(support_byte_ranges, chunkSize, data, checksum):
+ class ChunkedServerHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+ def sendheaders(s, extra=[], length=len(data)):
+ s.send_response(200)
+ s.send_header("Content-Length", str(length))
+ s.send_header("Access-Control-Allow-Origin", "http://localhost:8888")
+ s.send_header("Access-Control-Expose-Headers", "Content-Length, Accept-Ranges")
+ s.send_header("Content-type", "application/octet-stream")
+ if support_byte_ranges:
+ s.send_header("Accept-Ranges", "bytes")
+ for i in extra:
+ s.send_header(i[0], i[1])
+ s.end_headers()
+
+ def do_HEAD(s):
+ s.sendheaders()
+
+ def do_OPTIONS(s):
+ s.sendheaders([("Access-Control-Allow-Headers", "Range")], 0)
+
+ def do_GET(s):
+ if not support_byte_ranges:
+ s.sendheaders()
+ s.wfile.write(data)
+ else:
+ (start, end) = s.headers.get("range").split("=")[1].split("-")
+ start = int(start)
+ end = int(end)
+ end = min(len(data)-1, end)
+ length = end-start+1
+ s.sendheaders([],length)
+ s.wfile.write(data[start:end+1])
+ s.wfile.close()
+
+ expectedConns = 11
+ httpd = BaseHTTPServer.HTTPServer(('localhost', 11111), ChunkedServerHandler)
+ for i in range(expectedConns+1):
+ httpd.handle_request()
+
class browser(BrowserCore):
@staticmethod
def audio():
@@ -85,7 +124,10 @@ If manually bisecting:
cwd = os.getcwd()
try:
os.chdir(path_from_root('third_party', 'lzma.js'))
- Popen(['sh', './doit.sh']).communicate()
+ if WINDOWS and Building.which('mingw32-make'): # On Windows prefer using MinGW make if it exists, otherwise fall back to hoping we have cygwin make.
+ Popen(['doit.bat']).communicate()
+ else:
+ Popen(['sh', './doit.sh']).communicate()
finally:
os.chdir(cwd)
@@ -185,7 +227,7 @@ If manually bisecting:
self.reftest(path_from_root('tests', 'htmltest.png'))
output = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_sdl.cpp'), '-o', 'something.js', '-g', '--split', '100', '--pre-js', 'reftest.js']).communicate()
assert os.path.exists(os.path.join(self.get_dir(), 'something.js')), 'must be main js file'
- assert os.path.exists(self.get_dir() + '/something/' + path_from_root('tests', 'hello_world_sdl.cpp.js')), 'must be functions js file'
+ assert os.path.exists(os.path.join(self.get_dir(), 'something', 'hello_world_sdl.cpp.js')), 'must be functions js file'
assert os.path.exists(os.path.join(self.get_dir(), 'something.include.html')), 'must be js include file'
open(os.path.join(self.get_dir(), 'something.html'), 'w').write('''
@@ -1159,8 +1201,14 @@ keydown(100);keyup(100); // trigger the end
Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'test_egl_width_height.c'), '-o', 'page.html']).communicate()
self.run_browser('page.html', 'Should print "(300, 150)" -- the size of the canvas in pixels', '/report_result?1')
+ def get_freealut_library(self):
+ if WINDOWS and Building.which('cmake'):
+ return self.get_library('freealut', os.path.join('hello_world.bc'), configure=['cmake', '.'], configure_args=['-DBUILD_TESTS=ON'])
+ else:
+ return self.get_library('freealut', os.path.join('examples', '.libs', 'hello_world.bc'), make_args=['EXEEXT=.bc'])
+
def test_freealut(self):
- programs = self.get_library('freealut', os.path.join('examples', '.libs', 'hello_world.bc'), make_args=['EXEEXT=.bc'])
+ programs = self.get_freealut_library()
for program in programs:
assert os.path.exists(program)
Popen([PYTHON, EMCC, '-O2', program, '-o', 'page.html']).communicate()
@@ -1256,51 +1304,16 @@ keydown(100);keyup(100); // trigger the end
chunkSize = 1024
data = os.urandom(10*chunkSize+1) # 10 full chunks and one 1 byte chunk
- expectedConns = 11
- import zlib
checksum = zlib.adler32(data)
- def chunked_server(support_byte_ranges):
- class ChunkedServerHandler(BaseHTTPServer.BaseHTTPRequestHandler):
- def sendheaders(s, extra=[], length=len(data)):
- s.send_response(200)
- s.send_header("Content-Length", str(length))
- s.send_header("Access-Control-Allow-Origin", "http://localhost:8888")
- s.send_header("Access-Control-Expose-Headers", "Content-Length, Accept-Ranges")
- s.send_header("Content-type", "application/octet-stream")
- if support_byte_ranges:
- s.send_header("Accept-Ranges", "bytes")
- for i in extra:
- s.send_header(i[0], i[1])
- s.end_headers()
-
- def do_HEAD(s):
- s.sendheaders()
-
- def do_OPTIONS(s):
- s.sendheaders([("Access-Control-Allow-Headers", "Range")], 0)
-
- def do_GET(s):
- if not support_byte_ranges:
- s.sendheaders()
- s.wfile.write(data)
- else:
- (start, end) = s.headers.get("range").split("=")[1].split("-")
- start = int(start)
- end = int(end)
- end = min(len(data)-1, end)
- length = end-start+1
- s.sendheaders([],length)
- s.wfile.write(data[start:end+1])
- s.wfile.close()
- httpd = BaseHTTPServer.HTTPServer(('localhost', 11111), ChunkedServerHandler)
- for i in range(expectedConns+1):
- httpd.handle_request()
-
- server = multiprocessing.Process(target=chunked_server, args=(True,))
+ server = multiprocessing.Process(target=test_chunked_synchronous_xhr_server, args=(True,chunkSize,data,checksum,))
server.start()
self.run_browser(main, 'Chunked binary synchronous XHR in Web Workers!', '/report_result?' + str(checksum))
server.terminate()
+ # Avoid race condition on cleanup, wait a bit so that processes have released file locks so that test tearDown won't
+ # attempt to rmdir() files in use.
+ if WINDOWS:
+ time.sleep(2)
def test_glgears(self):
self.btest('hello_world_gles.c', reference='gears.png', reference_slack=1,
diff --git a/third_party/lzma.js/doit.bat b/third_party/lzma.js/doit.bat
new file mode 100644
index 00000000..17b4f473
--- /dev/null
+++ b/third_party/lzma.js/doit.bat
@@ -0,0 +1,4 @@
+cd lzip
+call mingw32-make lzip
+copy /Y lzip.exe ..\lzma-native.exe
+cd ..
diff --git a/tools/settings_template_readonly.py b/tools/settings_template_readonly.py
index 14b45a20..a2a16f19 100644
--- a/tools/settings_template_readonly.py
+++ b/tools/settings_template_readonly.py
@@ -18,6 +18,8 @@ JAVA = 'java' # executable
TEMP_DIR = '{{{ TEMP }}}'
+CRUNCH = os.path.expanduser(os.getenv('CRUNCH') or 'crunch') # executable
+
#CLOSURE_COMPILER = '..' # define this to not use the bundled version
########################################################################################################
diff --git a/tools/split.py b/tools/split.py
index f9e338aa..b15b1716 100644
--- a/tools/split.py
+++ b/tools/split.py
@@ -1,16 +1,13 @@
import sys
import os
+from sets import Set
def split_javascript_file(input_filename, output_filename_prefix, max_part_size_in_bytes):
try:
- # Contains the entire Emscripten generated Javascript code
- input_file = open(input_filename,'r')
-
# Javascript main file. On execution, this file needs to be loaded at last (!)
output_main_filename = output_filename_prefix + ".js"
output_main_file = open(output_main_filename,'w')
-
# File with HTML script tags to load the Javascript files in HTML later on
output_html_include_file = open(output_filename_prefix + ".include.html",'w')
@@ -22,8 +19,19 @@ def split_javascript_file(input_filename, output_filename_prefix, max_part_size_
function_buckets = {};
output_part_file = None
-
+
+ # Locate names of all the source files (.c/.cpp) that produced output to the .js file.
+ source_files = Set()
+ for line in open(input_filename,'r'):
+ if line.startswith("//FUNCTION_END_MARKER_OF_SOURCE_FILE_"):
+ associated_source_file_base = line[len("//FUNCTION_END_MARKER_OF_SOURCE_FILE_"):len(line)-1]
+ if not associated_source_file_base == "NO_SOURCE":
+ source_files.add(os.path.dirname(os.path.abspath(os.path.realpath(associated_source_file_base))))
+
+ common_source_file_prefix = os.path.commonprefix(list(source_files))
+
# Iterate over Javascript source; write main file; parse function declarations.
+ input_file = open(input_filename,'r')
for line in input_file:
if line == "//FUNCTION_BEGIN_MARKER\n":
js_function = "//Func\n"
@@ -36,8 +44,8 @@ def split_javascript_file(input_filename, output_filename_prefix, max_part_size_
associated_source_file_base = output_filename_prefix + "_functions";
else:
# Functions with a known associated source file are stored in a file in the directory `output_filename_prefix`
- associated_source_file_base = output_filename_prefix + os.path.realpath(associated_source_file_base)
-
+ associated_source_file_base = os.path.join(output_filename_prefix, os.path.relpath(os.path.abspath(os.path.realpath(associated_source_file_base)), common_source_file_prefix))
+
associated_source_file_base_lower = associated_source_file_base.lower()
# Add the function to its respective file
@@ -68,7 +76,7 @@ def split_javascript_file(input_filename, output_filename_prefix, max_part_size_
output_part_file = None
for js_function in function_buckets[associated_source_file_base][1]:
if output_part_file is None:
- output_html_include_file.write("<script type=\"text/javascript\" src=\"" + js_source_file + "\"></script>")
+ output_html_include_file.write("<script type=\"text/javascript\" src=\"" + js_source_file.replace('\\', '/') + "\"></script>")
output_part_file = open(js_source_file,'w')
output_part_file.write(js_function)
@@ -85,13 +93,13 @@ def split_javascript_file(input_filename, output_filename_prefix, max_part_size_
# Write the main Javascript file at last to the HTML includes because this file contains the code to start
# the execution of the generated Emscripten application and requires all the extracted functions.
- output_html_include_file.write("<script type=\"text/javascript\" src=\"" + output_main_filename + "\"></script>")
+ output_html_include_file.write("<script type=\"text/javascript\" src=\"" + output_main_filename.replace('\\', '/') + "\"></script>")
except Exception, e:
print >> sys.stderr, 'error: Splitting of Emscripten generated Javascript failed: %s' % str(e)
finally:
- if input_file is not None: input_file.close()
- if output_main_file is not None: output_main_file.close()
- if output_part_file is not None: output_part_file.close()
- if output_html_include_file is not None: output_html_include_file.close() \ No newline at end of file
+ if input_file is not None: input_file.close()
+ if output_main_file is not None: output_main_file.close()
+ if output_part_file is not None: output_part_file.close()
+ if output_html_include_file is not None: output_html_include_file.close() \ No newline at end of file