PageRenderTime 48ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/translator/c/genc.py

http://github.com/pypy/pypy
Python | 1012 lines | 862 code | 91 blank | 59 comment | 112 complexity | 85ff5278d2c6d09f9e88e783d7b6c454 MD5 | raw file
  1. import autopath
  2. import py
  3. import sys, os
  4. from pypy.translator.c.database import LowLevelDatabase
  5. from pypy.translator.c.extfunc import pre_include_code_lines
  6. from pypy.translator.llsupport.wrapper import new_wrapper
  7. from pypy.translator.gensupp import uniquemodulename, NameManager
  8. from pypy.translator.tool.cbuild import ExternalCompilationInfo
  9. from pypy.rpython.lltypesystem import lltype
  10. from pypy.tool.udir import udir
  11. from pypy.tool import isolate, runsubprocess
  12. from pypy.translator.c.support import log, c_string_constant
  13. from pypy.rpython.typesystem import getfunctionptr
  14. from pypy.translator.c import gc
  15. from pypy.rlib import exports
  16. from pypy.tool.nullpath import NullPyPathLocal
  17. def import_module_from_directory(dir, modname):
  18. file, pathname, description = imp.find_module(modname, [str(dir)])
  19. try:
  20. mod = imp.load_module(modname, file, pathname, description)
  21. finally:
  22. if file:
  23. file.close()
  24. return mod
  25. class ProfOpt(object):
  26. #XXX assuming gcc style flags for now
  27. name = "profopt"
  28. def __init__(self, compiler):
  29. self.compiler = compiler
  30. def first(self):
  31. platform = self.compiler.platform
  32. if platform.name.startswith('darwin'):
  33. # XXX incredible hack for darwin
  34. cfiles = self.compiler.cfiles
  35. STR = '/*--no-profiling-for-this-file!--*/'
  36. no_prof = []
  37. prof = []
  38. for cfile in self.compiler.cfiles:
  39. if STR in cfile.read():
  40. no_prof.append(cfile)
  41. else:
  42. prof.append(cfile)
  43. p_eci = self.compiler.eci.merge(
  44. ExternalCompilationInfo(compile_extra=['-fprofile-generate'],
  45. link_extra=['-fprofile-generate']))
  46. ofiles = platform._compile_o_files(prof, p_eci)
  47. _, eci = self.compiler.eci.get_module_files()
  48. ofiles += platform._compile_o_files(no_prof, eci)
  49. return platform._finish_linking(ofiles, p_eci, None, True)
  50. else:
  51. return self.build('-fprofile-generate')
  52. def probe(self, exe, args):
  53. # 'args' is a single string typically containing spaces
  54. # and quotes, which represents several arguments.
  55. self.compiler.platform.execute(exe, args)
  56. def after(self):
  57. return self.build('-fprofile-use')
  58. def build(self, option):
  59. eci = ExternalCompilationInfo(compile_extra=[option],
  60. link_extra=[option])
  61. return self.compiler._build(eci)
  62. class CCompilerDriver(object):
  63. def __init__(self, platform, cfiles, eci, outputfilename=None,
  64. profbased=False):
  65. # XXX config might contain additional link and compile options.
  66. # We need to fish for it somehow.
  67. self.platform = platform
  68. self.cfiles = cfiles
  69. self.eci = eci
  70. self.outputfilename = outputfilename
  71. self.profbased = profbased
  72. def _build(self, eci=ExternalCompilationInfo(), shared=False):
  73. outputfilename = self.outputfilename
  74. if shared:
  75. if outputfilename:
  76. basename = outputfilename
  77. else:
  78. basename = self.cfiles[0].purebasename
  79. outputfilename = 'lib' + basename
  80. return self.platform.compile(self.cfiles, self.eci.merge(eci),
  81. outputfilename=outputfilename,
  82. standalone=not shared)
  83. def build(self, shared=False):
  84. if self.profbased:
  85. return self._do_profbased()
  86. return self._build(shared=shared)
  87. def _do_profbased(self):
  88. ProfDriver, args = self.profbased
  89. profdrv = ProfDriver(self)
  90. dolog = getattr(log, profdrv.name)
  91. dolog(args)
  92. exename = profdrv.first()
  93. dolog('Gathering profile data from: %s %s' % (
  94. str(exename), args))
  95. profdrv.probe(exename, args)
  96. return profdrv.after()
  97. class CBuilder(object):
  98. c_source_filename = None
  99. _compiled = False
  100. modulename = None
  101. split = False
  102. cpython_extension = False
  103. def __init__(self, translator, entrypoint, config, gcpolicy=None,
  104. secondary_entrypoints=()):
  105. self.translator = translator
  106. self.entrypoint = entrypoint
  107. self.entrypoint_name = getattr(self.entrypoint, 'func_name', None)
  108. self.originalentrypoint = entrypoint
  109. self.config = config
  110. self.gcpolicy = gcpolicy # for tests only, e.g. rpython/memory/
  111. self.eci = self.get_eci()
  112. self.secondary_entrypoints = secondary_entrypoints
  113. def get_eci(self):
  114. pypy_include_dir = py.path.local(autopath.pypydir).join('translator', 'c')
  115. include_dirs = [pypy_include_dir]
  116. return ExternalCompilationInfo(include_dirs=include_dirs)
  117. def build_database(self):
  118. translator = self.translator
  119. gcpolicyclass = self.get_gcpolicyclass()
  120. if self.config.translation.gcrootfinder == "asmgcc":
  121. if not self.standalone:
  122. raise NotImplementedError("--gcrootfinder=asmgcc requires standalone")
  123. db = LowLevelDatabase(translator, standalone=self.standalone,
  124. cpython_extension=self.cpython_extension,
  125. gcpolicyclass=gcpolicyclass,
  126. thread_enabled=self.config.translation.thread,
  127. sandbox=self.config.translation.sandbox)
  128. self.db = db
  129. # give the gc a chance to register interest in the start-up functions it
  130. # need (we call this for its side-effects of db.get())
  131. list(db.gcpolicy.gc_startup_code())
  132. # build entrypoint and eventually other things to expose
  133. pf = self.getentrypointptr()
  134. if isinstance(pf, list):
  135. for one_pf in pf:
  136. db.get(one_pf)
  137. self.c_entrypoint_name = None
  138. else:
  139. pfname = db.get(pf)
  140. for func, _ in self.secondary_entrypoints:
  141. bk = translator.annotator.bookkeeper
  142. db.get(getfunctionptr(bk.getdesc(func).getuniquegraph()))
  143. self.c_entrypoint_name = pfname
  144. for obj in exports.EXPORTS_obj2name.keys():
  145. db.getcontainernode(obj)
  146. exports.clear()
  147. db.complete()
  148. self.collect_compilation_info(db)
  149. return db
  150. have___thread = None
  151. def merge_eci(self, *ecis):
  152. self.eci = self.eci.merge(*ecis)
  153. def collect_compilation_info(self, db):
  154. # we need a concrete gcpolicy to do this
  155. self.merge_eci(db.gcpolicy.compilation_info())
  156. all = []
  157. for node in self.db.globalcontainers():
  158. eci = node.compilation_info()
  159. if eci:
  160. all.append(eci)
  161. self.merge_eci(*all)
  162. def get_gcpolicyclass(self):
  163. if self.gcpolicy is None:
  164. name = self.config.translation.gctransformer
  165. if self.config.translation.gcrootfinder == "asmgcc":
  166. name = "%s+asmgcroot" % (name,)
  167. return gc.name_to_gcpolicy[name]
  168. return self.gcpolicy
  169. # use generate_source(defines=DEBUG_DEFINES) to force the #definition
  170. # of the macros that enable debugging assertions
  171. DEBUG_DEFINES = {'RPY_ASSERT': 1,
  172. 'RPY_LL_ASSERT': 1}
  173. def generate_graphs_for_llinterp(self, db=None):
  174. # prepare the graphs as when the source is generated, but without
  175. # actually generating the source.
  176. if db is None:
  177. db = self.build_database()
  178. graphs = db.all_graphs()
  179. db.gctransformer.prepare_inline_helpers(graphs)
  180. for node in db.containerlist:
  181. if hasattr(node, 'funcgens'):
  182. for funcgen in node.funcgens:
  183. funcgen.patch_graph(copy_graph=False)
  184. return db
  185. def generate_source(self, db=None, defines={}, exe_name=None):
  186. assert self.c_source_filename is None
  187. translator = self.translator
  188. if db is None:
  189. db = self.build_database()
  190. pf = self.getentrypointptr()
  191. if self.modulename is None:
  192. self.modulename = uniquemodulename('testing')
  193. modulename = self.modulename
  194. targetdir = udir.ensure(modulename, dir=1)
  195. if self.config.translation.dont_write_c_files:
  196. targetdir = NullPyPathLocal(targetdir)
  197. self.targetdir = targetdir
  198. defines = defines.copy()
  199. if self.config.translation.countmallocs:
  200. defines['COUNT_OP_MALLOCS'] = 1
  201. if self.config.translation.sandbox:
  202. defines['RPY_SANDBOXED'] = 1
  203. if CBuilder.have___thread is None:
  204. CBuilder.have___thread = self.translator.platform.check___thread()
  205. if not self.standalone:
  206. assert not self.config.translation.instrument
  207. if self.cpython_extension:
  208. defines['PYPY_CPYTHON_EXTENSION'] = 1
  209. else:
  210. defines['PYPY_STANDALONE'] = db.get(pf)
  211. if self.config.translation.instrument:
  212. defines['INSTRUMENT'] = 1
  213. if CBuilder.have___thread:
  214. if not self.config.translation.no__thread:
  215. defines['USE___THREAD'] = 1
  216. if self.config.translation.shared:
  217. defines['PYPY_MAIN_FUNCTION'] = "pypy_main_startup"
  218. self.eci = self.eci.merge(ExternalCompilationInfo(
  219. export_symbols=["pypy_main_startup"]))
  220. self.eci, cfile, extra = gen_source(db, modulename, targetdir,
  221. self.eci, defines=defines,
  222. split=self.split)
  223. self.c_source_filename = py.path.local(cfile)
  224. self.extrafiles = self.eventually_copy(extra)
  225. self.gen_makefile(targetdir, exe_name=exe_name)
  226. return cfile
  227. def eventually_copy(self, cfiles):
  228. extrafiles = []
  229. for fn in cfiles:
  230. fn = py.path.local(fn)
  231. if not fn.relto(udir):
  232. newname = self.targetdir.join(fn.basename)
  233. fn.copy(newname)
  234. fn = newname
  235. extrafiles.append(fn)
  236. return extrafiles
  237. class ModuleWithCleanup(object):
  238. def __init__(self, mod):
  239. self.__dict__['mod'] = mod
  240. def __getattr__(self, name):
  241. mod = self.__dict__['mod']
  242. obj = getattr(mod, name)
  243. parentself = self
  244. if callable(obj) and getattr(obj, '__module__', None) == mod.__name__:
  245. # The module must be kept alive with the function.
  246. # This wrapper avoids creating a cycle.
  247. class Wrapper:
  248. def __init__(self, obj):
  249. self.myself = parentself
  250. self.func = obj
  251. def __call__(self, *args, **kwargs):
  252. return self.func(*args, **kwargs)
  253. obj = Wrapper(obj)
  254. return obj
  255. def __setattr__(self, name, val):
  256. mod = self.__dict__['mod']
  257. setattr(mod, name, val)
  258. def __del__(self):
  259. import sys
  260. if sys.platform == "win32":
  261. from _ctypes import FreeLibrary as dlclose
  262. else:
  263. from _ctypes import dlclose
  264. # XXX fish fish fish
  265. mod = self.__dict__['mod']
  266. dlclose(mod._lib._handle)
  267. try:
  268. del sys.modules[mod.__name__]
  269. except KeyError:
  270. pass
  271. class CExtModuleBuilder(CBuilder):
  272. standalone = False
  273. cpython_extension = True
  274. _module = None
  275. _wrapper = None
  276. def get_eci(self):
  277. from distutils import sysconfig
  278. python_inc = sysconfig.get_python_inc()
  279. eci = ExternalCompilationInfo(
  280. include_dirs=[python_inc],
  281. includes=["Python.h",
  282. ],
  283. )
  284. return eci.merge(CBuilder.get_eci(self))
  285. def getentrypointptr(self): # xxx
  286. if self._wrapper is None:
  287. self._wrapper = new_wrapper(self.entrypoint, self.translator)
  288. return self._wrapper
  289. def compile(self):
  290. assert self.c_source_filename
  291. assert not self._compiled
  292. export_symbols = [self.db.get(self.getentrypointptr()),
  293. 'RPython_StartupCode',
  294. ]
  295. if self.config.translation.countmallocs:
  296. export_symbols.append('malloc_counters')
  297. extsymeci = ExternalCompilationInfo(export_symbols=export_symbols)
  298. self.eci = self.eci.merge(extsymeci)
  299. if sys.platform == 'win32':
  300. self.eci = self.eci.merge(ExternalCompilationInfo(
  301. library_dirs = [py.path.local(sys.exec_prefix).join('LIBs'),
  302. py.path.local(sys.executable).dirpath(),
  303. ],
  304. ))
  305. files = [self.c_source_filename] + self.extrafiles
  306. self.translator.platform.compile(files, self.eci, standalone=False)
  307. self._compiled = True
  308. def _make_wrapper_module(self):
  309. fname = 'wrap_' + self.c_source_filename.purebasename
  310. modfile = self.c_source_filename.new(purebasename=fname, ext=".py")
  311. entrypoint_ptr = self.getentrypointptr()
  312. wrapped_entrypoint_c_name = self.db.get(entrypoint_ptr)
  313. CODE = """
  314. import ctypes
  315. _lib = ctypes.PyDLL(r"%(so_name)s")
  316. _entry_point = getattr(_lib, "%(c_entrypoint_name)s")
  317. _entry_point.restype = ctypes.py_object
  318. _entry_point.argtypes = %(nargs)d*(ctypes.py_object,)
  319. def entrypoint(*args):
  320. return _entry_point(*args)
  321. try:
  322. _malloc_counters = _lib.malloc_counters
  323. except AttributeError:
  324. pass
  325. else:
  326. _malloc_counters.restype = ctypes.py_object
  327. _malloc_counters.argtypes = 2*(ctypes.py_object,)
  328. def malloc_counters():
  329. return _malloc_counters(None, None)
  330. _rpython_startup = _lib.RPython_StartupCode
  331. _rpython_startup()
  332. """ % {'so_name': self.c_source_filename.new(ext=self.translator.platform.so_ext),
  333. 'c_entrypoint_name': wrapped_entrypoint_c_name,
  334. 'nargs': len(lltype.typeOf(entrypoint_ptr).TO.ARGS)}
  335. modfile.write(CODE)
  336. self._module_path = modfile
  337. def _import_module(self, isolated=False):
  338. if self._module is not None:
  339. return self._module
  340. assert self._compiled
  341. assert not self._module
  342. self._make_wrapper_module()
  343. if not isolated:
  344. mod = ModuleWithCleanup(self._module_path.pyimport())
  345. else:
  346. mod = isolate.Isolate((str(self._module_path.dirpath()),
  347. self._module_path.purebasename))
  348. self._module = mod
  349. return mod
  350. def get_entry_point(self, isolated=False):
  351. self._import_module(isolated=isolated)
  352. return getattr(self._module, "entrypoint")
  353. def get_malloc_counters(self, isolated=False):
  354. self._import_module(isolated=isolated)
  355. return self._module.malloc_counters
  356. def cleanup(self):
  357. #assert self._module
  358. if isinstance(self._module, isolate.Isolate):
  359. isolate.close_isolate(self._module)
  360. def gen_makefile(self, targetdir, exe_name=None):
  361. pass
  362. class CStandaloneBuilder(CBuilder):
  363. standalone = True
  364. split = True
  365. executable_name = None
  366. shared_library_name = None
  367. def getprofbased(self):
  368. profbased = None
  369. if self.config.translation.instrumentctl is not None:
  370. profbased = self.config.translation.instrumentctl
  371. else:
  372. # xxx handling config.translation.profopt is a bit messy, because
  373. # it could be an empty string (not to be confused with None) and
  374. # because noprofopt can be used as an override.
  375. profopt = self.config.translation.profopt
  376. if profopt is not None and not self.config.translation.noprofopt:
  377. profbased = (ProfOpt, profopt)
  378. return profbased
  379. def has_profopt(self):
  380. profbased = self.getprofbased()
  381. return (profbased and isinstance(profbased, tuple)
  382. and profbased[0] is ProfOpt)
  383. def getentrypointptr(self):
  384. # XXX check that the entrypoint has the correct
  385. # signature: list-of-strings -> int
  386. bk = self.translator.annotator.bookkeeper
  387. return getfunctionptr(bk.getdesc(self.entrypoint).getuniquegraph())
  388. def cmdexec(self, args='', env=None, err=False, expect_crash=False):
  389. assert self._compiled
  390. res = self.translator.platform.execute(self.executable_name, args,
  391. env=env)
  392. if res.returncode != 0:
  393. if expect_crash:
  394. return res.out, res.err
  395. print >> sys.stderr, res.err
  396. raise Exception("Returned %d" % (res.returncode,))
  397. if expect_crash:
  398. raise Exception("Program did not crash!")
  399. if err:
  400. return res.out, res.err
  401. return res.out
  402. def build_main_for_shared(self, shared_library_name, entrypoint, exe_name):
  403. import time
  404. time.sleep(1)
  405. self.shared_library_name = shared_library_name
  406. # build main program
  407. eci = self.get_eci()
  408. kw = {}
  409. if self.translator.platform.cc == 'gcc':
  410. kw['libraries'] = [self.shared_library_name.purebasename[3:]]
  411. kw['library_dirs'] = [self.targetdir]
  412. else:
  413. kw['libraries'] = [self.shared_library_name.new(ext='')]
  414. eci = eci.merge(ExternalCompilationInfo(
  415. separate_module_sources=['''
  416. int %s(int argc, char* argv[]);
  417. int main(int argc, char* argv[])
  418. { return %s(argc, argv); }
  419. ''' % (entrypoint, entrypoint)
  420. ],
  421. **kw
  422. ))
  423. eci = eci.convert_sources_to_files(
  424. cache_dir=self.targetdir)
  425. return self.translator.platform.compile(
  426. [], eci,
  427. outputfilename=exe_name)
  428. def compile(self, exe_name=None):
  429. assert self.c_source_filename
  430. assert not self._compiled
  431. shared = self.config.translation.shared
  432. extra_opts = []
  433. if self.config.translation.make_jobs != 1:
  434. extra_opts += ['-j', str(self.config.translation.make_jobs)]
  435. self.translator.platform.execute_makefile(self.targetdir,
  436. extra_opts)
  437. if shared:
  438. self.shared_library_name = self.executable_name.new(
  439. purebasename='lib' + self.executable_name.purebasename,
  440. ext=self.translator.platform.so_ext)
  441. self._compiled = True
  442. return self.executable_name
  443. def gen_makefile(self, targetdir, exe_name=None):
  444. cfiles = [self.c_source_filename] + self.extrafiles
  445. if exe_name is not None:
  446. exe_name = targetdir.join(exe_name)
  447. mk = self.translator.platform.gen_makefile(
  448. cfiles, self.eci,
  449. path=targetdir, exe_name=exe_name,
  450. shared=self.config.translation.shared)
  451. if self.has_profopt():
  452. profopt = self.config.translation.profopt
  453. mk.definition('ABS_TARGET', '$(shell python -c "import sys,os; print os.path.abspath(sys.argv[1])" $(TARGET))')
  454. mk.definition('DEFAULT_TARGET', 'profopt')
  455. mk.definition('PROFOPT', profopt)
  456. rules = [
  457. ('clean', '', 'rm -f $(OBJECTS) $(TARGET) $(GCMAPFILES) $(ASMFILES) *.gc?? ../module_cache/*.gc??'),
  458. ('clean_noprof', '', 'rm -f $(OBJECTS) $(TARGET) $(GCMAPFILES) $(ASMFILES)'),
  459. ('debug', '', '$(MAKE) CFLAGS="$(DEBUGFLAGS) -DRPY_ASSERT" debug_target'),
  460. ('debug_exc', '', '$(MAKE) CFLAGS="$(DEBUGFLAGS) -DRPY_ASSERT -DDO_LOG_EXC" debug_target'),
  461. ('debug_mem', '', '$(MAKE) CFLAGS="$(DEBUGFLAGS) -DRPY_ASSERT -DTRIVIAL_MALLOC_DEBUG" debug_target'),
  462. ('no_obmalloc', '', '$(MAKE) CFLAGS="-g -O2 -DRPY_ASSERT -DNO_OBMALLOC" $(TARGET)'),
  463. ('linuxmemchk', '', '$(MAKE) CFLAGS="$(DEBUGFLAGS) -DRPY_ASSERT -DLINUXMEMCHK" debug_target'),
  464. ('llsafer', '', '$(MAKE) CFLAGS="-O2 -DRPY_LL_ASSERT" $(TARGET)'),
  465. ('lldebug', '', '$(MAKE) CFLAGS="$(DEBUGFLAGS) -DRPY_ASSERT -DRPY_LL_ASSERT" debug_target'),
  466. ('profile', '', '$(MAKE) CFLAGS="-g -O1 -pg $(CFLAGS) -fno-omit-frame-pointer" LDFLAGS="-pg $(LDFLAGS)" $(TARGET)'),
  467. ]
  468. if self.has_profopt():
  469. rules.append(
  470. ('profopt', '', [
  471. '$(MAKENOPROF)',
  472. '$(MAKE) CFLAGS="-fprofile-generate $(CFLAGS)" LDFLAGS="-fprofile-generate $(LDFLAGS)" $(TARGET)',
  473. 'cd $(PYPYDIR)/translator/goal && $(ABS_TARGET) $(PROFOPT)',
  474. '$(MAKE) clean_noprof',
  475. '$(MAKE) CFLAGS="-fprofile-use $(CFLAGS)" LDFLAGS="-fprofile-use $(LDFLAGS)" $(TARGET)']))
  476. for rule in rules:
  477. mk.rule(*rule)
  478. if self.config.translation.gcrootfinder == 'asmgcc':
  479. trackgcfiles = [cfile[:cfile.rfind('.')] for cfile in mk.cfiles]
  480. if self.translator.platform.name == 'msvc':
  481. trackgcfiles = [f for f in trackgcfiles
  482. if f.startswith(('implement', 'testing',
  483. '../module_cache/module'))]
  484. sfiles = ['%s.s' % (c,) for c in trackgcfiles]
  485. lblsfiles = ['%s.lbl.s' % (c,) for c in trackgcfiles]
  486. gcmapfiles = ['%s.gcmap' % (c,) for c in trackgcfiles]
  487. mk.definition('ASMFILES', sfiles)
  488. mk.definition('ASMLBLFILES', lblsfiles)
  489. mk.definition('GCMAPFILES', gcmapfiles)
  490. if sys.platform == 'win32':
  491. mk.definition('DEBUGFLAGS', '/MD /Zi')
  492. else:
  493. mk.definition('DEBUGFLAGS', '-O2 -fomit-frame-pointer -g')
  494. if self.config.translation.shared:
  495. mk.definition('PYPY_MAIN_FUNCTION', "pypy_main_startup")
  496. else:
  497. mk.definition('PYPY_MAIN_FUNCTION', "main")
  498. if sys.platform == 'win32':
  499. python = sys.executable.replace('\\', '/') + ' '
  500. else:
  501. python = sys.executable + ' '
  502. # Is there a command 'python' that runs python 2.5-2.7?
  503. # If there is, then we can use it instead of sys.executable
  504. returncode, stdout, stderr = runsubprocess.run_subprocess(
  505. "python", "-V")
  506. if (stdout.startswith('Python 2.') or
  507. stderr.startswith('Python 2.')):
  508. python = 'python '
  509. if self.translator.platform.name == 'msvc':
  510. lblofiles = []
  511. for cfile in mk.cfiles:
  512. f = cfile[:cfile.rfind('.')]
  513. if f in trackgcfiles:
  514. ofile = '%s.lbl.obj' % (f,)
  515. else:
  516. ofile = '%s.obj' % (f,)
  517. lblofiles.append(ofile)
  518. mk.definition('ASMLBLOBJFILES', lblofiles)
  519. mk.definition('OBJECTS', 'gcmaptable.obj $(ASMLBLOBJFILES)')
  520. # /Oi (enable intrinsics) and /Ob1 (some inlining) are mandatory
  521. # even in debug builds
  522. mk.definition('ASM_CFLAGS', '$(CFLAGS) $(CFLAGSEXTRA) /Oi /Ob1')
  523. mk.rule('.SUFFIXES', '.s', [])
  524. mk.rule('.s.obj', '',
  525. 'cmd /c $(MASM) /nologo /Cx /Cp /Zm /coff /Fo$@ /c $< $(INCLUDEDIRS)')
  526. mk.rule('.c.gcmap', '',
  527. ['$(CC) /nologo $(ASM_CFLAGS) /c /FAs /Fa$*.s $< $(INCLUDEDIRS)',
  528. 'cmd /c ' + python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -fmsvc -t $*.s > $@']
  529. )
  530. mk.rule('gcmaptable.c', '$(GCMAPFILES)',
  531. 'cmd /c ' + python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -fmsvc $(GCMAPFILES) > $@')
  532. else:
  533. mk.definition('OBJECTS', '$(ASMLBLFILES) gcmaptable.s')
  534. mk.rule('%.s', '%.c', '$(CC) $(CFLAGS) $(CFLAGSEXTRA) -frandom-seed=$< -o $@ -S $< $(INCLUDEDIRS)')
  535. mk.rule('%.lbl.s %.gcmap', '%.s',
  536. [python +
  537. '$(PYPYDIR)/translator/c/gcc/trackgcroot.py '
  538. '-t $< > $*.gctmp',
  539. 'mv $*.gctmp $*.gcmap'])
  540. mk.rule('gcmaptable.s', '$(GCMAPFILES)',
  541. [python +
  542. '$(PYPYDIR)/translator/c/gcc/trackgcroot.py '
  543. '$(GCMAPFILES) > $@.tmp',
  544. 'mv $@.tmp $@'])
  545. mk.rule('.PRECIOUS', '%.s', "# don't remove .s files if Ctrl-C'ed")
  546. else:
  547. if sys.platform == 'win32':
  548. mk.definition('DEBUGFLAGS', '/MD /Zi')
  549. else:
  550. mk.definition('DEBUGFLAGS', '-O1 -g')
  551. if sys.platform == 'win32':
  552. mk.rule('debug_target', 'debugmode_$(DEFAULT_TARGET)', 'rem')
  553. else:
  554. mk.rule('debug_target', '$(TARGET)', '#')
  555. mk.write()
  556. #self.translator.platform,
  557. # ,
  558. # self.eci, profbased=self.getprofbased()
  559. self.executable_name = mk.exe_name
  560. # ____________________________________________________________
  561. SPLIT_CRITERIA = 65535 # support VC++ 7.2
  562. #SPLIT_CRITERIA = 32767 # enable to support VC++ 6.0
  563. MARKER = '/*/*/' # provide an easy way to split after generating
  564. class SourceGenerator:
  565. one_source_file = True
  566. def __init__(self, database, preimplementationlines=[]):
  567. self.database = database
  568. self.preimpl = preimplementationlines
  569. self.extrafiles = []
  570. self.path = None
  571. self.namespace = NameManager()
  572. def set_strategy(self, path, split=True):
  573. all_nodes = list(self.database.globalcontainers())
  574. # split off non-function nodes. We don't try to optimize these, yet.
  575. funcnodes = []
  576. othernodes = []
  577. for node in all_nodes:
  578. if node.nodekind == 'func':
  579. funcnodes.append(node)
  580. else:
  581. othernodes.append(node)
  582. # for now, only split for stand-alone programs.
  583. #if self.database.standalone:
  584. if split:
  585. self.one_source_file = False
  586. self.funcnodes = funcnodes
  587. self.othernodes = othernodes
  588. self.path = path
  589. def uniquecname(self, name):
  590. assert name.endswith('.c')
  591. return self.namespace.uniquename(name[:-2]) + '.c'
  592. def makefile(self, name):
  593. log.writing(name)
  594. filepath = self.path.join(name)
  595. if name.endswith('.c'):
  596. self.extrafiles.append(filepath)
  597. return filepath.open('w')
  598. def getextrafiles(self):
  599. return self.extrafiles
  600. def getothernodes(self):
  601. return self.othernodes[:]
  602. def getbasecfilefornode(self, node, basecname):
  603. # For FuncNode instances, use the python source filename (relative to
  604. # the top directory):
  605. def invent_nice_name(g):
  606. # Lookup the filename from the function.
  607. # However, not all FunctionGraph objs actually have a "func":
  608. if hasattr(g, 'func'):
  609. if g.filename.endswith('.py'):
  610. localpath = py.path.local(g.filename)
  611. pypkgpath = localpath.pypkgpath()
  612. if pypkgpath:
  613. relpypath = localpath.relto(pypkgpath)
  614. return relpypath.replace('.py', '.c')
  615. return None
  616. if hasattr(node.obj, 'graph'):
  617. name = invent_nice_name(node.obj.graph)
  618. if name is not None:
  619. return name
  620. elif node._funccodegen_owner is not None:
  621. name = invent_nice_name(node._funccodegen_owner.graph)
  622. if name is not None:
  623. return "data_" + name
  624. return basecname
  625. def splitnodesimpl(self, basecname, nodes, nextra, nbetween,
  626. split_criteria=SPLIT_CRITERIA):
  627. # Gather nodes by some criteria:
  628. nodes_by_base_cfile = {}
  629. for node in nodes:
  630. c_filename = self.getbasecfilefornode(node, basecname)
  631. if c_filename in nodes_by_base_cfile:
  632. nodes_by_base_cfile[c_filename].append(node)
  633. else:
  634. nodes_by_base_cfile[c_filename] = [node]
  635. # produce a sequence of nodes, grouped into files
  636. # which have no more than SPLIT_CRITERIA lines
  637. for basecname in nodes_by_base_cfile:
  638. iternodes = iter(nodes_by_base_cfile[basecname])
  639. done = [False]
  640. def subiter():
  641. used = nextra
  642. for node in iternodes:
  643. impl = '\n'.join(list(node.implementation())).split('\n')
  644. if not impl:
  645. continue
  646. cost = len(impl) + nbetween
  647. yield node, impl
  648. del impl
  649. if used + cost > split_criteria:
  650. # split if criteria met, unless we would produce nothing.
  651. raise StopIteration
  652. used += cost
  653. done[0] = True
  654. while not done[0]:
  655. yield self.uniquecname(basecname), subiter()
  656. def gen_readable_parts_of_source(self, f):
  657. split_criteria_big = SPLIT_CRITERIA
  658. if py.std.sys.platform != "win32":
  659. if self.database.gcpolicy.need_no_typeptr():
  660. pass # XXX gcc uses toooooons of memory???
  661. else:
  662. split_criteria_big = SPLIT_CRITERIA * 4
  663. if self.one_source_file:
  664. return gen_readable_parts_of_main_c_file(f, self.database,
  665. self.preimpl)
  666. #
  667. # All declarations
  668. #
  669. database = self.database
  670. structdeflist = database.getstructdeflist()
  671. name = 'structdef.h'
  672. fi = self.makefile(name)
  673. print >> f, '#include "%s"' % name
  674. gen_structdef(fi, database)
  675. fi.close()
  676. name = 'forwarddecl.h'
  677. fi = self.makefile(name)
  678. print >> f, '#include "%s"' % name
  679. gen_forwarddecl(fi, database)
  680. fi.close()
  681. #
  682. # Implementation of functions and global structures and arrays
  683. #
  684. print >> f
  685. print >> f, '/***********************************************************/'
  686. print >> f, '/*** Implementations ***/'
  687. print >> f
  688. for line in self.preimpl:
  689. print >> f, line
  690. print >> f, '#include "src/g_include.h"'
  691. print >> f
  692. name = self.uniquecname('structimpl.c')
  693. print >> f, '/* %s */' % name
  694. fc = self.makefile(name)
  695. print >> fc, '/***********************************************************/'
  696. print >> fc, '/*** Structure Implementations ***/'
  697. print >> fc
  698. print >> fc, '#define PYPY_NOT_MAIN_FILE'
  699. print >> fc, '#include "common_header.h"'
  700. print >> fc, '#include "structdef.h"'
  701. print >> fc, '#include "forwarddecl.h"'
  702. print >> fc
  703. print >> fc, '#include "src/g_include.h"'
  704. print >> fc
  705. print >> fc, MARKER
  706. print >> fc, '/***********************************************************/'
  707. fc.close()
  708. nextralines = 11 + 1
  709. for name, nodeiter in self.splitnodesimpl('nonfuncnodes.c',
  710. self.othernodes,
  711. nextralines, 1):
  712. print >> f, '/* %s */' % name
  713. fc = self.makefile(name)
  714. print >> fc, '/***********************************************************/'
  715. print >> fc, '/*** Non-function Implementations ***/'
  716. print >> fc
  717. print >> fc, '#define PYPY_NOT_MAIN_FILE'
  718. print >> fc, '#include "common_header.h"'
  719. print >> fc, '#include "structdef.h"'
  720. print >> fc, '#include "forwarddecl.h"'
  721. print >> fc
  722. print >> fc, '#include "src/g_include.h"'
  723. print >> fc
  724. print >> fc, MARKER
  725. for node, impl in nodeiter:
  726. print >> fc, '\n'.join(impl)
  727. print >> fc, MARKER
  728. print >> fc, '/***********************************************************/'
  729. fc.close()
  730. nextralines = 8 + len(self.preimpl) + 4 + 1
  731. for name, nodeiter in self.splitnodesimpl('implement.c',
  732. self.funcnodes,
  733. nextralines, 1,
  734. split_criteria_big):
  735. print >> f, '/* %s */' % name
  736. fc = self.makefile(name)
  737. print >> fc, '/***********************************************************/'
  738. print >> fc, '/*** Implementations ***/'
  739. print >> fc
  740. print >> fc, '#define PYPY_NOT_MAIN_FILE'
  741. print >> fc, '#define PYPY_FILE_NAME "%s"' % name
  742. print >> fc, '#include "common_header.h"'
  743. print >> fc, '#include "structdef.h"'
  744. print >> fc, '#include "forwarddecl.h"'
  745. print >> fc
  746. for line in self.preimpl:
  747. print >> fc, line
  748. print >> fc
  749. print >> fc, '#include "src/g_include.h"'
  750. print >> fc
  751. print >> fc, MARKER
  752. for node, impl in nodeiter:
  753. print >> fc, '\n'.join(impl)
  754. print >> fc, MARKER
  755. print >> fc, '/***********************************************************/'
  756. fc.close()
  757. print >> f
  758. def gen_structdef(f, database):
  759. structdeflist = database.getstructdeflist()
  760. print >> f, '/***********************************************************/'
  761. print >> f, '/*** Structure definitions ***/'
  762. print >> f
  763. for node in structdeflist:
  764. if hasattr(node, 'forward_decl'):
  765. if node.forward_decl:
  766. print >> f, node.forward_decl
  767. elif node.name is not None:
  768. print >> f, '%s %s;' % (node.typetag, node.name)
  769. print >> f
  770. for node in structdeflist:
  771. for line in node.definition():
  772. print >> f, line
  773. def gen_forwarddecl(f, database):
  774. print >> f, '/***********************************************************/'
  775. print >> f, '/*** Forward declarations ***/'
  776. print >> f
  777. for node in database.globalcontainers():
  778. for line in node.forward_declaration():
  779. print >> f, line
  780. # this function acts as the fallback for small sources for now.
  781. # Maybe we drop this completely if source splitting is the way
  782. # to go. Currently, I'm quite fine with keeping a working fallback.
  783. # XXX but we need to reduce code duplication.
  784. def gen_readable_parts_of_main_c_file(f, database, preimplementationlines=[]):
  785. #
  786. # All declarations
  787. #
  788. print >> f
  789. gen_structdef(f, database)
  790. print >> f
  791. gen_forwarddecl(f, database)
  792. #
  793. # Implementation of functions and global structures and arrays
  794. #
  795. print >> f
  796. print >> f, '/***********************************************************/'
  797. print >> f, '/*** Implementations ***/'
  798. print >> f
  799. print >> f, '#define PYPY_FILE_NAME "%s"' % os.path.basename(f.name)
  800. for line in preimplementationlines:
  801. print >> f, line
  802. print >> f, '#include "src/g_include.h"'
  803. print >> f
  804. blank = True
  805. graphs = database.all_graphs()
  806. database.gctransformer.prepare_inline_helpers(graphs)
  807. for node in database.globalcontainers():
  808. if blank:
  809. print >> f
  810. blank = False
  811. for line in node.implementation():
  812. print >> f, line
  813. blank = True
  814. def gen_startupcode(f, database):
  815. # generate the start-up code and put it into a function
  816. print >> f, 'char *RPython_StartupCode(void) {'
  817. print >> f, '\tchar *error = NULL;'
  818. for line in database.gcpolicy.gc_startup_code():
  819. print >> f,"\t" + line
  820. # put float infinities in global constants, we should not have so many of them for now to make
  821. # a table+loop preferable
  822. for dest, value in database.late_initializations:
  823. print >> f, "\t%s = %s;" % (dest, value)
  824. firsttime = True
  825. for node in database.containerlist:
  826. lines = list(node.startupcode())
  827. if lines:
  828. if firsttime:
  829. firsttime = False
  830. else:
  831. print >> f, '\tif (error) return error;'
  832. for line in lines:
  833. print >> f, '\t'+line
  834. print >> f, '\treturn error;'
  835. print >> f, '}'
  836. def commondefs(defines):
  837. from pypy.rlib.rarithmetic import LONG_BIT, LONGLONG_BIT
  838. defines['PYPY_LONG_BIT'] = LONG_BIT
  839. defines['PYPY_LONGLONG_BIT'] = LONGLONG_BIT
  840. def add_extra_files(eci):
  841. srcdir = py.path.local(autopath.pypydir).join('translator', 'c', 'src')
  842. files = [
  843. srcdir / 'profiling.c',
  844. srcdir / 'debug_print.c',
  845. ]
  846. return eci.merge(ExternalCompilationInfo(separate_module_files=files))
  847. def gen_source(database, modulename, targetdir,
  848. eci, defines={}, split=False):
  849. if isinstance(targetdir, str):
  850. targetdir = py.path.local(targetdir)
  851. filename = targetdir.join(modulename + '.c')
  852. f = filename.open('w')
  853. incfilename = targetdir.join('common_header.h')
  854. fi = incfilename.open('w')
  855. #
  856. # Header
  857. #
  858. print >> f, '#include "common_header.h"'
  859. print >> f
  860. commondefs(defines)
  861. for key, value in defines.items():
  862. print >> fi, '#define %s %s' % (key, value)
  863. eci.write_c_header(fi)
  864. print >> fi, '#include "src/g_prerequisite.h"'
  865. fi.close()
  866. if database.translator is None or database.translator.rtyper is None:
  867. preimplementationlines = []
  868. else:
  869. preimplementationlines = list(
  870. pre_include_code_lines(database, database.translator.rtyper))
  871. #
  872. # 1) All declarations
  873. # 2) Implementation of functions and global structures and arrays
  874. #
  875. sg = SourceGenerator(database, preimplementationlines)
  876. sg.set_strategy(targetdir, split)
  877. if split:
  878. database.prepare_inline_helpers()
  879. sg.gen_readable_parts_of_source(f)
  880. gen_startupcode(f, database)
  881. f.close()
  882. if 'INSTRUMENT' in defines:
  883. fi = incfilename.open('a')
  884. n = database.instrument_ncounter
  885. print >>fi, "#define INSTRUMENT_NCOUNTER %d" % n
  886. fi.close()
  887. eci = add_extra_files(eci)
  888. eci = eci.convert_sources_to_files(being_main=True)
  889. files, eci = eci.get_module_files()
  890. return eci, filename, sg.getextrafiles() + list(files)