94415


RubyのメソッドをCで定義しようとしたところ、下記のエラーが発生しました。  
こちらのエラーが発生する原因と解消方法が知りたいです。

[code]

    $ rake compile 
    cd tmp/x86_64-linux/mandoc/2.7.7
    /home/gemmaro/.guix-profile/bin/make
    compiling ../../../../ext/mandoc/mandoc.c
    ../../../../ext/mandoc/mandoc.c: In function ‘rb_mparse_initialize’:
    ../../../../ext/mandoc/mandoc.c:28:57: error: type of formal parameter 2 is incomplete
       28 |   struct mparse* parse = mparse_alloc(NUM2INT(options), (enum mandoc_os)(NUM2INT(oe_e)), StringValueCStr(os_s));
          |                                                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    make: *** [Makefile:245: mandoc.o] Error 1
    rake aborted!
    Command failed with status (2): [/home/gemmaro/.guix-profile/bin/make...]
    /gnu/store/...-ruby-rake-compiler-1.1.1/lib/ruby/vendor_ruby/gems/rake-compiler-1.1.1/lib/rake/extensiontask.rb:167:in `block (2 levels) in define_compile_tasks'
    /gnu/store/...-ruby-rake-compiler-1.1.1/lib/ruby/vendor_ruby/gems/rake-compiler-1.1.1/lib/rake/extensiontask.rb:166:in `block in define_compile_tasks'
    Tasks: TOP => compile => compile:x86_64-linux => compile:mandoc:x86_64-linux => copy:mandoc:x86_64-linux:2.7.7 => tmp/x86_64-linux/mandoc/2.7.7/mandoc.so
    (See full trace by running task with --trace)
    
[/code]

※`/gnu/store/<ハッシュ値>`のハッシュ値は冗長のため`...`としました。

背景として、Rubyで[libmandoc](https://mandoc.bsd.lv/man/mandoc.3.html)のC拡張ライブラリを書こうとしており、現在`mparse_alloc`関数をRubyのメソッド用に定義しようとしています（対応するメソッドは`Mandoc::Mparse#initialize`）。  
`mparse_alloc`関数のシグネチャを以下に示します。

[code]

    struct mparse *
    mparse_alloc(int options, enum mandoc_os oe_e, char *os_s);
    
[/code]

ここで第2引数の型`mandoc_os`は`roff.h`に定義されており、以下の定義となっています。

>
[code]

>     enum  mandoc_os {
>       MANDOC_OS_OTHER = 0,
>       MANDOC_OS_NETBSD,
>       MANDOC_OS_OPENBSD
>     };
>  
[/code]

作成中の`ext/mandoc/mandoc.c`を以下に示します。  
このように、列挙型の値を期待している関数の呼び出しでその列挙型の値を使ったときに今回のエラー（`rb_mparse_initialize`関数内部の1行目）が発生していることがわかります。

[code]

    #include <ruby.h>
    #include <mandoc.h>
    #include <mandoc_parse.h>
    #include <roff.h>
    
    void rb_mparse_free(void* data)
    {
      mparse_free((struct mparse*)data);
      free(data);
    }
    
    static const rb_data_type_t mparse_type = {
      .wrap_struct_name = "mparse",
      .function = {
        .dfree = rb_mparse_free,
      },
      .flags = RUBY_TYPED_FREE_IMMEDIATELY,
    };
    
    VALUE rb_mparse_alloc(VALUE self)
    {
      struct mparse* data = malloc(sizeof(struct mparse*));
      return TypedData_Wrap_Struct(self, &mparse_type, data);
    }
    
    VALUE rb_mparse_initialize(VALUE self, VALUE options, VALUE oe_e, VALUE os_s)
    {
      struct mparse* parse = mparse_alloc(NUM2INT(options), (enum mandoc_os)(NUM2INT(oe_e)), StringValueCStr(os_s));
      DATA_PTR(self) = parse;
      return self;
    }
    
    void Init_mandoc(void)
    {
      VALUE mMandoc = rb_define_module("Mandoc");
    
      VALUE cMparse = rb_define_class_under(mMandoc, "Mparse", rb_cObject);
      rb_define_alloc_func(cMparse, rb_mparse_alloc);
      rb_define_method(cMparse, "initialize", rb_mparse_initialize, 3);
    }
    
[/code]

なお、エラーメッセージで検索したところ[stack overflow > How to fix "type of formal parameter 1 is
incomplete" in
C](https://stackoverflow.com/q/45423191)やこれに類する質問がありましたが、今回の場合は要素数が不定になりうる配列とは状況が違うように思われました。

試したこととして、実際にmandocで`mparse_alloc`関数が使用されているところを参考に第2引数を定数 (`MANDOC_OS_OTHER`)
に置き換えましたが、同一のエラーが発生しました。  
以下に`cgi.c`からの抜粋を示します。

>
[code]

>       mp = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1 |
>           MPARSE_VALIDATE, MANDOC_OS_OTHER, req->q.manpath);
>  
[/code]

バージョンは以下です。  
mandocのバージョンは1.14.6です。

[code]

    $ ruby --version 
    ruby 2.7.7p221 (2022-11-24 revision 168ec2b1e5) [x86_64-linux]
    
    $ gcc --version 
    gcc (GCC) 12.2.0
    Copyright (C) 2022 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.  There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    
[/code]

※上記で引用したコード片は[mandoc](https://mandoc.bsd.lv/)のISCライセンスにしたがいます。


CC BY-SA 4.0
2023-04-03T15:01:15.593
94408
2023-04-04T12:58:32.267
57802
question
ruby c
RubyのC拡張でメソッドを定義するとコンパイル時にエラー「error: type of formal parameter 2 is incomplete」が出る


試せる環境が手元に無いので推測ですが、ヘッダーファイルのインクルード順を変更するとコンパイルできないでしょうか。

[code]

    #include <roff.h> // enum mandoc_osが定義されているこれを<mandoc_parse.h>より前に持ってくる
    #include <mandoc.h>
    #include <mandoc_parse.h> // mparse_allocのプロトタイプ宣言が書かれている
    
[/code]

ネットで調べた範囲だと、`enum
mandoc_os`を前方宣言または定義する前に`mparse_alloc`のプロトタイプ宣言が書かれてしまって、警告`'enum mandoc_os'
declared inside parameter list will not be visible outside of this definition
or declaration`が出る状況なのではないかと推測します。

`error: type of formal parameter 2 is incomplete`の日本語訳：  
`エラー: 正式な 2 番目の仮引数の型が不完全です`


CC BY-SA 4.0
2023-04-04T12:52:24.157
94415
2023-04-04T12:58:32.267
2023-04-04T12:58:32.267
7291
7291
94408
answer