Source

pypy / pypy / translator / c / genc.py

The branch 'remove-PYPY_NOT_MAIN_FILE' does not exist.
Full commit
Armin Rigo 5a872d1 
Amaury Forgeot d… 1ff2a82 
Armin Rigo 5a872d1 
Armin Rigo f2be5fb 
Manuel Jacob 576d58a 






Armin Rigo 5a872d1 

Manuel Jacob 576d58a 

Armin Rigo 8c6c6d4 
Maciej Fijalkows… 75307d4 
Armin Rigo 5a872d1 
Armin Rigo 2907bd0 

Ronny Pfannschmi… 172bef2 




Ronny Pfannschmi… 27d3aac 
Ronny Pfannschmi… 172bef2 
Ronny Pfannschmi… 27d3aac 
Ronny Pfannschmi… 172bef2 




Ronny Pfannschmi… 27d3aac 
Ronny Pfannschmi… 172bef2 

Maciej Fijalkows… 75307d4 









Jason Creighton 5bc5123 
Maciej Fijalkows… 75307d4 










































holger krekel e215860 







Maciej Fijalkows… 75307d4 
holger krekel e215860 

Maciej Fijalkows… 75307d4 
holger krekel e215860 
Maciej Fijalkows… 75307d4 

holger krekel e215860 
Maciej Fijalkows… 75307d4 











Armin Rigo 5a872d1 


Armin Rigo a10d381 
Samuele Pedroni 2fe2cc2 
Amaury Forgeot d… a1819d0 
Armin Rigo 5a872d1 
holger krekel e215860 

Armin Rigo 5a872d1 

Armin Rigo 4ac21ef 
Armin Rigo b7f6c6f 
Carl Friedrich B… e820a54 
Armin Rigo 619f904 
Maciej Fijalkows… 75307d4 
holger krekel e215860 
Maciej Fijalkows… 75307d4 


Armin Rigo 79606d1 
Maciej Fijalkows… 75307d4 
Armin Rigo 5a872d1 
Armin Rigo 8c6c6d4 
Armin Rigo 5a872d1 

Carl Friedrich B… e820a54 

Armin Rigo f2be5fb 



Carl Friedrich B… e820a54 
Amaury Forgeot d… a1819d0 
Carl Friedrich B… e820a54 
Armin Rigo 0ae1857 

Armin Rigo 8c6c6d4 
Armin Rigo 6210a06 
Carl Friedrich B… e263dc7 



Christian Tismer 54180fe 
Armin Rigo 5a872d1 
Armin Rigo 4ac21ef 





holger krekel e215860 




Armin Rigo 4ac21ef 
holger krekel e215860 



Armin Rigo 5a872d1 
Armin Rigo 6210a06 

Armin Rigo 5a872d1 

Samuele Pedroni 1d721d1 

Armin Rigo 9624ebb 


Armin Rigo 6210a06 

Armin Rigo 9624ebb 
Armin Rigo 6210a06 
Armin Rigo a820297 

Maciej Fijalkows… b776a51 
Armin Rigo a820297 

Armin Rigo 9624ebb 
Carl Friedrich B… e820a54 

Armin Rigo f2be5fb 

Manuel Jacob 576d58a 

Armin Rigo f2be5fb 

Carl Friedrich B… e820a54 
Armin Rigo 3b904fb 




Maciej Fijalkows… 75307d4 







Maciej Fijalkows… b776a51 
Maciej Fijalkows… 75307d4 



Jason Creighton 1d548ac 
Armin Rigo 5a872d1 




Armin Rigo a10d381 


Armin Rigo 5a872d1 
Antonio Cuni 90fbcd6 


Armin Rigo 5a872d1 
Armin Rigo da78552 
Carl Friedrich B… e820a54 

Armin Rigo 1c4e756 

Samuele Pedroni 1d721d1 
Maciej Fijalkows… 75307d4 
Armin Rigo 5a872d1 
Samuele Pedroni dea0de6 
Amaury Forgeot d… a1819d0 

Armin Rigo 5a872d1 
Amaury Forgeot d… e4eef33 
Samuele Pedroni dea0de6 
Amaury Forgeot d… c16499d 
Anders Chrigströ… eaa0ad5 
Samuele Pedroni ba6a7ac 

holger krekel e215860 



Amaury Forgeot d… e4eef33 


Armin Rigo 5a872d1 
Maciej Fijalkows… 75307d4 
Jason Creighton 1d548ac 
Carl Friedrich B… e820a54 
Armin Rigo 5a872d1 
Maciej Fijalkows… 75307d4 









Armin Rigo 5a872d1 
Carl Friedrich B… 821a806 





Maciej Fijalkows… 75307d4 
Armin Rigo 4ac21ef 
Maciej Fijalkows… 75307d4 




Armin Rigo 4ac21ef 
Maciej Fijalkows… 75307d4 




Carl Friedrich B… 821a806 






Maciej Fijalkows… b5a2e0b 



Carl Friedrich B… 821a806 








Armin Rigo 5a872d1 

Amaury Forgeot d… a1819d0 
Armin Rigo 8c6c6d4 

Armin Rigo 5a872d1 
Armin Rigo 79606d1 


Amaury Forgeot d… a1819d0 




Armin Rigo 79606d1 

Armin Rigo 8c6c6d4 



Armin Rigo 5a872d1 



Maciej Fijalkows… b5a2e0b 






Amaury Forgeot d… 846280c 








Maciej Fijalkows… 75307d4 

Armin Rigo 5a872d1 

Armin Rigo 8c6c6d4 









Maciej Fijalkows… b5a2e0b 
Armin Rigo 8c6c6d4 




Samuele Pedroni 41599bd 
Armin Rigo 8c6c6d4 














Maciej Fijalkows… 75307d4 
Armin Rigo 8c6c6d4 







Armin Rigo 5a872d1 
Armin Rigo 8c6c6d4 


Carl Friedrich B… 821a806 
Armin Rigo 8c6c6d4 



Armin Rigo 5a872d1 
Armin Rigo 8c6c6d4 


Samuele Pedroni 41599bd 
Armin Rigo 5a872d1 
Armin Rigo 8c6c6d4 



Armin Rigo 5a872d1 
Armin Rigo 8c6c6d4 


Armin Rigo 5a872d1 
holger krekel e215860 
Maciej Fijalkows… 75307d4 

