summaryrefslogtreecommitdiff
path: root/tests/run/cpp_extern.srctree
blob: d2c11bb5fc64d81c4ff491dc0ca00931c018d46e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# mode: run
# tag: cpp
# ticket: 1839

"""
PYTHON setup.py build_ext --inplace
PYTHON -c "from foo import test; test()"
PYTHON -c "from bar import test; test()"
PYTHON -c "from baz import test; test()"
"""

######## setup.py ########

from Cython.Build import cythonize
from Cython.Distutils.extension import Extension
from distutils.core import setup

foo = Extension(
    "foo",
    ["foo.pyx", "foo1.cpp", "foo2.cpp"],
)
bar = Extension(
    "bar",
    ["bar.pyx", "bar1.c", "bar2.cpp"],
)
baz = Extension(
    "baz",
    ["baz.pyx", "baz1.c", "baz2.cpp"],
    define_macros = [("__PYX_EXTERN_C", 'extern "C"')],
)

setup(
    ext_modules=cythonize([foo, bar, baz]),
)

######## foo.pyx ########

# distutils: language = c++

from libcpp cimport vector

cdef public vector.vector[int] get_vector():
    return [1,2,3]

cdef extern from "foo_header.h":
    cdef size_t size_vector1()
    cdef size_t size_vector2()

def test():
    assert size_vector1() == 3
    assert size_vector2() == 3

######## foo_header.h ########

size_t size_vector1();
size_t size_vector2();

######## foo1.cpp ########

#include <vector>
#include "foo.h"

size_t size_vector1() {
    return get_vector().size();
}

######## foo2.cpp ########

#include <vector>
extern "C" {
// #include within `extern "C"` is legal.
// We want to make sure here that Cython C++ functions are flagged as `extern "C++"`.
// Otherwise they would be interpreted with C-linkage if the header is include within a `extern "C"` block.
#include "foo.h"
}

size_t size_vector2() {
    return get_vector().size();
}

######## bar.pyx ########

cdef public char get_char():
    return 42

cdef extern from "bar_header.h":
    cdef int get_int1()
    cdef int get_int2()

def test():
    assert get_int1() == 42
    assert get_int2() == 42

######## bar_header.h ########

int get_int1();
int get_int2();

######## bar1.c ########

#include "bar.h"

int get_int1() { return (int)get_char(); }

######## bar2.cpp ########

extern "C" {
#include "bar.h"
}

extern "C" int get_int2() { return (int)get_char(); }

######## baz.pyx ########

# distutils: language = c++

cdef public char get_char():
    return 42

cdef extern from "baz_header.h":
    cdef int get_int1()
    cdef int get_int2()

def test():
    assert get_int1() == 42
    assert get_int2() == 42

######## baz_header.h ########

#ifdef __cplusplus
  #define BAZ_EXTERN_C extern "C"
#else
  #define BAZ_EXTERN_C
#endif

BAZ_EXTERN_C int get_int1();
int get_int2();

######## baz1.c ########

#undef __PYX_EXTERN_C
#define __PYX_EXTERN_C
#include "baz.h"

int get_int1() { return (int)get_char(); }

######## baz2.cpp ########

#include "baz.h"

int get_int2() { return (int)get_char(); }