diff options
-rw-r--r-- | MANIFEST | 1 | ||||
-rw-r--r-- | ext/Thread/Thread.xs | 107 | ||||
-rw-r--r-- | perl.c | 6 | ||||
-rw-r--r-- | perl.h | 94 | ||||
-rw-r--r-- | pp_sys.c | 2 | ||||
-rw-r--r-- | sv.c | 35 | ||||
-rw-r--r-- | thread.sym | 1 | ||||
-rw-r--r-- | util.c | 2 | ||||
-rw-r--r-- | win32/Makefile | 10 | ||||
-rw-r--r-- | win32/config.bc | 2 | ||||
-rw-r--r-- | win32/config_H.bc | 2 | ||||
-rw-r--r-- | win32/makedef.pl | 4 | ||||
-rw-r--r-- | win32/makefile.mk | 13 |
13 files changed, 168 insertions, 111 deletions
@@ -802,6 +802,7 @@ t/pragma/warn-1global Tests of global warnings for warning.t t/pragma/warning.t See if warning controls work taint.c Tainting code thread.h Threading header +thread.sym Symbols for threads toke.c The tokener universal.c The default UNIVERSAL package methods unixish.h Defines that are assumed on Unix diff --git a/ext/Thread/Thread.xs b/ext/Thread/Thread.xs index 9c0325e07d..7bbe0889e7 100644 --- a/ext/Thread/Thread.xs +++ b/ext/Thread/Thread.xs @@ -5,13 +5,26 @@ /* Magic signature for Thread's mg_private is "Th" */ #define Thread_MAGIC_SIGNATURE 0x5468 +#ifdef __cplusplus +#ifdef I_UNISTD +#include <unistd.h> +#endif +#endif +#include <fcntl.h> + static U32 threadnum = 0; static int sig_pipe[2]; + +#ifndef THREAD_RET_TYPE +typedef struct thread *Thread; +#define THREAD_RET_TYPE void * +#define THREAD_RET_CAST(x) ((THREAD_RET_TYPE) x) +#endif; static void -remove_thread(t) -Thread t; +remove_thread(struct thread *t) { +#ifdef USE_THREADS DEBUG_L(WITH_THR(PerlIO_printf(PerlIO_stderr(), "%p: remove_thread %p\n", thr, t))); MUTEX_LOCK(&threads_mutex); @@ -21,12 +34,13 @@ Thread t; t->next->prev = t->prev; COND_BROADCAST(&nthreads_cond); MUTEX_UNLOCK(&threads_mutex); +#endif } static THREAD_RET_TYPE -threadstart(arg) -void *arg; +threadstart(void *arg) { +#ifdef USE_THREADS #ifdef FAKE_THREADS Thread savethread = thr; LOGOP myop; @@ -75,8 +89,10 @@ void *arg; AV *returnav; int i, ret; dJMPENV; + DEBUG_L(PerlIO_printf(PerlIO_stderr(), "new thread %p waiting to start\n", + thr)); - /* Don't call *anything* requiring dTHR until after pthread_setspecific */ + /* Don't call *anything* requiring dTHR until after SET_THR() */ /* * Wait until our creator releases us. If we didn't do this, then * it would be potentially possible for out thread to carry on and @@ -190,15 +206,16 @@ void *arg; /* us unless we're detached, in which */ /* case noone sees the value anyway. */ #endif +#else + return THREAD_RET_CAST(NULL); +#endif } static SV * -newthread(startsv, initargs, class) -SV *startsv; -AV *initargs; -char *class; +newthread (SV *startsv, AV *initargs, char *Class) { dTHR; +#ifdef USE_THREADS dSP; Thread savethread; int i; @@ -212,8 +229,8 @@ char *class; thr = new_struct_thread(thr); SPAGAIN; DEBUG_L(PerlIO_printf(PerlIO_stderr(), - "%p: newthread, tid is %u, preparing stack\n", - savethread, thr->tid)); + "%p: newthread (%p), tid is %u, preparing stack\n", + savethread, thr, thr->tid)); /* The following pushes the arg list and startsv onto the *new* stack */ PUSHMARK(sp); /* Could easily speed up the following greatly */ @@ -221,9 +238,8 @@ char *class; XPUSHs(SvREFCNT_inc(*av_fetch(initargs, i, FALSE))); XPUSHs(SvREFCNT_inc(startsv)); PUTBACK; - #ifdef THREAD_CREATE - THREAD_CREATE(thr, threadstart); + err = THREAD_CREATE(thr, threadstart); #else /* On your marks... */ MUTEX_LOCK(&thr->mutex); @@ -237,6 +253,8 @@ char *class; MUTEX_UNLOCK(&thr->mutex); #endif if (err) { + DEBUG_L(PerlIO_printf(PerlIO_stderr(), + "%p: create of %p failed %d\n", savethread, thr, err)); /* Thread creation failed--clean up */ SvREFCNT_dec(thr->cvcache); remove_thread(thr); @@ -255,26 +273,32 @@ char *class; sv = newSViv(thr->tid); sv_magic(sv, thr->oursv, '~', 0, 0); SvMAGIC(sv)->mg_private = Thread_MAGIC_SIGNATURE; - return sv_bless(newRV_noinc(sv), gv_stashpv(class, TRUE)); + return sv_bless(newRV_noinc(sv), gv_stashpv(Class, TRUE)); +#else + croak("No threads in this perl"); + return &sv_undef; +#endif } +static Signal_t handle_thread_signal _((int sig)); + static Signal_t -handle_thread_signal(sig) -int sig; +handle_thread_signal(int sig) { char c = (char) sig; write(sig_pipe[0], &c, 1); } MODULE = Thread PACKAGE = Thread +PROTOTYPES: DISABLE void -new(class, startsv, ...) - char * class +new(Class, startsv, ...) + char * Class SV * startsv AV * av = av_make(items - 2, &ST(2)); PPCODE: - XPUSHs(sv_2mortal(newthread(startsv, av, class))); + XPUSHs(sv_2mortal(newthread(startsv, av, Class))); void join(t) @@ -282,6 +306,7 @@ join(t) AV * av = NO_INIT int i = NO_INIT PPCODE: +#ifdef USE_THREADS DEBUG_L(PerlIO_printf(PerlIO_stderr(), "%p: joining %p (state %u)\n", thr, t, ThrSTATE(t));); MUTEX_LOCK(&t->mutex); @@ -306,11 +331,13 @@ join(t) /* Could easily speed up the following if necessary */ for (i = 0; i <= AvFILL(av); i++) XPUSHs(sv_2mortal(*av_fetch(av, i, FALSE))); +#endif void detach(t) Thread t CODE: +#ifdef USE_THREADS DEBUG_L(PerlIO_printf(PerlIO_stderr(), "%p: detaching %p (state %u)\n", thr, t, ThrSTATE(t));); MUTEX_LOCK(&t->mutex); @@ -333,6 +360,7 @@ detach(t) croak("can't detach thread"); /* NOTREACHED */ } +#endif void equal(t1, t2) @@ -345,26 +373,34 @@ void flags(t) Thread t PPCODE: +#ifdef USE_THREADS PUSHs(sv_2mortal(newSViv(t->flags))); +#endif void -self(class) - char * class +self(Class) + char * Class PREINIT: SV *sv; - PPCODE: + PPCODE: +#ifdef USE_THREADS sv = newSViv(thr->tid); sv_magic(sv, thr->oursv, '~', 0, 0); SvMAGIC(sv)->mg_private = Thread_MAGIC_SIGNATURE; - PUSHs(sv_2mortal(sv_bless(newRV_noinc(sv), gv_stashpv(class, TRUE)))); + PUSHs(sv_2mortal(sv_bless(newRV_noinc(sv), gv_stashpv(Class, TRUE)))); +#endif U32 tid(t) Thread t CODE: +#ifdef USE_THREADS MUTEX_LOCK(&t->mutex); RETVAL = t->tid; MUTEX_UNLOCK(&t->mutex); +#else + RETVAL = 0; +#endif OUTPUT: RETVAL @@ -377,13 +413,18 @@ DESTROY(t) void yield() CODE: +{ +#ifdef USE_THREADS YIELD; +#endif +} void cond_wait(sv) SV * sv MAGIC * mg = NO_INIT -CODE: +CODE: +#ifdef USE_THREADS if (SvROK(sv)) sv = SvRV(sv); @@ -400,12 +441,14 @@ CODE: COND_WAIT(MgOWNERCONDP(mg), MgMUTEXP(mg)); MgOWNER(mg) = thr; MUTEX_UNLOCK(MgMUTEXP(mg)); - +#endif + void cond_signal(sv) SV * sv MAGIC * mg = NO_INIT CODE: +#ifdef USE_THREADS if (SvROK(sv)) sv = SvRV(sv); @@ -418,12 +461,14 @@ CODE: } COND_SIGNAL(MgCONDP(mg)); MUTEX_UNLOCK(MgMUTEXP(mg)); +#endif void cond_broadcast(sv) SV * sv MAGIC * mg = NO_INIT -CODE: +CODE: +#ifdef USE_THREADS if (SvROK(sv)) sv = SvRV(sv); @@ -437,16 +482,18 @@ CODE: } COND_BROADCAST(MgCONDP(mg)); MUTEX_UNLOCK(MgMUTEXP(mg)); +#endif void -list(class) - char * class +list(Class) + char * Class PREINIT: Thread t; AV * av; SV ** svp; int n = 0; PPCODE: +#ifdef USE_THREADS av = newAV(); /* * Iterate until we have enough dynamic storage for all threads. @@ -462,7 +509,7 @@ list(class) SV *sv = newSViv(0); /* fill in tid later */ sv_magic(sv, 0, '~', 0, 0); /* fill in other magic later */ av_push(av, sv_bless(newRV_noinc(sv), - gv_stashpv(class, TRUE))); + gv_stashpv(Class, TRUE))); } } @@ -496,6 +543,7 @@ list(class) for (svp = AvARRAY(av); n > 0; n--, svp++) PUSHs(*svp); (void)sv_2mortal((SV*)av); +#endif MODULE = Thread PACKAGE = Thread::Signal @@ -530,3 +578,4 @@ await_signal() RETVAL = c ? psig_ptr[c] : &sv_no; OUTPUT: RETVAL + @@ -2867,11 +2867,11 @@ init_main_thread() thr->prev = thr; MUTEX_UNLOCK(&threads_mutex); -#ifdef HAVE_THREAD_INTERN - init_thread_intern(thr); +#ifdef INIT_THREAD_INTERN + INIT_THREAD_INTERN(thr); #else thr->self = pthread_self(); -#endif /* HAVE_THREAD_INTERN */ +#endif /* INIT_THREAD_INTERN */ SET_THR(thr); /* @@ -29,6 +29,22 @@ #include "embed.h" +#ifdef __cplusplus +# define START_EXTERN_C extern "C" { +# define END_EXTERN_C } +# define EXTERN_C extern "C" +#else +# define START_EXTERN_C +# define END_EXTERN_C +# define EXTERN_C +#endif + +#if defined(USE_THREADS) /* && !defined(PERL_CORE) && !defined(PERLDLL) */ +#ifndef CRIPPLED_CC +#define CRIPPLED_CC +#endif +#endif + #ifdef OP_IN_REGISTER # ifdef __GNUC__ # define stringify_immed(s) #s @@ -64,21 +80,6 @@ register struct op *op asm(stringify(OP_IN_REGISTER)); #define WITH_THR(s) do { dTHR; s; } while (0) -#ifdef USE_THREADS -# ifdef FAKE_THREADS -# include "fakethr.h" -# else -# ifdef WIN32 -# include "win32/win32thread.h" -# else -# include <pthread.h> -typedef pthread_mutex_t perl_mutex; -typedef pthread_cond_t perl_cond; -typedef pthread_key_t perl_key; -# endif /* WIN32 */ -# endif /* FAKE_THREADS */ -#endif /* USE_THREADS */ - /* * SOFT_CAST can be used for args to prototyped functions to retain some * type checking; it only casts if the compiler does not know prototypes. @@ -949,7 +950,31 @@ typedef I32 (*filter_t) _((int, SV *, int)); # include "unixish.h" # endif # endif -#endif +#endif + +/* + * USE_THREADS needs to be after unixish.h as <pthread.h> includes <sys/signal.h> + * which defines NSIG - which will stop inclusion of <signal.h> + * this results in many functions being undeclared which bothers C++ + * May make sense to have threads after "*ish.h" anyway + */ + +#ifdef USE_THREADS +# ifdef FAKE_THREADS +# include "fakethr.h" +# else +# ifdef WIN32 +# include <win32thread.h> +# else +# include <pthread.h> +typedef pthread_mutex_t perl_mutex; +typedef pthread_cond_t perl_cond; +typedef pthread_key_t perl_key; +# endif /* WIN32 */ +# endif /* FAKE_THREADS */ +#endif /* USE_THREADS */ + + #ifdef VMS # define STATUS_NATIVE statusvalue_vms @@ -1029,7 +1054,7 @@ union any { }; #ifdef USE_THREADS -#define ARGSproto struct thread * +#define ARGSproto struct thread *thr #else #define ARGSproto void #endif /* USE_THREADS */ @@ -1121,13 +1146,7 @@ EXT char Error[1]; #define U_I(what) ((unsigned int)(what)) #define U_L(what) ((U32)(what)) #else -# ifdef __cplusplus - extern "C" { -# endif -U32 cast_ulong _((double)); -# ifdef __cplusplus - } -# endif +EXTERN_C U32 cast_ulong _((double)); #define U_S(what) ((U16)cast_ulong((double)(what))) #define U_I(what) ((unsigned int)cast_ulong((double)(what))) #define U_L(what) (cast_ulong((double)(what))) @@ -1138,15 +1157,11 @@ U32 cast_ulong _((double)); #define I_V(what) ((IV)(what)) #define U_V(what) ((UV)(what)) #else -# ifdef __cplusplus - extern "C" { -# endif +START_EXTERN_C I32 cast_i32 _((double)); IV cast_iv _((double)); UV cast_uv _((double)); -# ifdef __cplusplus - } -# endif +END_EXTERN_C #define I_32(what) (cast_i32((double)(what))) #define I_V(what) (cast_iv((double)(what))) #define U_V(what) (cast_uv((double)(what))) @@ -1251,9 +1266,7 @@ char *strcpy(), *strcat(); #ifdef I_MATH # include <math.h> #else -# ifdef __cplusplus - extern "C" { -# endif +START_EXTERN_C double exp _((double)); double log _((double)); double log10 _((double)); @@ -1265,9 +1278,7 @@ char *strcpy(), *strcat(); double cos _((double)); double atan2 _((double,double)); double pow _((double,double)); -# ifdef __cplusplus - }; -# endif +END_EXTERN_C #endif #ifndef __cplusplus @@ -1364,7 +1375,7 @@ EXT struct thread * thr; /* Currently executing (fake) thread */ /* VMS doesn't use environ array and NeXT has problems with crt0.o globals */ #if !defined(VMS) && !(defined(NeXT) && defined(__DYNAMIC__)) -#ifndef DONT_DECLARE_STD +#if !defined(DONT_DECLARE_STD) || (defined(__svr4__) && defined(__GNUC__) && defined(sun)) extern char ** environ; /* environment variables supplied via exec */ #endif #else @@ -1985,10 +1996,7 @@ struct interpreter { #include "thread.h" #include "pp.h" -#ifdef __cplusplus -extern "C" { -#endif - +START_EXTERN_C #include "proto.h" #ifdef EMBED @@ -1999,9 +2007,7 @@ extern "C" { #define sv_setptrref(rv,ptr) sv_setref_iv(rv,Nullch,(IV)ptr) #endif -#ifdef __cplusplus -}; -#endif +END_EXTERN_C /* The following must follow proto.h */ @@ -550,7 +550,7 @@ PP(pp_tie) CATCH_SET(oldcatch); #else ENTER; - perl_call_sv((SV*)gv, G_SCALAR); + perl_call_sv((SV*)GvCV(gv), G_SCALAR); SPAGAIN; #endif sv = TOPs; @@ -3589,9 +3589,10 @@ SV *ref; return sv; } -#ifdef CRIPPLED_CC + + SV * -newRV_noinc(ref) +Perl_newRV_noinc(ref) SV *ref; { register SV *sv; @@ -3600,7 +3601,6 @@ SV *ref; SvREFCNT_dec(ref); return sv; } -#endif /* CRIPPLED_CC */ /* make an exact duplicate of old */ @@ -3794,21 +3794,21 @@ I32 lref; } } -#ifndef SvTRUE I32 -SvTRUE(sv) +sv_true(sv) register SV *sv; { + dTHR; if (!sv) return 0; if (SvGMAGICAL(sv)) mg_get(sv); if (SvPOK(sv)) { - register XPV* Xpv; - if ((Xpv = (XPV*)SvANY(sv)) && - (*Xpv->xpv_pv > '0' || - Xpv->xpv_cur > 1 || - (Xpv->xpv_cur && *Xpv->xpv_pv != '0'))) + register XPV* tXpv; + if ((tXpv = (XPV*)SvANY(sv)) && + (*tXpv->xpv_pv > '0' || + tXpv->xpv_cur > 1 || + (tXpv->xpv_cur && *tXpv->xpv_pv != '0'))) return 1; else return 0; @@ -3824,42 +3824,34 @@ register SV *sv; } } } -#endif /* !SvTRUE */ -#ifndef SvIV IV -SvIV(sv) +sv_iv(sv) register SV *sv; { if (SvIOK(sv)) return SvIVX(sv); return sv_2iv(sv); } -#endif /* !SvIV */ -#ifndef SvUV UV -SvUV(sv) +sv_uv(sv) register SV *sv; { if (SvIOK(sv)) return SvUVX(sv); return sv_2uv(sv); } -#endif /* !SvUV */ -#ifndef SvNV double -SvNV(sv) +sv_nv(sv) register SV *sv; { if (SvNOK(sv)) return SvNVX(sv); return sv_2nv(sv); } -#endif /* !SvNV */ -#ifdef CRIPPLED_CC char * sv_pvn(sv, lp) SV *sv; @@ -3871,7 +3863,6 @@ STRLEN *lp; } return sv_2pv(sv, lp); } -#endif char * sv_pvn_force(sv, lp) diff --git a/thread.sym b/thread.sym new file mode 100644 index 0000000000..4e768b56d8 --- /dev/null +++ b/thread.sym @@ -0,0 +1 @@ +#
\ No newline at end of file @@ -2602,7 +2602,7 @@ struct thread *t; INIT_THREAD_INTERN(thr); #else thr->self = pthread_self(); -#endif /* HAVE_THREAD_INTERN */ +#endif /* INIT_THREAD_INTERN */ return thr; } #endif /* USE_THREADS */ diff --git a/win32/Makefile b/win32/Makefile index 3e26dfc38f..08fdb693f4 100644 --- a/win32/Makefile +++ b/win32/Makefile @@ -11,7 +11,7 @@ # newly built perl. INST_DRV=c: INST_TOP=$(INST_DRV)\perl -BUILDOPT=-DUSE_THREADS -TP +BUILDOPT=-DUSE_THREADS CORECCOPT= # @@ -204,7 +204,7 @@ WIN32_C = perllib.c \ WIN32_OBJ = win32.obj \ win32io.obj \ win32sck.obj \ - win32thread.obj + win32thread.obj PERL95_OBJ = perl95.obj \ win32mt.obj \ @@ -273,7 +273,7 @@ DYNALOADMODULES= \ $(OPCODE_DLL) \ $(SDBM_FILE_DLL)\ $(IO_DLL) \ - $(ATTRS_DLL) \ + $(ATTRS_DLL) \ $(THREAD_DLL) POD2HTML=$(PODDIR)\pod2html @@ -307,13 +307,13 @@ config.w32 : $(CFGSH_TMPL) .\config.h : $(CFGH_TMPL) -del /f config.h copy $(CFGH_TMPL) config.h - ..\config.sh : config.w32 $(MINIPERL) config_sh.PL $(MINIPERL) -I..\lib config_sh.PL "INST_DRV=$(INST_DRV)" \ "INST_TOP=$(INST_TOP)" "cc=$(CC)" "ccflags=$(OPTIMIZE) $(DEFINES)" \ "cf_email=$(EMAIL)" "libs=$(LIBFILES)" "incpath=$(CCINCDIR)" \ "libpth=$(CCLIBDIR)" "libc=$(LIBC)" \ + "LINK_FLAGS=$(LINK_FLAGS)" \ config.w32 > ..\config.sh $(CONFIGPM) : $(MINIPERL) ..\config.sh config_h.PL ..\minimod.pl @@ -387,7 +387,7 @@ $(PERL95EXE): $(PERLDLL) $(CONFIGPM) $(PERL95_OBJ) del perl95.exe $(DYNALOADER).c: $(MINIPERL) $(EXTDIR)\DynaLoader\dl_win32.xs $(CONFIGPM) - if not exist ..\lib\auto md ..\lib\auto + if not exist ..\lib\auto mkdir ..\lib\auto $(XCOPY) $(EXTDIR)\$(*B)\$(*B).pm $(LIBDIR)\$(NULL) cd $(EXTDIR)\$(*B) $(XSUBPP) dl_win32.xs > $(*B).c diff --git a/win32/config.bc b/win32/config.bc index 3933c2789c..60e9b47e62 100644 --- a/win32/config.bc +++ b/win32/config.bc @@ -83,7 +83,7 @@ cryptlib='' csh='undef' d_Gconvert='gcvt((x),(n),(b))' d_access='define' -d_alarm='define' +d_alarm='undef' d_archlib='define' d_attribut='undef' d_bcmp='undef' diff --git a/win32/config_H.bc b/win32/config_H.bc index 460b58577c..61fb5a3241 100644 --- a/win32/config_H.bc +++ b/win32/config_H.bc @@ -113,7 +113,7 @@ * This symbol, if defined, indicates that the alarm routine is * available. */ -#define HAS_ALARM /**/ +/*#define HAS_ALARM /**/ /* HASATTRIBUTE: * This symbol indicates the C compiler can check for function attributes, diff --git a/win32/makedef.pl b/win32/makedef.pl index 8bc7a8a46a..e39874211a 100644 --- a/win32/makedef.pl +++ b/win32/makedef.pl @@ -154,7 +154,11 @@ Perl_eval_mutex Perl_eval_cond Perl_eval_owner Perl_threads_mutex +Perl_new_struct_thread +Perl_nthreads Perl_nthreads_cond +Perl_per_thread_magicals +Perl_thrsv Perl_unlock_condpair Perl_vtbl_mutex Perl_magic_mutexfree diff --git a/win32/makefile.mk b/win32/makefile.mk index 655efb7395..3dc00a215a 100644 --- a/win32/makefile.mk +++ b/win32/makefile.mk @@ -96,7 +96,7 @@ RUNTIME = -MD .ENDIF INCLUDES = -I.\include -I. -I.. #PCHFLAGS = -Fp$(INTDIR)\vcmoduls.pch -YX -DEFINES = -DWIN32 $(BUILDOPT) -D_CONSOLE -D_WIN32_WINNT=0x400 +DEFINES = -DWIN32 -D_CONSOLE $(BUILDOPT) LOCDEFS = -DPERLDLL SUBSYS = console @@ -131,7 +131,7 @@ LIBFILES = oldnames.lib kernel32.lib user32.lib gdi32.lib \ version.lib odbc32.lib odbccp32.lib CFLAGS = -nologo -W3 $(INCLUDES) $(DEFINES) $(LOCDEFS) $(PCHFLAGS) $(OPTIMIZE) -LINK_FLAGS = -nologo $(LIBFILES) $(LINK_DBG) -machine:I386 +LINK_FLAGS = -nologo $(LIBFILES) $(LINK_DBG) -machine:$(PROCESSOR_ARCHITECTURE) OBJOUT_FLAG = -Fo .ENDIF @@ -315,7 +315,6 @@ CORE_H = ..\av.h \ .\include\sys\socket.h \ .\win32.h - EXTENSIONS=DynaLoader Socket IO Fcntl Opcode SDBM_File attrs Thread DYNALOADER=$(EXTDIR)\DynaLoader\DynaLoader @@ -601,7 +600,7 @@ minitest : $(MINIPERL) $(GLOBEXE) $(CONFIGPM) cd ..\t && \ $(MINIPERL) -I..\lib test base/*.t comp/*.t cmd/*.t io/*.t op/*.t pragma/*.t -test : all +test-prep : all $(XCOPY) $(PERLEXE) ..\t\$(NULL) $(XCOPY) $(PERLDLL) ..\t\$(NULL) .IF "$(CCTYPE)" == "BORLAND" @@ -609,8 +608,14 @@ test : all .ELSE $(XCOPY) $(GLOBEXE) ..\t\$(NULL) .ENDIF + +test : test-prep cd ..\t && $(PERLEXE) -I..\lib harness +test-notty : test-prep + set PERL_SKIP_TTY_TEST=1 && \ + cd ..\t && $(PERLEXE) -I.\lib harness + clean : -@erase miniperlmain.obj -@erase $(MINIPERL) |