Armin Rigo 5a872d1 

Amaury Forgeot d… e4eef33 
Armin Rigo 5a872d1 
holger krekel e215860 
Armin Rigo 5a872d1 
Maciej Fijalkows… b5a2e0b 

















Armin Rigo 5a872d1 



Armin Rigo c084920 
Armin Rigo 5a872d1 
Maciej Fijalkows… 3c7f989 
Maciej Fijalkows… 75307d4 
Samuele Pedroni 2fe2cc2 

Maciej Fijalkows… 75307d4 
Maciej Fijalkows… 3c7f989 

Armin Rigo 618631c 
Maciej Fijalkows… 75307d4 
Maciej Fijalkows… 3c7f989 

Armin Rigo f4b79da 

Maciej Fijalkows… 75307d4 
Armin Rigo 5a872d1 
holger krekel e215860 






Jason Creighton 1d548ac 
holger krekel e215860 




















Armin Rigo 5a872d1 

holger krekel e215860 


David Schneider 5b0e029 








Armin Rigo 5a872d1 


holger krekel e215860 
Maciej Fijalkows… 75307d4 
Jason Creighton 1d548ac 

holger krekel e215860 




Maciej Fijalkows… b5a2e0b 
Carl Friedrich B… 12fd0b0 
Maciej Fijalkows… 75307d4 


Eric van Riet Pa… 2fb7ad0 
Maciej Fijalkows… 75307d4 
Amaury Forgeot d… 7a14535 

Armin Rigo e9f7368 

Amaury Forgeot d… 34bb160 


Maciej Fijalkows… 75307d4 
Armin Rigo e9f7368 
Carl Friedrich B… 36621d6 
Maciej Fijalkows… 75307d4 










Armin Rigo 5a872d1 
Ronny Pfannschmi… 27d3aac 
Maciej Fijalkows… 75307d4 
Christian Tismer f159879 
Maciej Fijalkows… 0af03a9 






Amaury Forgeot d… 7a14535 
Armin Rigo 1145904 
Maciej Fijalkows… 75307d4 
Armin Rigo a0be15b 
Armin Rigo e9f7368 
Armin Rigo a0be15b 

Maciej Fijalkows… 0af03a9 
holger krekel e215860 




Ronny Pfannschmi… 27d3aac 
Armin Rigo 46dc1cc 
Maciej Fijalkows… 0af03a9 


Christian Tismer f159879 
Maciej Fijalkows… 0af03a9 









Armin Rigo a41e644 
Maciej Fijalkows… 0af03a9 




Ronny Pfannschmi… 27d3aac 
Maciej Fijalkows… 0af03a9 
Amaury Forgeot d… bc84260 
Ronny Pfannschmi… 27d3aac 
Maciej Fijalkows… 0af03a9 


Armin Rigo a41e644 
Maciej Fijalkows… 0af03a9 
Ronny Pfannschmi… 27d3aac 

Armin Rigo 017e187 
Armin Rigo 0a74070 
Maciej Fijalkows… 0af03a9 
Ronny Pfannschmi… 27d3aac 

Armin Rigo 0a74070 

Hakan Ardo 3174681 
Maciej Fijalkows… 75307d4 
Maciej Fijalkows… ce45b7a 
Armin Rigo a0be15b 
Armin Rigo e9f7368 
Armin Rigo a0be15b 

Armin Rigo e9f7368 
Armin Rigo 8ca9a74 
Armin Rigo e9f7368 
Armin Rigo 8ca9a74 
Maciej Fijalkows… 75307d4 




Armin Rigo 5a872d1 










Amaury Forgeot d… ea51e86 
Armin Rigo 5a872d1 




Samuele Pedroni 2fe2cc2 
Armin Rigo 5a872d1 








Samuele Pedroni 2fe2cc2 
Armin Rigo 5a872d1 





















Alex Gaynor 658bf01 


Carl Friedrich B… 9a6c4ff 
Alex Gaynor 658bf01 








Carl Friedrich B… 9a6c4ff 

Amaury Forgeot d… 1ff2a82 
Carl Friedrich B… 9a6c4ff 



Amaury Forgeot d… 1ff2a82 


Carl Friedrich B… 9a6c4ff 

Alex Gaynor 658bf01 

Carl Friedrich B… 65a643f 

Alex Gaynor 658bf01 








Armin Rigo 5a872d1 

Amaury Forgeot d… ba80e19 
Alex Gaynor 658bf01 

















Armin Rigo 5a872d1 
Amaury Forgeot d… 1ff2a82 
Amaury Forgeot d… 33ac21e 




Amaury Forgeot d… 1ff2a82 










Armin Rigo 5a872d1 
Armin Rigo 3846bab 
Carl Friedrich B… 65a643f 
Armin Rigo 3846bab 



Amaury Forgeot d… 1ff2a82 
Armin Rigo 5a872d1 


Amaury Forgeot d… 33ac21e 
Amaury Forgeot d… 1ff2a82 
Amaury Forgeot d… 33ac21e 
Amaury Forgeot d… 1ff2a82 
Amaury Forgeot d… 33ac21e 
Amaury Forgeot d… ea51e86 
Armin Rigo 5a872d1 







Amaury Forgeot d… 1ff2a82 

Armin Rigo 5a872d1 



Carl Friedrich B… b2903aa 
Armin Rigo 5a872d1 

Amaury Forgeot d… 1ff2a82 







Amaury Forgeot d… ea51e86 
Amaury Forgeot d… 1ff2a82 


Armin Rigo 5a872d1 
Amaury Forgeot d… 1ff2a82 



Armin Rigo 5a872d1 
Amaury Forgeot d… ea51e86 
Carl Friedrich B… b2903aa 
Armin Rigo 5a872d1 
Carl Friedrich B… 65a643f 

Amaury Forgeot d… 1ff2a82 








Amaury Forgeot d… ea51e86 
Amaury Forgeot d… 1ff2a82 

Armin Rigo 5a872d1 
Amaury Forgeot d… 1ff2a82 



Armin Rigo 5a872d1 


Armin Rigo 01e8a22 
Armin Rigo 5a872d1 




Armin Rigo 01e8a22 


Armin Rigo 0416f2b 
Armin Rigo a738b4b 
Armin Rigo 5a872d1 



Armin Rigo 01e8a22 

Armin Rigo 5a872d1 






Amaury Forgeot d… ea51e86 







