diff options
author | Alon Zakai <alonzakai@gmail.com> | 2013-09-10 14:30:47 -0700 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2013-09-10 14:30:47 -0700 |
commit | ea729bea8c5008dedcdfd79aaf3b2deba3eec52b (patch) | |
tree | 33468a444c19bcdf0edc5bf33aa1e39371280bcc | |
parent | 690a9e16e812301245a12a6ac8f7597552255719 (diff) | |
parent | 48b79570deeee7fa22a6c5876aa949601aa7549d (diff) |
Merge pull request #1605 from juj/mingw32make_nmake_cmake
Mingw32make nmake cmake
-rw-r--r-- | tests/test_other.py | 124 | ||||
-rw-r--r-- | tools/shared.py | 55 |
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() |