-
-
Notifications
You must be signed in to change notification settings - Fork 649
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Switch to Py2 and Py3 shards. #6289
Changes from all commits
f88b788
98e98e6
b84ddc0
c61dedb
f33f2cd
0f2758e
b8702fe
488536f
af52957
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,7 +19,7 @@ | |
|
||
from pants.engine.selectors import Get, constraint_for | ||
from pants.util.contextutil import temporary_dir | ||
from pants.util.dirutil import safe_mkdir, safe_mkdtemp | ||
from pants.util.dirutil import read_file, safe_mkdir, safe_mkdtemp | ||
from pants.util.memo import memoized_property | ||
from pants.util.objects import datatype | ||
|
||
|
@@ -275,6 +275,50 @@ | |
} | ||
''' | ||
|
||
# NB: This is a "patch" applied to CFFI's generated sources to remove the ifdefs that would | ||
# usually cause only one of the two module definition functions to be defined. Instead, we define | ||
# both. Since `patch` is not available in all relevant environments (notably, many docker images), | ||
# this is accomplished using string replacement. To (re)-generate this patch, fiddle with the | ||
# unmodified output of `ffibuilder.emit_c_code`. | ||
CFFI_C_PATCH_BEFORE = ''' | ||
# ifdef _MSC_VER | ||
PyMODINIT_FUNC | ||
# if PY_MAJOR_VERSION >= 3 | ||
PyInit_native_engine(void) { return NULL; } | ||
# else | ||
initnative_engine(void) { } | ||
# endif | ||
# endif | ||
#elif PY_MAJOR_VERSION >= 3 | ||
PyMODINIT_FUNC | ||
PyInit_native_engine(void) | ||
{ | ||
return _cffi_init("native_engine", 0x2601, &_cffi_type_context); | ||
} | ||
#else | ||
PyMODINIT_FUNC | ||
initnative_engine(void) | ||
{ | ||
_cffi_init("native_engine", 0x2601, &_cffi_type_context); | ||
} | ||
#endif | ||
''' | ||
CFFI_C_PATCH_AFTER = ''' | ||
#endif | ||
|
||
PyObject* // PyMODINIT_FUNC for PY3 | ||
wrapped_PyInit_native_engine(void) | ||
{ | ||
return _cffi_init("native_engine", 0x2601, &_cffi_type_context); | ||
} | ||
|
||
void // PyMODINIT_FUNC for PY2 | ||
wrapped_initnative_engine(void) | ||
{ | ||
_cffi_init("native_engine", 0x2601, &_cffi_type_context); | ||
} | ||
''' | ||
|
||
|
||
def get_build_cflags(): | ||
"""Synthesize a CFLAGS env var from the current python env for building of C modules.""" | ||
|
@@ -314,14 +358,15 @@ def bootstrap_c_source(output_dir, module_name=NATIVE_ENGINE_MODULE): | |
# (it kept the binary working) but inconvenient (it was relying on unspecified behavior, it meant | ||
# our binaries couldn't be stripped which inflated them by 2~3x, and it reduced the amount of LTO | ||
# we could use, which led to unmeasured performance hits). | ||
def rename_symbol_in_file(f): | ||
with open(f, 'r') as fh: | ||
for line in fh: | ||
if line.startswith('init{}'.format(module_name)) or line.startswith('PyInit_{}'.format(module_name)): | ||
yield 'wrapped_' + line | ||
else: | ||
yield line | ||
file_content = ''.join(rename_symbol_in_file(temp_c_file)) | ||
# | ||
# We additionally remove the ifdefs that apply conditional `init` logic for Py2 vs Py3, in order | ||
# to define a module that is loadable by either 2 or 3. | ||
# TODO: Because PyPy uses the same `init` function name regardless of the python version, this | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To my knowledge we have never supported running on PyPy like pex does. Perhaps kill the TODO. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At one point about two years ago I ran pants under PyPy, and saw a 30 percent speedup... would be awesome to be able to support it at some point... |
||
# trick does not work there: we leave its conditional in place. | ||
file_content = read_file(temp_c_file).decode('utf-8') | ||
if CFFI_C_PATCH_BEFORE not in file_content: | ||
raise Exception('The patch for the CFFI generated code will not apply cleanly.') | ||
file_content = file_content.replace(CFFI_C_PATCH_BEFORE, CFFI_C_PATCH_AFTER) | ||
|
||
_replace_file(c_file, file_content) | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,25 @@ | ||
// This file creates the unmangled symbol initnative_engine which cffi will use as the entry point | ||
// to this shared library. | ||
// This file creates the unmangled symbols initnative_engine and PyInit_native_engine, which cffi | ||
// will use as the entry point to this shared library in python 2 and python 3, respectively. | ||
// | ||
// It calls the extern'd wrapped_initnative_engine (generated in | ||
// It calls the extern'd wrapped_initnative_engine and wrapped_PyInit_native_engine (generated in | ||
// src/rust/engine/src/cffi/native_engine.c by build-support/native-engine/bootstrap_cffi.py). | ||
// This is a bit awkward and fiddly, but necessary because rust doesn't currently have a way to | ||
// re-export symbols from C libraries, other than this. | ||
// See https://github.com/rust-lang/rust/issues/36342 | ||
|
||
use std::os::raw; | ||
|
||
extern "C" { | ||
pub fn wrapped_initnative_engine(); | ||
pub fn wrapped_PyInit_native_engine() -> *mut raw::c_void; | ||
} | ||
|
||
#[no_mangle] | ||
pub extern "C" fn initnative_engine() { | ||
unsafe { wrapped_initnative_engine() } | ||
} | ||
|
||
#[no_mangle] | ||
pub unsafe extern "C" fn PyInit_native_engine() -> *mut raw::c_void { | ||
wrapped_PyInit_native_engine() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the general philosophy on skipping py3 test given
in .travis.yml?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To make it past the "internal" tests in order to run the unit tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh gotcha. Thanks!