Skip to content
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

[setuptools] [distutils] Python builds failed on master #24028

Closed
lidizheng opened this issue Aug 31, 2020 · 17 comments · Fixed by #24029
Closed

[setuptools] [distutils] Python builds failed on master #24028

lidizheng opened this issue Aug 31, 2020 · 17 comments · Fixed by #24029

Comments

@gnossen
Copy link
Contributor

gnossen commented Aug 31, 2020

Interesting. Whatever changed in setuptools, it's causing the __wrap_memcpy hack to fail:

    /usr/include/unistd.h:366:16: note: code may be misoptimized unless -fno-strict-aliasing is used
    /tmp/ccdqoMwn.ltrans1.ltrans.o: In function `grpc_core::(anonymous namespace)::XdsRoutingLb::RoutePicker::Pick(grpc_core::LoadBalancingPolicy::PickArgs) [clone .lto_priv.4464]':
    <artificial>:(.text+0x389e): undefined reference to `__wrap_memcpy'
    <artificial>:(.text+0x38c8): undefined reference to `__wrap_memcpy'
    <artificial>:(.text+0x39a5): undefined reference to `__wrap_memcpy'
    /tmp/ccdqoMwn.ltrans3.ltrans.o: In function `http_client_start_transport_stream_op_batch(grpc_call_element*, grpc_transport_stream_op_batch*)':
    <artificial>:(.text+0x17034): undefined reference to `__wrap_memcpy'
    <artificial>:(.text+0x170bd): undefined reference to `__wrap_memcpy'
    /tmp/ccdqoMwn.ltrans3.ltrans.o:<artificial>:(.text+0x1742a): more undefined references to `__wrap_memcpy' follow
    collect2: error: ld returned 1 exit status

@gnossen
Copy link
Contributor

gnossen commented Aug 31, 2020

Potentially related: pypa/setuptools#2232

@lidizheng
Copy link
Contributor Author

The discussion seems mainly about the install location. The compilation failure you mentioned is a behavior change in compiler. So, I guess there are still some undiscovered issue.

@gnossen
Copy link
Contributor

gnossen commented Aug 31, 2020

It's about whether we're pulling in setuptools' vendored distutils or Debian's vendored (and patched) distutils. Prior to version 50, we were getting Debian's, whereas now we're getting setuptool's packaged version. Since distutils controls the exact compiler invocation, I think it's likely that difference is significant.

I don't have full compiler invocations handy from before setuptools 50, but the object that fails to link appears to be an intermediary target used in link-time optimization. I wasn't aware that we were using LTO before, so it's possible that it's a feature of the packaged distutils version that we didn't have before.

@lidizheng
Copy link
Contributor Author

Mentioned in https://github.com/pypa/setuptools/issues/2350 that setting environment variable SETUPTOOLS_USE_DISTUTILS=stdlib fixes this problem. TIL that Debian and Ubuntu has patched distutils. Let's see how setuptools owners decided to fix this issue.

@lidizheng
Copy link
Contributor Author

Reopen since the we still need to plan for how to adapt to the new distutils changes introduced by setuptools 50.0.0+.

@gnossen
Copy link
Contributor

gnossen commented Aug 31, 2020

I was expecting that maybe -Wl,-wrap,memcpy didn't get propagated from setup.py down to the compiler invocation, but it's in there:

x86_64-linux-gnu-g++ -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions \
  -Wl,-z,relro -I/var/local/git/grpc/include -std=gnu99 -fno-wrapv \
  python_build/temp.linux-x86_64-3.5/src/core/ext/filters/census/grpc_context.o ... \
  -L/usr/lib -lrt -lm -o python_build/lib.linux-x86_64-3.5/grpc/_cython/cygrpc.cpython-35m-x86_64-linux-gnu.so \
  -lpthread -Wl,-wrap,memcpy -static-libgcc

So far, the only difference I've found is the use of LTO.

@gnossen
Copy link
Contributor

gnossen commented Aug 31, 2020

Comparison of compilation of single translation unit:

My machine:

x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare \
  -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat \
  -Werror=format-security -g -fwrapv -O2 -fPIC -D_WIN32_WINNT=1536 \
  -DGPR_BACKWARDS_COMPATIBILITY_MODE=1 -DHAVE_CONFIG_H=1 \
  -DGRPC_ENABLE_FORK_SUPPORT=1 \
  -DPyMODINIT_FUNC=extern "C" __attribute__((visibility ("default"))) PyObject* \
  -DGRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK=1 -Isrc/python/grpcio \
  -Iinclude -I. -Ithird_party/abseil-cpp -Ithird_party/address_sorting/include -Ithird_party/cares \
  ... \
  -I/usr/local/google/home/rbellevi/Dev/grpc/venv3.7/include/python3.7m -c src/core/ext/filters/census/grpc_context.cc \
  -o python_build/temp.linux-x86_64-3.7/src/core/ext/filters/census/grpc_context.o -std=c++11 \
  -std=gnu99 -fvisibility=hidden -fno-wrapv -fno-exceptions -pthread

