Совместное использование глобальных переменных в нескольких модулях Cython - PullRequest
0 голосов
/ 15 мая 2018

Я хочу обернуть динамически связанную библиотеку c, с которой связаны все модули Cython.Проблема в том, что я получаю ошибку сегментации.Я читал, что переменные, которые выставляются для Cython через выражение extern, не одинаковы для каждого модуля.Например, вы не можете манипулировать int в одном модуле и видеть измененный int в другом модуле.Я думаю, что это причина моих ошибок сегментации.

Вот мой реальный пример:

Получите репозиторий jrtk под https://bitbucket.org/stueker/jrtk/src/master/. Я ссылаюсь на созданную библиотекукогда вы строите проект с помощью следующих команд терминала:

mkdir build
cmake ..
make

Я поместил следующие файлы в папку рядом с репозиторием.

setup.py :

from distutils.core import setup
from Cython.Build import cythonize
from distutils.extension import Extension
import os
import shutil
import subprocess
import sys


def find_tcl():
    build_path = "build"
    try:
        os.mkdir(build_path)
    except FileExistsError:
        print("build already exists")

    cmake_cache = "CMakeCache.txt"
    tcl_include = "TCL_INCLUDE_PATH"
    separator = ":PATH="

    if sys.platform.startswith('win'):
        shell = True
    else:
        shell = False
    cmake_cmd = ["cmake", ".."]

    print("################### Calling CMAKE ###################")
    retCode = subprocess.check_call(cmake_cmd, cwd=build_path, stderr=subprocess.STDOUT, shell=shell)
    print("################### CMAKE returned ###################")

    text = open(os.path.join(build_path, cmake_cache)).read()
    start = text.find(tcl_include)

    include_path = text[start:text.find(os.linesep, start)]
    return include_path.replace(tcl_include, "").replace(separator, "").strip()

jrtk_root = "/home/simon/janus/jrtk"

def declare_cython_extensions(source_path):
    libs = ["janus"]
    lib_dirs = [jrtk_root + os.path.sep + "build"]

    postfix = "/include"
    base_dir = jrtk_root + os.path.sep + "source"
    (path, dirs, _) = next(os.walk(base_dir))
    include_dirs = [os.path.join(path, d) + postfix for d in dirs]
    include_dirs.extend([base_dir, find_tcl()])

    extension_list = []
    for (path, folders, files) in os.walk(source_path):
        for f in files:
            if f.endswith(".pyx"):
                ext = Extension(f.replace(".pyx", ""),
                                [os.path.join(path, f)],
                                libraries=libs,
                                library_dirs=lib_dirs,
                                include_dirs=include_dirs,
                                define_macros=[("DISABLE_TK", None),
                                               ("DISABLE_READLINE", None),
                                               # In TCL8.6 deprecated and needs this flag to activate
                                               ("USE_INTERP_ERRORLINE", None)]
                                )
                extension_list.append(ext)

    return extension_list


extensions = declare_cython_extensions(".")
ext_modules = cythonize(extensions)

setup(
  name='Global setup',
  ext_modules=ext_modules
)

CMakeLists.txt :

cmake_minimum_required( VERSION 3.5 )

project( JRTK_CYTHON )

set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_LIST_DIR}/cmake )

set ( INCLUDE_DIRECTORIES "")

find_package(TCL 8.5  REQUIRED)
list(APPEND INCLUDE_DIRECTORIES "${TCL_INCLUDE_PATH}")

itfMain.pyx : Tcl_Interp является структурой, а interp является глобальным указателемк такой структуре.

from c_itfMain cimport Tcl_Interp, Itf_Lib_Init, interp, ClientData

cdef extern from "../jrtk/source/itf/include/itf/itf.h":
    ctypedef struct TypeInfo:
        pass

cdef extern from "../jrtk/source/itf/source/itf.c":
     cdef int itfCreate(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])


cdef extern from "../jrtk/source/models/source/tags.c":
    TypeInfo tagsInfo


def jrtk_Init():
    rv = Itf_Lib_Init(0, NULL)

def tagsTest():
    print("Hello")
    print(interp.errorLine)
    rv = itfCreate(&tagsInfo, interp, 2, ["Tags", "tagTest"])

itf.pyx :

from c_itfMain cimport Itf_Lib_Init

def jrtk_Init():
    rv = Itf_Lib_Init(0, NULL)

c_itfMain.pxd :

cdef extern from "../jrtk/source/itf/source/itfMain.c":
    cdef int Itf_Lib_Init(int argc, char ** argv)
    cdef Tcl_Interp *interp

cdef extern from "../jrtk/source/itf/include/itf/itf.h":
    ctypedef void*ClientData

cdef extern from "/usr/include/tcl.h":
    cdef struct Tcl_Interp:
        char *result
        void (*freeProc)(char *blockPtr)
        int errorLine

Я скомпилировал этот код Cython с помощью: python3 setup.py build_ext --inplace

test.py :

import itfMain
import itf

itf.jrtk_Init()
itfMain.tagsTest()

Этот скрипт завершится ошибкой со следующим выводом:

# ===========================================================================
#  ____  ____  _____ _
# |__  ||  _ \|_   _| |
#    | || |_| | | | | |/ |       V6.0.0, n/a
#    | ||  _ <  | | |   <   ------------------------------------------------
#    | ||_| |_| |_| |_|\_|    Karlsruhe Institute of Technology, Germany
#   _| | JANUS Recognition        Carnegie Mellon University, USA
#  \__/        Toolkit
#                              (c) 1993-2017
# ===========================================================================
started library: on desktop.3573, Di 15. Mai 21:18:24 CEST 2018
Janus Binary: 
using lib: ./lib
using lib: /home/simon/janus/janus_lt/gui-tcl
using lib: /home/simon/janus/janus_lt/tcl-lib
using lib: /usr/lib
using lib: /usr/lib/tcltk
using lib: /usr/lib/tcltk/tcl8.6
using lib: /usr/lib/tcltk/x86_64-linux-gnu
using lib: /usr/local/lib/tcltk
using lib: /usr/local/share/tcltk
using lib: /usr/share/tcltk
using lib: /usr/share/tcltk/tcl8.6
using env: TCL_LIBRARY=/usr/lib/tcl8.6
using env: JANUS_LIBRARY=/home/simon/janus/jrtk/library
INFO : Using doParallelServer function
INFO : This machine (desktop) is running Linux 4.13.0-41-generic (x86_64) with Tcl 8.6
executing library 
# ============================= {Main Program} ==============================

Hello
Segmentation fault (core dumped)

Если вы измените значение itf.jrtk_Init() на itfMain.jrtk_Init(), то ошибки сегментации не произойдет.В моей голове есть эта библиотека с ее функциями и глобальной переменной, которые имеют одинаковое значение из каждого модуля.Если один модуль инициирует изменение одного var, все модули будут знать.Я должен ошибаться с этим предположением, но что происходит и как исправить / обойти это?

Небольшой побочный вопрос.Есть ли разница между TypeInfo tagsInfo и cdef TypeInfo tagsInfo в файле pxd?

Я думаю, что у меня есть похожая проблема, как у этого парня (https://groups.google.com/forum/#!topic/cython-users/GAAPYb2X304),, но у меня уже есть динамически связанная библиотека.

...