Skip to content

Commit 2b03402

Browse files
committed
Added cmake toolchain file for Emscripten and a other.test_cmake to tests its functionality.
1 parent 1bc86fd commit 2b03402

4 files changed

Lines changed: 122 additions & 0 deletions

File tree

cmake/Platform/Emscripten.cmake

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# This file is a 'toolchain description file' for CMake.
2+
# It teaches CMake about the Emscripten compiler, so that CMake can generate Unix Makefiles
3+
# from CMakeLists.txt that invoke emcc.
4+
5+
# To use this toolchain file with CMake, invoke CMake with the following command line parameters
6+
# cmake -DEMSCRIPTEN=1
7+
# -DCMAKE_TOOLCHAIN_FILE=<EmscriptenRoot>/cmake/Platform/Emscripten.cmake
8+
# -DCMAKE_MODULE_PATH=<EmscriptenRoot>/cmake
9+
# -DCMAKE_BUILD_TYPE=<Debug|RelWithDebInfo|Release|MinSizeRel>
10+
# -G "Unix Makefiles"
11+
# <path/to/CMakeLists.txt> # Note, pass in here ONLY the path to the file, not the filename 'CMakeLists.txt' itself.
12+
13+
# After that, build the generated Makefile with the command 'make'. On Windows, you may download and use 'mingw32-make' instead.
14+
15+
# the name of the target operating system
16+
SET(CMAKE_SYSTEM_NAME Emscripten)
17+
SET(CMAKE_SYSTEM_VERSION 1)
18+
19+
if ("$ENV{EMCC_BIN}" STREQUAL "")
20+
message(ERROR "Environment variable EMCC_BIN has not been set! Please point it to Emscripten root directory!")
21+
endif()
22+
23+
#message(STATUS "CMake is using Emscripten toolchain file, Emscripten root path '$ENV{EMCC_BIN}'.")
24+
25+
SET(CMAKE_FIND_ROOT_PATH $ENV{EMCC_BIN})
26+
27+
FILE(TO_CMAKE_PATH "$ENV{EMCC_BIN}" EMCC_PATH)
28+
29+
# Specify the compilers to use for C and C++
30+
SET(CMAKE_C_COMPILER ${EMCC_PATH}/emcc)
31+
SET(CMAKE_CXX_COMPILER ${EMCC_PATH}/em++)
32+
SET(CMAKE_AR ${EMCC_PATH}/emar)
33+
SET(CMAKE_RANLIB ${EMCC_PATH}/emranlib)
34+
35+
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
36+
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
37+
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH)
38+
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
39+
40+
# Specify the program to use when building static libraries. Force Emscripten-related command line options to clang.
41+
SET(CMAKE_CXX_ARCHIVE_CREATE "${CMAKE_CXX_COMPILER} -o <TARGET> -emit-llvm <LINK_FLAGS> <OBJECTS>")
42+
SET(CMAKE_C_ARCHIVE_CREATE "${CMAKE_C_COMPILER} -o <TARGET> -emit-llvm <LINK_FLAGS> <OBJECTS>")
43+
44+
# Set a global EMSCRIPTEN variable that can be used in client CMakeLists.txt to detect when building using Emscripten.
45+
# There seems to be some kind of bug with CMake, so you might need to define this manually on the command line with "-DEMSCRIPTEN=1".
46+
SET(EMSCRIPTEN 1)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
cmake_minimum_required(VERSION 2.8)
2+
3+
project(hello_world_gles.html)
4+
5+
file(GLOB sourceFiles ../../hello_world_gles.c)
6+
7+
if (CMAKE_BUILD_TYPE STREQUAL Debug)
8+
SET(linkFlags "")
9+
else() # Either MinSizeRel, RelWithDebInfo or Release, all which run with optimizations enabled.
10+
SET(linkFlags "-O2")
11+
endif()
12+
13+
add_executable(hello_world_gles.html ${sourceFiles})
14+
set_target_properties(hello_world_gles.html PROPERTIES LINK_FLAGS "${linkFlags}")
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
cmake_minimum_required(VERSION 2.8)
2+
3+
project(hello_world.js)
4+
5+
file(GLOB sourceFiles ../../hello_world.cpp)
6+
7+
if (CMAKE_BUILD_TYPE STREQUAL Debug)
8+
SET(linkFlags "")
9+
else() # Either MinSizeRel, RelWithDebInfo or Release, all which run with optimizations enabled.
10+
SET(linkFlags "-O2")
11+
endif()
12+
13+
add_executable(hello_world.js ${sourceFiles})
14+
set_target_properties(hello_world.js PROPERTIES LINK_FLAGS "${linkFlags}")

tests/runner.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7451,6 +7451,54 @@ def test_emcc(self):
74517451
# TODO: test normal project linking, static and dynamic: get_library should not need to be told what to link!
74527452
# TODO: deprecate llvm optimizations, dlmalloc, etc. in emscripten.py.
74537453

7454+
def test_cmake(self):
7455+
emscriptencmaketoolchain = path_from_root('cmake', 'Platform', 'Emscripten.cmake')
7456+
7457+
# On Windows, we want to build cmake-generated Makefiles with mingw32-make instead of e.g. cygwin make, since mingw32-make
7458+
# understands Windows paths, and cygwin make additionally produces a cryptic 'not valid bitcode file' errors on files that
7459+
# *are* valid bitcode files.
7460+
if os.name == 'nt':
7461+
make_command = 'mingw32-make'
7462+
else:
7463+
make_command = 'make'
7464+
7465+
cmake_cases = ['target_js', 'target_html']
7466+
cmake_outputs = ['hello_world.js', 'hello_world_gles.html']
7467+
for i in range(0, 2):
7468+
for configuration in ['Debug', 'Release']:
7469+
7470+
# Create a temp workspace folder
7471+
cmakelistsdir = path_from_root('tests', 'cmake', cmake_cases[i])
7472+
tempdirname = tempfile.mkdtemp(prefix='emscripten_test_' + self.__class__.__name__ + '_', dir=TEMP_DIR)
7473+
try:
7474+
os.chdir(tempdirname)
7475+
7476+
# Run Cmake
7477+
cmd = ['cmake', '-DCMAKE_TOOLCHAIN_FILE='+emscriptencmaketoolchain, '-DCMAKE_BUILD_TYPE=' + configuration, '-G' 'Unix Makefiles', cmakelistsdir]
7478+
ret = Popen(cmd, stdout=PIPE, stderr=PIPE).communicate()
7479+
if 'error' in ret[1].lower():
7480+
print >> sys.stderr, 'Failed command: ' + ' '.join(cmd)
7481+
print >> sys.stderr, 'Result:\n' + ret[1]
7482+
raise Exception('cmake call failed!') # cmake spams this silly message to stderr, so hide it: "Platform/Emscripten to use this system, please send your config file to [email protected] so it can be added to cmake"
7483+
assert os.path.exists(tempdirname + '/Makefile'), 'CMake call did not produce a Makefile!'
7484+
7485+
# Build
7486+
cmd = [make_command]
7487+
ret = Popen(cmd, stdout=PIPE).communicate()
7488+
if 'error' in ret[0].lower() and not '0 error(s)' in ret[0].lower():
7489+
print >> sys.stderr, 'Failed command: ' + ' '.join(cmd)
7490+
print >> sys.stderr, 'Result:\n' + ret[0]
7491+
raise Exception('make failed!')
7492+
assert os.path.exists(tempdirname + '/' + cmake_outputs[i]), 'Building a cmake-generated Makefile failed to produce an output file!'
7493+
7494+
# Run through node, if CMake produced a .js file.
7495+
if cmake_outputs[i].endswith('.js'):
7496+
ret = Popen([NODE_JS, tempdirname + '/' + cmake_outputs[i]], stdout=PIPE).communicate()[0]
7497+
assert 'hello, world!' in ret, 'Running cmake-based .js application failed!'
7498+
finally:
7499+
os.chdir(path_from_root('tests')) # Move away from the directory we are about to remove.
7500+
shutil.rmtree(tempdirname)
7501+
74547502
def test_Os(self):
74557503
for opt in ['s', '0']:
74567504
output = Popen(['python', EMCC, path_from_root('tests', 'hello_world.c'), '-O' + opt], stdout=PIPE, stderr=PIPE).communicate()

0 commit comments

Comments
 (0)