Armin Rigo 5a872d1 








Michael Hudson-D… 64b5329 
Armin Rigo 5a872d1 














Armin Rigo 79606d1 
David Schneider 1a44e52 
Armin Rigo 79606d1 
David Schneider 1a44e52 
Armin Rigo 79606d1 
Maciej Fijalkows… cb3113a 

Maciej Fijalkows… 139ceb2 
Amaury Forgeot d… b7aba3f 
Amaury Forgeot d… 8144ea8 
Amaury Forgeot d… bd54df1 
Amaury Forgeot d… a96792e 
Amaury Forgeot d… 8144ea8 
Amaury Forgeot d… 58342f3 
Amaury Forgeot d… 5cc488d 
Maciej Fijalkows… 139ceb2 

Amaury Forgeot d… 8144ea8 
Amaury Forgeot d… 6519032 
Amaury Forgeot d… 5e1a89e 
Amaury Forgeot d… 751d2ac 
Amaury Forgeot d… c16499d 
Amaury Forgeot d… 33ac21e 
Maciej Fijalkows… 139ceb2 
Armin Rigo 2907bd0 

Maciej Fijalkows… 139ceb2 
Maciej Fijalkows… cb3113a 
Antonio Cuni 90fbcd6 
Amaury Forgeot d… e4eef33 

Armin Rigo 5a872d1 

Antonio Cuni 90fbcd6 
Armin Rigo 5a872d1 









Armin Rigo 79606d1 
Armin Rigo 5a872d1 


Amaury Forgeot d… 846280c 
Armin Rigo 4ac21ef 
Armin Rigo 5a872d1 






Amaury Forgeot d… ea51e86 
Samuele Pedroni 2fe2cc2 
Amaury Forgeot d… 1ff2a82 
Armin Rigo 5a872d1 




Amaury Forgeot d… c16499d 
Amaury Forgeot d… e4eef33 

Amaury Forgeot d… c16499d 
Amaury Forgeot d… e4eef33 

Maciej Fijalkows… cb3113a 
Amaury Forgeot d… 3d4fb2d 
Maciej Fijalkows… 75307d4 
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
import autopath
import contextlib
import py
import sys, os
from pypy.rlib import exports
from pypy.rpython.lltypesystem import lltype
from pypy.rpython.typesystem import getfunctionptr
from pypy.tool import isolate, runsubprocess
from pypy.tool.nullpath import NullPyPathLocal
from pypy.tool.udir import udir
from pypy.translator.c import gc
from pypy.translator.c.database import LowLevelDatabase
from pypy.translator.c.extfunc import pre_include_code_lines
from pypy.translator.c.support import log
from pypy.translator.gensupp import uniquemodulename, NameManager
from pypy.translator.llsupport.wrapper import new_wrapper
from pypy.translator.tool.cbuild import ExternalCompilationInfo

_CYGWIN = sys.platform == 'cygwin'

_CPYTHON_RE = py.std.re.compile('^Python 2.[567]')

def get_recent_cpython_executable():

    if sys.platform == 'win32':
        python = sys.executable.replace('\\', '/')
    else:
        python = sys.executable
    # Is there a command 'python' that runs python 2.5-2.7?
    # If there is, then we can use it instead of sys.executable
    returncode, stdout, stderr = runsubprocess.run_subprocess(
        "python", "-V")
    if _CPYTHON_RE.match(stdout) or _CPYTHON_RE.match(stderr):
        python = 'python'
    return python


class ProfOpt(object):
    #XXX assuming gcc style flags for now
    name = "profopt"

    def __init__(self, compiler):
        self.compiler = compiler

    def first(self):
        platform = self.compiler.platform
        if platform.name.startswith('darwin'):
            # XXX incredible hack for darwin
            STR = '/*--no-profiling-for-this-file!--*/'
            no_prof = []
            prof = []
            for cfile in self.compiler.cfiles:
                if STR in cfile.read():
                    no_prof.append(cfile)
                else:
                    prof.append(cfile)
            p_eci = self.compiler.eci.merge(
                ExternalCompilationInfo(compile_extra=['-fprofile-generate'],
                                        link_extra=['-fprofile-generate']))
            ofiles = platform._compile_o_files(prof, p_eci)
            _, eci = self.compiler.eci.get_module_files()
            ofiles += platform._compile_o_files(no_prof, eci)
            return platform._finish_linking(ofiles, p_eci, None, True)
        else:
            return self.build('-fprofile-generate')

    def probe(self, exe, args):
        # 'args' is a single string typically containing spaces
        # and quotes, which represents several arguments.
        self.compiler.platform.execute(exe, args)

    def after(self):
        return self.build('-fprofile-use')

    def build(self, option):
        eci = ExternalCompilationInfo(compile_extra=[option],
                                      link_extra=[option])
        return self.compiler._build(eci)

class CCompilerDriver(object):
    def __init__(self, platform, cfiles, eci, outputfilename=None,
                 profbased=False):
        # XXX config might contain additional link and compile options.
        #     We need to fish for it somehow.
        self.platform = platform
        self.cfiles = cfiles
        self.eci = eci
        self.outputfilename = outputfilename
        self.profbased = profbased

    def _build(self, eci=ExternalCompilationInfo(), shared=False):
        outputfilename = self.outputfilename
        if shared:
            if outputfilename:
                basename = outputfilename
            else:
                basename = self.cfiles[0].purebasename
            outputfilename = 'lib' + basename
        return self.platform.compile(self.cfiles, self.eci.merge(eci),
                                     outputfilename=outputfilename,
                                     standalone=not shared)

    def build(self, shared=False):
        if self.profbased:
            return self._do_profbased()
        return self._build(shared=shared)

    def _do_profbased(self):
        ProfDriver, args = self.profbased
        profdrv = ProfDriver(self)
        dolog = getattr(log, profdrv.name)
        dolog(args)
        exename = profdrv.first()
        dolog('Gathering profile data from: %s %s' % (
            str(exename), args))
        profdrv.probe(exename, args)
        return profdrv.after()
    
