aboutsummaryrefslogtreecommitdiff
path: root/emcc.py
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2011-11-20 21:02:46 -0800
committerAlon Zakai <alonzakai@gmail.com>2011-11-20 21:02:46 -0800
commit386dc0fa02d54a8d91a0993259415f5713d5e781 (patch)
tree4068314930d5947b34c3419150f798fbbd57b147 /emcc.py
parentdfe5f60e7c44d3f7fc7ac92e0ce6e76497319480 (diff)
sketch of emcc
Diffstat (limited to 'emcc.py')
-rwxr-xr-xemcc.py231
1 files changed, 231 insertions, 0 deletions
diff --git a/emcc.py b/emcc.py
new file mode 100755
index 00000000..2499e5d9
--- /dev/null
+++ b/emcc.py
@@ -0,0 +1,231 @@
+#!/usr/bin/env python
+
+'''
+emcc - compiler helper script
+=============================
+
+emcc is a drop-in replacement for a compiler like gcc or clang.
+
+Tell your build system to use this instead of the compiler, linker, ar and
+ranlib. All the normal build commands will be sent to this script, which
+will proxy them to the appropriate LLVM build commands, in order to
+generate proper code for Emscripten to later process.
+
+For example, compilation will be translated into calls to clang
+with -emit-llvm, and linking will be translated into calls to llvm-link,
+and so forth.
+
+emcc is only meant to *COMPILE* source code into LLVM bitcode. It does
+not do optimizations (in fact, it will disable -Ox flags and warn you
+about that). The reason is that doing such optimizations early can lead
+to bitcode that Emscripten cannot process properly, or can process but
+not fully optimize. You can (and probably should) still run LLVM
+optimizations though, by telling emscripten.py to do so (or run LLVM
+opt yourself, but be careful with the parameters you pass).
+
+Example uses:
+
+ * For configure, instead of ./configure, cmake, etc., run emconfiguren.py
+ with that command as an argument, for example
+
+ emconfiguren.py ./configure [options]
+
+ emconfiguren.py is a tiny script that just sets some environment vars
+ as a convenience. The command just shown is equivalent to
+
+ EMMAKEN_JUST_CONFIGURE=1 RANLIB=PATH/emcc.py AR=PATH/emcc.py CXX=PATH/em++.py CC=PATH/emcc.py ./configure [options]
+
+ where PATH is the path to this file.
+
+ EMMAKEN_JUST_CONFIGURE tells emcc that it is being run in ./configure,
+ so it should relay everything to gcc/g++. You should not define that when
+ running make, of course.
+
+ * With CMake, the same command will work (with cmake instead of ./configure). You may also be
+ able to do the following in your CMakeLists.txt:
+
+ SET(CMAKE_C_COMPILER "PATH/emcc.py")
+ SET(CMAKE_CXX_COMPILER "PATH/em++.py")
+ SET(CMAKE_LINKER "PATH/emcc.py")
+ SET(CMAKE_CXX_LINKER "PATH/emcc.py")
+ SET(CMAKE_C_LINK_EXECUTABLE "PATH/emcc.py")
+ SET(CMAKE_CXX_LINK_EXECUTABLE "PATH/emcc.py")
+ SET(CMAKE_AR "PATH/emcc.py")
+ SET(CMAKE_RANLIB "PATH/emcc.py")
+
+ * For SCons the shared.py can be imported like so:
+ __file__ = str(Dir('#/project_path_to_emscripten/dummy/dummy'))
+ __rootpath__ = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
+ def path_from_root(*pathelems):
+ return os.path.join(__rootpath__, *pathelems)
+ exec(open(path_from_root('tools', 'shared.py'), 'r').read())
+
+ For using the Emscripten compilers/linkers/etc. you can do:
+ env = Environment()
+ ...
+ env.Append(CCFLAGS = COMPILER_OPTS)
+ env.Replace(LINK = LLVM_LD)
+ env.Replace(LD = LLVM_LD)
+ TODO: Document all relevant setup changes
+
+After setting that up, run your build system normally. It should generate
+LLVM instead of the normal output, and end up with .ll files that you can
+give to Emscripten. Note that this tool doesn't run Emscripten itself. Note
+also that you may need to do some manual fiddling later, for example to
+link files that weren't linked, and them llvm-dis them.
+
+Note the appearance of em++.py instead of emcc.py
+for the C++ compiler. This is needed for cases where we get
+a C++ file with a C extension, in which case CMake can be told
+to run g++ on it despite the .c extension, see
+
+ https://github.com/kripken/emscripten/issues/6
+
+(If a similar situation occurs with ./configure, you can do the same there too.)
+
+emcc can be influenced by a few environment variables:
+
+ EMMAKEN_NO_SDK - Will tell emcc *not* to use the emscripten headers. Instead
+ your system headers will be used.
+
+ EMMAKEN_COMPILER - The compiler to be used, if you don't want the default clang.
+
+'''
+
+import sys
+import os
+import subprocess
+
+################### XXX
+print >> sys.stderr, '***This is a WORK IN PROGRESS***'
+################### XXX
+
+print >> sys.stderr, 'emcc.py: ', ' '.join(sys.argv)
+
+__rootpath__ = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
+def path_from_root(*pathelems):
+ return os.path.join(__rootpath__, *pathelems)
+exec(open(path_from_root('tools', 'shared.py'), 'r').read())
+
+# If this is a configure-type thing, just do that
+CONFIGURE_CONFIG = os.environ.get('EMMAKEN_JUST_CONFIGURE')
+CMAKE_CONFIG = 'CMakeFiles/cmTryCompileExec.dir' in ' '.join(sys.argv)# or 'CMakeCCompilerId' in ' '.join(sys.argv)
+if CONFIGURE_CONFIG or CMAKE_CONFIG:
+ compiler = 'g++' if 'CXXCompiler' in ' '.join(sys.argv) or os.environ.get('EMMAKEN_CXX') else 'gcc'
+ cmd = [compiler] + EMSDK_OPTS + sys.argv[1:]
+ print >> sys.stderr, 'emcc.py, just configuring: ', cmd
+ exit(os.execvp(compiler, cmd))
+
+try:
+ #f=open('/dev/shm/tmp/waka.txt', 'a')
+ #f.write('Args: ' + ' '.join(sys.argv) + '\nCMake? ' + str(CMAKE_CONFIG) + '\n')
+ #f.close()
+
+ if os.environ.get('EMMAKEN_COMPILER'):
+ CXX = os.environ['EMMAKEN_COMPILER']
+ else:
+ CXX = CLANG
+
+ CC = to_cc(CXX)
+
+ # If we got here from a redirection through emmakenxx.py, then force a C++ compiler here
+ if os.environ.get('EMMAKEN_CXX'):
+ CC = CXX
+
+ CC_ADDITIONAL_ARGS = COMPILER_OPTS # + ['-g']?
+ ALLOWED_LINK_ARGS = ['-f', '-help', '-o', '-print-after', '-print-after-all', '-print-before',
+ '-print-before-all', '-time-passes', '-v', '-verify-dom-info', '-version' ]
+ TWO_PART_DISALLOWED_LINK_ARGS = ['-L'] # Ignore thingsl like |-L .|
+
+ EMMAKEN_CFLAGS = os.environ.get('EMMAKEN_CFLAGS')
+ if EMMAKEN_CFLAGS: CC_ADDITIONAL_ARGS += EMMAKEN_CFLAGS.split(' ')
+
+ # ---------------- End configs -------------
+
+ if len(sys.argv) == 2 and 'conftest' not in ' '.join(sys.argv): # Avoid messing with configure, see below too
+ # ranlib
+ sys.exit(0)
+ if len(sys.argv) == 1 or sys.argv[1] in ['x', 't']:
+ # noop ar
+ sys.exit(0)
+
+ use_cxx = True
+ use_linker = True
+ header = False # pre-compiled headers. We fake that by just copying the file
+
+ opts = []
+ files = []
+ for i in range(1, len(sys.argv)):
+ arg = sys.argv[i]
+ if arg.startswith('-'):
+ opts.append(arg)
+ else:
+ files.append(arg)
+ if arg.endswith('.c'):
+ use_cxx = False
+ if arg.endswith(('.c', '.cc', '.cpp', '.dT')):
+ use_linker = False
+ if arg.endswith('.h') and sys.argv[i-1] != '-include':
+ header = True
+ use_linker = False
+
+ if '--version' in opts:
+ use_linker = False
+
+ if set(sys.argv[1]).issubset(set('-cruqs')): # ar
+ sys.argv = sys.argv[:1] + sys.argv[3:] + ['-o='+sys.argv[2]]
+ assert use_linker, 'Linker should be used in this case'
+
+ if use_linker:
+ call = LLVM_LD
+ newargs = ['-disable-opt']
+ found_o = False
+ i = 0
+ while i < len(sys.argv)-1:
+ i += 1
+ arg = sys.argv[i]
+ if found_o:
+ newargs.append('-o=%s' % arg)
+ found_o = False
+ continue
+ if arg.startswith('-'):
+ if arg == '-o':
+ found_o = True
+ continue
+ prefix = arg.split('=')[0]
+ if prefix in ALLOWED_LINK_ARGS:
+ newargs.append(arg)
+ if arg in TWO_PART_DISALLOWED_LINK_ARGS:
+ i += 1
+ elif arg.endswith('.so'):
+ continue # .so's do not exist yet, in many cases
+ else:
+ # not option, so just append
+ newargs.append(arg)
+ elif not header:
+ call = CXX if use_cxx else CC
+ newargs = sys.argv[1:]
+ for i in range(len(newargs)):
+ if newargs[i].startswith('-O'):
+ print >> sys.stderr, 'emcc.py: WARNING: Optimization flags (-Ox) are ignored in emcc. Tell emscripten.py to do that, or run LLVM opt.'
+ newargs[i] = ''
+ newargs = [ arg for arg in newargs if arg is not '' ] + CC_ADDITIONAL_ARGS
+ newargs.append('-emit-llvm')
+ if not use_linker:
+ newargs.append('-c')
+ else:
+ print >> sys.stderr, 'Just copy.'
+ shutil.copy(sys.argv[-1], sys.argv[-2])
+ exit(0)
+
+ #f=open('/dev/shm/tmp/waka.txt', 'a')
+ #f.write('Calling: ' + ' '.join(newargs) + '\n\n')
+ #f.close()
+
+ print >> sys.stderr, "Running:", call, ' '.join(newargs)
+
+ os.execvp(call, [call] + newargs)
+except Exception, e:
+ print 'Error in emcc.py. (Is the config file ~/.emscripten set up properly?) Error:', e
+ raise
+