Возврат хэша Perl с помощью XS (ошибка: ‘void’ отсутствует в typemap)

#perl #xs

#perl #xs

Вопрос:

Я пытаюсь добавить вызов к привязкам Perl для Augeas (Config::Augeas). Я бы хотел, чтобы этот новый вызов возвращал хэш Perl. Я написал это:

 void                                                               
aug_span(aug, path);
      Config_Augeas* aug
      char* path                      
    PREINIT:                        
      int ret ;                                                          
      char *filename = NULL;                                                                   
      uint label_start, label_end, value_start, value_end, span_start, span_end;
      HV *span_hash;
    CODE:
      ret = aug_span(aug, path, amp;filename, amp;label_start, amp;label_end, amp;value_start, amp;value_end, amp;span_start, amp;span_end);
      span_hash = newHV();
      hv_store(span_hash, "filename", 8, newSVpv(filename, strlen(filename)), 0);
      hv_store(span_hash, "label_start", 11, newSViv(label_start), 0);
      hv_store(span_hash, "label_end", 9, newSViv(label_end), 0);
      hv_store(span_hash, "value_start", 11, newSViv(value_start), 0);
      hv_store(span_hash, "value_end", 9, newSViv(value_end), 0);     
      hv_store(span_hash, "span_start", 10, newSViv(span_start), 0);
      hv_store(span_hash, "span_end", 8, newSViv(span_end), 0);
      RETVAL = newRV_noinc((SV *)span_hash);
    OUTPUT:
      RETVAL
  

Но когда я его создаю, я получаю:

 lib/Config/Augeas.xs -> lib/Config/Augeas.c
Use of uninitialized value within %ExtUtils::ParseXS::type_kind in hash element at /usr/share/perl/5.10/ExtUtils/ParseXS.pm line 785, <GEN7> line 170.
Error: 'void' not in typemap in Augeas.xs, line 167
cc -I/usr/lib/perl/5.10/CORE -DXS_VERSION="0.701" -DVERSION="0.701" -fPIC -Wall -Wformat -Werror=format-security -c -D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -O2 -g -o lib/Config/Augeas.o lib/Config/Augeas.c
lib/Config/Augeas.xs: In function u2018XS_Config__AugeasPtr_spanu2019:
lib/Config/Augeas.xs:158: warning: value computed is not used
lib/Config/Augeas.xs:159: warning: value computed is not used
lib/Config/Augeas.xs:160: warning: value computed is not used
lib/Config/Augeas.xs:161: warning: value computed is not used
lib/Config/Augeas.xs:162: warning: value computed is not used
lib/Config/Augeas.xs:163: warning: value computed is not used
lib/Config/Augeas.xs:164: warning: value computed is not used
lib/Config/Augeas.xs:165: error: u2018RETVALu2019 undeclared (first use in this function)
lib/Config/Augeas.xs:165: error: (Each undeclared identifier is reported only once
lib/Config/Augeas.xs:165: error: for each function it appears in.)
error building lib/Config/Augeas.o from 'lib/Config/Augeas.c' at /usr/share/perl/5.10/ExtUtils/CBuilder/Base.pm line 110.
  

Что я делаю не так?

Комментарии:

1. Кстати, я думаю, вы можете избежать этих предупреждений, используя (void)hv_store(...)

Ответ №1:

Попробуйте сделать это:

 SV *
aug_span(aug, path);
      Config_Augeas* aug
      char* path                      
    PREINIT:                        
      int ret ;                                                          
      char *filename = NULL;                                                                   
      uint label_start, label_end, value_start, value_end, span_start, span_end;
      HV *span_hash;
    CODE:
      ret = aug_span(aug, path, amp;filename, amp;label_start, amp;label_end, amp;value_start, amp;value_end, amp;span_start, amp;span_end);
      span_hash = newHV();
      hv_store(span_hash, "filename", 8, newSVpv(filename, strlen(filename)), 0);
      hv_store(span_hash, "label_start", 11, newSViv(label_start), 0);
      hv_store(span_hash, "label_end", 9, newSViv(label_end), 0);
      hv_store(span_hash, "value_start", 11, newSViv(value_start), 0);
      hv_store(span_hash, "value_end", 9, newSViv(value_end), 0);     
      hv_store(span_hash, "span_start", 10, newSViv(span_start), 0);
      hv_store(span_hash, "span_end", 8, newSViv(span_end), 0);
      RETVAL = sv_2mortal((SV*)newRV_noinc((SV *)span_hash));
    OUTPUT:
      RETVAL
  

Изменения: возвращаемый тип (void => SV *), и я использую sv_2mortal для возвращаемого SV *. Поскольку в стеке не учитываются ссылки, необходимо пометить SV * для уничтожения при следующей «подходящей» возможности.

Ответ №2:

Ваша функция имеет тип void , когда она должна быть an SV * . Смотрите Этот раздел perlxs .

Комментарии:

1. Сейчас он компилируется, но при его использовании происходит сброс ядра:'(

2. Оказывается, дамп ядра пришел откуда-то еще.