PageRenderTime 50ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/translator/driver.py

https://bitbucket.org/pypy/pypy/
Python | 870 lines | 773 code | 52 blank | 45 comment | 41 complexity | 9fa4e3524c7586102c5b761eb546a830 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import sys, os
  2. import os.path
  3. import shutil
  4. from pypy.translator.translator import TranslationContext
  5. from pypy.translator.tool.taskengine import SimpleTaskEngine
  6. from pypy.translator.goal import query
  7. from pypy.translator.goal.timing import Timer
  8. from pypy.annotation import model as annmodel
  9. from pypy.annotation.listdef import s_list_of_strings
  10. from pypy.annotation import policy as annpolicy
  11. from pypy.tool.udir import udir
  12. from pypy.tool.debug_print import debug_start, debug_print, debug_stop
  13. from pypy.rlib.entrypoint import secondary_entrypoints
  14. import py
  15. from pypy.tool.ansi_print import ansi_log
  16. log = py.log.Producer("translation")
  17. py.log.setconsumer("translation", ansi_log)
  18. def taskdef(taskfunc, deps, title, new_state=None, expected_states=[],
  19. idemp=False, earlycheck=None):
  20. taskfunc.task_deps = deps
  21. taskfunc.task_title = title
  22. taskfunc.task_newstate = None
  23. taskfunc.task_expected_states = expected_states
  24. taskfunc.task_idempotent = idemp
  25. taskfunc.task_earlycheck = earlycheck
  26. return taskfunc
  27. # TODO:
  28. # sanity-checks using states
  29. _BACKEND_TO_TYPESYSTEM = {
  30. 'c': 'lltype',
  31. }
  32. def backend_to_typesystem(backend):
  33. return _BACKEND_TO_TYPESYSTEM.get(backend, 'ootype')
  34. # set of translation steps to profile
  35. PROFILE = set([])
  36. class Instrument(Exception):
  37. pass
  38. class ProfInstrument(object):
  39. name = "profinstrument"
  40. def __init__(self, datafile, compiler):
  41. self.datafile = datafile
  42. self.compiler = compiler
  43. def first(self):
  44. return self.compiler._build()
  45. def probe(self, exe, args):
  46. env = os.environ.copy()
  47. env['_INSTRUMENT_COUNTERS'] = str(self.datafile)
  48. self.compiler.platform.execute(exe, args, env=env)
  49. def after(self):
  50. # xxx
  51. os._exit(0)
  52. class TranslationDriver(SimpleTaskEngine):
  53. _backend_extra_options = {}
  54. def __init__(self, setopts=None, default_goal=None,
  55. disable=[],
  56. exe_name=None, extmod_name=None,
  57. config=None, overrides=None):
  58. self.timer = Timer()
  59. SimpleTaskEngine.__init__(self)
  60. self.log = log
  61. if config is None:
  62. from pypy.config.pypyoption import get_pypy_config
  63. config = get_pypy_config(translating=True)
  64. self.config = config
  65. if overrides is not None:
  66. self.config.override(overrides)
  67. if setopts is not None:
  68. self.config.set(**setopts)
  69. self.exe_name = exe_name
  70. self.extmod_name = extmod_name
  71. self.done = {}
  72. self.disable(disable)
  73. if default_goal:
  74. default_goal, = self.backend_select_goals([default_goal])
  75. if default_goal in self._maybe_skip():
  76. default_goal = None
  77. self.default_goal = default_goal
  78. self.extra_goals = []
  79. self.exposed = []
  80. # expose tasks
  81. def expose_task(task, backend_goal=None):
  82. if backend_goal is None:
  83. backend_goal = task
  84. def proc():
  85. return self.proceed(backend_goal)
  86. self.exposed.append(task)
  87. setattr(self, task, proc)
  88. backend, ts = self.get_backend_and_type_system()
  89. for task in self.tasks:
  90. explicit_task = task
  91. parts = task.split('_')
  92. if len(parts) == 1:
  93. if task in ('annotate',):
  94. expose_task(task)
  95. else:
  96. task, postfix = parts
  97. if task in ('rtype', 'backendopt', 'llinterpret',
  98. 'pyjitpl'):
  99. if ts:
  100. if ts == postfix:
  101. expose_task(task, explicit_task)
  102. else:
  103. expose_task(explicit_task)
  104. elif task in ('source', 'compile', 'run'):
  105. if backend:
  106. if backend == postfix:
  107. expose_task(task, explicit_task)
  108. elif ts:
  109. if ts == backend_to_typesystem(postfix):
  110. expose_task(explicit_task)
  111. else:
  112. expose_task(explicit_task)
  113. def set_extra_goals(self, goals):
  114. self.extra_goals = goals
  115. def set_backend_extra_options(self, extra_options):
  116. self._backend_extra_options = extra_options
  117. def get_info(self): # XXX more?
  118. d = {'backend': self.config.translation.backend}
  119. return d
  120. def get_backend_and_type_system(self):
  121. type_system = self.config.translation.type_system
  122. backend = self.config.translation.backend
  123. return backend, type_system
  124. def backend_select_goals(self, goals):
  125. backend, ts = self.get_backend_and_type_system()
  126. postfixes = [''] + ['_'+p for p in (backend, ts) if p]
  127. l = []
  128. for goal in goals:
  129. for postfix in postfixes:
  130. cand = "%s%s" % (goal, postfix)
  131. if cand in self.tasks:
  132. new_goal = cand
  133. break
  134. else:
  135. raise Exception, "cannot infer complete goal from: %r" % goal
  136. l.append(new_goal)
  137. return l
  138. def disable(self, to_disable):
  139. self._disabled = to_disable
  140. def _maybe_skip(self):
  141. maybe_skip = []
  142. if self._disabled:
  143. for goal in self.backend_select_goals(self._disabled):
  144. maybe_skip.extend(self._depending_on_closure(goal))
  145. return dict.fromkeys(maybe_skip).keys()
  146. def setup(self, entry_point, inputtypes, policy=None, extra={}, empty_translator=None):
  147. standalone = inputtypes is None
  148. self.standalone = standalone
  149. if standalone:
  150. # the 'argv' parameter
  151. inputtypes = [s_list_of_strings]
  152. self.inputtypes = inputtypes
  153. if policy is None:
  154. policy = annpolicy.AnnotatorPolicy()
  155. if standalone:
  156. policy.allow_someobjects = False
  157. self.policy = policy
  158. self.extra = extra
  159. if empty_translator:
  160. translator = empty_translator
  161. else:
  162. translator = TranslationContext(config=self.config)
  163. self.entry_point = entry_point
  164. self.translator = translator
  165. self.libdef = None
  166. self.secondary_entrypoints = []
  167. if self.config.translation.secondaryentrypoints:
  168. for key in self.config.translation.secondaryentrypoints.split(","):
  169. try:
  170. points = secondary_entrypoints[key]
  171. except KeyError:
  172. raise KeyError(
  173. "Entrypoints not found. I only know the keys %r." %
  174. (", ".join(secondary_entrypoints.keys()), ))
  175. self.secondary_entrypoints.extend(points)
  176. self.translator.driver_instrument_result = self.instrument_result
  177. def setup_library(self, libdef, policy=None, extra={}, empty_translator=None):
  178. """ Used by carbon python only. """
  179. self.setup(None, None, policy, extra, empty_translator)
  180. self.libdef = libdef
  181. self.secondary_entrypoints = libdef.functions
  182. def instrument_result(self, args):
  183. backend, ts = self.get_backend_and_type_system()
  184. if backend != 'c' or sys.platform == 'win32':
  185. raise Exception("instrumentation requires the c backend"
  186. " and unix for now")
  187. datafile = udir.join('_instrument_counters')
  188. makeProfInstrument = lambda compiler: ProfInstrument(datafile, compiler)
  189. pid = os.fork()
  190. if pid == 0:
  191. # child compiling and running with instrumentation
  192. self.config.translation.instrument = True
  193. self.config.translation.instrumentctl = (makeProfInstrument,
  194. args)
  195. raise Instrument
  196. else:
  197. pid, status = os.waitpid(pid, 0)
  198. if os.WIFEXITED(status):
  199. status = os.WEXITSTATUS(status)
  200. if status != 0:
  201. raise Exception, "instrumentation child failed: %d" % status
  202. else:
  203. raise Exception, "instrumentation child aborted"
  204. import array, struct
  205. n = datafile.size()//struct.calcsize('L')
  206. datafile = datafile.open('rb')
  207. counters = array.array('L')
  208. counters.fromfile(datafile, n)
  209. datafile.close()
  210. return counters
  211. def info(self, msg):
  212. log.info(msg)
  213. def _profile(self, goal, func):
  214. from cProfile import Profile
  215. from pypy.tool.lsprofcalltree import KCacheGrind
  216. d = {'func':func}
  217. prof = Profile()
  218. prof.runctx("res = func()", globals(), d)
  219. KCacheGrind(prof).output(open(goal + ".out", "w"))
  220. return d['res']
  221. def _do(self, goal, func, *args, **kwds):
  222. title = func.task_title
  223. if goal in self.done:
  224. self.log.info("already done: %s" % title)
  225. return
  226. else:
  227. self.log.info("%s..." % title)
  228. debug_start('translation-task')
  229. debug_print('starting', goal)
  230. self.timer.start_event(goal)
  231. try:
  232. instrument = False
  233. try:
  234. if goal in PROFILE:
  235. res = self._profile(goal, func)
  236. else:
  237. res = func()
  238. except Instrument:
  239. instrument = True
  240. if not func.task_idempotent:
  241. self.done[goal] = True
  242. if instrument:
  243. self.proceed('compile')
  244. assert False, 'we should not get here'
  245. finally:
  246. try:
  247. debug_stop('translation-task')
  248. self.timer.end_event(goal)
  249. except (KeyboardInterrupt, SystemExit):
  250. raise
  251. except:
  252. pass
  253. #import gc; gc.dump_rpy_heap('rpyheap-after-%s.dump' % goal)
  254. return res
  255. def task_annotate(self):
  256. """ Annotate
  257. """
  258. # includes annotation and annotatation simplifications
  259. translator = self.translator
  260. policy = self.policy
  261. self.log.info('with policy: %s.%s' % (policy.__class__.__module__, policy.__class__.__name__))
  262. annmodel.DEBUG = self.config.translation.debug
  263. annotator = translator.buildannotator(policy=policy)
  264. if self.secondary_entrypoints is not None:
  265. for func, inputtypes in self.secondary_entrypoints:
  266. if inputtypes == Ellipsis:
  267. continue
  268. rettype = annotator.build_types(func, inputtypes, False)
  269. if self.entry_point:
  270. s = annotator.build_types(self.entry_point, self.inputtypes)
  271. translator.entry_point_graph = annotator.bookkeeper.getdesc(self.entry_point).getuniquegraph()
  272. else:
  273. s = None
  274. self.sanity_check_annotation()
  275. if self.entry_point and self.standalone and s.knowntype != int:
  276. raise Exception("stand-alone program entry point must return an "
  277. "int (and not, e.g., None or always raise an "
  278. "exception).")
  279. annotator.simplify()
  280. return s
  281. #
  282. task_annotate = taskdef(task_annotate, [], "Annotating&simplifying")
  283. def sanity_check_annotation(self):
  284. translator = self.translator
  285. irreg = query.qoutput(query.check_exceptblocks_qgen(translator))
  286. if irreg:
  287. self.log.info("Some exceptblocks seem insane")
  288. lost = query.qoutput(query.check_methods_qgen(translator))
  289. assert not lost, "lost methods, something gone wrong with the annotation of method defs"
  290. so = query.qoutput(query.polluted_qgen(translator))
  291. tot = len(translator.graphs)
  292. percent = int(tot and (100.0*so / tot) or 0)
  293. # if there are a few SomeObjects even if the policy doesn't allow
  294. # them, it means that they were put there in a controlled way
  295. # and then it's not a warning.
  296. if not translator.annotator.policy.allow_someobjects:
  297. pr = self.log.info
  298. elif percent == 0:
  299. pr = self.log.info
  300. else:
  301. pr = log.WARNING
  302. pr("-- someobjectness %2d%% (%d of %d functions polluted by SomeObjects)" % (percent, so, tot))
  303. def task_rtype_lltype(self):
  304. """ RTyping - lltype version
  305. """
  306. rtyper = self.translator.buildrtyper(type_system='lltype')
  307. insist = not self.config.translation.insist
  308. rtyper.specialize(dont_simplify_again=True,
  309. crash_on_first_typeerror=insist)
  310. #
  311. task_rtype_lltype = taskdef(task_rtype_lltype, ['annotate'], "RTyping")
  312. RTYPE = 'rtype_lltype'
  313. def task_rtype_ootype(self):
  314. """ RTyping - ootype version
  315. """
  316. # Maybe type_system should simply be an option used in task_rtype
  317. insist = not self.config.translation.insist
  318. rtyper = self.translator.buildrtyper(type_system="ootype")
  319. rtyper.specialize(dont_simplify_again=True,
  320. crash_on_first_typeerror=insist)
  321. #
  322. task_rtype_ootype = taskdef(task_rtype_ootype, ['annotate'], "ootyping")
  323. OOTYPE = 'rtype_ootype'
  324. def task_pyjitpl_lltype(self):
  325. """ Generate bytecodes for JIT and flow the JIT helper functions
  326. ootype version
  327. """
  328. get_policy = self.extra['jitpolicy']
  329. self.jitpolicy = get_policy(self)
  330. #
  331. from pypy.jit.metainterp.warmspot import apply_jit
  332. apply_jit(self.translator, policy=self.jitpolicy,
  333. backend_name=self.config.translation.jit_backend, inline=True)
  334. #
  335. self.log.info("the JIT compiler was generated")
  336. #
  337. task_pyjitpl_lltype = taskdef(task_pyjitpl_lltype,
  338. [RTYPE],
  339. "JIT compiler generation")
  340. def task_pyjitpl_ootype(self):
  341. """ Generate bytecodes for JIT and flow the JIT helper functions
  342. ootype version
  343. """
  344. get_policy = self.extra['jitpolicy']
  345. self.jitpolicy = get_policy(self)
  346. #
  347. from pypy.jit.metainterp.warmspot import apply_jit
  348. apply_jit(self.translator, policy=self.jitpolicy,
  349. backend_name='cli', inline=True) #XXX
  350. #
  351. self.log.info("the JIT compiler was generated")
  352. #
  353. task_pyjitpl_ootype = taskdef(task_pyjitpl_ootype,
  354. [OOTYPE],
  355. "JIT compiler generation")
  356. def task_jittest_lltype(self):
  357. """ Run with the JIT on top of the llgraph backend
  358. """
  359. # parent process loop: spawn a child, wait for the child to finish,
  360. # print a message, and restart
  361. from pypy.translator.goal import unixcheckpoint
  362. unixcheckpoint.restartable_point(auto='run')
  363. # load the module pypy/jit/tl/jittest.py, which you can hack at
  364. # and restart without needing to restart the whole translation process
  365. from pypy.jit.tl import jittest
  366. jittest.jittest(self)
  367. #
  368. task_jittest_lltype = taskdef(task_jittest_lltype,
  369. [RTYPE],
  370. "test of the JIT on the llgraph backend")
  371. def task_backendopt_lltype(self):
  372. """ Run all backend optimizations - lltype version
  373. """
  374. from pypy.translator.backendopt.all import backend_optimizations
  375. backend_optimizations(self.translator)
  376. #
  377. task_backendopt_lltype = taskdef(task_backendopt_lltype,
  378. [RTYPE, '??pyjitpl_lltype',
  379. '??jittest_lltype'],
  380. "lltype back-end optimisations")
  381. BACKENDOPT = 'backendopt_lltype'
  382. def task_backendopt_ootype(self):
  383. """ Run all backend optimizations - ootype version
  384. """
  385. from pypy.translator.backendopt.all import backend_optimizations
  386. backend_optimizations(self.translator)
  387. #
  388. task_backendopt_ootype = taskdef(task_backendopt_ootype,
  389. [OOTYPE], "ootype back-end optimisations")
  390. OOBACKENDOPT = 'backendopt_ootype'
  391. def task_stackcheckinsertion_lltype(self):
  392. from pypy.translator.transform import insert_ll_stackcheck
  393. count = insert_ll_stackcheck(self.translator)
  394. self.log.info("inserted %d stack checks." % (count,))
  395. task_stackcheckinsertion_lltype = taskdef(
  396. task_stackcheckinsertion_lltype,
  397. ['?'+BACKENDOPT, RTYPE, 'annotate'],
  398. "inserting stack checks")
  399. STACKCHECKINSERTION = 'stackcheckinsertion_lltype'
  400. def possibly_check_for_boehm(self):
  401. if self.config.translation.gc == "boehm":
  402. from pypy.rpython.tool.rffi_platform import configure_boehm
  403. from pypy.translator.platform import CompilationError
  404. try:
  405. configure_boehm(self.translator.platform)
  406. except CompilationError, e:
  407. i = 'Boehm GC not installed. Try e.g. "translate.py --gc=hybrid"'
  408. raise Exception(str(e) + '\n' + i)
  409. def task_database_c(self):
  410. """ Create a database for further backend generation
  411. """
  412. translator = self.translator
  413. if translator.annotator is not None:
  414. translator.frozen = True
  415. if self.libdef is not None:
  416. cbuilder = self.libdef.getcbuilder(self.translator, self.config)
  417. self.standalone = False
  418. standalone = False
  419. else:
  420. standalone = self.standalone
  421. if standalone:
  422. from pypy.translator.c.genc import CStandaloneBuilder as CBuilder
  423. else:
  424. from pypy.translator.c.genc import CExtModuleBuilder as CBuilder
  425. cbuilder = CBuilder(self.translator, self.entry_point,
  426. config=self.config,
  427. secondary_entrypoints=self.secondary_entrypoints)
  428. if not standalone: # xxx more messy
  429. cbuilder.modulename = self.extmod_name
  430. database = cbuilder.build_database()
  431. self.log.info("database for generating C source was created")
  432. self.cbuilder = cbuilder
  433. self.database = database
  434. #
  435. task_database_c = taskdef(task_database_c,
  436. [STACKCHECKINSERTION, '?'+BACKENDOPT, RTYPE, '?annotate'],
  437. "Creating database for generating c source",
  438. earlycheck = possibly_check_for_boehm)
  439. def task_source_c(self):
  440. """ Create C source files from the generated database
  441. """
  442. cbuilder = self.cbuilder
  443. database = self.database
  444. if self._backend_extra_options.get('c_debug_defines', False):
  445. defines = cbuilder.DEBUG_DEFINES
  446. else:
  447. defines = {}
  448. if self.exe_name is not None:
  449. exe_name = self.exe_name % self.get_info()
  450. else:
  451. exe_name = None
  452. c_source_filename = cbuilder.generate_source(database, defines,
  453. exe_name=exe_name)
  454. self.log.info("written: %s" % (c_source_filename,))
  455. if self.config.translation.dump_static_data_info:
  456. from pypy.translator.tool.staticsizereport import dump_static_data_info
  457. targetdir = cbuilder.targetdir
  458. fname = dump_static_data_info(self.log, database, targetdir)
  459. dstname = self.compute_exe_name() + '.staticdata.info'
  460. shutil.copy(str(fname), str(dstname))
  461. self.log.info('Static data info written to %s' % dstname)
  462. #
  463. task_source_c = taskdef(task_source_c, ['database_c'], "Generating c source")
  464. def compute_exe_name(self):
  465. newexename = self.exe_name % self.get_info()
  466. if '/' not in newexename and '\\' not in newexename:
  467. newexename = './' + newexename
  468. return py.path.local(newexename)
  469. def create_exe(self):
  470. """ Copy the compiled executable into translator/goal
  471. """
  472. if self.exe_name is not None:
  473. exename = self.c_entryp
  474. newexename = mkexename(self.compute_exe_name())
  475. shutil.copy(str(exename), str(newexename))
  476. if self.cbuilder.shared_library_name is not None:
  477. soname = self.cbuilder.shared_library_name
  478. newsoname = newexename.new(basename=soname.basename)
  479. shutil.copy(str(soname), str(newsoname))
  480. self.log.info("copied: %s" % (newsoname,))
  481. self.c_entryp = newexename
  482. self.log.info('usession directory: %s' % (udir,))
  483. self.log.info("created: %s" % (self.c_entryp,))
  484. def task_compile_c(self):
  485. """ Compile the generated C code using either makefile or
  486. translator/platform
  487. """
  488. cbuilder = self.cbuilder
  489. kwds = {}
  490. if self.standalone and self.exe_name is not None:
  491. kwds['exe_name'] = self.compute_exe_name().basename
  492. cbuilder.compile(**kwds)
  493. if self.standalone:
  494. self.c_entryp = cbuilder.executable_name
  495. self.create_exe()
  496. else:
  497. isolated = self._backend_extra_options.get('c_isolated', False)
  498. self.c_entryp = cbuilder.get_entry_point(isolated=isolated)
  499. #
  500. task_compile_c = taskdef(task_compile_c, ['source_c'], "Compiling c source")
  501. def backend_run(self, backend):
  502. c_entryp = self.c_entryp
  503. standalone = self.standalone
  504. if standalone:
  505. os.system(c_entryp)
  506. else:
  507. runner = self.extra.get('run', lambda f: f())
  508. runner(c_entryp)
  509. def task_run_c(self):
  510. self.backend_run('c')
  511. #
  512. task_run_c = taskdef(task_run_c, ['compile_c'],
  513. "Running compiled c source",
  514. idemp=True)
  515. def task_llinterpret_lltype(self):
  516. from pypy.rpython.llinterp import LLInterpreter
  517. py.log.setconsumer("llinterp operation", None)
  518. translator = self.translator
  519. interp = LLInterpreter(translator.rtyper)
  520. bk = translator.annotator.bookkeeper
  521. graph = bk.getdesc(self.entry_point).getuniquegraph()
  522. v = interp.eval_graph(graph,
  523. self.extra.get('get_llinterp_args',
  524. lambda: [])())
  525. log.llinterpret.event("result -> %s" % v)
  526. #
  527. task_llinterpret_lltype = taskdef(task_llinterpret_lltype,
  528. [STACKCHECKINSERTION, '?'+BACKENDOPT, RTYPE],
  529. "LLInterpreting")
  530. def task_source_cli(self):
  531. from pypy.translator.cli.gencli import GenCli
  532. from pypy.translator.cli.entrypoint import get_entrypoint
  533. if self.entry_point is not None: # executable mode
  534. entry_point_graph = self.translator.graphs[0]
  535. entry_point = get_entrypoint(entry_point_graph)
  536. else:
  537. # library mode
  538. assert self.libdef is not None
  539. bk = self.translator.annotator.bookkeeper
  540. entry_point = self.libdef.get_entrypoint(bk)
  541. self.gen = GenCli(udir, self.translator, entry_point, config=self.config)
  542. filename = self.gen.generate_source()
  543. self.log.info("Wrote %s" % (filename,))
  544. task_source_cli = taskdef(task_source_cli, ["?" + OOBACKENDOPT, OOTYPE],
  545. 'Generating CLI source')
  546. def task_compile_cli(self):
  547. from pypy.translator.oosupport.support import unpatch_os
  548. from pypy.translator.cli.test.runtest import CliFunctionWrapper
  549. filename = self.gen.build_exe()
  550. self.c_entryp = CliFunctionWrapper(filename)
  551. # restore original os values
  552. if hasattr(self, 'old_cli_defs'):
  553. unpatch_os(self.old_cli_defs)
  554. self.log.info("Compiled %s" % filename)
  555. if self.standalone and self.exe_name:
  556. self.copy_cli_exe()
  557. task_compile_cli = taskdef(task_compile_cli, ['source_cli'],
  558. 'Compiling CLI source')
  559. def copy_cli_exe(self):
  560. # XXX messy
  561. main_exe = self.c_entryp._exe
  562. usession_path, main_exe_name = os.path.split(main_exe)
  563. pypylib_dll = os.path.join(usession_path, 'pypylib.dll')
  564. basename = self.exe_name % self.get_info()
  565. dirname = basename + '-data/'
  566. if '/' not in dirname and '\\' not in dirname:
  567. dirname = './' + dirname
  568. if not os.path.exists(dirname):
  569. os.makedirs(dirname)
  570. shutil.copy(main_exe, dirname)
  571. shutil.copy(pypylib_dll, dirname)
  572. if bool(os.getenv('PYPY_GENCLI_COPYIL')):
  573. shutil.copy(os.path.join(usession_path, 'main.il'), dirname)
  574. newexename = basename
  575. f = file(newexename, 'w')
  576. f.write(r"""#!/bin/bash
  577. LEDIT=`type -p ledit`
  578. EXE=`readlink $0`
  579. if [ -z $EXE ]
  580. then
  581. EXE=$0
  582. fi
  583. if uname -s | grep -iq Cygwin
  584. then
  585. MONO=
  586. else
  587. MONO=mono
  588. # workaround for known mono buggy versions
  589. VER=`mono -V | head -1 | sed s/'Mono JIT compiler version \(.*\) (.*'/'\1/'`
  590. if [[ 2.1 < "$VER" && "$VER" < 2.4.3 ]]
  591. then
  592. MONO="mono -O=-branch"
  593. fi
  594. fi
  595. $LEDIT $MONO "$(dirname $EXE)/$(basename $EXE)-data/%s" "$@" # XXX doesn't work if it's placed in PATH
  596. """ % main_exe_name)
  597. f.close()
  598. os.chmod(newexename, 0755)
  599. def copy_cli_dll(self):
  600. dllname = self.gen.outfile
  601. usession_path, dll_name = os.path.split(dllname)
  602. pypylib_dll = os.path.join(usession_path, 'pypylib.dll')
  603. shutil.copy(dllname, '.')
  604. shutil.copy(pypylib_dll, '.')
  605. # main.exe is a stub but is needed right now because it's
  606. # referenced by pypylib.dll. Will be removed in the future
  607. translator_path, _ = os.path.split(__file__)
  608. main_exe = os.path.join(translator_path, 'cli/src/main.exe')
  609. shutil.copy(main_exe, '.')
  610. self.log.info("Copied to %s" % os.path.join(os.getcwd(), dllname))
  611. def task_run_cli(self):
  612. pass
  613. task_run_cli = taskdef(task_run_cli, ['compile_cli'],
  614. 'XXX')
  615. def task_source_jvm(self):
  616. from pypy.translator.jvm.genjvm import GenJvm
  617. from pypy.translator.jvm.node import EntryPoint
  618. entry_point_graph = self.translator.graphs[0]
  619. is_func = not self.standalone
  620. entry_point = EntryPoint(entry_point_graph, is_func, is_func)
  621. self.gen = GenJvm(udir, self.translator, entry_point)
  622. self.jvmsource = self.gen.generate_source()
  623. self.log.info("Wrote JVM code")
  624. task_source_jvm = taskdef(task_source_jvm, ["?" + OOBACKENDOPT, OOTYPE],
  625. 'Generating JVM source')
  626. def task_compile_jvm(self):
  627. from pypy.translator.oosupport.support import unpatch_os
  628. from pypy.translator.jvm.test.runtest import JvmGeneratedSourceWrapper
  629. self.jvmsource.compile()
  630. self.c_entryp = JvmGeneratedSourceWrapper(self.jvmsource)
  631. # restore original os values
  632. if hasattr(self, 'old_cli_defs'):
  633. unpatch_os(self.old_cli_defs)
  634. self.log.info("Compiled JVM source")
  635. if self.standalone and self.exe_name:
  636. self.copy_jvm_jar()
  637. task_compile_jvm = taskdef(task_compile_jvm, ['source_jvm'],
  638. 'Compiling JVM source')
  639. def copy_jvm_jar(self):
  640. import subprocess
  641. basename = self.exe_name % self.get_info()
  642. root = udir.join('pypy')
  643. manifest = self.create_manifest(root)
  644. jnajar = py.path.local(__file__).dirpath('jvm', 'src', 'jna.jar')
  645. classlist = self.create_classlist(root, [jnajar])
  646. jarfile = py.path.local(basename + '.jar')
  647. self.log.info('Creating jar file')
  648. oldpath = root.chdir()
  649. subprocess.call(['jar', 'cmf', str(manifest), str(jarfile), '@'+str(classlist)])
  650. oldpath.chdir()
  651. # create a convenience script
  652. newexename = basename
  653. f = file(newexename, 'w')
  654. f.write("""#!/bin/bash
  655. LEDIT=`type -p ledit`
  656. EXE=`readlink $0`
  657. if [ -z $EXE ]
  658. then
  659. EXE=$0
  660. fi
  661. $LEDIT java -Xmx256m -jar $EXE.jar "$@"
  662. """)
  663. f.close()
  664. os.chmod(newexename, 0755)
  665. def create_manifest(self, root):
  666. filename = root.join('manifest.txt')
  667. manifest = filename.open('w')
  668. manifest.write('Main-class: pypy.Main\n\n')
  669. manifest.close()
  670. return filename
  671. def create_classlist(self, root, additional_jars=[]):
  672. import subprocess
  673. # first, uncompress additional jars
  674. for jarfile in additional_jars:
  675. oldpwd = root.chdir()
  676. subprocess.call(['jar', 'xf', str(jarfile)])
  677. oldpwd.chdir()
  678. filename = root.join('classlist.txt')
  679. classlist = filename.open('w')
  680. classfiles = list(root.visit('*.class', True))
  681. classfiles += root.visit('*.so', True)
  682. classfiles += root.visit('*.dll', True)
  683. classfiles += root.visit('*.jnilib', True)
  684. for classfile in classfiles:
  685. print >> classlist, classfile.relto(root)
  686. classlist.close()
  687. return filename
  688. def task_run_jvm(self):
  689. pass
  690. task_run_jvm = taskdef(task_run_jvm, ['compile_jvm'],
  691. 'XXX')
  692. def proceed(self, goals):
  693. if not goals:
  694. if self.default_goal:
  695. goals = [self.default_goal]
  696. else:
  697. self.log.info("nothing to do")
  698. return
  699. elif isinstance(goals, str):
  700. goals = [goals]
  701. goals.extend(self.extra_goals)
  702. goals = self.backend_select_goals(goals)
  703. return self._execute(goals, task_skip = self._maybe_skip())
  704. def from_targetspec(targetspec_dic, config=None, args=None,
  705. empty_translator=None,
  706. disable=[],
  707. default_goal=None):
  708. if args is None:
  709. args = []
  710. driver = TranslationDriver(config=config, default_goal=default_goal,
  711. disable=disable)
  712. # patch some attributes of the os module to make sure they
  713. # have the same value on every platform.
  714. backend, ts = driver.get_backend_and_type_system()
  715. if backend in ('cli', 'jvm'):
  716. from pypy.translator.oosupport.support import patch_os
  717. driver.old_cli_defs = patch_os()
  718. target = targetspec_dic['target']
  719. spec = target(driver, args)
  720. try:
  721. entry_point, inputtypes, policy = spec
  722. except ValueError:
  723. entry_point, inputtypes = spec
  724. policy = None
  725. driver.setup(entry_point, inputtypes,
  726. policy=policy,
  727. extra=targetspec_dic,
  728. empty_translator=empty_translator)
  729. return driver
  730. from_targetspec = staticmethod(from_targetspec)
  731. def prereq_checkpt_rtype(self):
  732. assert 'pypy.rpython.rmodel' not in sys.modules, (
  733. "cannot fork because the rtyper has already been imported")
  734. prereq_checkpt_rtype_lltype = prereq_checkpt_rtype
  735. prereq_checkpt_rtype_ootype = prereq_checkpt_rtype
  736. # checkpointing support
  737. def _event(self, kind, goal, func):
  738. if kind == 'planned' and func.task_earlycheck:
  739. func.task_earlycheck(self)
  740. if kind == 'pre':
  741. fork_before = self.config.translation.fork_before
  742. if fork_before:
  743. fork_before, = self.backend_select_goals([fork_before])
  744. if not fork_before in self.done and fork_before == goal:
  745. prereq = getattr(self, 'prereq_checkpt_%s' % goal, None)
  746. if prereq:
  747. prereq()
  748. from pypy.translator.goal import unixcheckpoint
  749. unixcheckpoint.restartable_point(auto='run')
  750. def mkexename(name):
  751. if sys.platform == 'win32':
  752. name = name.new(ext='exe')
  753. return name