CI:

ccache gcc -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv \
  -O2 -Wall -Wstrict-prototypes -g -fdebug-prefix-map=/build/python3.5-3.5.3=. \
  -fstack-protector-strong -Wformat -Werror=format-security -g \
  -flto -fuse-linker-plugin -ffat-lto-objects -I/var/local/git/grpc/include -std=gnu99 \
  -fno-wrapv -fPIC -D_WIN32_WINNT=1536 -DGPR_BACKWARDS_COMPATIBILITY_MODE=1 \
  -DHAVE_CONFIG_H=1 -DGRPC_ENABLE_FORK_SUPPORT=1 \
  -DPyMODINIT_FUNC=extern "C" __attribute__((visibility ("default"))) PyObject* \
  -DGRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK=1 -Isrc/python/grpcio -Iinclude -I. \
  -Ithird_party/abseil-cpp -Ithird_party/address_sorting/include -Ithird_party/cares \
  ... \
  -I/var/local/git/grpc/py35_native/include/python3.5m -c src/core/ext/filters/census/grpc_context.cc \
  -o python_build/temp.linux-x86_64-3.5/src/core/ext/filters/census/grpc_context.o \
  -std=c++11 -std=gnu99 -fvisibility=hidden -fno-wrapv -fno-exceptions -pthread

@veblush
Copy link
Contributor

veblush commented Aug 31, 2020

It's worth mentioning the PR removing wrap-memory hack. This would be helpful to stay with setuptool 50 in future. Note that it sill has another problem with Windows Python, TypeError: _commandfile_spawn() got an unexpected keyword argument 'env'. (test)

@lidizheng
Copy link
Contributor Author

I saw the Windows issue. It could be introduced by the distutils behavior change. Pinning to older version solved it.

@gnossen
Copy link
Contributor

gnossen commented Aug 31, 2020

Using export SETUPTOOLS_USE_DISTUTILS=stdlib fixes the issue on all platforms, meaning that pypa/setuptools#2232 is indeed the root cause. Unfortunately, this doesn't do a whole lot for us. We could potentially just add os.environ["SETUPTOOLS_USE_DISTUTILS"] = "stdlib" to setup.py before we import setuptools. That would solve the case where people invoke us as a subprocess. But if someone uses us as a library, then the import statement might be a no-op and we would end up using the system library anyway. But I'm not sure if that's a case that's worth taking into consideration. Does anyone ever try to import our setup.py file?

It's also worth noting that the maintainer of setuptools called this environment variable "temporary." We may need to track down the underlying issues, but it seems like this is a problem for distro maintainers and the setuptools maintainers, not for us.

@lidizheng
Copy link
Contributor Author

lidizheng commented Aug 31, 2020

Good finding! I would doubt anyone trying to import our setup.py. In the most extreme definition, the compilation of our library is part of our API contract. But we already doing a bunch of hacky things, like monkey patching distutils, patching multiple compilers. At this moment, I prefer to use the pin-back solution, since the environment variable is marked as "temporary".


Let's wait for how setuptools owners reply to https://github.com/pypa/setuptools/issues/2350 and pypa/setuptools#2232

@gnossen
Copy link
Contributor

gnossen commented Sep 1, 2020

I don't think pinning back setuptools is sufficient. Right now, if someone on Debian or Ubuntu does pip install grpcio, it won't work.

Just tested the debian:latest Docker image with setuptools 50.0.0. It worked with no modifications. A Debian user would have to explicitly update their setuptools to hit this problem, so I agree that pinning back in CI should be sufficient for now. If we receive any user issues about this, we can just recommend the SETUPTOOLS_USE_DISTUTILS environment variable.

@lidizheng
Copy link
Contributor Author

This plan sounds good. Closing this issue unless there is a need for another patch.

@chongkong
Copy link

I think the root cause is that distutils is imported before setuptools in commands.py, which breaks the monkeypatching behavior of setuptools. (setuptools monkeypatches some distutils methods thus should be imported before distutils). Setting SETUPTOOLS_USE_DISTUTILS=stdlib is doing the opposite (not monkey-patching the distutils explicitly), which is a legacy behavior and discouraged, only provided for the ease of transition.

@xerdink
Copy link

xerdink commented Sep 1, 2020

I have set SETUPTOOLS_USE_DISTUTILS=stdlib but still build fails in setuptools==50.0

Now I'm downgrading setuptools.

@gnossen
Copy link
Contributor

gnossen commented Sep 1, 2020

@chongkong Thanks for the suggestion! Giving that a shot here.

@lidizheng lidizheng changed the title Python builds failed on master [Setuptools] [Distutils] Python builds failed on master Sep 2, 2020
@lidizheng lidizheng changed the title [Setuptools] [Distutils] Python builds failed on master [setuptools] [distutils] Python builds failed on master Sep 2, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants