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