def build( modules, module_path, datadirs=None ):
	if '--debug-build' in sys.argv:
		raise RuntimeError(modules)
	output = {'executeables':[], 'rust':[], 'c':[], 'c++':[], 'c#':[], 'go':[], 'javascript':[], 'java':[], 'xml':[], 'json':[], 'python':[], 'html':[], 'verilog':[], 'nim':[], 'lua':[], 'dart':[], 'datadirs':datadirs, 'datafiles':{}}
	python_main = {'name':'main.py', 'script':[]}
	go_main = {'name':'main.go', 'source':[]}
	tagged  = {}
	link    = []
	giws    = []   ## xml jni generator so c++ can call into java, blocks tagged with @gwis are compiled and linked with the final exe.
	java2rusthon = []
	nim_wrappers = []
	libdl = False ## provides: dlopen, dlclose, for dynamic libs. Nim needs this
	cached_json = {}
	gyp_builds  = {}

	if modules['bash']:
		for mod in modules['bash']:
			if 'tag' in mod and mod['tag']:
				tag = mod['tag']
				if tag.startswith('http://') or tag.startswith('https://'):
					if not tag.endswith('.git'):
						raise SyntaxError('only git repos links are allowed: '+tag)
					if not os.path.isdir(GITCACHE):
						print 'making new rusthon cache folder: ' + GITCACHE
						os.mkdir(GITCACHE)

					gitname = tag.split('/')[-1][:-4]
					projectdir = os.path.join(GITCACHE, gitname)

					rebuild = True
					if gitname not in os.listdir(GITCACHE):
						cmd = ['git', 'clone', tag]
						subprocess.check_call(cmd, cwd=GITCACHE)
					elif '--git-sync' in sys.argv:
						cmd = ['git', 'pull']
						subprocess.check_call(cmd, cwd=projectdir)
					else:
						rebuild = False

					if rebuild or '--force-rebuild-deps' in sys.argv:
						print 'rebuilding git repo: ' + tag
						## TODO restrict the bash syntax allowed here,
						## or build it in a sandbox or docker container.
						for line in mod['code'].splitlines():
							if not line.strip(): continue
							if not is_restricted_bash(line):
								raise SyntaxError('bash build script syntax is restricted:\n'+line)
							else:
								print '>>'+line
							subprocess.check_call( line.split(), cwd=projectdir )

				else:
					output['datafiles'][tag] = mod['code']


	if modules['gyp']:
		for mod in modules['gyp']:
			if 'tag' in mod and mod['tag']:
				if not mod['tag'] != 'binding.gyp':
					raise RuntimeError('nw-gyp requires the gyp file is named `binding.gyp`')

			output['datafiles']['binding.gyp'] = mod['code']

			gypcfg = json.loads( mod['code'].replace("'", '"') )
			#if len(gypcfg['targets']) > 1:
			#	continue
			for gtarget in gypcfg['targets']:
				for gsrc in gtarget['sources']:
					gyp_builds[ gsrc ] = {
						'gyp':mod['code'],
						'src': None
					}


	if modules['javascript']:
		for mod in modules['javascript']:
			if 'tag' in mod and mod['tag']:
				tagged[ mod['tag'] ] = mod['code']
				if '.' in mod['tag']:
					output['datafiles'][mod['tag']] = mod['code']

	if modules['json']:
		for mod in modules['json']:
			cached_json[ mod['name'] ] = mod['code']
			output['json'].append(mod)

	if modules['c#']:
		for mod in modules['c#']:
			output['c#'].append(mod)

	if modules['elm']:
		for mod in modules['elm']:
			tmpelm = tempfile.gettempdir() + '/MyApp.elm'
			tmpjs = tempfile.gettempdir() + '/elm-output.js'
			open(tmpelm, 'wb').write(mod['code'])
			subprocess.check_call(['elm-make', tmpelm, '--output', tmpjs])
			elmdata = open(tmpjs,'rb').read()
			output['datafiles'][mod['tag']] = elmdata
			tagged[ mod['tag'] ] = elmdata


	if modules['coffee']:
		for mod in modules['coffee']:
			tmpcoff = tempfile.gettempdir() + '/temp.coffee'
			tmpjs = tempfile.gettempdir() + '/coffee-output.js'
			open(tmpcoff, 'wb').write(mod['code'])
			subprocess.check_call(['coffee', '--compile', '--bare', '--output', tmpjs, tmpcoff])
			coffdata = open(tmpjs+'/temp.js','rb').read()
			output['datafiles'][mod['tag']] = coffdata
			tagged[ mod['tag'] ] = coffdata

	if modules['rapydscript']:
		for mod in modules['rapydscript']:
			tmprapyd = tempfile.gettempdir() + '/temp.rapyd'
			tmpjs = tempfile.gettempdir() + '/rapyd-output.js'
			open(tmprapyd, 'wb').write(mod['code'].encode('utf-8'))
			subprocess.check_call(['rapydscript', tmprapyd, '--bare', '--output', tmpjs])
			rapydata = open(tmpjs,'rb').read()
			output['datafiles'][mod['tag']] = rapydata
			tagged[ mod['tag'] ] = rapydata

	if modules['nim']:
		libdl = True
		## if compile_nim_lib is False then use old hack to compile nim source by extracting it and forcing into a single file.
		compile_nim_lib = True
		nimbin = os.path.expanduser('~/Nim/bin/nim')
		niminclude = os.path.expanduser('~/Nim/lib')

		if os.path.isfile(nimbin):
			mods_sorted_by_index = sorted(modules['nim'], key=lambda mod: mod.get('index'))
			for mod in mods_sorted_by_index:

				if mod['tag']:  ## save standalone nim program, can be run with `rusthon.py my.md --run=myapp.nim`
					output['nim'].append(mod)

				else:  ## use nim to translate to C and build later as staticlib
					tmpfile = tempfile.gettempdir() + '/rusthon_build.nim'
					nimsrc = mod['code'].replace('\t', '  ')  ## nim will not accept tabs, replace with two spaces.
					gen_nim_wrappers( nimsrc, nim_wrappers )
					open(tmpfile, 'wb').write( nimsrc )
					if compile_nim_lib:
						## lets nim compile the library
						#cmd = [nimbin, 'compile', '--app:staticLib', '--noMain', '--header']  ## staticlib has problems linking with dlopen,etc.
						cmd = [nimbin, 'compile', '--app:lib', '--noMain', '--header']
					else:
						cmd = [
							nimbin,
							'compile',
							'--header',
							'--noMain',
							'--noLinking',
							'--compileOnly',
							'--genScript',   ## broken?
							'--app:staticLib', ## Araq says staticlib and noMain will not work together.
							'--deadCodeElim:on',
						]
					if 'import threadpool' in nimsrc:
						cmd.append('--threads:on')
					cmd.append('rusthon_build.nim')

					print('-------- compile nim program -----------')
					print(' '.join(cmd))
					subprocess.check_call(cmd, cwd=tempfile.gettempdir())

					if compile_nim_lib:
						## staticlib broken in nim? missing dlopen
						libname = 'rusthon_build'
						link.append(libname)
						#output['c'].append({'source':mod['code'], 'staticlib':libname+'.a'})
						output['c'].append(
							{'source':mod['code'], 'dynamiclib':libname+'.so', 'name':'lib%s.so'%libname}

						)
					else:
						## get source from nim cache ##
						nimcache = os.path.join(tempfile.gettempdir(), 'nimcache')
						nim_stdlib = hack_nim_stdlib(
							open(os.path.join(nimcache,'stdlib_system.c'), 'rb').read()
						)
						#nim_header = open(os.path.join(nimcache,'rusthon_build.h'), 'rb').read()
						nim_code   = hack_nim_code(
							open(os.path.join(nimcache,'rusthon_build.c'), 'rb').read()
						)

						## gets compiled below
						cfg = {
							'dynamic'   : True,
							'link-dirs' :[nimcache, niminclude],
							#'build-dirs':[nimcache],  ## not working
							'index'    : mod['index'],
							'code'     : '\n'.join([nim_stdlib, nim_code])
							#'code'     : header
						}
						modules['c'].append( cfg )
		else:
			print('WARNING: can not find nim compiler')

	if modules['java']:
		mods_sorted_by_index = sorted(modules['java'], key=lambda mod: mod.get('index'))
		javafiles = []
		tmpdir = tempfile.gettempdir()
		for mod in mods_sorted_by_index:
			if mod['tag']=='java2rusthon':
				rcode = java_to_rusthon( mod['code'] )
				java2rusthon.append( rcode )
			elif 'name' in mod:
				jpath = os.path.join(tmpdir, mod['name'])
				if '/' in mod['name']:
					jdir,jname = os.path.split(jpath)
					if not os.path.isdir(jdir):
						os.makedirs(jdir)
				open(jpath, 'wb').write(mod['code'])
				javafiles.append( jpath )
			else:
				raise SyntaxError('java code must have a tag header: `java2rusthon` or a file path')

		if javafiles:
			output['java'].append( compile_java( javafiles ) )


	if modules['xml']:
		mods_sorted_by_index = sorted(modules['xml'], key=lambda mod: mod.get('index'))
		for mod in mods_sorted_by_index:
			if mod['tag']=='gwis':
				giws.append(mod['code'])  ## hand written bindings should get saved in output tar.
				bindings = compile_giws_bindings(mod['code'])
				modules['c++'].append( {'code':bindings, 'index': mod['index']})  ## gets compiled below
			else:
				output['xml'].append(mod)

	js_merge  = []
	cpp_merge = []
	cpp_links = []
	cpp_idirs = []
	cpp_defines = []
	compile_mode = 'binary'
	exename = 'rusthon-test-bin'
	tagged_trans_src = {}


	if modules['rusthon']:
		mods_sorted_by_index = sorted(modules['rusthon'], key=lambda mod: mod.get('index'))
		for mod in mods_sorted_by_index:
			script = mod['code']
			index = mod.get('index')
			header = script.splitlines()[0]
			backend = 'c++'  ## default to c++ backend
			if header.startswith('#backend:'):
				backend = header.split(':')[-1].strip()
				if ' ' in backend:
					backend, compile_mode = backend.split(' ')
				if '\t' in backend:
					backend, compile_mode = backend.split('\t')

				if backend not in 'c++ rust javascript go verilog dart lua'.split():
					raise SyntaxError('invalid backend: %s' %backend)

				if compile_mode and compile_mode not in 'binary staticlib dynamiclib'.split():
					raise SyntaxError('invalid backend option <%s> (valid types: binary, staticlib, dynamiclib)' %backend)

			if backend == 'verilog':
				vcode = translate_to_verilog( script )
				modules['verilog'].append( {'code':vcode, 'index': index})  ## gets compiled below

			elif backend == 'c++':
				if mod['tag'] and mod['tag'] and '.' not in mod['tag']:
					exename = mod['tag']

				## user named output for external build tools that need .h,.hpp,.cpp, files output to hardcoded paths.
				if mod['tag'] and (mod['tag'].endswith('.h') or mod['tag'].endswith('.hpp') or mod['tag'].endswith('.cpp') or mod['tag'].endswith('.cc')):
					pyjs = python_to_pythonjs(script, cpp=True, module_path=module_path)
					use_try = True
					if '--no-except' in sys.argv:
						use_try = False
					elif mod['tag'] in gyp_builds.keys():  ## nw-gyp builds without c++ exceptions
						use_try = False

					pak = translate_to_cpp(
						pyjs, 
						cached_json_files=cached_json, 
						insert_runtime=mod['tag'] in gyp_builds.keys(),
						use_try = use_try
					)
					if '--debug-c++' in sys.argv:
						raise RuntimeError(pak)
					## pak contains: c_header and cpp_header
					output['datafiles'][ mod['tag'] ] = pak['main']  ## save to output c++ to tar

					if mod['tag'] in gyp_builds.keys():
						gyp_builds[ mod['tag'] ]['src'] = pak['main']

					if 'user-headers' in pak:
						for classtag in pak['user-headers'].keys():
							classheader = pak['user-headers'][ classtag ]
							headerfile  = classheader['file']
							if headerfile in output['datafiles']:
								output['datafiles'][ headerfile ] += '\n' + '\n'.join(classheader['source'])
							else:
								output['datafiles'][ headerfile ] = '\n'  + '\n'.join(classheader['source'])

				else:
					cpp_merge.append(script)

					if 'links' in mod:
						cpp_links.extend(mod['links'])
					if 'include-dirs' in mod:
						cpp_idirs.extend(mod['include-dirs'])
					if 'defines' in mod:
						cpp_defines.extend(mod['defines'])

			elif backend == 'rust':
				pyjs = python_to_pythonjs(script, rust=True, module_path=module_path)
				rustcode = translate_to_rust( pyjs )
				modules['rust'].append( {'code':rustcode, 'index': index})  ## gets compiled below

			elif backend == 'go':
				pyjs = python_to_pythonjs(script, go=True, module_path=module_path)
				gocode = translate_to_go( pyjs )
				#modules['go'].append( {'code':gocode})  ## gets compiled below
				go_main['source'].append( gocode )

			elif backend == 'javascript':
				if mod['tag'] and mod['tag'].endswith('.js'):  ## saves to external js file
					js = compile_js( mod['code'], module_path, main_name=mod['tag'] )
					mod['build'] = {'script':js[mod['tag']]}
					tagged[ mod['tag'] ] = js[mod['tag']]
					tagged_trans_src[ mod['tag'] ] = mod['code']  ## so user can embed original source using <!tagname>
					for name in js:
						output['javascript'].append( {'name':name, 'script':js[name], 'index': index} )
				else:
					js_merge.append(mod)

			elif backend == 'lua':
				pyjs = python_to_pythonjs(script, lua=True, module_path=module_path)
				luacode = translate_to_lua( pyjs )
				name = 'main.lua'
				if mod['tag']: name = mod['tag']
				if not name.endswith('.lua'): name += '.lua'
				output['lua'].append( {'name':name, 'script':luacode, 'index': index} )

			elif backend == 'dart':
				pyjs = python_to_pythonjs(script, dart=True, module_path=module_path)
				dartcode = translate_to_dart( pyjs )
				name = 'main.dart'
				if mod['tag']: name = mod['tag']
				if not name.endswith('.dart'): name += '.dart'
				output['dart'].append( {'name':name, 'script':dartcode, 'index': index} )

	if js_merge:
		taggroups = {}
		for mod in js_merge:
			tagname = mod['tag']
			if tagname not in taggroups:
				taggroups[tagname] = []

			src = taggroups[tagname]
			src.append( mod['code'] )
		for tagname in taggroups.keys():
			groupsrc = '\n'.join( taggroups[tagname] )
			js = compile_js( groupsrc, module_path, main_name=tagname )
			tagged[ tagname ]           = js[ tagname ]
			tagged_trans_src[ tagname ] = groupsrc

			for name in js:
				output['javascript'].append( {'name':name, 'script':js[name], 'index': index} )


	cpyembed = []
	nuitka = []
	nuitka_include_path = None  ## TODO option for this
	nuitka_module_name  = 'unnamed_nuitka_module'
	if modules['python']:
		mods_sorted_by_index = sorted(modules['python'], key=lambda mod: mod.get('index'))
		for mod in mods_sorted_by_index:
			if mod['tag']:
				name = mod['tag']
				if name == 'nuitka' or name.startswith('nuitka:'):
					if ':' in name:
						nuitka_module_name = name.split(':')[-1]
					if not len(nuitka):
						## __file__ is undefined when CPython is embedded
						#cpyembed.append('sys.path.append(os.path.dirname(__file__))')
						#cpyembed.append('print sys.argv')  ## also undefined
						cpyembed.append('import sys')
						cpyembed.append('sys.path.append("./")')
						cpyembed.append('from %s import *'%nuitka_module_name)

					nuitka.append(mod['code'])

				elif name == 'embed' or name == 'embed:cpython':
					cpyembed.append(mod['code'])
				else:
					if not name.endswith('.py'):
						name += '.py'
					output['python'].append( {'name':name, 'script':mod['code']} )
			else:
				if len(output['python'])==0:
					python_main['script'].append( mod['code'] )
				else:
					output['python'][-1]['script'] += '\n' + mod['code']


	if cpp_merge:
		merge = []
		nuitka_funcs = []
		if java2rusthon:
			merge.extend(java2rusthon)
			java2rusthon = None
		if nim_wrappers:
			## inserts generated rusthon nim wrappers into script before translation ##
			nim_wrappers.insert(0,'# nim wrappers generated by rusthon #')
			nim_wrappers.insert(1, 'with extern(abi="C"):')
			merge.extend(nim_wrappers)
		if nuitka:
			#npak = nuitka_compile_integrated('\n'.join(nuitka), nuitka_funcs)
			#for h in npak['files']:
			#	modules['c++'].append(
			#		{'code':h['data'], 'tag':h['name'], 'index':0}
			#	)
			nsrc = '\n'.join(nuitka)
			output['c++'].append(
				{
					'staticlib'   : nuitka_compile( nsrc, nuitka_module_name ),
					'source-name' : 'my_nuitka_module.py',
					'name'        : 'my_nuitka_module.so',
					'source'      : nsrc,
				}
			)

		merge.extend(cpp_merge)
		script = '\n'.join(merge)
		pyjs = python_to_pythonjs(script, cpp=True, module_path=module_path)
		pak = translate_to_cpp( pyjs, cached_json_files=cached_json )   ## pak contains: c_header and cpp_header
		n = len(modules['c++']) + len(giws)
		cppcode = pak['main']
		#if nuitka:
		#	cppcode = npak['main'] + '\n' + cppcode
		if cpyembed:
			inlinepy = ('\n'.join(cpyembed)).replace('\n', '\\n').replace('"', '\\"')
			staticstr = 'const char* __python_main_script__ = "%s";\n' %inlinepy
			cppcode = staticstr + cppcode
		modules['c++'].append(
			{'code':cppcode, 'index':n+1, 'links':cpp_links, 'include-dirs':cpp_idirs, 'defines':cpp_defines}
		)  ## gets compiled below



	## HTML ##
	if modules['html']:
		mods_sorted_by_index = sorted(modules['html'], key=lambda mod: mod.get('index'))
		for mod in mods_sorted_by_index:
			html = []
			for line in mod['code'].splitlines():
				## `~/some/path/myscript.js` special syntax to copy javascript directly into the output html, good for testing locally.
				if line.strip().startswith('<script ') and line.strip().endswith('</script>') and 'src="~/' in line:
					url = line.split('src="')[-1].split('"')[0]
					url = os.path.expanduser( url )

					if os.path.isfile(url):
						html.append('<script type="text/javascript">')
						html.append( open(url, 'rb').read().decode('utf-8') )
						html.append('</script>')
					elif 'git="' in line:
						giturl = line.split('git="')[-1].split('"')[0]
						print 'downloading library-> ' + giturl
						cmd = ['git', 'clone', giturl]
						subprocess.check_call(cmd, cwd=os.environ['HOME'])
						assert os.path.isfile(url)
						html.append('<script type="text/javascript">')
						html.append( open(url, 'rb').read().decode('utf-8') )
						html.append('</script>')
					elif 'source="' in line:
						srcurl = line.split('source="')[-1].split('"')[0]
						print 'downloading javascript-> ' + srcurl
						import urllib
						srcdata = urllib.urlopen(srcurl).read()
						srcpath = os.path.split(url)[0]
						if not os.path.isdir(srcpath):
							os.makedirs(srcpath)
						open(url, 'wb').write(srcdata)
						assert os.path.isfile(url)
						html.append('<script type="text/javascript">')
						html.append( open(url, 'rb').read().decode('utf-8') )
						html.append('</script>')

					else:
						print('ERROR: could not find file to inline: %s' %url)
						html.append( line )
				elif line.strip().startswith('<link ') and ('href="~/' in line or "href='~/" in line):
					zipurl = None
					if 'zip="' in line:
						zipurl = line.split('zip="')[-1].split('"')[0]

					if 'href="' in line:
						url = line.split('href="')[-1].split('"')[0]
					else:
						url = line.split("href='")[-1].split("'")[0]

					url = os.path.expanduser( url )
					if os.path.isfile(url):
						html.append('<style>')
						html.append( open(url, 'rb').read() )
						html.append('</style>')
					elif zipurl:
						import urllib
						print 'downloading css library->' + zipurl
						zipdata = urllib.urlopen(zipurl).read()
						open('/tmp/csslib.zip', 'wb').write( zipdata )
						subprocess.check_call(['unzip', '/tmp/csslib.zip'], cwd=os.environ['HOME'])
						html.append('<style>')
						html.append( open(url, 'rb').read() )
						html.append('</style>')

					else:
						print('ERROR: could not find css file to inline: %s' %url)
						html.append( line )

				else:
					html.append( line )

			html = unicode('\n'.join(html))

			for tagname in tagged:
				tag = u'<@%s>' %tagname
				js  = tagged[tagname]
				if html in tag:
					## TODO fix this ugly mess
					try:
						## javascript with unicode
						xxx = u'<script type="text/javascript" id="%s_transpiled">\n%s</script>' %(tagname, js)
					except UnicodeDecodeError:
						## rusthon translated to js
						xxx = u'<script type="text/javascript" id="%s_transpiled">\n%s</script>' %(tagname, js.decode('utf-8'))
					html = html.replace(tag, xxx)

				if tagname in tagged_trans_src.keys():
					stag = u'<!%s>' %tagname
					py  = tagged_trans_src[tagname]
					if stag in html:
						## TODO fix this ugly mess
						try:
							xxx = u'<script type="text/rusthon" id="%s">\n%s</script>' %(tagname, py)
						except UnicodeDecodeError:
							xxx = u'<script type="text/rusthon" id="%s">\n%s</script>' %(tagname, py.decode('utf-8'))
						html = html.replace(stag, xxx)


			mod['code'] = html
			output['html'].append( mod )
			## inlines js app into openshift default style python server ##
			if '--openshift-python' in sys.argv:
				import base64
				bcoded = base64.b64encode(mod['code'].encode('utf-8'))
				wsgi = [ OPENSHIFT_PY[0]%bcoded, OPENSHIFT_PY[1] ]
				output['datafiles']['wsgi.py'] = '\n'.join(wsgi).encode('utf-8')

	if modules['verilog']:
		source = []
		mainmod = None
		mods_sorted_by_index = sorted(modules['verilog'], key=lambda mod: mod.get('index'))
		for mod in mods_sorted_by_index:
			source.append( mod['code'] )
			if 'name' in mod and mod['name']=='main':
				mainmod = mod
			elif mainmod is None:
				mainmod = mod

		source = '\n'.join(source)

		mod = {}
		output['verilog'].append(mod)

		if os.path.isfile('/usr/bin/iverilog') or os.path.isfile('/usr/local/bin/iverilog'):
			mod['source'] = source
			mod['binary'] = tempfile.gettempdir() + '/rusthon-sv-build.vvp'
			mod['name']   = 'main.vvp'
			output['executeables'].append( mod['binary'] )
			tmpfile = tempfile.gettempdir() + '/rusthon-verilog-build.sv'
			open(tmpfile, 'wb').write( source )
			## note: iverilog defaults to verilog mode, not systemverilog, `-g2005-sv` is required. '-g2012' also works.
			cmd = [
				'iverilog',
				'-g2005-sv',
				'-o',
				'rusthon-sv-build.vvp',
				tmpfile
			]
			p = subprocess.Popen(cmd, cwd=tempfile.gettempdir(), stdout=subprocess.PIPE, stderr=subprocess.PIPE )
			p.wait()
			if p.returncode != 0:
				srclines = source.splitlines()
				err = p.stderr.read()  ## ends with "I give up."
				errors = []
				for line in err.splitlines():
					if 'syntax error' in line:
						errors.append('- - - - - - - - - - - -')
						lineno = int( line.split(':')[-2] )
						e = [
							'Syntax Error - line: %s' %lineno,
						]
						if lineno-2 < len(srclines):
							e.append( srclines[lineno-2] )
						if lineno-1 < len(srclines):
							e.append( srclines[lineno-1] )
						if lineno < len(srclines):
							e.append( srclines[lineno] )

						errors.extend( e )
					else:
						errors.append(line)

				msg = [' '.join(cmd)]
				for i,line in enumerate(source.splitlines()):
					msg.append('%s:	%s' %(i+1, line))
				msg.extend(errors)
				raise RuntimeError('\n'.join(msg))


		else:
			print('WARNING: could not find iverilog')
			mod['code'] = source

	if modules['go']:
		for mod in modules['go']:
			if 'name' in mod:
				name = mod['name']
				if name=='main':
					go_main['source'].append( mod['code'] )
				else:
					output['go'].append( mod )
			else:
				go_main['source'].append( mod['code'] )

	if go_main['source']:
		go_main['source'] = '\n'.join(go_main['source'])
		output['go'].insert( 0, go_main )

	if output['go']:
		source = [ mod['source'] for mod in output['go'] ]
		tmpfile = tempfile.gettempdir() + '/rusthon-go-build.go'
		open(tmpfile, 'wb').write( '\n'.join(source) )
		if GO_EXE:
			cmd = [GO_EXE, 'build', tmpfile]
			subprocess.check_call([GO_EXE, 'build', tmpfile], cwd=tempfile.gettempdir() )
			mod['binary'] = tempfile.gettempdir() + '/rusthon-go-build'
			output['executeables'].append(tempfile.gettempdir() + '/rusthon-go-build')


	if modules['rust']:
		source = []
		mainmod = None
		mods_sorted_by_index = sorted(modules['rust'], key=lambda mod: mod.get('index'))
		for mod in mods_sorted_by_index:
			source.append( mod['code'] )
			if 'name' in mod and mod['name']=='main':
				mainmod = mod
			elif mainmod is None:
				mainmod = mod

		tmpfile = tempfile.gettempdir() + '/rusthon-build.rs'
		data = '\n'.join(source)
		open(tmpfile, 'wb').write( data )

		pak = None
		if modules['c++']:
			libname = 'rusthon-lib%s' %len(output['rust'])
			link.append(libname)
			subprocess.check_call(['rustc', '--crate-name', 'rusthon', '--crate-type', 'staticlib' ,'-o', tempfile.gettempdir() + '/'+libname,  tmpfile] )
			pak = {'source':data, 'staticlib':libname, 'name':'lib'+libname+'.a'}

		else:
			subprocess.check_call(['rustc', '--crate-name', 'rusthon', '-o', tempfile.gettempdir() + '/rusthon-bin',  tmpfile] )
			pak = {'source':data, 'binary':tempfile.gettempdir() + '/rusthon-bin', 'name':'rusthon-bin'}
			output['executeables'].append(tempfile.gettempdir() + '/rusthon-bin')

		assert pak
		mainmod['build'] = pak
		output['rust'].append( pak )


	if modules['c']:
		dynamiclib = False
		source   = []
		cinclude = []
		cbuild   = []
		mods_sorted_by_index = sorted(modules['c'], key=lambda mod: mod.get('index'))
		for mod in mods_sorted_by_index:
			if 'dynamic' in mod and mod['dynamic']:
				dynamiclib = True
			if 'link-dirs' in mod:
				cinclude.extend(mod['link-dirs'])
			if 'build-dirs' in mod:
				for bdir in mod['build-dirs']:
					for fname in os.listdir(bdir):
						if fname.endswith('.c'):
							cbuild.append(os.path.join(bdir,fname))

			if 'code' in mod and mod['code']:
				source.append( mod['code'] )
			else:
				## module must contain a build config
				raise RuntimeError('missing code')

		if source:
			data = '\n'.join(source)
			cpak = {'source':data}
			output['c'].append(cpak)

			libname = 'default-clib%s' %len(output['c'])  ## TODO user named
			link.append(libname)
			dynamic_path = tempfile.gettempdir() + '/lib'+libname+'.so'
			static_path = tempfile.gettempdir() + '/lib'+libname+'.a'
			object_path = tempfile.gettempdir() + '/'+libname+'.o'


			tmpfile = tempfile.gettempdir() + '/rusthon-build.c'
			open(tmpfile, 'wb').write( data )

			cmd = ['gcc']
			for idir in cinclude:
				cmd.append('-I'+idir)
			cmd.extend(['-c', tmpfile])


			if dynamiclib:
				cmd.extend(
					[
						'-fPIC',
						'-O3',
						'-fomit-frame-pointer',
						'-Wall', '-Wno-unused',
						'-o', object_path
					]
				)
				subprocess.check_call(cmd)

				cmd = [
					'gcc',
					'-shared',
					'-Wl,-soname,lib%s.so' %libname,
					#'-Wl,-rpath,/tmp',
					'-Wl,--export-dynamic',
					'-pthread', '-o', dynamic_path,
					object_path
				]
				subprocess.check_call(cmd)
				cpak['dynamiclib'] = dynamic_path
				cpak['name']       = 'lib%s.so' %libname

			else:

				if cbuild:
					#gcc: fatal error: cannot specify -o with -c, -S or -E with multiple files
					#cmd.extend(cbuild)  ## extra c files `/some/path/*.c`
					raise RuntimeError('TODO fix building multiple .c files at once using gcc option -o')

				cmd.extend(['-o', object_path ])

				print('========== compiling C static library =========')
				print(' '.join(cmd))
				subprocess.check_call( cmd )
				print('========== ar : staticlib ==========')
				cmd = ['ar', 'rcs', static_path, object_path]
				subprocess.check_call( cmd )
				cpak['staticlib'] = libname+'.a'
				cpak['name']      = libname+'.a'


	if modules['c++']:
		links = []
		idirs = []
		source = []
		defines = []
		mods_sorted_by_index = sorted(modules['c++'], key=lambda mod: mod.get('index'))
		mainmod = None
		builddir = tempfile.gettempdir()
		#compile_mode = 'binary'
		for mod in mods_sorted_by_index:
			if 'tag' in mod and mod['tag'] and ( mod['tag'].endswith('.hpp') or mod['tag'].endswith('.hpp') ):
				## allows plain header files to be included in build directory ##
				open(
					os.path.join(builddir, mod['tag']), 'wb'
				).write( mod['code'] )
				output['c++'].append( mod )
			else:
				source.append( mod['code'] )

			if 'name' in mod and mod['name']=='main':
				mainmod = mod
			elif mainmod is None:
				mainmod = mod
			if 'links' in mod:
				links.extend(mod['links'])
			if 'include-dirs' in mod:
				idirs.extend(mod['include-dirs'])
			if 'defines' in mod:
				defines.extend(mod['defines'])

			#if 'compile-mode' in mod:
			#	compile_mode = mod['compile-mode']

			if 'tag' in mod and mod['tag'] and '.' not in mod['tag']:
				exename = mod['tag']

		tmpfile = builddir + '/rusthon-c++-build.cpp'
		data = '\n'.join(source)
		open(tmpfile, 'wb').write( data )
		cmd = ['g++']

		if compile_mode=='binary':
			cmd.extend(['-O3', '-fprofile-generate', '-march=native', '-mtune=native', '-I'+tempfile.gettempdir()])

		cmd.append('-Wl,-rpath,/usr/local/lib/')  ## extra user installed dynamic libs
		cmd.append('-Wl,-rpath,./')  ## can not load dynamic libs from same directory without this
		cmd.append(tmpfile)

		if '/' in exename and not os.path.isdir( os.path.join(builddir,os.path.split(exename)[0]) ):
			os.makedirs(os.path.join(builddir,os.path.split(exename)[0]))

		if compile_mode == 'binary':
			cmd.extend(['-o', os.path.join(builddir,exename)])
		elif compile_mode == 'dynamiclib':
			cmd.extend(
				['-shared', '-fPIC']
			)
			exename += '.so'
			cmd.extend(['-o', os.path.join(builddir,exename)])

		cmd.extend(
			['-pthread', '-std=c++11' ]
		)

		for D in defines:
			cmd.append('-D%s' %D)

		if nuitka:
			## note: linking happens after the object-bin above is created `-o ruston-c++-bin`,
			## fixes the error: undefined reference to `_PyThreadState_Current', etc.
			#if not nuitka_include_path:
			#	nuitka_include_path = '/usr/local/lib/python2.7/dist-packages/nuitka/build/include'
			#cmd.append('-I'+nuitka_include_path)
			cmd.append('-I/usr/include/python2.7')
			cmd.append('-lpython2.7')

		if idirs:
			for idir in idirs:
				cmd.append('-I'+idir)

		if links:
			for lib in links:
				cmd.append('-l'+lib)

		## always link to libdl, external libraries may require dl_open, etc.
		cmd.append('-ldl')


		if link or giws:

			if giws:   ## link to the JVM if giws bindings were compiled ##
				cmd.append('-ljvm')

				os.environ['LD_LIBRARY_PATH']=''
				#for jrepath in 'include include/linux jre/lib/i386 jre/lib/i386/client/'.split():
				for jrepath in 'include include/linux'.split():
					cmd.append('-I%s/%s' %(os.environ['JAVA_HOME'], jrepath))
				for jrepath in 'jre/lib/amd64 jre/lib/amd64/server/'.split():
					cmd.append('-L%s/%s' %(os.environ['JAVA_HOME'], jrepath))
					os.environ['LD_LIBRARY_PATH'] += ':%s/%s'%(os.environ['JAVA_HOME'], jrepath)
				#raise RuntimeError(os.environ['LD_LIBRARY_PATH'])

			#else:  ## TODO fix jvm with static c libs
			#	cmd.append('-static')

			if link:  ## c staticlibs or giws c++ wrappers ##
				cmd.append('-L' + tempfile.gettempdir() + '/.')
				for libname in link:
					cmd.append('-l'+libname)

		print('========== g++ : compile main ==========')
		print(' '.join(cmd))
		subprocess.check_call( cmd )
		mainmod['build'] = {
			'source':data, 
			'binary':tempfile.gettempdir() + '/' + exename, 
			'name':exename
		}
		if compile_mode == 'binary':
			output['c++'].append( mainmod['build'] )
			output['executeables'].append(tempfile.gettempdir() + '/' + exename)
		else:
			output['datafiles'][ exename ] = open(tempfile.gettempdir() + '/' + exename, 'rb').read()

	if python_main['script']:
		python_main['script'] = '\n'.join(python_main['script'])
		output['python'].append( python_main )

	if modules['bazel']:
		# http://bazel.io/docs/build-ref.html#workspaces
		## a WORKSPACE file is required, even if empty.
		tmpdir = tempfile.gettempdir()
		open(tmpdir+'/WORKSPACE', 'wb')

		for filename in output['datafiles'].keys():
			open(tmpdir+'/'+filename, 'wb').write(output['datafiles'][filename])

		bazelbuilds = []
		mods_sorted_by_index = sorted(modules['bazel'], key=lambda mod: mod.get('index'))
		for mod in mods_sorted_by_index:
			bazelconfig = mod['code']
			open(tmpdir+'/BUILD', 'wb').write(bazelconfig)
			for chk in bazelconfig.split(','):
				chk = chk.strip()
				words = chk.split()
				if chk.endswith('"') and 'name' in words and '=' in words:
					chk = chk.split()
					bazelbuilds.append(chk[-1][1:-1])


		assert len(bazelbuilds)==1
		buildname = bazelbuilds[0]
		#subprocess.check_call(['bazel', 'build', ':'+buildname], cwd=tmpdir)
		subprocess.check_call(['bazel', 'run', ':'+buildname], cwd=tmpdir)

	if gyp_builds:
		tmpdir = tempfile.gettempdir()
		for gname in gyp_builds.keys():
			gbuild = gyp_builds[gname]
			if gbuild['src']:
				open(tmpdir+'/binding.gyp', 'wb').write(gbuild['gyp'])
				open(tmpdir+'/'+gname, 'wb').write( gbuild['src'] )
				subprocess.check_call(['nw-gyp', 'configure', '--target=0.12.3'], cwd=tmpdir)
				subprocess.check_call(['nw-gyp', 'build'], cwd=tmpdir)

				node_module = open(tmpdir+'/build/Release/binding.node', 'rb').read()
				output['datafiles']['binding.node'] = node_module


	return output
dataset/ETHPy150Open rusthon/Rusthon/rusthon.py/build/swapped operands of `in`