31641


CからPython3の関数を呼び出そうとしていますがうまくコンパイルできません  
pycall.cからpycall.pyのHiという関数を呼び出そうとしてしているのですが、リンクが失敗しているように見えます

どうすればいいのでしょうか?

コンパイル時のコマンド

[code]

    clang -I`python3-config --prefix`/Headers -o pycall pycall.c
    
[/code]

エラーメッセージ

[code]

    pycall.c:4:36: warning: implicit declaration of function 'PyString_FromString' is invalid in C99 [-Wimplicit-function-declaration]
        PyObject *pycallModuleString = PyString_FromString((char*)"pycall");
                                       ^
    pycall.c:4:15: warning: incompatible integer to pointer conversion initializing 'PyObject *' (aka 'struct _object *') with an expression of type 'int' [-Wint-conversion]
        PyObject *pycallModuleString = PyString_FromString((char*)"pycall");
                  ^                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    2 warnings generated.
    Undefined symbols for architecture x86_64:
      "_PyFloat_AsDouble", referenced from:
          _main in pycall-4fd2bb.o
      "_PyImport_Import", referenced from:
          _main in pycall-4fd2bb.o
      "_PyObject_CallObject", referenced from:
          _main in pycall-4fd2bb.o
      "_PyObject_GetAttrString", referenced from:
          _main in pycall-4fd2bb.o
      "_PyString_FromString", referenced from:
          _main in pycall-4fd2bb.o
      "_Py_BuildValue", referenced from:
          _main in pycall-4fd2bb.o
    ld: symbol(s) not found for architecture x86_64
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    
[/code]

pycall.c

[code]

    #include <Python.h>
    
    int main() {
        PyObject *pycallModuleString = PyString_FromString((char*)"pycall");
        PyObject *pycallModule = PyImport_Import(pycallModuleString);
    
        PyObject *HiFunction = PyObject_GetAttrString(pycallModule, (char*)"Hi");
        PyObject *args = Py_BuildValue("()");
        PyObject *myResult = PyObject_CallObject(HiFunction, args);
        double result = PyFloat_AsDouble(myResult);
        printf("%f\n", result);
    }
    
[/code]

pycall.py

[code]

    def Hi():
        print("Hi! I am Python3.6")
        return 3.6
    
[/code]


CC BY-SA 3.0
2017-01-04T14:47:02.553
31620
2017-01-05T14:02:36.427
5246
question
c python3
C言語からPython3で作った関数を呼び出せない


>
[code]

>     pycall.c:4:36: warning: implicit declaration of function
> 'PyString_FromString' is invalid in C99 [-Wimplicit-function-declaration]
>         PyObject *pycallModuleString = PyString_FromString((char*)"pycall");
>  
[/code]

C++言語と異なりC言語では宣言されていない関数の使用を認めているため、警告に留められていますが、当然ながら存在しない関数ですので呼び出すことができません。

[Python 3 への拡張モジュール移植 / オブジェクト API の変更 / str/unicode
の統合](http://docs.python.jp/3/howto/cporting.html#str-unicode-
unification)によると`PyString_*`系APIは`PyUnicode_*`系と`PyBytes_*`系に変更されています。  
適切に修正する必要があります。


CC BY-SA 3.0
2017-01-04T22:41:56.930
31625
2017-01-05T08:51:08.953
2017-01-05T08:51:08.953
49
4236
31620
answer


気付いた点は以下です。

  * 最初に `Py_Initialize()` を実行(python interpreter を初期化)する
  * Python 側の import path(`sys.path` 変数) に `pycall.py` があるディレクトリパスを追加
  * パス名を python object に変換する場合は `PyUnicode_DecodeFSDefault()` を使用

以下では `pycall.py` と `pycall` が同じディレクトリに置かれていて、そのディレクトリで `pycall` を実行するものとしています。

**pycall.c**

[code]

    #include <Python.h>
    
    int main() {
      Py_Initialize();
    
      /* PYTHONPATH を使用する場合は不要 */
      PyObject* sysPath = PySys_GetObject("path");
      PyObject* dir = PyUnicode_DecodeFSDefault(".");
      PyList_Append(sysPath, dir);
      /* ここまで */
    
      PyObject *pycallModuleString = PyUnicode_DecodeFSDefault("pycall");
      PyObject *pycallModule = PyImport_Import(pycallModuleString);
    
      PyObject *HiFunction = PyObject_GetAttrString(pycallModule, "Hi");
      PyObject *args = Py_BuildValue("()");
      PyObject *myResult = PyObject_CallObject(HiFunction, args);
      double result = PyFloat_AsDouble(myResult);
      printf("%f\n", result);
    }
    
    $ ls
    pycall.c pycall.py
    
    # こちらの環境には clang がインストールされていないので gcc を使います
    $ gcc $(python3-config --includes) -o pycall pycall.c $(python3-config --ldflags)
    $ ./pycall
    Hi! I am Python3.6
    3.600000
    
[/code]

`sys.path` に `.`(current directory)を追加していますが、環境変数 `PYTHONPATH` に `pycall.py`
のディレクトリパスを指定して実行する場合には不要になります。例えば、以下の様に指定して実行します。

[code]

    $ PYTHONPATH='.' ./pycall
    Hi! I am Python3.6
    3.600000
    
[/code]


CC BY-SA 3.0
2017-01-05T14:02:36.427
31641
2017-01-05T14:02:36.427
31620
answer