class CBuilder(object):
    c_source_filename = None
    _compiled = False
    modulename = None
    split = False
    cpython_extension = False
    
    def __init__(self, translator, entrypoint, config, gcpolicy=None,
            secondary_entrypoints=()):
        self.translator = translator
        self.entrypoint = entrypoint
        self.entrypoint_name = getattr(self.entrypoint, 'func_name', None)
        self.originalentrypoint = entrypoint
        self.config = config
        self.gcpolicy = gcpolicy    # for tests only, e.g. rpython/memory/
        self.eci = self.get_eci()
        self.secondary_entrypoints = secondary_entrypoints

    def get_eci(self):
        pypy_include_dir = py.path.local(autopath.pypydir).join('translator', 'c')
        include_dirs = [pypy_include_dir]
        return ExternalCompilationInfo(include_dirs=include_dirs)

    def build_database(self):
        translator = self.translator

        gcpolicyclass = self.get_gcpolicyclass()

        if self.config.translation.gcrootfinder == "asmgcc":
            if not self.standalone:
                raise NotImplementedError("--gcrootfinder=asmgcc requires standalone")

        db = LowLevelDatabase(translator, standalone=self.standalone,
                              cpython_extension=self.cpython_extension,
                              gcpolicyclass=gcpolicyclass,
                              thread_enabled=self.config.translation.thread,
                              sandbox=self.config.translation.sandbox)
        self.db = db
        
        # give the gc a chance to register interest in the start-up functions it
        # need (we call this for its side-effects of db.get())
        list(db.gcpolicy.gc_startup_code())

        # build entrypoint and eventually other things to expose
        pf = self.getentrypointptr()
        if isinstance(pf, list):
            for one_pf in pf:
                db.get(one_pf)
            self.c_entrypoint_name = None
        else:
            pfname = db.get(pf)

            for func, _ in self.secondary_entrypoints:
                bk = translator.annotator.bookkeeper
                db.get(getfunctionptr(bk.getdesc(func).getuniquegraph()))

            self.c_entrypoint_name = pfname

        for obj in exports.EXPORTS_obj2name.keys():
            db.getcontainernode(obj)
        exports.clear()
        db.complete()

        self.collect_compilation_info(db)
        return db

    have___thread = None

    def merge_eci(self, *ecis):
        self.eci = self.eci.merge(*ecis)

    def collect_compilation_info(self, db):
        # we need a concrete gcpolicy to do this
        self.merge_eci(db.gcpolicy.compilation_info())

        all = []
        for node in self.db.globalcontainers():
            eci = node.compilation_info()
            if eci:
                all.append(eci)
        self.merge_eci(*all)

    def get_gcpolicyclass(self):
        if self.gcpolicy is None:
            name = self.config.translation.gctransformer
            if name == "framework":
                name = "%s+%s" % (name, self.config.translation.gcrootfinder)
            return gc.name_to_gcpolicy[name]
        return self.gcpolicy

    # use generate_source(defines=DEBUG_DEFINES) to force the #definition
    # of the macros that enable debugging assertions
    DEBUG_DEFINES = {'RPY_ASSERT': 1,
                     'RPY_LL_ASSERT': 1}

    def generate_graphs_for_llinterp(self, db=None):
        # prepare the graphs as when the source is generated, but without
        # actually generating the source.
        if db is None:
            db = self.build_database()
        graphs = db.all_graphs()
        db.gctransformer.prepare_inline_helpers(graphs)
        for node in db.containerlist:
            if hasattr(node, 'funcgens'):
                for funcgen in node.funcgens:
                    funcgen.patch_graph(copy_graph=False)
        return db

    def generate_source(self, db=None, defines={}, exe_name=None):
        assert self.c_source_filename is None

        if db is None:
            db = self.build_database()
        pf = self.getentrypointptr()
        if self.modulename is None:
            self.modulename = uniquemodulename('testing')
        modulename = self.modulename
        targetdir = udir.ensure(modulename, dir=1)
        if self.config.translation.dont_write_c_files:
            targetdir = NullPyPathLocal(targetdir)

        self.targetdir = targetdir
        defines = defines.copy()
        if self.config.translation.countmallocs:
            defines['COUNT_OP_MALLOCS'] = 1
        if self.config.translation.sandbox:
            defines['RPY_SANDBOXED'] = 1
        if CBuilder.have___thread is None:
            CBuilder.have___thread = self.translator.platform.check___thread()
        if not self.standalone:
            assert not self.config.translation.instrument
            if self.cpython_extension:
                defines['PYPY_CPYTHON_EXTENSION'] = 1
        else:
            defines['PYPY_STANDALONE'] = db.get(pf)
            if self.config.translation.instrument:
                defines['PYPY_INSTRUMENT'] = 1
            if CBuilder.have___thread:
                if not self.config.translation.no__thread:
                    defines['USE___THREAD'] = 1
            if self.config.translation.shared:
                defines['PYPY_MAIN_FUNCTION'] = "pypy_main_startup"
                self.eci = self.eci.merge(ExternalCompilationInfo(
                    export_symbols=["pypy_main_startup"]))
        self.eci, cfile, extra = gen_source(db, modulename, targetdir,
                                            self.eci, defines=defines,
                                            split=self.split)
        self.c_source_filename = py.path.local(cfile)
        self.extrafiles = self.eventually_copy(extra)
        self.gen_makefile(targetdir, exe_name=exe_name)
        return cfile

    def eventually_copy(self, cfiles):
        extrafiles = []
        for fn in cfiles:
            fn = py.path.local(fn)
            if not fn.relto(udir):
                newname = self.targetdir.join(fn.basename)
                fn.copy(newname)
                fn = newname
            extrafiles.append(fn)
        return extrafiles

class ModuleWithCleanup(object):
    def __init__(self, mod):
        self.__dict__['mod'] = mod

    def __getattr__(self, name):
        mod = self.__dict__['mod']
        obj = getattr(mod, name)
        parentself = self
        if callable(obj) and getattr(obj, '__module__', None) == mod.__name__:
            # The module must be kept alive with the function.
            # This wrapper avoids creating a cycle.
            class Wrapper:
                def __init__(self, obj):
                    self.myself = parentself
                    self.func = obj
                def __call__(self, *args, **kwargs):
                    return self.func(*args, **kwargs)
            obj = Wrapper(obj)
        return obj

    def __setattr__(self, name, val):
        mod = self.__dict__['mod']
        setattr(mod, name, val)

    def __del__(self):
        import sys
        if sys.platform == "win32":
            from _ctypes import FreeLibrary as dlclose
        else:
            from _ctypes import dlclose
        # XXX fish fish fish
        mod = self.__dict__['mod']
        dlclose(mod._lib._handle)
        try:
            del sys.modules[mod.__name__]
        except KeyError:
            pass


class CExtModuleBuilder(CBuilder):
    standalone = False
    cpython_extension = True
    _module = None
    _wrapper = None

    def get_eci(self):
        from distutils import sysconfig
        python_inc = sysconfig.get_python_inc()
        eci = ExternalCompilationInfo(
            include_dirs=[python_inc],
            includes=["Python.h",
                      ],
            )
        return eci.merge(CBuilder.get_eci(self))

    def getentrypointptr(self): # xxx
        if self._wrapper is None:
            self._wrapper = new_wrapper(self.entrypoint, self.translator)
        return self._wrapper

    def compile(self):
        assert self.c_source_filename 
        assert not self._compiled
        export_symbols = [self.db.get(self.getentrypointptr()),
                          'RPython_StartupCode',
                          ]
        if self.config.translation.countmallocs:
            export_symbols.append('malloc_counters')
        extsymeci = ExternalCompilationInfo(export_symbols=export_symbols)
        self.eci = self.eci.merge(extsymeci)

        if sys.platform == 'win32':
            self.eci = self.eci.merge(ExternalCompilationInfo(
                library_dirs = [py.path.local(sys.exec_prefix).join('LIBs'),
                                py.path.local(sys.executable).dirpath(),
                                ],
                ))


        files = [self.c_source_filename] + self.extrafiles
        self.translator.platform.compile(files, self.eci, standalone=False)
        self._compiled = True

    def _make_wrapper_module(self):
        fname = 'wrap_' + self.c_source_filename.purebasename
        modfile = self.c_source_filename.new(purebasename=fname, ext=".py")

        entrypoint_ptr = self.getentrypointptr()
        wrapped_entrypoint_c_name = self.db.get(entrypoint_ptr)
        
        CODE = """
import ctypes

_lib = ctypes.PyDLL(r"%(so_name)s")

_entry_point = getattr(_lib, "%(c_entrypoint_name)s")
_entry_point.restype = ctypes.py_object
_entry_point.argtypes = %(nargs)d*(ctypes.py_object,)

def entrypoint(*args):
    return _entry_point(*args)

try:
    _malloc_counters = _lib.malloc_counters
except AttributeError:
    pass
else:
    _malloc_counters.restype = ctypes.py_object
    _malloc_counters.argtypes = 2*(ctypes.py_object,)

    def malloc_counters():
        return _malloc_counters(None, None)

_rpython_startup = _lib.RPython_StartupCode
_rpython_startup()
""" % {'so_name': self.c_source_filename.new(ext=self.translator.platform.so_ext),
       'c_entrypoint_name': wrapped_entrypoint_c_name,
       'nargs': len(lltype.typeOf(entrypoint_ptr).TO.ARGS)}
        modfile.write(CODE)
        self._module_path = modfile
       
    def _import_module(self, isolated=False):
        if self._module is not None:
            return self._module
        assert self._compiled
        assert not self._module
        self._make_wrapper_module()
        if not isolated:
            mod = ModuleWithCleanup(self._module_path.pyimport())
        else:
            mod = isolate.Isolate((str(self._module_path.dirpath()),
                                   self._module_path.purebasename))
        self._module = mod
        return mod
        
    def get_entry_point(self, isolated=False):
        self._import_module(isolated=isolated)
        return getattr(self._module, "entrypoint")

    def get_malloc_counters(self, isolated=False):
        self._import_module(isolated=isolated)
        return self._module.malloc_counters
                       
    def cleanup(self):
        #assert self._module
        if isinstance(self._module, isolate.Isolate):
            isolate.close_isolate(self._module)

    def gen_makefile(self, targetdir, exe_name=None):
        pass

