]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | from __future__ import print_function |
2 | ||
3 | import os | |
4 | import pkgutil | |
5 | import shutil | |
6 | import subprocess | |
7 | import sys | |
8 | import tempfile | |
9 | import textwrap | |
10 | from distutils.ccompiler import new_compiler | |
11 | from distutils.errors import CompileError, LinkError | |
11fdf7f2 TL |
12 | import distutils.sysconfig |
13 | ||
14 | unwrapped_customize = distutils.sysconfig.customize_compiler | |
15 | ||
16 | clang = False | |
17 | ||
18 | def filter_unsupported_flags(flags): | |
19 | if clang: | |
20 | return [f for f in flags if not (f == '-mcet' or | |
21 | f.startswith('-fcf-protection'))] | |
22 | else: | |
23 | return flags | |
24 | ||
25 | def monkey_with_compiler(compiler): | |
26 | unwrapped_customize(compiler) | |
27 | if compiler.compiler_type == 'unix': | |
28 | if compiler.compiler[0].find('clang') != -1: | |
29 | global clang | |
30 | clang = True | |
31 | compiler.compiler = filter_unsupported_flags(compiler.compiler) | |
32 | compiler.compiler_so = filter_unsupported_flags( | |
33 | compiler.compiler_so) | |
34 | ||
35 | distutils.sysconfig.customize_compiler = monkey_with_compiler | |
7c673cae FG |
36 | |
37 | if not pkgutil.find_loader('setuptools'): | |
38 | from distutils.core import setup | |
39 | from distutils.extension import Extension | |
40 | else: | |
41 | from setuptools import setup | |
42 | from setuptools.extension import Extension | |
43 | ||
44 | # PEP 440 versioning of the Ceph FS package on PyPI | |
45 | # Bump this version, after every changeset | |
46 | ||
47 | __version__ = '2.0.0' | |
48 | ||
49 | ||
50 | def get_python_flags(): | |
51 | cflags = {'I': [], 'extras': []} | |
52 | ldflags = {'l': [], 'L': [], 'extras': []} | |
53 | ||
54 | if os.environ.get('VIRTUAL_ENV', None): | |
55 | python = "python" | |
56 | else: | |
57 | python = 'python' + str(sys.version_info.major) + '.' + str(sys.version_info.minor) | |
58 | ||
59 | python_config = python + '-config' | |
60 | ||
11fdf7f2 TL |
61 | for cflag in filter_unsupported_flags(subprocess.check_output( |
62 | [python_config, "--cflags"]).strip().decode('utf-8').split()): | |
7c673cae FG |
63 | if cflag.startswith('-I'): |
64 | cflags['I'].append(cflag.replace('-I', '')) | |
65 | else: | |
66 | cflags['extras'].append(cflag) | |
67 | ||
11fdf7f2 TL |
68 | for ldflag in filter_unsupported_flags(subprocess.check_output( |
69 | [python_config, "--ldflags"]).strip().decode('utf-8').split()): | |
7c673cae FG |
70 | if ldflag.startswith('-l'): |
71 | ldflags['l'].append(ldflag.replace('-l', '')) | |
72 | if ldflag.startswith('-L'): | |
73 | ldflags['L'].append(ldflag.replace('-L', '')) | |
74 | else: | |
75 | ldflags['extras'].append(ldflag) | |
76 | ||
77 | return { | |
78 | 'cflags': cflags, | |
79 | 'ldflags': ldflags | |
80 | } | |
81 | ||
82 | ||
83 | def check_sanity(): | |
84 | """ | |
85 | Test if development headers and library for cephfs is available by compiling a dummy C program. | |
86 | """ | |
87 | CEPH_SRC_DIR = os.path.join( | |
88 | os.path.dirname(os.path.abspath(__file__)), | |
89 | '..', | |
90 | '..' | |
91 | ) | |
92 | ||
93 | tmp_dir = tempfile.mkdtemp(dir=os.environ.get('TMPDIR', os.path.dirname(__file__))) | |
94 | tmp_file = os.path.join(tmp_dir, 'cephfs_dummy.c') | |
95 | ||
96 | with open(tmp_file, 'w') as fp: | |
97 | dummy_prog = textwrap.dedent(""" | |
98 | #include <stddef.h> | |
99 | #include "cephfs/libcephfs.h" | |
100 | ||
101 | int main(void) { | |
102 | struct ceph_mount_info *cmount = NULL; | |
103 | ceph_init(cmount); | |
104 | return 0; | |
105 | } | |
106 | """) | |
107 | fp.write(dummy_prog) | |
108 | ||
109 | compiler = new_compiler() | |
11fdf7f2 | 110 | distutils.sysconfig.customize_compiler(compiler) |
7c673cae FG |
111 | |
112 | if {'MAKEFLAGS', 'MFLAGS', 'MAKELEVEL'}.issubset(set(os.environ.keys())): | |
113 | # The setup.py has been invoked by a top-level Ceph make. | |
114 | # Set the appropriate CFLAGS and LDFLAGS | |
115 | ||
116 | compiler.set_library_dirs([os.environ.get('CEPH_LIBDIR')]) | |
117 | ||
118 | try: | |
119 | compiler.define_macro('_FILE_OFFSET_BITS', '64') | |
120 | ||
121 | link_objects = compiler.compile( | |
122 | sources=[tmp_file], | |
123 | output_dir=tmp_dir, | |
124 | extra_preargs=['-iquote{path}'.format(path=os.path.join(CEPH_SRC_DIR, 'include'))] | |
125 | ) | |
126 | ||
127 | compiler.link_executable( | |
128 | objects=link_objects, | |
129 | output_progname=os.path.join(tmp_dir, 'cephfs_dummy'), | |
130 | libraries=['cephfs'], | |
131 | output_dir=tmp_dir, | |
132 | ) | |
133 | ||
134 | except CompileError: | |
135 | print('\nCompile Error: Ceph FS development headers not found', file=sys.stderr) | |
136 | return False | |
137 | except LinkError: | |
138 | print('\nLink Error: Ceph FS library not found', file=sys.stderr) | |
139 | return False | |
140 | else: | |
141 | return True | |
142 | finally: | |
143 | shutil.rmtree(tmp_dir) | |
144 | ||
145 | ||
146 | if 'BUILD_DOC' in os.environ.keys(): | |
147 | pass | |
148 | elif check_sanity(): | |
149 | pass | |
150 | else: | |
151 | sys.exit(1) | |
152 | ||
153 | cmdclass = {} | |
154 | try: | |
155 | from Cython.Build import cythonize | |
156 | from Cython.Distutils import build_ext | |
157 | ||
158 | cmdclass = {'build_ext': build_ext} | |
159 | except ImportError: | |
160 | print("WARNING: Cython is not installed.") | |
161 | ||
162 | if not os.path.isfile('cephfs.c'): | |
163 | print('ERROR: Cannot find Cythonized file cephfs.c', file=sys.stderr) | |
164 | sys.exit(1) | |
165 | else: | |
166 | def cythonize(x, **kwargs): | |
167 | return x | |
168 | ||
169 | source = "cephfs.c" | |
170 | else: | |
171 | source = "cephfs.pyx" | |
172 | ||
173 | # Disable cythonification if we're not really building anything | |
174 | if (len(sys.argv) >= 2 and | |
175 | any(i in sys.argv[1:] for i in ('--help', 'clean', 'egg_info', '--version') | |
176 | )): | |
177 | def cythonize(x, **kwargs): | |
178 | return x | |
179 | ||
180 | flags = get_python_flags() | |
181 | ||
182 | setup( | |
183 | name='cephfs', | |
184 | version=__version__, | |
185 | description="Python bindings for the Ceph FS library", | |
186 | long_description=( | |
187 | "This package contains Python bindings for interacting with the " | |
188 | "Ceph Filesystem (Ceph FS) library. Ceph FS is a POSIX-compliant " | |
189 | "filesystem that uses a Ceph Storage Cluster to store its data. The " | |
190 | "Ceph filesystem uses the same Ceph Storage Cluster system as " | |
191 | "Ceph Block Devices, Ceph Object Storage with its S3 and Swift APIs, " | |
192 | "or native bindings (librados)." | |
193 | ), | |
194 | url='https://github.com/ceph/ceph/tree/master/src/pybind/cephfs', | |
195 | license='LGPLv2+', | |
196 | platforms='Linux', | |
197 | ext_modules=cythonize( | |
198 | [ | |
199 | Extension( | |
200 | "cephfs", | |
201 | [source], | |
202 | include_dirs=flags['cflags']['I'], | |
203 | library_dirs=flags['ldflags']['L'], | |
204 | libraries=['cephfs'] + flags['ldflags']['l'], | |
205 | extra_compile_args=flags['cflags']['extras'] + flags['ldflags']['extras'], | |
206 | ) | |
207 | ], | |
208 | build_dir=os.environ.get("CYTHON_BUILD_DIR", None), | |
209 | include_path=[ | |
210 | os.path.join(os.path.dirname(__file__), "..", "rados") | |
211 | ] | |
212 | ), | |
213 | classifiers=[ | |
214 | 'Intended Audience :: Developers', | |
215 | 'Intended Audience :: System Administrators', | |
216 | 'License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+)', | |
217 | 'Operating System :: POSIX :: Linux', | |
218 | 'Programming Language :: Cython', | |
219 | 'Programming Language :: Python :: 2.7', | |
220 | 'Programming Language :: Python :: 3.4', | |
221 | 'Programming Language :: Python :: 3.5' | |
222 | ], | |
223 | cmdclass=cmdclass, | |
224 | ) |