aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2013-09-10 14:30:47 -0700
committerAlon Zakai <alonzakai@gmail.com>2013-09-10 14:30:47 -0700
commitea729bea8c5008dedcdfd79aaf3b2deba3eec52b (patch)
tree33468a444c19bcdf0edc5bf33aa1e39371280bcc
parent690a9e16e812301245a12a6ac8f7597552255719 (diff)
parent48b79570deeee7fa22a6c5876aa949601aa7549d (diff)
Merge pull request #1605 from juj/mingw32make_nmake_cmake
Mingw32make nmake cmake
-rw-r--r--tests/test_other.py124
-rw-r--r--tools/shared.py55
2 files changed, 115 insertions, 64 deletions
diff --git a/tests/test_other.py b/tests/test_other.py
index 627995e9..64be60fa 100644
--- a/tests/test_other.py
+++ b/tests/test_other.py
@@ -275,71 +275,77 @@ f.close()
# TODO: deprecate llvm optimizations, dlmalloc, etc. in emscripten.py.
def test_cmake(self):
- # On Windows, we want to build cmake-generated Makefiles with mingw32-make instead of e.g. cygwin make, since mingw32-make
- # understands Windows paths, and cygwin make additionally produces a cryptic 'not valid bitcode file' errors on files that
- # *are* valid bitcode files.
+ # Test all supported generators.
+ if WINDOWS:
+ generators = ['MinGW Makefiles', 'NMake Makefiles']
+ else:
+ generators = ['Unix Makefiles']
+
+ make_commands = { 'MinGW Makefiles': ['mingw32-make'], 'NMake Makefiles': ['nmake', '/NOLOGO'], 'Unix Makefiles': ['make'] }
if os.name == 'nt':
- make_command = 'mingw32-make'
- generator = 'MinGW Makefiles'
emconfigure = path_from_root('emconfigure.bat')
else:
- make_command = 'make'
- generator = 'Unix Makefiles'
emconfigure = path_from_root('emconfigure')
- cmake_cases = ['target_js', 'target_html']
- cmake_outputs = ['hello_world.js', 'hello_world_gles.html']
- for i in range(0, 2): # Test both JS and HTML build outputs from CMake.
- for configuration in ['Debug', 'Release']:
- # CMake can be invoked in two ways, using 'emconfigure cmake', or by directly running 'cmake'.
- # Test both methods.
- for invoke_method in ['cmake', 'emconfigure']:
-
- # Create a temp workspace folder
- cmakelistsdir = path_from_root('tests', 'cmake', cmake_cases[i])
- tempdirname = tempfile.mkdtemp(prefix='emscripten_test_' + self.__class__.__name__ + '_', dir=TEMP_DIR)
- try:
- os.chdir(tempdirname)
-
- verbose_level = int(os.getenv('EM_BUILD_VERBOSE')) if os.getenv('EM_BUILD_VERBOSE') != None else 0
-
- # Run Cmake
- if invoke_method == 'cmake':
- # Test invoking cmake directly.
- cmd = ['cmake', '-DCMAKE_TOOLCHAIN_FILE='+path_from_root('cmake', 'Platform', 'Emscripten.cmake'),
- '-DCMAKE_BUILD_TYPE=' + configuration, '-G', generator, cmakelistsdir]
- else:
- # Test invoking via 'emconfigure cmake'
- cmd = [emconfigure, 'cmake', '-DCMAKE_BUILD_TYPE=' + configuration, '-G', generator, cmakelistsdir]
-
- ret = Popen(cmd, stdout=None if verbose_level >= 2 else PIPE, stderr=None if verbose_level >= 1 else PIPE).communicate()
- if len(ret) > 1 and ret[1] != None and len(ret[1].strip()) > 0:
- logging.error(ret[1]) # If there were any errors, print them directly to console for diagnostics.
- if len(ret) > 1 and ret[1] != None and 'error' in ret[1].lower():
- logging.error('Failed command: ' + ' '.join(cmd))
- logging.error('Result:\n' + ret[1])
- raise Exception('cmake call failed!')
- assert os.path.exists(tempdirname + '/Makefile'), 'CMake call did not produce a Makefile!'
-
- # Build
- cmd = [make_command] + (['VERBOSE=1'] if verbose_level >= 3 else [])
- ret = Popen(cmd, stdout=None if verbose_level >= 2 else PIPE).communicate()
- if len(ret) > 1 and ret[1] != None and len(ret[1].strip()) > 0:
- logging.error(ret[1]) # If there were any errors, print them directly to console for diagnostics.
- if len(ret) > 0 and ret[0] != None and 'error' in ret[0].lower() and not '0 error(s)' in ret[0].lower():
- logging.error('Failed command: ' + ' '.join(cmd))
- logging.error('Result:\n' + ret[0])
- raise Exception('make failed!')
- assert os.path.exists(tempdirname + '/' + cmake_outputs[i]), 'Building a cmake-generated Makefile failed to produce an output file %s!' % tempdirname + '/' + cmake_outputs[i]
-
- # Run through node, if CMake produced a .js file.
- if cmake_outputs[i].endswith('.js'):
- ret = Popen(listify(NODE_JS) + [tempdirname + '/' + cmake_outputs[i]], stdout=PIPE).communicate()[0]
- assert 'hello, world!' in ret, 'Running cmake-based .js application failed!'
- finally:
- os.chdir(path_from_root('tests')) # Move away from the directory we are about to remove.
- shutil.rmtree(tempdirname)
+ for generator in generators:
+ if generator == 'NMake Makefiles' and not Building.which('nmake'):
+ print >> sys.stderr, 'Skipping NMake test for CMake support, since nmake was not found in PATH. Run this test in Visual Studio command prompt to easily access nmake.'
+ continue
+
+ make = make_commands[generator]
+ cmake_cases = ['target_js', 'target_html']
+ cmake_outputs = ['hello_world.js', 'hello_world_gles.html']
+ for i in range(0, 2):
+ for configuration in ['Debug', 'Release']:
+ # CMake can be invoked in two ways, using 'emconfigure cmake', or by directly running 'cmake'.
+ # Test both methods.
+ for invoke_method in ['cmake', 'emconfigure']:
+
+ # Create a temp workspace folder
+ cmakelistsdir = path_from_root('tests', 'cmake', cmake_cases[i])
+ tempdirname = tempfile.mkdtemp(prefix='emscripten_test_' + self.__class__.__name__ + '_', dir=TEMP_DIR)
+ try:
+ os.chdir(tempdirname)
+
+ verbose_level = int(os.getenv('EM_BUILD_VERBOSE')) if os.getenv('EM_BUILD_VERBOSE') != None else 0
+
+ # Run Cmake
+ if invoke_method == 'cmake':
+ # Test invoking cmake directly.
+ cmd = ['cmake', '-DCMAKE_TOOLCHAIN_FILE='+path_from_root('cmake', 'Platform', 'Emscripten.cmake'),
+ '-DCMAKE_BUILD_TYPE=' + configuration, '-G', generator, cmakelistsdir]
+ else:
+ # Test invoking via 'emconfigure cmake'
+ cmd = [emconfigure, 'cmake', '-DCMAKE_BUILD_TYPE=' + configuration, '-G', generator, cmakelistsdir]
+
+ ret = Popen(cmd, stdout=None if verbose_level >= 2 else PIPE, stderr=None if verbose_level >= 1 else PIPE).communicate()
+ if len(ret) > 1 and ret[1] != None and len(ret[1].strip()) > 0:
+ logging.error(ret[1]) # If there were any errors, print them directly to console for diagnostics.
+ if len(ret) > 1 and ret[1] != None and 'error' in ret[1].lower():
+ logging.error('Failed command: ' + ' '.join(cmd))
+ logging.error('Result:\n' + ret[1])
+ raise Exception('cmake call failed!')
+ assert os.path.exists(tempdirname + '/Makefile'), 'CMake call did not produce a Makefile!'
+
+ # Build
+ cmd = make + (['VERBOSE=1'] if verbose_level >= 3 else [])
+ ret = Popen(cmd, stdout=None if verbose_level >= 2 else PIPE).communicate()
+ if len(ret) > 1 and ret[1] != None and len(ret[1].strip()) > 0:
+ logging.error(ret[1]) # If there were any errors, print them directly to console for diagnostics.
+ if len(ret) > 0 and ret[0] != None and 'error' in ret[0].lower() and not '0 error(s)' in ret[0].lower():
+ logging.error('Failed command: ' + ' '.join(cmd))
+ logging.error('Result:\n' + ret[0])
+ raise Exception('make failed!')
+ assert os.path.exists(tempdirname + '/' + cmake_outputs[i]), 'Building a cmake-generated Makefile failed to produce an output file %s!' % tempdirname + '/' + cmake_outputs[i]
+
+ # Run through node, if CMake produced a .js file.
+ if cmake_outputs[i].endswith('.js'):
+ ret = Popen(listify(NODE_JS) + [tempdirname + '/' + cmake_outputs[i]], stdout=PIPE).communicate()[0]
+ assert 'hello, world!' in ret, 'Running cmake-based .js application failed!'
+ finally:
+ os.chdir(path_from_root('tests')) # Move away from the directory we are about to remove.
+ shutil.rmtree(tempdirname)
def test_failure_error_code(self):
for compiler in [EMCC, EMXX]:
diff --git a/tools/shared.py b/tools/shared.py
index 8031d99c..94daadae 100644
--- a/tools/shared.py
+++ b/tools/shared.py
@@ -820,14 +820,52 @@ class Building:
env['EMSCRIPTEN'] = path_from_root()
return env
+ # Finds the given executable 'program' in PATH. Operates like the Unix tool 'which'.
+ @staticmethod
+ def which(program):
+ import os
+ def is_exe(fpath):
+ return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
+
+ fpath, fname = os.path.split(program)
+ if fpath:
+ if is_exe(program):
+ return program
+ else:
+ for path in os.environ["PATH"].split(os.pathsep):
+ path = path.strip('"')
+ exe_file = os.path.join(path, program)
+ if is_exe(exe_file):
+ return exe_file
+
+ if WINDOWS and not '.' in fname:
+ if is_exe(exe_file + '.exe'):
+ return exe_file + '.exe'
+ if is_exe(exe_file + '.cmd'):
+ return exe_file + '.cmd'
+ if is_exe(exe_file + '.bat'):
+ return exe_file + '.bat'
+
+ return None
+
@staticmethod
def handle_CMake_toolchain(args, env):
- # Don't append a toolchain file if the user specified one already.
- for arg in args:
- if '-DCMAKE_TOOLCHAIN_FILE' in arg:
- return args
- args.append('-DCMAKE_TOOLCHAIN_FILE=' + path_from_root('cmake', 'Platform', 'Emscripten.cmake'))
+ def has_substr(array, substr):
+ for arg in array:
+ if substr in arg:
+ return True
+ return False
+
+ # Append the Emscripten toolchain file if the user didn't specify one.
+ if not has_substr(args, '-DCMAKE_TOOLCHAIN_FILE'):
+ args.append('-DCMAKE_TOOLCHAIN_FILE=' + path_from_root('cmake', 'Platform', 'Emscripten.cmake'))
+
+ # On Windows specify MinGW Makefiles if we have MinGW and no other toolchain was specified, to avoid CMake
+ # pulling in a native Visual Studio, or Unix Makefiles.
+ if WINDOWS and not '-G' in args and Building.which('mingw32-make'):
+ args += ['-G', 'MinGW Makefiles']
+
return args
@staticmethod
@@ -858,6 +896,13 @@ class Building:
logging.error('Executable to run not specified.')
sys.exit(1)
#args += ['VERBOSE=1']
+
+ # On Windows prefer building with mingw32-make instead of make, if it exists.
+ if WINDOWS and args[0] == 'make':
+ mingw32_make = Building.which('mingw32-make')
+ if mingw32_make:
+ args[0] = mingw32_make
+
try:
process = Popen(args, stdout=stdout, stderr=stderr, env=env)
process.communicate()