class CStandaloneBuilder(CBuilder):
    standalone = True
    split = True
    executable_name = None
    shared_library_name = None

    def getprofbased(self):
        profbased = None
        if self.config.translation.instrumentctl is not None:
            profbased = self.config.translation.instrumentctl
        else:
            # xxx handling config.translation.profopt is a bit messy, because
            # it could be an empty string (not to be confused with None) and
            # because noprofopt can be used as an override.
            profopt = self.config.translation.profopt
            if profopt is not None and not self.config.translation.noprofopt:
                profbased = (ProfOpt, profopt)
        return profbased

    def has_profopt(self):
        profbased = self.getprofbased()
        return (profbased and isinstance(profbased, tuple)
                and profbased[0] is ProfOpt)

    def getentrypointptr(self):
        # XXX check that the entrypoint has the correct
        # signature:  list-of-strings -> int
        bk = self.translator.annotator.bookkeeper
        return getfunctionptr(bk.getdesc(self.entrypoint).getuniquegraph())

    def cmdexec(self, args='', env=None, err=False, expect_crash=False):
        assert self._compiled
        res = self.translator.platform.execute(self.executable_name, args,
                                               env=env)
        if res.returncode != 0:
            if expect_crash:
                return res.out, res.err
            print >> sys.stderr, res.err
            raise Exception("Returned %d" % (res.returncode,))
        if expect_crash:
            raise Exception("Program did not crash!")
        if err:
            return res.out, res.err
        return res.out

    def build_main_for_shared(self, shared_library_name, entrypoint, exe_name):
        import time
        time.sleep(1)
        self.shared_library_name = shared_library_name
        # build main program
        eci = self.get_eci()
        kw = {}
        if self.translator.platform.cc == 'gcc':
            kw['libraries'] = [self.shared_library_name.purebasename[3:]]
            kw['library_dirs'] = [self.targetdir]
        else:
            kw['libraries'] = [self.shared_library_name.new(ext='')]
        eci = eci.merge(ExternalCompilationInfo(
            separate_module_sources=['''
                int %s(int argc, char* argv[]);

                int main(int argc, char* argv[])
                { return %s(argc, argv); }
                ''' % (entrypoint, entrypoint)
                ],
            **kw
            ))
        eci = eci.convert_sources_to_files(
            cache_dir=self.targetdir)
        return self.translator.platform.compile(
            [], eci,
            outputfilename=exe_name)

    def compile(self, exe_name=None):
        assert self.c_source_filename
        assert not self._compiled

        shared = self.config.translation.shared

        extra_opts = []
        if self.config.translation.make_jobs != 1:
            extra_opts += ['-j', str(self.config.translation.make_jobs)]
        self.translator.platform.execute_makefile(self.targetdir,
                                                  extra_opts)
        if shared:
            self.shared_library_name = self.executable_name.new(
                purebasename='lib' + self.executable_name.purebasename,
                ext=self.translator.platform.so_ext)
        self._compiled = True
        return self.executable_name

    def gen_makefile(self, targetdir, exe_name=None):
        cfiles = [self.c_source_filename] + self.extrafiles
        if exe_name is not None:
            exe_name = targetdir.join(exe_name)
        mk = self.translator.platform.gen_makefile(
            cfiles, self.eci,
            path=targetdir, exe_name=exe_name,
            shared=self.config.translation.shared)

        if self.has_profopt():
            profopt = self.config.translation.profopt
            mk.definition('ABS_TARGET', '$(shell python -c "import sys,os; print os.path.abspath(sys.argv[1])" $(TARGET))')
            mk.definition('DEFAULT_TARGET', 'profopt')
            mk.definition('PROFOPT', profopt)

        rules = [
            ('clean', '', 'rm -f $(OBJECTS) $(TARGET) $(GCMAPFILES) $(ASMFILES) *.gc?? ../module_cache/*.gc??'),
            ('clean_noprof', '', 'rm -f $(OBJECTS) $(TARGET) $(GCMAPFILES) $(ASMFILES)'),
            ('debug', '', '$(MAKE) CFLAGS="$(DEBUGFLAGS) -DRPY_ASSERT" debug_target'),
            ('debug_exc', '', '$(MAKE) CFLAGS="$(DEBUGFLAGS) -DRPY_ASSERT -DDO_LOG_EXC" debug_target'),
            ('debug_mem', '', '$(MAKE) CFLAGS="$(DEBUGFLAGS) -DRPY_ASSERT -DPYPY_USE_TRIVIAL_MALLOC" debug_target'),
            ('no_obmalloc', '', '$(MAKE) CFLAGS="-g -O2 -DRPY_ASSERT -DPYPY_NO_OBMALLOC" $(TARGET)'),
            ('linuxmemchk', '', '$(MAKE) CFLAGS="$(DEBUGFLAGS) -DRPY_ASSERT -DPPY_USE_LINUXMEMCHK" debug_target'),
            ('llsafer', '', '$(MAKE) CFLAGS="-O2 -DRPY_LL_ASSERT" $(TARGET)'),
            ('lldebug', '', '$(MAKE) CFLAGS="$(DEBUGFLAGS) -DRPY_ASSERT -DRPY_LL_ASSERT" debug_target'),
            ('profile', '', '$(MAKE) CFLAGS="-g -O1 -pg $(CFLAGS) -fno-omit-frame-pointer" LDFLAGS="-pg $(LDFLAGS)" $(TARGET)'),
            ]
        if self.has_profopt():
            rules.append(
                ('profopt', '', [
                '$(MAKENOPROF)',
                '$(MAKE) CFLAGS="-fprofile-generate $(CFLAGS)" LDFLAGS="-fprofile-generate $(LDFLAGS)" $(TARGET)',
                'cd $(PYPYDIR)/translator/goal && $(ABS_TARGET) $(PROFOPT)',
                '$(MAKE) clean_noprof',
                '$(MAKE) CFLAGS="-fprofile-use $(CFLAGS)" LDFLAGS="-fprofile-use $(LDFLAGS)" $(TARGET)']))
        for rule in rules:
            mk.rule(*rule)

        #XXX: this conditional part is not tested at all
        if self.config.translation.gcrootfinder == 'asmgcc':
            trackgcfiles = [cfile[:cfile.rfind('.')] for cfile in mk.cfiles]
            if self.translator.platform.name == 'msvc':
                trackgcfiles = [f for f in trackgcfiles
                                if f.startswith(('implement', 'testing',
                                                 '../module_cache/module'))]
            sfiles = ['%s.s' % (c,) for c in trackgcfiles]
            lblsfiles = ['%s.lbl.s' % (c,) for c in trackgcfiles]
            gcmapfiles = ['%s.gcmap' % (c,) for c in trackgcfiles]
            mk.definition('ASMFILES', sfiles)
            mk.definition('ASMLBLFILES', lblsfiles)
            mk.definition('GCMAPFILES', gcmapfiles)
            if sys.platform == 'win32':
                mk.definition('DEBUGFLAGS', '/MD /Zi')
            else:
                mk.definition('DEBUGFLAGS', '-O2 -fomit-frame-pointer -g')

            if self.config.translation.shared:
                mk.definition('PYPY_MAIN_FUNCTION', "pypy_main_startup")
            else:
                mk.definition('PYPY_MAIN_FUNCTION', "main")

            mk.definition('PYTHON', get_recent_cpython_executable())

            if self.translator.platform.name == 'msvc':
                lblofiles = []
                for cfile in mk.cfiles:
                    f = cfile[:cfile.rfind('.')]
                    if f in trackgcfiles:
                        ofile = '%s.lbl.obj' % (f,)
                    else:
                        ofile = '%s.obj' % (f,)

                    lblofiles.append(ofile)
                mk.definition('ASMLBLOBJFILES', lblofiles)
                mk.definition('OBJECTS', 'gcmaptable.obj $(ASMLBLOBJFILES)')
                # /Oi (enable intrinsics) and /Ob1 (some inlining) are mandatory
                # even in debug builds
                mk.definition('ASM_CFLAGS', '$(CFLAGS) $(CFLAGSEXTRA) /Oi /Ob1')
                mk.rule('.SUFFIXES', '.s', [])
                mk.rule('.s.obj', '',
                        'cmd /c $(MASM) /nologo /Cx /Cp /Zm /coff /Fo$@ /c $< $(INCLUDEDIRS)')
                mk.rule('.c.gcmap', '',
                        ['$(CC) /nologo $(ASM_CFLAGS) /c /FAs /Fa$*.s $< $(INCLUDEDIRS)',
                         'cmd /c $(PYTHON) $(PYPYDIR)/translator/c/gcc/trackgcroot.py -fmsvc -t $*.s > $@']
                        )
                mk.rule('gcmaptable.c', '$(GCMAPFILES)',
                        'cmd /c $(PYTHON) $(PYPYDIR)/translator/c/gcc/trackgcroot.py -fmsvc $(GCMAPFILES) > $@')

            else:
                mk.definition('OBJECTS', '$(ASMLBLFILES) gcmaptable.s')
                mk.rule('%.s', '%.c', '$(CC) $(CFLAGS) $(CFLAGSEXTRA) -frandom-seed=$< -o $@ -S $< $(INCLUDEDIRS)')
                mk.rule('%.lbl.s %.gcmap', '%.s',
                        [
                             '$(PYTHON) $(PYPYDIR)/translator/c/gcc/trackgcroot.py '
                             '-t $< > $*.gctmp',
                         'mv $*.gctmp $*.gcmap'])
                mk.rule('gcmaptable.s', '$(GCMAPFILES)',
                        [
                             '$(PYTHON) $(PYPYDIR)/translator/c/gcc/trackgcroot.py '
                             '$(GCMAPFILES) > $@.tmp',
                         'mv $@.tmp $@'])
                mk.rule('.PRECIOUS', '%.s', "# don't remove .s files if Ctrl-C'ed")

        else:
            if sys.platform == 'win32':
                mk.definition('DEBUGFLAGS', '/MD /Zi')
            else:
                mk.definition('DEBUGFLAGS', '-O1 -g')
        if sys.platform == 'win32':
            mk.rule('debug_target', 'debugmode_$(DEFAULT_TARGET)', 'rem')
        else:
            mk.rule('debug_target', '$(TARGET)', '#')
        mk.write()
        #self.translator.platform,
        #                           ,
        #                           self.eci, profbased=self.getprofbased()
        self.executable_name = mk.exe_name

