Issue 2168: Mac OS X fixes for SWIG tests. (Greg Noel)
[scons.git] / test / PharLap.py
1 #!/usr/bin/env python
2 #
3 # __COPYRIGHT__
4 #
5 # Permission is hereby granted, free of charge, to any person obtaining
6 # a copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish,
9 # distribute, sublicense, and/or sell copies of the Software, and to
10 # permit persons to whom the Software is furnished to do so, subject to
11 # the following conditions:
12 #
13 # The above copyright notice and this permission notice shall be included
14 # in all copies or substantial portions of the Software.
15 #
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
17 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
18 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 #
24
25 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
26
27 import os
28 import os.path
29 import string
30 import sys
31 import TestSCons
32 import time
33
34 test = TestSCons.TestSCons()
35
36 if sys.platform != 'win32':
37     test.skip_test('PharLap is only available on Windows; skipping test.\n')
38
39 if not test.detect_tool('linkloc'):
40     test.skip_test("Could not find 'linkloc', skipping test.\n")
41
42 if not test.detect_tool('386asm'):
43     test.skip_test("Could not find '386asm', skipping test.\n")
44
45 # From the Phar Lap minasm example program...
46 test.write("minasm.asm", r"""
47
48 ; MINASM.ASM - A minimal assembly language program which runs
49 ;       under ToolSuite.  You can use this program as a framework
50 ;       for large assembly language programs.
51 ;
52 .386
53
54 ;
55 ; Segmentation and segment ordering.
56 ;
57 ; First comes the code segment.
58 ;
59 _TEXT   segment use32 byte public 'CODE'
60 _TEXT   ends
61
62 ;
63 ; The data segment contains initialized RAM based data.  It will automatically
64 ; be placed in the ROM at link time and unpacked into RAM at run-time
65 ; by the __pl_unpackrom function.
66 ;
67 ; If you do not need any initialized data in your assembly language program,
68 ; you can leave this segment empty and remove the call to __pl_unpackrom.
69 ;
70 ;
71 _DATA   segment use32 dword public 'DATA'
72
73 loopcount       dd 10d
74 rammessage      db 'This message is in RAM memory',0dh,0ah,0
75
76 _DATA   ends
77
78 ;
79 ; The BSS segment contains RAM based variables which
80 ; are initialized to zero at run-time.  Putting unitialized
81 ; variables which should start at zero here saves space in
82 ; the ROM.
83 ;
84 ; If you do not need any zero-initialized data in your assembly language
85 ; program, you can leave this segment empty (and optionally remove the
86 ; instructions below which initialize it).
87 ;
88 ; The segment name must be lower case for compatibility with the linker
89 ;
90 _bss    segment use32 dword public 'BSS'
91 dummy_bss db 32 dup(?)  ; Use a little bit of BSS just to test it
92 _bss    ends
93
94 ;
95 ; The const segment contains constants which will never
96 ; change.  It is put in the ROM and never copied to RAM.
97 ;
98 ; If you do not need any ROM based constants in your assembly language
99 ; program, you can leave this segment empty.
100 ;
101 _CONST  segment use32 dword public 'CONST'
102 rommessage      db 'This message is in ROM memory',0dh,0ah,0
103 _CONST  ends
104
105 ;
106 ; We're in flat model, so we'll put all the read-only segments we know about
107 ; in a code group, and the writeable segments in a data group, so that
108 ; we can use assume to easily get addressability to the segments.
109 ;
110 CGROUP group _TEXT, _CONST
111 DGROUP group _DATA, _bss
112
113         assume cs:CGROUP,ds:DGROUP
114 _TEXT   segment
115
116 ;
117 ; _main - the main routine of this program.
118 ;
119 ; We will display the RAM and ROM messages the number of times
120 ; specified in the loopcount variable.  This proves that we can
121 ; initialize RAM data out of ROM and the fact that we can
122 ; modify the loop count in memory verifies that it actually ends
123 ; up in RAM.
124 ;
125         public _main
126 _main proc near
127
128         mov     cl,0ah                  ; Skip a line before we start
129         call    PutCharTarget           ;
130 main_loop:
131         cmp     loopcount,0             ; Are we at the end of our loop?
132         je      short done_main         ;  yes.
133         lea     edx,rommessage          ; EDX -> ROM message
134         call    WriteStringTarget       ; Display it
135         lea     edx,rammessage          ; EDX -> RAM message
136         call    WriteStringTarget       ; Display it
137         dec     loopcount               ;
138         jmp     main_loop               ; Branch back for next loop iteration
139 done_main:
140         ret                             ; That's it!
141
142 _main endp
143
144 ;
145 ; WriteStringTarget - Display a string on the target console
146 ;
147 ; Inputs:
148 ;       EDX -> Null terminated ASCII string to display
149 ;
150 ; Outputs:
151 ;       All registers preserved
152 ;
153 WriteStringTarget proc near
154
155         push    ecx                     ; Save registers
156         push    edx                     ;
157
158 write_loop:
159         movzx   ecx,byte ptr [edx]      ; Get a character
160         jecxz   done_str                ; Branch if end of string
161         call    PutCharTarget           ; Display this character
162         inc     edx                     ; Bump scan pointer
163         jmp     write_loop              ; And loop back for next character
164
165 done_str:
166         pop     edx                     ; Restore registers
167         pop     ecx                     ;
168         ret                             ;  and return
169
170 WriteStringTarget endp
171
172 ;
173 ; PutCharTarget - Write a character on the target console
174 ;
175 ; This routine displays a character on the target console by using
176 ; the PutChar kernel service available through int 254.
177 ;
178 ; Inputs:
179 ;       CL = character to display
180 ;
181 ; Outputs:
182 ;       All registers preserved
183 ;
184 PutCharTarget proc near
185
186         push    eax             ; Save registers
187         push    ebx             ;
188         push    edx             ;
189
190         mov     ax,254Ah        ; Request Kernel Service
191         mov     bx,1            ; service code 1 = PutChar
192         movzx   edx,cl          ; EDX = character to display
193         int     0FEh            ; Int 254 is for kernel services
194
195         pop     edx             ; Restore registers
196         pop     ebx             ;
197         pop     eax             ;
198         ret                     ;  and return
199
200 PutCharTarget endp
201
202 ;
203 ; The __pl_unpackrom unpacks initialized RAM based data variables
204 ; out of the ROMINIT segment into their RAM area.  They are put
205 ; in the ROMINIT segment with the -ROMINIT switch in the link file.
206 ;
207 extrn __pl_unpackrom:near
208
209 ;
210 ; The _EtsExitProcess function is used to terminate our program
211 ;
212 extrn _EtsExitProcess:near
213
214 ;
215 ; The linker will define symbols for the beginning and end of the
216 ; BSS segment.
217 ;
218 extrn   __p_SEG__bss_BEGIN:dword
219 extrn   __p_SEG__bss_END:dword
220
221 ;
222 ; __p_start -- The entry point for our assembly language program.
223 ; We unpack the RAM based variables out of the ROM and clear the
224 ; BSS to zero, then call _main where the real work happens.  When
225 ; _main returns, we call EtsExitProcess(0) to terminate.
226 ;
227 public __p_start
228 __p_start proc near
229         pushad                          ; save initial regs
230         push    es                              ;
231         call    __pl_unpackrom          ; Call the unpacker 
232         cld                             ; Clear direction flag
233
234         lea     eax,__p_SEG__bss_END    ; load end address and 
235         lea     ebx,__p_SEG__bss_BEGIN  ; subtract start to get size
236         sub     eax,ebx
237         mov     ecx,eax                 ; This is size
238         inc     ecx
239         lea     edi,__p_SEG__bss_BEGIN  ; Zero from start address
240         mov     al,0                    ;Zero out BSS and C_COMMON      
241         rep     stosb
242
243         pop     es                      ; restore initial regs
244         popad
245         call    _main                   ; go do some work
246 stopme:
247         xor     eax,eax                 ; Call _EtsExitProcess(0)
248         push    eax                     ;
249         call    _EtsExitProcess         ;
250         pop     eax                     ;
251         jmp     stopme                  ;  .. in a loop just in case it ever
252                                         ;  comes back
253
254 __p_start endp
255
256 TD_hack:
257         mov     eax, __p_tdhack         ; force reference to TD-hack symbol
258
259 _TEXT   ends
260
261 ;
262 ;       Hack for Turbo Debugger/TDEMB - TD will fault if the .exe being
263 ;       debugged doesn't have an import table.  (TD looks for the address of
264 ;       the table, then dereferences that address wihtout checking for NULL).
265 ;
266 ;       This symbol, __p_tdhack, must be declared as an import in all the
267 ;       .emb files shipped.  IE:
268 ;
269 ;               -implib embkern.lib
270 ;               -import __p_tdhack
271 ;
272 ;       This forces the creation of an import table within the .EXE.
273 _DATA   segment
274 extrn   __p_tdhack:dword
275 _DATA   ends
276         end     __p_start
277 """)
278
279 test.write("foo.lnk","""
280 @baz\\bar.lnk
281 """)
282
283 test.subdir("baz")
284 test.write([ "baz", "bar.lnk"],"""
285 @asm.emb
286 """)
287
288 test.write("SConstruct", """
289 env=Environment(tools = [ 'linkloc', '386asm' ],
290                 ASFLAGS='-twocase -cvsym',
291                 LINKFLAGS='@foo.lnk')
292 env.Program(target='minasm', source='minasm.asm')
293 """)
294
295 test.run(arguments='.')
296
297 # Assume .exe extension...this test is for Windows only.
298 test.fail_test(not os.path.exists('minasm.exe'))
299 test.up_to_date(arguments='.')
300
301 # Updating a linker command file should cause a rebuild!
302 test.write([ "baz", "bar.lnk"],"""
303 -cvsym
304 @asm.emb
305 """)
306
307 oldtime = os.path.getmtime(test.workpath('minasm.exe'))
308 time.sleep(2) # Give the time stamp time to change
309 test.run(arguments = '.')
310 test.fail_test(oldtime == os.path.getmtime(test.workpath('minasm.exe')))
311
312 test.pass_test()