1#! /usr/bin/env python 2# 3# See README for usage instructions. 4from distutils import util 5import fnmatch 6import glob 7import os 8import pkg_resources 9import re 10import subprocess 11import sys 12import sysconfig 13import platform 14 15# We must use setuptools, not distutils, because we need to use the 16# namespace_packages option for the "google" package. 17from setuptools import setup, Extension, find_packages 18 19from distutils.command.build_py import build_py as _build_py 20from distutils.command.clean import clean as _clean 21from distutils.spawn import find_executable 22 23# Find the Protocol Compiler. 24if 'PROTOC' in os.environ and os.path.exists(os.environ['PROTOC']): 25 protoc = os.environ['PROTOC'] 26elif os.path.exists("../src/protoc"): 27 protoc = "../src/protoc" 28elif os.path.exists("../src/protoc.exe"): 29 protoc = "../src/protoc.exe" 30elif os.path.exists("../vsprojects/Debug/protoc.exe"): 31 protoc = "../vsprojects/Debug/protoc.exe" 32elif os.path.exists("../vsprojects/Release/protoc.exe"): 33 protoc = "../vsprojects/Release/protoc.exe" 34else: 35 protoc = find_executable("protoc") 36 37 38def GetVersion(): 39 """Gets the version from google/protobuf/__init__.py 40 41 Do not import google.protobuf.__init__ directly, because an installed 42 protobuf library may be loaded instead.""" 43 44 with open(os.path.join('google', 'protobuf', '__init__.py')) as version_file: 45 exec(version_file.read(), globals()) 46 global __version__ 47 return __version__ 48 49 50def generate_proto(source, require = True): 51 """Invokes the Protocol Compiler to generate a _pb2.py from the given 52 .proto file. Does nothing if the output already exists and is newer than 53 the input.""" 54 55 if not require and not os.path.exists(source): 56 return 57 58 output = source.replace(".proto", "_pb2.py").replace("../src/", "") 59 60 if (not os.path.exists(output) or 61 (os.path.exists(source) and 62 os.path.getmtime(source) > os.path.getmtime(output))): 63 print("Generating %s..." % output) 64 65 if not os.path.exists(source): 66 sys.stderr.write("Can't find required file: %s\n" % source) 67 sys.exit(-1) 68 69 if protoc is None: 70 sys.stderr.write( 71 "protoc is not installed nor found in ../src. Please compile it " 72 "or install the binary package.\n") 73 sys.exit(-1) 74 75 protoc_command = [ protoc, "-I../src", "-I.", "--python_out=.", source ] 76 if subprocess.call(protoc_command) != 0: 77 sys.exit(-1) 78 79def GenerateUnittestProtos(): 80 generate_proto("../src/google/protobuf/any_test.proto", False) 81 generate_proto("../src/google/protobuf/map_proto2_unittest.proto", False) 82 generate_proto("../src/google/protobuf/map_unittest.proto", False) 83 generate_proto("../src/google/protobuf/test_messages_proto3.proto", False) 84 generate_proto("../src/google/protobuf/test_messages_proto2.proto", False) 85 generate_proto("../src/google/protobuf/unittest_arena.proto", False) 86 generate_proto("../src/google/protobuf/unittest.proto", False) 87 generate_proto("../src/google/protobuf/unittest_custom_options.proto", False) 88 generate_proto("../src/google/protobuf/unittest_import.proto", False) 89 generate_proto("../src/google/protobuf/unittest_import_public.proto", False) 90 generate_proto("../src/google/protobuf/unittest_mset.proto", False) 91 generate_proto("../src/google/protobuf/unittest_mset_wire_format.proto", False) 92 generate_proto("../src/google/protobuf/unittest_no_generic_services.proto", False) 93 generate_proto("../src/google/protobuf/unittest_proto3_arena.proto", False) 94 generate_proto("../src/google/protobuf/util/json_format.proto", False) 95 generate_proto("../src/google/protobuf/util/json_format_proto3.proto", False) 96 generate_proto("google/protobuf/internal/any_test.proto", False) 97 generate_proto("google/protobuf/internal/descriptor_pool_test1.proto", False) 98 generate_proto("google/protobuf/internal/descriptor_pool_test2.proto", False) 99 generate_proto("google/protobuf/internal/factory_test1.proto", False) 100 generate_proto("google/protobuf/internal/factory_test2.proto", False) 101 generate_proto("google/protobuf/internal/file_options_test.proto", False) 102 generate_proto("google/protobuf/internal/import_test_package/inner.proto", False) 103 generate_proto("google/protobuf/internal/import_test_package/outer.proto", False) 104 generate_proto("google/protobuf/internal/missing_enum_values.proto", False) 105 generate_proto("google/protobuf/internal/message_set_extensions.proto", False) 106 generate_proto("google/protobuf/internal/more_extensions.proto", False) 107 generate_proto("google/protobuf/internal/more_extensions_dynamic.proto", False) 108 generate_proto("google/protobuf/internal/more_messages.proto", False) 109 generate_proto("google/protobuf/internal/no_package.proto", False) 110 generate_proto("google/protobuf/internal/packed_field_test.proto", False) 111 generate_proto("google/protobuf/internal/test_bad_identifiers.proto", False) 112 generate_proto("google/protobuf/internal/test_proto3_optional.proto", False) 113 generate_proto("google/protobuf/pyext/python.proto", False) 114 115 116class clean(_clean): 117 def run(self): 118 # Delete generated files in the code tree. 119 for (dirpath, dirnames, filenames) in os.walk("."): 120 for filename in filenames: 121 filepath = os.path.join(dirpath, filename) 122 if filepath.endswith("_pb2.py") or filepath.endswith(".pyc") or \ 123 filepath.endswith(".so") or filepath.endswith(".o"): 124 os.remove(filepath) 125 # _clean is an old-style class, so super() doesn't work. 126 _clean.run(self) 127 128class build_py(_build_py): 129 def run(self): 130 # Generate necessary .proto file if it doesn't exist. 131 generate_proto("../src/google/protobuf/descriptor.proto") 132 generate_proto("../src/google/protobuf/compiler/plugin.proto") 133 generate_proto("../src/google/protobuf/any.proto") 134 generate_proto("../src/google/protobuf/api.proto") 135 generate_proto("../src/google/protobuf/duration.proto") 136 generate_proto("../src/google/protobuf/empty.proto") 137 generate_proto("../src/google/protobuf/field_mask.proto") 138 generate_proto("../src/google/protobuf/source_context.proto") 139 generate_proto("../src/google/protobuf/struct.proto") 140 generate_proto("../src/google/protobuf/timestamp.proto") 141 generate_proto("../src/google/protobuf/type.proto") 142 generate_proto("../src/google/protobuf/wrappers.proto") 143 GenerateUnittestProtos() 144 145 # _build_py is an old-style class, so super() doesn't work. 146 _build_py.run(self) 147 148 def find_package_modules(self, package, package_dir): 149 exclude = ( 150 "*test*", 151 "google/protobuf/internal/*_pb2.py", 152 "google/protobuf/internal/_parameterized.py", 153 "google/protobuf/pyext/python_pb2.py", 154 ) 155 modules = _build_py.find_package_modules(self, package, package_dir) 156 return [(pkg, mod, fil) for (pkg, mod, fil) in modules 157 if not any(fnmatch.fnmatchcase(fil, pat=pat) for pat in exclude)] 158 159 160class test_conformance(_build_py): 161 target = 'test_python' 162 def run(self): 163 # Python 2.6 dodges these extra failures. 164 os.environ["CONFORMANCE_PYTHON_EXTRA_FAILURES"] = ( 165 "--failure_list failure_list_python-post26.txt") 166 cmd = 'cd ../conformance && make %s' % (test_conformance.target) 167 status = subprocess.check_call(cmd, shell=True) 168 169 170def get_option_from_sys_argv(option_str): 171 if option_str in sys.argv: 172 sys.argv.remove(option_str) 173 return True 174 return False 175 176 177if __name__ == '__main__': 178 ext_module_list = [] 179 warnings_as_errors = '--warnings_as_errors' 180 if get_option_from_sys_argv('--cpp_implementation'): 181 # Link libprotobuf.a and libprotobuf-lite.a statically with the 182 # extension. Note that those libraries have to be compiled with 183 # -fPIC for this to work. 184 compile_static_ext = get_option_from_sys_argv('--compile_static_extension') 185 libraries = ['protobuf'] 186 extra_objects = None 187 if compile_static_ext: 188 libraries = None 189 extra_objects = ['../src/.libs/libprotobuf.a', 190 '../src/.libs/libprotobuf-lite.a'] 191 test_conformance.target = 'test_python_cpp' 192 193 extra_compile_args = [] 194 195 if sys.platform != 'win32': 196 extra_compile_args.append('-Wno-write-strings') 197 extra_compile_args.append('-Wno-invalid-offsetof') 198 extra_compile_args.append('-Wno-sign-compare') 199 extra_compile_args.append('-Wno-unused-variable') 200 extra_compile_args.append('-std=c++11') 201 202 if sys.platform == 'darwin': 203 extra_compile_args.append("-Wno-shorten-64-to-32"); 204 extra_compile_args.append("-Wno-deprecated-register"); 205 206 # https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes 207 # C++ projects must now migrate to libc++ and are recommended to set a 208 # deployment target of macOS 10.9 or later, or iOS 7 or later. 209 if sys.platform == 'darwin': 210 mac_target = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') 211 if mac_target and (pkg_resources.parse_version(mac_target) < 212 pkg_resources.parse_version('10.9.0')): 213 os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.9' 214 os.environ['_PYTHON_HOST_PLATFORM'] = re.sub( 215 r'macosx-[0-9]+\.[0-9]+-(.+)', r'macosx-10.9-\1', 216 util.get_platform()) 217 218 # https://github.com/Theano/Theano/issues/4926 219 if sys.platform == 'win32': 220 extra_compile_args.append('-D_hypot=hypot') 221 222 # https://github.com/tpaviot/pythonocc-core/issues/48 223 if sys.platform == 'win32' and '64 bit' in sys.version: 224 extra_compile_args.append('-DMS_WIN64') 225 226 # MSVS default is dymanic 227 if (sys.platform == 'win32'): 228 extra_compile_args.append('/MT') 229 230 if "clang" in os.popen('$CC --version 2> /dev/null').read(): 231 extra_compile_args.append('-Wno-shorten-64-to-32') 232 233 if warnings_as_errors in sys.argv: 234 extra_compile_args.append('-Werror') 235 sys.argv.remove(warnings_as_errors) 236 237 # C++ implementation extension 238 ext_module_list.extend([ 239 Extension( 240 "google.protobuf.pyext._message", 241 glob.glob('google/protobuf/pyext/*.cc'), 242 include_dirs=[".", "../src"], 243 libraries=libraries, 244 extra_objects=extra_objects, 245 library_dirs=['../src/.libs'], 246 extra_compile_args=extra_compile_args, 247 ), 248 Extension( 249 "google.protobuf.internal._api_implementation", 250 glob.glob('google/protobuf/internal/api_implementation.cc'), 251 extra_compile_args=extra_compile_args + ['-DPYTHON_PROTO2_CPP_IMPL_V2'], 252 ), 253 ]) 254 os.environ['PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION'] = 'cpp' 255 256 # Keep this list of dependencies in sync with tox.ini. 257 install_requires = ['six>=1.9'] 258 if sys.version_info <= (2,7): 259 install_requires.append('ordereddict') 260 install_requires.append('unittest2') 261 262 setup( 263 name='protobuf', 264 version=GetVersion(), 265 description='Protocol Buffers', 266 download_url='https://github.com/protocolbuffers/protobuf/releases', 267 long_description="Protocol Buffers are Google's data interchange format", 268 url='https://developers.google.com/protocol-buffers/', 269 maintainer='protobuf@googlegroups.com', 270 maintainer_email='protobuf@googlegroups.com', 271 license='3-Clause BSD License', 272 classifiers=[ 273 "Programming Language :: Python", 274 "Programming Language :: Python :: 2", 275 "Programming Language :: Python :: 2.7", 276 "Programming Language :: Python :: 3", 277 "Programming Language :: Python :: 3.3", 278 "Programming Language :: Python :: 3.4", 279 "Programming Language :: Python :: 3.5", 280 "Programming Language :: Python :: 3.6", 281 "Programming Language :: Python :: 3.7", 282 ], 283 namespace_packages=['google'], 284 packages=find_packages( 285 exclude=[ 286 'import_test_package', 287 'protobuf_distutils', 288 ], 289 ), 290 test_suite='google.protobuf.internal', 291 cmdclass={ 292 'clean': clean, 293 'build_py': build_py, 294 'test_conformance': test_conformance, 295 }, 296 install_requires=install_requires, 297 ext_modules=ext_module_list, 298 ) 299