Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cython
Commits
20ff6c2a
Commit
20ff6c2a
authored
Nov 24, 2017
by
Stefan Behnel
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of
git+ssh://github.com/cython/cython
parents
32290bf8
8ccdda6d
Changes
16
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
389 additions
and
64 deletions
+389
-64
CHANGES.rst
CHANGES.rst
+3
-0
Cython/Compiler/Code.py
Cython/Compiler/Code.py
+76
-0
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+46
-5
Cython/Compiler/ModuleNode.py
Cython/Compiler/ModuleNode.py
+14
-20
Cython/Compiler/Nodes.py
Cython/Compiler/Nodes.py
+11
-12
Cython/Compiler/Parsing.py
Cython/Compiler/Parsing.py
+5
-1
Cython/Compiler/Symtab.py
Cython/Compiler/Symtab.py
+45
-21
docs/src/userguide/external_C_code.rst
docs/src/userguide/external_C_code.rst
+35
-0
tests/compile/cnamespec.h
tests/compile/cnamespec.h
+0
-1
tests/compile/cnamespec.pyx
tests/compile/cnamespec.pyx
+4
-1
tests/compile/verbatiminclude_cimport.srctree
tests/compile/verbatiminclude_cimport.srctree
+36
-0
tests/memoryview/memoryview.pyx
tests/memoryview/memoryview.pyx
+44
-0
tests/run/for_from_pyvar_loop_T601.pyx
tests/run/for_from_pyvar_loop_T601.pyx
+2
-1
tests/run/for_from_pyvar_loop_T601_extern_def.h
tests/run/for_from_pyvar_loop_T601_extern_def.h
+0
-2
tests/run/verbatiminclude.h
tests/run/verbatiminclude.h
+6
-0
tests/run/verbatiminclude.pyx
tests/run/verbatiminclude.pyx
+62
-0
No files found.
CHANGES.rst
View file @
20ff6c2a
...
@@ -36,6 +36,9 @@ Features added
...
@@ -36,6 +36,9 @@ Features added
* Some PEP-484/526 container type declarations are now considered for
* Some PEP-484/526 container type declarations are now considered for
loop optimisations.
loop optimisations.
* Indexing into memoryview slices with ``view[i][j]`` is now optimised into
``view[i, j]``.
* Python compatible ``cython.*`` types can now be mixed with type declarations
* Python compatible ``cython.*`` types can now be mixed with type declarations
in Cython syntax.
in Cython syntax.
...
...
Cython/Compiler/Code.py
View file @
20ff6c2a
...
@@ -80,6 +80,82 @@ modifier_output_mapper = {
...
@@ -80,6 +80,82 @@ modifier_output_mapper = {
is_self_assignment
=
re
.
compile
(
r" *(\
w+) = (
\1);\
s*$
").match
is_self_assignment
=
re
.
compile
(
r" *(\
w+) = (
\1);\
s*$
").match
class IncludeCode(object):
"""
An include file and/or verbatim C code to be included in the
generated sources.
"""
# attributes:
#
# pieces {order: unicode}: pieces of C code to be generated.
# For the included file, the key "
order
" is zero.
# For verbatim include code, the "
order
" is the "
order
"
# attribute of the original IncludeCode where this piece
# of C code was first added. This is needed to prevent
# duplication if the same include code is found through
# multiple cimports.
# location int: where to put this include in the C sources, one
# of the constants INITIAL, EARLY, LATE
# order int: sorting order (automatically set by increasing counter)
# Constants for location. If the same include occurs with different
# locations, the earliest one takes precedense.
INITIAL = 0
EARLY = 1
LATE = 2
counter = 1 # Counter for "
order
"
def __init__(self, include=None, verbatim=None, late=True, initial=False):
self.order = self.counter
type(self).counter += 1
self.pieces = {}
if include:
if include[0] == '<' and include[-1] == '>':
self.pieces[0] = u'#include {0}'.format(include)
late = False # system include is never late
else:
self.pieces[0] = u'#include "
{
0
}
"'.format(include)
if verbatim:
self.pieces[self.order] = verbatim
if initial:
self.location = self.INITIAL
elif late:
self.location = self.LATE
else:
self.location = self.EARLY
def dict_update(self, d, key):
"""
Insert `self` in dict `d` with key `key`. If that key already
exists, update the attributes of the existing value with `self`.
"""
if key in d:
other = d[key]
other.location = min(self.location, other.location)
other.pieces.update(self.pieces)
else:
d[key] = self
def sortkey(self):
return self.order
def mainpiece(self):
"""
Return the main piece of C code, corresponding to the include
file. If there was no include file, return None.
"""
return self.pieces.get(0)
def write(self, code):
# Write values of self.pieces dict, sorted by the keys
for k in sorted(self.pieces):
code.putln(self.pieces[k])
def get_utility_dir():
def get_utility_dir():
# make this a function and not global variables:
# make this a function and not global variables:
# http://trac.cython.org/cython_trac/ticket/475
# http://trac.cython.org/cython_trac/ticket/475
...
...
Cython/Compiler/ExprNodes.py
View file @
20ff6c2a
...
@@ -3690,23 +3690,33 @@ class IndexNode(_IndexingBaseNode):
...
@@ -3690,23 +3690,33 @@ class IndexNode(_IndexingBaseNode):
else
:
else
:
indices
=
[
self
.
index
]
indices
=
[
self
.
index
]
base_type
=
self
.
base
.
type
base
=
self
.
base
base_type
=
base
.
type
replacement_node
=
None
replacement_node
=
None
if
base_type
.
is_memoryviewslice
:
if
base_type
.
is_memoryviewslice
:
# memoryviewslice indexing or slicing
# memoryviewslice indexing or slicing
from
.
import
MemoryView
from
.
import
MemoryView
if
base
.
is_memview_slice
:
# For memory views, "view[i][j]" is the same as "view[i, j]" => use the latter for speed.
merged_indices
=
base
.
merged_indices
(
indices
)
if
merged_indices
is
not
None
:
base
=
base
.
base
base_type
=
base
.
type
indices
=
merged_indices
have_slices
,
indices
,
newaxes
=
MemoryView
.
unellipsify
(
indices
,
base_type
.
ndim
)
have_slices
,
indices
,
newaxes
=
MemoryView
.
unellipsify
(
indices
,
base_type
.
ndim
)
if
have_slices
:
if
have_slices
:
replacement_node
=
MemoryViewSliceNode
(
self
.
pos
,
indices
=
indices
,
base
=
self
.
base
)
replacement_node
=
MemoryViewSliceNode
(
self
.
pos
,
indices
=
indices
,
base
=
base
)
else
:
else
:
replacement_node
=
MemoryViewIndexNode
(
self
.
pos
,
indices
=
indices
,
base
=
self
.
base
)
replacement_node
=
MemoryViewIndexNode
(
self
.
pos
,
indices
=
indices
,
base
=
base
)
elif
base_type
.
is_buffer
or
base_type
.
is_pythran_expr
:
elif
base_type
.
is_buffer
or
base_type
.
is_pythran_expr
:
if
base_type
.
is_pythran_expr
or
len
(
indices
)
==
base_type
.
ndim
:
if
base_type
.
is_pythran_expr
or
len
(
indices
)
==
base_type
.
ndim
:
# Buffer indexing
# Buffer indexing
is_buffer_access
=
True
is_buffer_access
=
True
indices
=
[
index
.
analyse_types
(
env
)
for
index
in
indices
]
indices
=
[
index
.
analyse_types
(
env
)
for
index
in
indices
]
if
base_type
.
is_pythran_expr
:
if
base_type
.
is_pythran_expr
:
do_replacement
=
all
(
index
.
type
.
is_int
or
index
.
is_slice
or
index
.
type
.
is_pythran_expr
for
index
in
indices
)
do_replacement
=
all
(
index
.
type
.
is_int
or
index
.
is_slice
or
index
.
type
.
is_pythran_expr
for
index
in
indices
)
if
do_replacement
:
if
do_replacement
:
for
i
,
index
in
enumerate
(
indices
):
for
i
,
index
in
enumerate
(
indices
):
if
index
.
is_slice
:
if
index
.
is_slice
:
...
@@ -3716,7 +3726,7 @@ class IndexNode(_IndexingBaseNode):
...
@@ -3716,7 +3726,7 @@ class IndexNode(_IndexingBaseNode):
else
:
else
:
do_replacement
=
all
(
index
.
type
.
is_int
for
index
in
indices
)
do_replacement
=
all
(
index
.
type
.
is_int
for
index
in
indices
)
if
do_replacement
:
if
do_replacement
:
replacement_node
=
BufferIndexNode
(
self
.
pos
,
indices
=
indices
,
base
=
self
.
base
)
replacement_node
=
BufferIndexNode
(
self
.
pos
,
indices
=
indices
,
base
=
base
)
# On cloning, indices is cloned. Otherwise, unpack index into indices.
# On cloning, indices is cloned. Otherwise, unpack index into indices.
assert
not
isinstance
(
self
.
index
,
CloneNode
)
assert
not
isinstance
(
self
.
index
,
CloneNode
)
...
@@ -4425,6 +4435,37 @@ class MemoryViewSliceNode(MemoryViewIndexNode):
...
@@ -4425,6 +4435,37 @@ class MemoryViewSliceNode(MemoryViewIndexNode):
else
:
else
:
return
MemoryCopySlice
(
self
.
pos
,
self
)
return
MemoryCopySlice
(
self
.
pos
,
self
)
def
merged_indices
(
self
,
indices
):
"""Return a new list of indices/slices with 'indices' merged into the current ones
according to slicing rules.
Is used to implement "view[i][j]" => "view[i, j]".
Return None if the indices cannot (easily) be merged at compile time.
"""
if
not
indices
:
return
None
# NOTE: Need to evaluate "self.original_indices" here as they might differ from "self.indices".
new_indices
=
self
.
original_indices
[:]
indices
=
indices
[:]
for
i
,
s
in
enumerate
(
self
.
original_indices
):
if
s
.
is_slice
:
if
s
.
start
.
is_none
and
s
.
stop
.
is_none
and
s
.
step
.
is_none
:
# Full slice found, replace by index.
new_indices
[
i
]
=
indices
[
0
]
indices
.
pop
(
0
)
if
not
indices
:
return
new_indices
else
:
# Found something non-trivial, e.g. a partial slice.
return
None
elif
not
s
.
type
.
is_int
:
# Not a slice, not an integer index => could be anything...
return
None
if
indices
:
if
len
(
new_indices
)
+
len
(
indices
)
>
self
.
base
.
type
.
ndim
:
return
None
new_indices
+=
indices
return
new_indices
def
is_simple
(
self
):
def
is_simple
(
self
):
if
self
.
is_ellipsis_noop
:
if
self
.
is_ellipsis_noop
:
# TODO: fix SimpleCallNode.is_simple()
# TODO: fix SimpleCallNode.is_simple()
...
...
Cython/Compiler/ModuleNode.py
View file @
20ff6c2a
...
@@ -28,7 +28,7 @@ from . import Pythran
...
@@ -28,7 +28,7 @@ from . import Pythran
from
.Errors
import
error
,
warning
from
.Errors
import
error
,
warning
from
.PyrexTypes
import
py_object_type
from
.PyrexTypes
import
py_object_type
from
..Utils
import
open_new_file
,
replace_suffix
,
decode_filename
from
..Utils
import
open_new_file
,
replace_suffix
,
decode_filename
from
.Code
import
UtilityCode
from
.Code
import
UtilityCode
,
IncludeCode
from
.StringEncoding
import
EncodedString
from
.StringEncoding
import
EncodedString
from
.Pythran
import
has_np_pythran
from
.Pythran
import
has_np_pythran
...
@@ -86,16 +86,15 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
...
@@ -86,16 +86,15 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
self
.
scope
.
utility_code_list
.
extend
(
scope
.
utility_code_list
)
self
.
scope
.
utility_code_list
.
extend
(
scope
.
utility_code_list
)
for
inc
in
scope
.
c_includes
.
values
():
self
.
scope
.
process_include
(
inc
)
def
extend_if_not_in
(
L1
,
L2
):
def
extend_if_not_in
(
L1
,
L2
):
for
x
in
L2
:
for
x
in
L2
:
if
x
not
in
L1
:
if
x
not
in
L1
:
L1
.
append
(
x
)
L1
.
append
(
x
)
extend_if_not_in
(
self
.
scope
.
include_files_early
,
scope
.
include_files_early
)
extend_if_not_in
(
self
.
scope
.
include_files_late
,
scope
.
include_files_late
)
extend_if_not_in
(
self
.
scope
.
included_files
,
scope
.
included_files
)
extend_if_not_in
(
self
.
scope
.
included_files
,
scope
.
included_files
)
extend_if_not_in
(
self
.
scope
.
python_include_files
,
scope
.
python_include_files
)
if
merge_scope
:
if
merge_scope
:
# Ensure that we don't generate import code for these entries!
# Ensure that we don't generate import code for these entries!
...
@@ -621,8 +620,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
...
@@ -621,8 +620,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code
.
putln
(
""
)
code
.
putln
(
""
)
code
.
putln
(
"#define PY_SSIZE_T_CLEAN"
)
code
.
putln
(
"#define PY_SSIZE_T_CLEAN"
)
for
filename
in
env
.
python_include_files
:
for
inc
in
sorted
(
env
.
c_includes
.
values
(),
key
=
IncludeCode
.
sortkey
):
code
.
putln
(
'#include "%s"'
%
filename
)
if
inc
.
location
==
inc
.
INITIAL
:
inc
.
write
(
code
)
code
.
putln
(
"#ifndef Py_PYTHON_H"
)
code
.
putln
(
"#ifndef Py_PYTHON_H"
)
code
.
putln
(
" #error Python headers needed to compile C extensions, "
code
.
putln
(
" #error Python headers needed to compile C extensions, "
"please install development version of Python."
)
"please install development version of Python."
)
...
@@ -739,19 +739,13 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
...
@@ -739,19 +739,13 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
def
generate_includes
(
self
,
env
,
cimported_modules
,
code
,
early
=
True
,
late
=
True
):
def
generate_includes
(
self
,
env
,
cimported_modules
,
code
,
early
=
True
,
late
=
True
):
includes
=
[]
includes
=
[]
for
inc
in
sorted
(
env
.
c_includes
.
values
(),
key
=
IncludeCode
.
sortkey
):
if
inc
.
location
==
inc
.
EARLY
:
if
early
:
if
early
:
includes
+=
env
.
include_files_early
inc
.
write
(
code
)
elif
inc
.
location
==
inc
.
LATE
:
if
late
:
if
late
:
includes
+=
[
include
for
include
in
env
.
include_files_late
inc
.
write
(
code
)
if
include
not
in
env
.
include_files_early
]
for
filename
in
includes
:
byte_decoded_filenname
=
str
(
filename
)
if
byte_decoded_filenname
[
0
]
==
'<'
and
byte_decoded_filenname
[
-
1
]
==
'>'
:
code
.
putln
(
'#include %s'
%
byte_decoded_filenname
)
else
:
code
.
putln
(
'#include "%s"'
%
byte_decoded_filenname
)
if
early
:
if
early
:
code
.
putln_openmp
(
"#include <omp.h>"
)
code
.
putln_openmp
(
"#include <omp.h>"
)
...
...
Cython/Compiler/Nodes.py
View file @
20ff6c2a
...
@@ -471,6 +471,7 @@ class StatNode(Node):
...
@@ -471,6 +471,7 @@ class StatNode(Node):
class
CDefExternNode
(
StatNode
):
class
CDefExternNode
(
StatNode
):
# include_file string or None
# include_file string or None
# verbatim_include string or None
# body StatListNode
# body StatListNode
child_attrs
=
[
"body"
]
child_attrs
=
[
"body"
]
...
@@ -480,18 +481,16 @@ class CDefExternNode(StatNode):
...
@@ -480,18 +481,16 @@ class CDefExternNode(StatNode):
env
.
in_cinclude
=
1
env
.
in_cinclude
=
1
self
.
body
.
analyse_declarations
(
env
)
self
.
body
.
analyse_declarations
(
env
)
env
.
in_cinclude
=
old_cinclude_flag
env
.
in_cinclude
=
old_cinclude_flag
inc
=
self
.
include_file
if
inc
:
if
self
.
include_file
or
self
.
verbatim_include
:
# Determine whether include should be late
stats
=
self
.
body
.
stats
stats
=
self
.
body
.
stats
if
inc
[
0
]
==
'<'
and
inc
[
-
1
]
==
'>'
:
if
not
stats
:
# System include => always early
# Special case: empty 'cdef extern' blocks are early
env
.
add_include_file
(
inc
)
late
=
False
elif
stats
and
all
(
isinstance
(
node
,
CVarDefNode
)
for
node
in
stats
):
else
:
# Generate a late include if the body is not empty and
late
=
all
(
isinstance
(
node
,
CVarDefNode
)
for
node
in
stats
)
# all statements are variable or function declarations.
env
.
add_include_file
(
self
.
include_file
,
self
.
verbatim_include
,
late
)
env
.
add_include_file
(
inc
,
late
=
True
)
else
:
env
.
add_include_file
(
inc
)
def
analyse_expressions
(
self
,
env
):
def
analyse_expressions
(
self
,
env
):
return
self
return
self
...
...
Cython/Compiler/Parsing.py
View file @
20ff6c2a
...
@@ -3081,9 +3081,13 @@ def p_cdef_extern_block(s, pos, ctx):
...
@@ -3081,9 +3081,13 @@ def p_cdef_extern_block(s, pos, ctx):
ctx
.
namespace
=
p_string_literal
(
s
,
'u'
)[
2
]
ctx
.
namespace
=
p_string_literal
(
s
,
'u'
)[
2
]
if
p_nogil
(
s
):
if
p_nogil
(
s
):
ctx
.
nogil
=
1
ctx
.
nogil
=
1
body
=
p_suite
(
s
,
ctx
)
# Use "docstring" as verbatim string to include
verbatim_include
,
body
=
p_suite_with_docstring
(
s
,
ctx
,
True
)
return
Nodes
.
CDefExternNode
(
pos
,
return
Nodes
.
CDefExternNode
(
pos
,
include_file
=
include_file
,
include_file
=
include_file
,
verbatim_include
=
verbatim_include
,
body
=
body
,
body
=
body
,
namespace
=
ctx
.
namespace
)
namespace
=
ctx
.
namespace
)
...
...
Cython/Compiler/Symtab.py
View file @
20ff6c2a
...
@@ -1068,9 +1068,8 @@ class ModuleScope(Scope):
...
@@ -1068,9 +1068,8 @@ class ModuleScope(Scope):
# doc string Module doc string
# doc string Module doc string
# doc_cname string C name of module doc string
# doc_cname string C name of module doc string
# utility_code_list [UtilityCode] Queuing utility codes for forwarding to Code.py
# utility_code_list [UtilityCode] Queuing utility codes for forwarding to Code.py
# python_include_files [string] Standard Python headers to be included
# c_includes {key: IncludeCode} C headers or verbatim code to be generated
# include_files_early [string] C headers to be included before Cython decls
# See process_include() for more documentation
# include_files_late [string] C headers to be included after Cython decls
# string_to_entry {string : Entry} Map string const to entry
# string_to_entry {string : Entry} Map string const to entry
# identifier_to_entry {string : Entry} Map identifier string const to entry
# identifier_to_entry {string : Entry} Map identifier string const to entry
# context Context
# context Context
...
@@ -1113,9 +1112,7 @@ class ModuleScope(Scope):
...
@@ -1113,9 +1112,7 @@ class ModuleScope(Scope):
self
.
doc_cname
=
Naming
.
moddoc_cname
self
.
doc_cname
=
Naming
.
moddoc_cname
self
.
utility_code_list
=
[]
self
.
utility_code_list
=
[]
self
.
module_entries
=
{}
self
.
module_entries
=
{}
self
.
python_include_files
=
[
"Python.h"
]
self
.
c_includes
=
{}
self
.
include_files_early
=
[]
self
.
include_files_late
=
[]
self
.
type_names
=
dict
(
outer_scope
.
type_names
)
self
.
type_names
=
dict
(
outer_scope
.
type_names
)
self
.
pxd_file_loaded
=
0
self
.
pxd_file_loaded
=
0
self
.
cimported_modules
=
[]
self
.
cimported_modules
=
[]
...
@@ -1129,6 +1126,7 @@ class ModuleScope(Scope):
...
@@ -1129,6 +1126,7 @@ class ModuleScope(Scope):
for
var_name
in
[
'__builtins__'
,
'__name__'
,
'__file__'
,
'__doc__'
,
'__path__'
,
for
var_name
in
[
'__builtins__'
,
'__name__'
,
'__file__'
,
'__doc__'
,
'__path__'
,
'__spec__'
,
'__loader__'
,
'__package__'
,
'__cached__'
]:
'__spec__'
,
'__loader__'
,
'__package__'
,
'__cached__'
]:
self
.
declare_var
(
EncodedString
(
var_name
),
py_object_type
,
None
)
self
.
declare_var
(
EncodedString
(
var_name
),
py_object_type
,
None
)
self
.
process_include
(
Code
.
IncludeCode
(
"Python.h"
,
initial
=
True
))
def
qualifying_scope
(
self
):
def
qualifying_scope
(
self
):
return
self
.
parent_module
return
self
.
parent_module
...
@@ -1251,24 +1249,50 @@ class ModuleScope(Scope):
...
@@ -1251,24 +1249,50 @@ class ModuleScope(Scope):
module
=
module
.
lookup_submodule
(
submodule
)
module
=
module
.
lookup_submodule
(
submodule
)
return
module
return
module
def
add_include_file
(
self
,
filename
,
late
=
False
):
def
add_include_file
(
self
,
filename
,
verbatim_include
=
None
,
late
=
False
):
if
filename
in
self
.
python_include_files
:
"""
return
Add `filename` as include file. Add `verbatim_include` as
# Possibly, the same include appears both as early and as late
verbatim text in the C file.
# include. We'll deal with this at code generation time.
Both `filename` and `verbatim_include` can be `None` or empty.
if
late
:
"""
incs
=
self
.
include_files_late
inc
=
Code
.
IncludeCode
(
filename
,
verbatim_include
,
late
=
late
)
else
:
self
.
process_include
(
inc
)
incs
=
self
.
include_files_early
if
filename
not
in
incs
:
def
process_include
(
self
,
inc
):
incs
.
append
(
filename
)
"""
Add `inc`, which is an instance of `IncludeCode`, to this
`ModuleScope`. This either adds a new element to the
`c_includes` dict or it updates an existing entry.
In detail: the values of the dict `self.c_includes` are
instances of `IncludeCode` containing the code to be put in the
generated C file. The keys of the dict are needed to ensure
uniqueness in two ways: if an include file is specified in
multiple "cdef extern" blocks, only one `#include` statement is
generated. Second, the same include might occur multiple times
if we find it through multiple "cimport" paths. So we use the
generated code (of the form `#include "header.h"`) as dict key.
If verbatim code does not belong to any include file (i.e. it
was put in a `cdef extern from *` block), then we use a unique
dict key: namely, the `sortkey()`.
One `IncludeCode` object can contain multiple pieces of C code:
one optional "main piece" for the include file and several other
pieces for the verbatim code. The `IncludeCode.dict_update`
method merges the pieces of two different `IncludeCode` objects
if needed.
"""
key
=
inc
.
mainpiece
()
if
key
is
None
:
key
=
inc
.
sortkey
()
inc
.
dict_update
(
self
.
c_includes
,
key
)
inc
=
self
.
c_includes
[
key
]
def
add_imported_module
(
self
,
scope
):
def
add_imported_module
(
self
,
scope
):
if
scope
not
in
self
.
cimported_modules
:
if
scope
not
in
self
.
cimported_modules
:
for
filename
in
scope
.
include_files_early
:
for
inc
in
scope
.
c_includes
.
values
():
self
.
add_include_file
(
filename
,
late
=
False
)
self
.
process_include
(
inc
)
for
filename
in
scope
.
include_files_late
:
self
.
add_include_file
(
filename
,
late
=
True
)
self
.
cimported_modules
.
append
(
scope
)
self
.
cimported_modules
.
append
(
scope
)
for
m
in
scope
.
cimported_modules
:
for
m
in
scope
.
cimported_modules
:
self
.
add_imported_module
(
m
)
self
.
add_imported_module
(
m
)
...
...
docs/src/userguide/external_C_code.rst
View file @
20ff6c2a
...
@@ -328,6 +328,41 @@ are entirely on your own with this feature. If you want to declare a name
...
@@ -328,6 +328,41 @@ are entirely on your own with this feature. If you want to declare a name
the C file for it, you can do this using a C name declaration. Consider this
the C file for it, you can do this using a C name declaration. Consider this
an advanced feature, only for the rare cases where everything else fails.
an advanced feature, only for the rare cases where everything else fails.
Including verbatim C code
-------------------------
For advanced use cases, Cython allows you to directly write C code
as "docstring" of a ``cdef extern from`` block::
cdef extern from *:
"""
/* This is C code which will be put
* in the .c file output by Cython */
static long square(long x) {return x * x;}
#define assign(x, y) ((x) = (y))
"""
long square(long x)
void assign(long& x, long y)
The above is essentially equivalent to having the C code in a file
``header.h`` and writing ::
cdef extern from "header.h":
long square(long x)
void assign(long& x, long y)
It is also possible to combine a header file and verbatim C code::
cdef extern from "badheader.h":
"""
/* This macro breaks stuff */
#undef int
"""
# Stuff from badheader.h
In this case, the C code ``#undef int`` is put right after
``#include "badheader.h"`` in the C code generated by Cython.
Using Cython Declarations from C
Using Cython Declarations from C
================================
================================
...
...
tests/compile/cnamespec.h
deleted
100644 → 0
View file @
32290bf8
int
c_a
,
c_b
;
tests/compile/cnamespec.pyx
View file @
20ff6c2a
# mode: compile
# mode: compile
cdef
extern
from
"cnamespec.h"
:
cdef
extern
from
*
:
"""
int c_a, c_b;
"""
int
a
"c_a"
,
b
"c_b"
int
a
"c_a"
,
b
"c_b"
cdef
struct
foo
"c_foo"
:
cdef
struct
foo
"c_foo"
:
...
...
tests/compile/verbatiminclude_cimport.srctree
0 → 100644
View file @
20ff6c2a
PYTHON setup.py build_ext --inplace
######## setup.py ########
from Cython.Build import cythonize
from distutils.core import setup
setup(
ext_modules = cythonize("*.pyx"),
)
######## test.pyx ########
from moda cimport DEFINE_A
from modb cimport DEFINE_B
######## moda.pxd ########
from verbatim cimport DEFINE_ONCE as DEFINE_A
######## modb.pxd ########
from verbatim cimport DEFINE_ONCE as DEFINE_B
######## verbatim.pxd ########
# Check that we include this only once
cdef extern from *:
"""
#ifdef DEFINE_ONCE
#error "DEFINE_ONCE already defined"
#endif
#define DEFINE_ONCE 1
"""
int DEFINE_ONCE
tests/memoryview/memoryview.pyx
View file @
20ff6c2a
...
@@ -1039,3 +1039,47 @@ def min_max_tree_restructuring():
...
@@ -1039,3 +1039,47 @@ def min_max_tree_restructuring():
cdef
char
[:]
aview
=
a
cdef
char
[:]
aview
=
a
return
max
(
<
char
>
1
,
aview
[
0
]),
min
(
<
char
>
5
,
aview
[
2
])
return
max
(
<
char
>
1
,
aview
[
0
]),
min
(
<
char
>
5
,
aview
[
2
])
@
cython
.
test_fail_if_path_exists
(
'//MemoryViewSliceNode'
,
)
@
cython
.
test_assert_path_exists
(
'//MemoryViewIndexNode'
,
)
#@cython.boundscheck(False) # reduce C code clutter
def
optimised_index_of_slice
(
int
[:,:,:]
arr
,
int
x
,
int
y
,
int
z
):
"""
>>> arr = IntMockBuffer("A", list(range(10*10*10)), shape=(10,10,10))
>>> optimised_index_of_slice(arr, 2, 3, 4)
acquired A
(123, 123)
(223, 223)
(133, 133)
(124, 124)
(234, 234)
(123, 123)
(123, 123)
(123, 123)
(134, 134)
(134, 134)
(234, 234)
(234, 234)
(234, 234)
released A
"""
print
(
arr
[
1
,
2
,
3
],
arr
[
1
][
2
][
3
])
print
(
arr
[
x
,
2
,
3
],
arr
[
x
][
2
][
3
])
print
(
arr
[
1
,
y
,
3
],
arr
[
1
][
y
][
3
])
print
(
arr
[
1
,
2
,
z
],
arr
[
1
][
2
][
z
])
print
(
arr
[
x
,
y
,
z
],
arr
[
x
][
y
][
z
])
print
(
arr
[
1
,
2
,
3
],
arr
[:,
2
][
1
][
3
])
print
(
arr
[
1
,
2
,
3
],
arr
[:,
2
,
:][
1
,
3
])
print
(
arr
[
1
,
2
,
3
],
arr
[:,
2
,
3
][
1
])
print
(
arr
[
1
,
y
,
z
],
arr
[
1
,
:][
y
][
z
])
print
(
arr
[
1
,
y
,
z
],
arr
[
1
,
:][
y
,
z
])
print
(
arr
[
x
,
y
,
z
],
arr
[
x
][:][:][
y
][:][:][
z
])
print
(
arr
[
x
,
y
,
z
],
arr
[:][
x
][:][
y
][:][:][
z
])
print
(
arr
[
x
,
y
,
z
],
arr
[:,
:][
x
][:,
:][
y
][:][
z
])
tests/run/for_from_pyvar_loop_T601.pyx
View file @
20ff6c2a
...
@@ -26,7 +26,8 @@ def for_in_plain_ulong():
...
@@ -26,7 +26,8 @@ def for_in_plain_ulong():
print
j
print
j
cdef
extern
from
"for_from_pyvar_loop_T601_extern_def.h"
:
cdef
extern
from
*
:
"""typedef unsigned long Ulong;"""
ctypedef
unsigned
long
Ulong
ctypedef
unsigned
long
Ulong
cdef
Ulong
size
():
cdef
Ulong
size
():
...
...
tests/run/for_from_pyvar_loop_T601_extern_def.h
deleted
100644 → 0
View file @
32290bf8
typedef
unsigned
long
Ulong
;
tests/run/verbatiminclude.h
0 → 100644
View file @
20ff6c2a
static
long
cube
(
long
x
)
{
return
x
*
x
*
x
;
}
#define long broken_long
tests/run/verbatiminclude.pyx
0 → 100644
View file @
20ff6c2a
cdef
extern
from
"verbatiminclude.h"
:
long
cube
(
long
)
cdef
extern
from
*
:
"""
static long square(long x)
{
return x * x;
}
"""
long
square
(
long
)
cdef
extern
from
"verbatiminclude.h"
:
"typedef int myint;"
ctypedef
int
myint
cdef
extern
from
"verbatiminclude.h"
:
"#undef long"
cdef
class
C
:
cdef
myint
val
cdef
extern
from
"Python.h"
:
"""
#define Py_SET_SIZE(obj, size) Py_SIZE((obj)) = (size)
"""
void
Py_SET_SIZE
(
object
,
Py_ssize_t
)
def
test_square
(
x
):
"""
>>> test_square(4)
16
"""
return
square
(
x
)
def
test_cube
(
x
):
"""
>>> test_cube(4)
64
"""
return
cube
(
x
)
def
test_class
():
"""
>>> test_class()
42
"""
cdef
C
x
=
C
()
x
.
val
=
42
return
x
.
val
def
test_set_size
(
x
,
size
):
# This function manipulates Python objects in a bad way, so we
# do not call it. The real test is that it compiles.
Py_SET_SIZE
(
x
,
size
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment