如何从Sage调用C代码(或编译后的库)?

如果您有一些C/C++代码想要从Sage调用以供自己使用,本文档适合您。

  • 你想不想 contribute 通过将您的接口添加到Sage的代码?(更复杂的)指令是 available here

从hello.c调用“Hello_world()”

假设您有一个名为 ~/my_dir/hello.c 包含:

#include <stdio.h>

void hello_world(){
    printf("Hello World\n");
}

为了从Sage调用此函数,您必须创建一个Cython文件(即扩展名为.pyx的文件)。这里, ~/my_dir/hello_sage.pyx 包含描述要调用的函数的签名的标头:

cdef extern from "hello.c":
    void hello_world()

def my_bridge_function():
    hello_world() # This is the C function from hello.c

现在,您可以在Sage中加载该文件,并通过Python函数调用C代码 my_bridge_function **

sage: %runfile hello_sage.pyx
Compiling ./hello_sage.pyx...
sage: my_bridge_function()
Hello World

参数和返回值

使用更复杂的参数和返回值调用函数的工作方式与此相同。要了解更多关于Cython语言的信息, click here

下面的示例定义了一个获取和返回的函数 int * 指针,并涉及到一些内存分配。C代码定义了一个函数,其目的是返回两个向量之和作为第三个向量。

The C file (double_vector.c)

#include <string.h>

int * sum_of_two_vectors(int n, int * vec1, int * vec2){
  /*
     INPUT : two arrays vec1,vec2 of n integers
     OUTPUT: an array of size n equal to vec1+vec2
  */
  int * sum = (int *) malloc(n*sizeof(int));
  int i;

  for(i=0;i<n;i++)
    sum[i] = vec1[i] + vec2[i];
  return sum;
}

The Cython file (double_vector_sage.pyx)

cdef extern from "double_vector.c":
    int * sum_of_two_vectors(int n, int * vec1, int * vec2)

from libc.stdlib cimport malloc, free

def sage_sum_of_vectors(n, list1, list2):
    cdef int * vec1 = <int *> malloc(n*sizeof(int))
    cdef int * vec2 = <int *> malloc(n*sizeof(int))

    # Fill the vectors
    for i in range(n):
        vec1[i] = list1[i]
        vec2[i] = list2[i]

    # Call the C function
    cdef int * vec3 = sum_of_two_vectors(n,vec1,vec2)

    # Save the answer in a Python object
    answer = [vec3[i] for i in range(n)]

    free(vec1)
    free(vec2)
    free(vec3)

    return answer

Call from Sage **

sage: %runfile double_vector_sage.pyx
Compiling ./double_vector_sage.pyx...
sage: sage_sum_of_vectors(3,[1,1,1],[2,3,4])
[3, 4, 5]

从已编译的库中调用代码

程序又一次非常相似。出于我们的目的,我们从该文件构建一个库 ~/my_dir/hello.c

 #include <stdio.h>

 void hello_world(){
     printf("Hello World\n");
}

我们还需要一个 ~/my_dir/hello.h 头文件:

void hello_world();

我们现在可以 compile it 作为类库:

[user@localhost ~/my_dir/] gcc -c -Wall -Werror -fpic hello.c
[user@localhost ~/my_dir/] gcc -shared -o libhello.so hello.o

我们现在唯一需要的文件是 hello.hlibhello.so (如果愿意,您可以删除其他组件)。我们现在必须指出 .so.h 我们的标题中的文件 ~/my_dir/hello_sage.pyx 文件:

# distutils: libraries = /home/username/my_dir/hello

cdef extern from "hello.h":
    void hello_world()

def my_bridge_function():
    hello_world() # This is the C function from hello.c

备注

说明书 # distutils: libraries = /home/username/my_dir/hello 指示库实际命名为 /home/username/my_dir/hello 。根据您的需要进行更改。有关这些说明的更多信息,请参阅http://cython.readthedocs.io/en/latest/src/reference/compilation.html#configuring-the-c-build

我们现在可以 load 此文件位于Sage和 call 功能::

sage: %runfile hello_sage.pyx
Compiling ./hello_sage.pyx...
sage: my_bridge_function()
Hello World