Re: gec: Is it possible to specify a signature for a external C call?

Berend de Boer <[email protected]> Wed, 14 Nov 2007 09:59:31 +1300
Newsgroups gmane.comp.lang.eiffel.gobo.general
Message-ID <[email protected]>
>>>>> "Eric" == Eric Bezault <ericb-D6Qt/9opevxWk0Htik3J/[email protected]> writes:

    >> It works, because they emit a prototype. That had to be coded, so
    >> it's not luck.

    Eric> The luck is that it's not specified anywhere in the standard
    Eric> and you might have no prototype if you specify a header file
    Eric> that does not contain such prototype.

Well, but that's a bug of the coder isn't it? You specify a header file,
but one without the prototype, there's little you can do. Would fail in
your case as well, i.e. I write a .h file, but make a type when
specifying the header and that bad header exists on my system and
there's no warning either.


    Eric> Does it work as well when you add assertions to these external
    Eric> routines?

Forgot to test that, sorry.

But it seems to be the case,

For SmartEiffel, more specifically:

1. The Eiffel code:

  class POSIX_TIME

	posix_difftime (time_end, time_start: INTEGER): DOUBLE is
			-- Computes the difference between two times in seconds.
		require
			time_end_positive: time_end > 0
		external "C"
		end

2. In the .h file SE generates, I have this:

  /* Extra external prototype for line 36 of /home/berend/src/eposix/src/capi/spec/se/capi_time.e:*/
  T5 posix_difftime(T2 a1,T2 a2);
  /*POSIX_TIME*/
  T5 r414posix_difftime(se_dump_stack*caller,T2 a1,T2 a2);


   So it generates two things: the extra prototype, and the prototype
   for the external stub.

3. SE generates a wrapper to call posix_difftime which looks like this:

  /*POSIX_TIME*/
  T5 r414posix_difftime(se_dump_stack*caller,T2 a1,T2 a2){
  T5 R=0;
  void**locals[3];
  static se_frame_descriptor fd={"posix_difftime CAPI_TIME",0,3,"time_end%E2%time_start%E2%Result%E5%",1};
  se_dump_stack ds;
  ds.fd=&fd;
  ds.current=NULL;
  ds.p=0x19401D04/*l29c2/capi_time.e*/;
  ds.caller=caller;
  ds.locals=locals;
  ds.exception_origin=NULL;
  locals[0]=(void**)&a1;
  locals[1]=(void**)&a2;
  locals[2]=(void**)&R;
  set_dump_stack_top(&ds);/*link*/
  se_require_uppermost_flag=1;
  if(fd.assertion_flag){
  fd.assertion_flag=0;
  (ds.p=0x19402040/*l32c32/capi_time.e*/);
  ac_req((int32_t)((a1)>(/*IC*/(T2)(INT8_C(0)))),"time_end_positive");
  fd.assertion_flag=1;
  }
  /*l36c12/capi_time.e*/(ds.p=0x19402418/*l36c12/capi_time.e*/);
  R=(posix_difftime(a1,a2));
  /*l36c12/capi_time.e*/set_dump_stack_top(caller);/*unlink*/
  return R;
  }

And you can see the assertion check there.


The stub for the external call is always generated in debug
mode. Haven't looked at boost mode. You wouldn't need it in that case I
imagine. You only need a stub if you want to see a stack frame perhaps,
and if you want to check assertions.


For ISE Eiffel the situation is similar:

1. A prototype is generated:

     extern EIF_REAL_64 posix_difftime(EIF_INTEGER_32, EIF_INTEGER_32);

2. A wrapper function is generated:

  /* posix_difftime */

  EIF_TYPED_VALUE Fap3q5s (EIF_REFERENCE Current, EIF_TYPED_VALUE arg1x, EIF_TYPED_VALUE arg2x)
  {
    GTCX
    RTEX;
    EIF_REAL_64 Result = (EIF_REAL_64) 0;
    RTSN;
    RTDA;
    RTLD;

    if (arg2x.type == SK_REF) arg2x.it_i4 = * (EIF_INTEGER_32 *) arg2x.it_r;
  #define arg2 arg2x.it_i4
    if (arg1x.type == SK_REF) arg1x.it_i4 = * (EIF_INTEGER_32 *) arg1x.it_r;
  #define arg1 arg1x.it_i4
    RTLI(1);
    RTLR(0,Current);

    RTLU (SK_REAL64, &Result);
    RTLU(SK_INT32,&arg1);
    RTLU(SK_INT32,&arg2);
    RTLU (SK_REF, &Current);
    RTEAA("posix_difftime", RTUD(70), Current, 0, 2, 1114);
    RTSA(Dtype(Current));
    RTSC;
    RTIV2(Current, RTAL);
    if (RTAL & CK_REQUIRE | RTAC) {
      RTHOOK(1);
      RTCT("time_end_positive", EX_PRE);
      RTTE((EIF_BOOLEAN)(arg1 > ((EIF_INTEGER_32) 0L)), label_1);
      RTCK;
      RTJB;
    label_1:
      RTCF;
    }
  body:;
    Result = (EIF_REAL_64)posix_difftime(arg1, arg2);
    RTVI2(Current, RTAL);
    RTRS;
    RTHOOK(2);
    RTLE;
    RTLO(4);
    RTEE;
    { EIF_TYPED_VALUE r; r.type = SK_REAL64; r.it_r8 = Result; return r; }
  #undef arg2
  #undef arg1
  }

As you can see, assertion checking works fine.

There was an annoying issue with previous versions of EiffelStudio where
you could not redefine a feature that was declared external, but that's
no longer the case. I hope Gobo allows one redefine external features as
well.

-- 
Cheers,

Berend de Boer


[Non-text portions of this message have been removed]