# ____________________________________________________________

SPLIT_CRITERIA = 65535 # support VC++ 7.2
#SPLIT_CRITERIA = 32767 # enable to support VC++ 6.0

MARKER = '/*/*/' # provide an easy way to split after generating

class SourceGenerator:
    one_source_file = True

    def __init__(self, database):
        self.database = database
        self.extrafiles = []
        self.path = None
        self.namespace = NameManager()

    def set_strategy(self, path, split=True):
        all_nodes = list(self.database.globalcontainers())
        # split off non-function nodes. We don't try to optimize these, yet.
        funcnodes = []
        othernodes = []
        for node in all_nodes:
            if node.nodekind == 'func':
                funcnodes.append(node)
            else:
                othernodes.append(node)
        if split:
            self.one_source_file = False
        self.funcnodes = funcnodes
        self.othernodes = othernodes
        self.path = path

    def uniquecname(self, name):
        assert name.endswith('.c')
        return self.namespace.uniquename(name[:-2]) + '.c'

    def makefile(self, name):
        log.writing(name)
        filepath = self.path.join(name)
        if name.endswith('.c'):
            self.extrafiles.append(filepath)
        return filepath.open('w')

    def getextrafiles(self):
        return self.extrafiles

    def getothernodes(self):
        return self.othernodes[:]

    def getbasecfilefornode(self, node, basecname):
        # For FuncNode instances, use the python source filename (relative to
        # the top directory):
        def invent_nice_name(g):
            # Lookup the filename from the function.
            # However, not all FunctionGraph objs actually have a "func":
            if hasattr(g, 'func'):
                if g.filename.endswith('.py'):
                    localpath = py.path.local(g.filename)
                    pypkgpath = localpath.pypkgpath()
                    if pypkgpath:
                        relpypath =  localpath.relto(pypkgpath)
                        return relpypath.replace('.py', '.c')
            return None
        if hasattr(node.obj, 'graph'):
            # Regular RPython functions
            name = invent_nice_name(node.obj.graph)
            if name is not None:
                return name
        elif node._funccodegen_owner is not None:
            # Data nodes that belong to a known function
            graph = getattr(node._funccodegen_owner, 'graph', None)
            name = invent_nice_name(graph)
            if name is not None:
                return "data_" + name
        return basecname

    def splitnodesimpl(self, basecname, nodes, nextra, nbetween,
                       split_criteria=SPLIT_CRITERIA):
        # Gather nodes by some criteria:
        nodes_by_base_cfile = {}
        for node in nodes:
            c_filename = self.getbasecfilefornode(node, basecname)
            if c_filename in nodes_by_base_cfile:
                nodes_by_base_cfile[c_filename].append(node)
            else:
                nodes_by_base_cfile[c_filename] = [node]

        # produce a sequence of nodes, grouped into files
        # which have no more than SPLIT_CRITERIA lines
        for basecname in sorted(nodes_by_base_cfile):
            iternodes = iter(nodes_by_base_cfile[basecname])
            done = [False]
            def subiter():
                used = nextra
                for node in iternodes:
                    impl = '\n'.join(list(node.implementation())).split('\n')
                    if not impl:
                        continue
                    cost = len(impl) + nbetween
                    yield node, impl
                    del impl
                    if used + cost > split_criteria:
                        # split if criteria met, unless we would produce nothing.
                        raise StopIteration
                    used += cost
                done[0] = True
            while not done[0]:
                yield self.uniquecname(basecname), subiter()

    @contextlib.contextmanager
    def write_on_included_file(self, f, name):
        fi = self.makefile(name)
        print >> f, '#include "%s"' % name
        yield fi
        fi.close()

    @contextlib.contextmanager
    def write_on_maybe_separate_source(self, f, name):
        print >> f, '/* %s */' % name
        if self.one_source_file:
            yield f
        else:
            fi = self.makefile(name)
            yield fi
            fi.close()

    def gen_readable_parts_of_source(self, f):
        split_criteria_big = SPLIT_CRITERIA
        if py.std.sys.platform != "win32":
            if self.database.gcpolicy.need_no_typeptr():
                pass    # XXX gcc uses toooooons of memory???
            else:
                split_criteria_big = SPLIT_CRITERIA * 4 

        #
        # All declarations
        #
        with self.write_on_included_file(f, 'structdef.h') as fi:
            gen_structdef(fi, self.database)
        with self.write_on_included_file(f, 'forwarddecl.h') as fi:
            gen_forwarddecl(fi, self.database)
        with self.write_on_included_file(f, 'preimpl.h') as fi:
            gen_preimpl(fi, self.database)

        #
        # Implementation of functions and global structures and arrays
        #
        print >> f
        print >> f, '/***********************************************************/'
        print >> f, '/***  Implementations                                    ***/'
        print >> f

        print >> f, '#define PYPY_FILE_NAME "%s"' % os.path.basename(f.name)
        print >> f, '#include "src/g_include.h"'
        print >> f

        nextralines = 11 + 1
        for name, nodeiter in self.splitnodesimpl('nonfuncnodes.c',
                                                   self.othernodes,
                                                   nextralines, 1):
            with self.write_on_maybe_separate_source(f, name) as fc:
                if fc is not f:
                    print >> fc, '/***********************************************************/'
                    print >> fc, '/***  Non-function Implementations                       ***/'
                    print >> fc
                    print >> fc, '#include "common_header.h"'
                    print >> fc, '#include "structdef.h"'
                    print >> fc, '#include "forwarddecl.h"'
                    print >> fc, '#include "preimpl.h"'
                    print >> fc
                    print >> fc, '#include "src/g_include.h"'
                    print >> fc
                print >> fc, MARKER
                for node, impl in nodeiter:
                    print >> fc, '\n'.join(impl)
                    print >> fc, MARKER
                print >> fc, '/***********************************************************/'

        nextralines = 12
        for name, nodeiter in self.splitnodesimpl('implement.c',
                                                   self.funcnodes,
                                                   nextralines, 1,
                                                   split_criteria_big):
            with self.write_on_maybe_separate_source(f, name) as fc:
                if fc is not f:
                    print >> fc, '/***********************************************************/'
                    print >> fc, '/***  Implementations                                    ***/'
                    print >> fc
                    print >> fc, '#define PYPY_FILE_NAME "%s"' % name
                    print >> fc, '#include "common_header.h"'
                    print >> fc, '#include "structdef.h"'
                    print >> fc, '#include "forwarddecl.h"'
                    print >> fc, '#include "preimpl.h"'
                    print >> fc, '#include "src/g_include.h"'
                    print >> fc
                print >> fc, MARKER
                for node, impl in nodeiter:
                    print >> fc, '\n'.join(impl)
                    print >> fc, MARKER
                print >> fc, '/***********************************************************/'
        print >> f


def gen_structdef(f, database):
    structdeflist = database.getstructdeflist()
    print >> f, '/***********************************************************/'
    print >> f, '/***  Structure definitions                              ***/'
    print >> f
    for node in structdeflist:
        if hasattr(node, 'forward_decl'):
            if node.forward_decl:
                print >> f, node.forward_decl
        elif node.name is not None:
            print >> f, '%s %s;' % (node.typetag, node.name)
    print >> f
    for node in structdeflist:
        for line in node.definition():
            print >> f, line

def gen_forwarddecl(f, database):
    print >> f, '/***********************************************************/'
    print >> f, '/***  Forward declarations                               ***/'
    print >> f
    for node in database.globalcontainers():
        for line in node.forward_declaration():
            print >> f, line

def gen_preimpl(f, database):
    if database.translator is None or database.translator.rtyper is None:
        return
    preimplementationlines = pre_include_code_lines(
        database, database.translator.rtyper)
    for line in preimplementationlines:
        print >> f, line

def gen_startupcode(f, database):
    # generate the start-up code and put it into a function
    print >> f, 'char *RPython_StartupCode(void) {'
    print >> f, '\tchar *error = NULL;'
    for line in database.gcpolicy.gc_startup_code():
        print >> f,"\t" + line

    # put float infinities in global constants, we should not have so many of them for now to make
    # a table+loop preferable
    for dest, value in database.late_initializations:
        print >> f, "\t%s = %s;" % (dest, value)

    firsttime = True
    for node in database.containerlist:
        lines = list(node.startupcode())
        if lines:
            if firsttime:
                firsttime = False
            else:
                print >> f, '\tif (error) return error;'
            for line in lines:
                print >> f, '\t'+line
    print >> f, '\treturn error;'
    print >> f, '}'

def commondefs(defines):
    from pypy.rlib.rarithmetic import LONG_BIT, LONGLONG_BIT
    defines['PYPY_LONG_BIT'] = LONG_BIT
    defines['PYPY_LONGLONG_BIT'] = LONGLONG_BIT

def add_extra_files(eci):
    srcdir = py.path.local(autopath.pypydir).join('translator', 'c', 'src')
    files = [
        srcdir / 'entrypoint.c',       # ifdef PYPY_STANDALONE
        srcdir / 'allocator.c',        # ifdef PYPY_STANDALONE
        srcdir / 'mem.c',
        srcdir / 'exception.c',
        srcdir / 'rtyper.c',           # ifdef HAVE_RTYPER
        srcdir / 'support.c',
        srcdir / 'pyobj.c',
        srcdir / 'profiling.c',
        srcdir / 'debug_print.c',
        srcdir / 'debug_traceback.c',  # ifdef HAVE_RTYPER
        srcdir / 'stack.c',
        srcdir / 'threadlocal.c',
        srcdir / 'asm.c',
        srcdir / 'instrument.c',
        srcdir / 'int.c',
    ]
    if _CYGWIN:
        files.append(srcdir / 'cygwin_wait.c')
    return eci.merge(ExternalCompilationInfo(separate_module_files=files))


def gen_source(database, modulename, targetdir,
               eci, defines={}, split=False):
    if isinstance(targetdir, str):
        targetdir = py.path.local(targetdir)

    filename = targetdir.join(modulename + '.c')
    f = filename.open('w')
    incfilename = targetdir.join('common_header.h')
    fi = incfilename.open('w')

    #
    # Header
    #
    print >> f, '#include "common_header.h"'
    print >> f
    commondefs(defines)
    for key, value in defines.items():
        print >> fi, '#define %s %s' % (key, value)

    eci.write_c_header(fi)
    print >> fi, '#include "src/g_prerequisite.h"'

    fi.close()

    #
    # 1) All declarations
    # 2) Implementation of functions and global structures and arrays
    #
    sg = SourceGenerator(database)
    sg.set_strategy(targetdir, split)
    database.prepare_inline_helpers()
    sg.gen_readable_parts_of_source(f)

    gen_startupcode(f, database)
    f.close()

    if 'PYPY_INSTRUMENT' in defines:
        fi = incfilename.open('a')
        n = database.instrument_ncounter
        print >>fi, "#define PYPY_INSTRUMENT_NCOUNTER %d" % n
        fi.close()

    eci = add_extra_files(eci)
    eci = eci.convert_sources_to_files()
    files, eci = eci.get_module_files()
    return eci, filename, sg.getextrafiles() + list(files)