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

Build executor Cython extension #992

Closed

Conversation

calebmarchent
Copy link

setup.py to create folly Cython bindings

Minimum required to get fbthrift to compile in OSS, so only includes executor

Cython requires that source files (pyx and pxd) are in a directory matching the extension name, to provide this a tree of symbolic links is created and the Cython compile happens in that directory.

FIXME: Handle systems that lack required tooling gracefully (don't cause build failure)

  • Python3 > 3.6 available?
  • Cython installed?

Test Plan:

Dimensions to consider in test plan:

  • Distro:

    • Ubuntu 16.04
  • Cython?

    • With / without Cython installed
  • Python Version

    • Only test with Python3
  • Install with alternative DESTDIR

  • Configure CMake in source dir

  • Configure CMake in _build dir

@calebmarchent calebmarchent force-pushed the build_python_bindings_in_oss branch 2 times, most recently from 67c4f91 to 90efb01 Compare January 9, 2019 15:30
@yfeldblum yfeldblum requested a review from simpkins January 10, 2019 08:01
@calebmarchent
Copy link
Author

Since creation of the original PR; I have added the following checks:

  • Installation works with cmake from alternate dir
  • Can install to an alternative location, (without root privileges)
  • Gracefully handle environments lacking the tools to build the python extension
  • Folly needs to be compiled with -fPIC (Position Independent Code), which it is not by default
  • Resulting python extension tree contains many unexpected files, owning to overlap with pathname "folly/"

I have no further updates planned for this PR, pending review feedback

CMake/FindCython.cmake Outdated Show resolved Hide resolved
CMakeLists.txt Outdated Show resolved Hide resolved
@@ -13,3 +13,31 @@ install(
)

add_subdirectory(experimental/exception_tracer)

get_target_property(pic folly POSITION_INDEPENDENT_CODE)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this always false by default?

I think we should strongly discourage building libfolly as a shared library in most circumstances. When the cython build is enabled maybe we should compile the code twice: once as libfolly.a library to be used by downstream C++ dependencies, and a separate PIC build just for Cython users. Perhaps it would be good to have the Cython extension directly include all of the folly code rather than linking against folly as a separate shared library.

That said, I'm not really that familiar with the current python code in folly and how it gets used to know if bundling all of folly directly into it makes sense in practice. (This would potentially pose a challenge for dependencies that want to depend on folly both via the cython extension and directly as a C++ library.)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I followed the example for singleton_thread_local_overload in top-level CMakeLists.txt.
I could look into, cherry-picking the objects required by the python extensions into code into the a new library; will see how far I get.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't bother with cherry-picking objects to create a new library, I was more just suggesting building two different versions of the existing library.

e.g., we could build libfolly.a and libfolly_pic.a, and the cython extension could link in libfolly_pic.a You could probably do this relatively easily with something like

add_library(folly_pic $<TARGET_OBJECTS:folly_base>)
set_property(TARGET folly_pic PROPERTY POSITION_INDEPENDENT_CODE 1)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have updated the diff to include a folly_pic library; but it pretty much means compiling all the sources twice. (I tested the suggested code:

add_library(folly_pic $<TARGET_OBJECTS:folly_base>)
set_property(TARGET folly_pic PROPERTY POSITION_INDEPENDENT_CODE 1)

but this resulted in a "folly_pic" which was compiled without -fPIC; because this option was not applied to the creation of the objects in folly_base.

I have also read quite a bit further on the subject of position independent code; while it may have a performance impact on the compiled code, as I understanding Darwin enable PIC by default and its mandatory for iOS.

https://eli.thegreenplace.net/2011/11/03/position-independent-code-pic-in-shared-libraries/
(specifically "The costs of PIC")

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it will mean compiling everything twice, but I think this is probably the right thing to do. I would generally be inclined to:

  • Add an option to control if the cython extension should be built or not, so that this can be disabled even if Cython is available on the system.
  • If the building the Cython extension is enabled and BUILD_SHARED_LIBS was not explicitly enabled, do compile everything twice (once for the static libfolly.a library to be installed, and once for the libfolly_pic.a library to link into the extension). If PIC is unconditionally enabled one Mac or other systems we could potentially avoid double compiling there.

It's possible we might want/need another configuration option to control if the Cython extension links against folly statically (bundling all of the folly code directly into the extension) or dynamically. Linking against things dynamically is much more common for Python extensions. However, since folly provides no ABI compatibility guarantees across changes deploying folly as a shared library is somewhat dangerous. For a python extension we might be able to do something a little smarter by deploying folly as a shared library installed in the python extension directory, and including $ORIGIN in the extensions rpath, so that the python extension can find it but it would be found by normal C++ link commands. We might also want to stick the commit ID in the shared library's soname to make sure code can't run if it somehow ends up running with an unexpected version of the library.

folly/CMakeLists.txt Show resolved Hide resolved
folly/setup.py Outdated
ext = Extension("folly.executor",
sources=['folly/executor.pyx'],
include_dirs=[os.getcwd()+"/..", os.getcwd()],
libraries=['folly', 'glog', 'double-conversion', 'iberty'])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming the dependencies on glog, double-conversion and iberty are only indirect dependencies through libfolly.

It would be nicer to pass this information in to the setup module, as the list of dependencies can be somewhat dynamic based on what was detected by CMake at folly's configure time.
In the CMake code, get_target_property(YOUR_VAR_NAME folly INTERFACE_LINK_LIBRARIES) will get the list of libraries that folly depends on.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I shall experiment with it and see what I can do.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've spent quite a while looking into this: I cannot see an elegant way to pass the values form get_target_property(YOUR_VAR_NAME folly INTERFACE_LINK_LIBRARIES) through to setup.py. To give an example the output of:

Threads::Threads;/usr/lib/x86_64-linux-gnu/libboost_context.so;/usr/lib/x86_64-linux-gnu/libboost_chrono.so;/usr/lib/x86_64-linux-gnu/libboost_date_time.so;/usr/lib/x86_64-linux-gnu/libboost_filesystem.so;/usr/lib/x86_64-linux-gnu/libboost_program_options.so;/usr/lib/x86_64-linux-gnu/libboost_regex.so;/usr/lib/x86_64-linux-gnu/libboost_system.so;/usr/lib/x86_64-linux-gnu/libboost_thread.so;/usr/lib/x86_64-linux-gnu/libboost_atomic.so;/usr/lib/x86_64-linux-gnu/libpthread.so;/usr/lib/x86_64-linux-gnu/libdouble-conversion.so;/usr/lib/x86_64-linux-gnu/libglog.so;/usr/lib/x86_64-linux-gnu/libevent.so;/usr/lib/x86_64-linux-gnu/libssl.so;/usr/lib/x86_64-linux-gnu/libcrypto.so;/usr/lib/x86_64-linux-gnu/libz.so;/usr/lib/x86_64-linux-gnu/libbz2.so;/usr/lib/x86_64-linux-gnu/liblzma.so;/usr/lib/x86_64-linux-gnu/liblz4.so;/usr/lib/x86_64-linux-gnu/libzstd.so;/usr/lib/x86_64-linux-gnu/libsnappy.so;/usr/lib/x86_64-linux-gnu/libiberty.a;dl;gflags

In fact its probably easier to read the libfolly.pc (pkg-config) file back and use that from within setup.py.
This rubs against one of the most challenging parts of building with two systems, CMake and Cython's distutils.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting the info from libfolly.pc would be nice if that isn't too hard.

Landing the current code as-is for now is also okay with me, and we can come back later to improve it if we need to. One thing I might check is if libelf and libdwarf need to be included here if they were found at configure time. If they are found FOLLY_USE_SYMBOLIZER will default to ON, and I think folly's init code may then depend on these libraries.

@calebmarchent calebmarchent force-pushed the build_python_bindings_in_oss branch from 347aa93 to ab1fa91 Compare January 16, 2019 20:04
Caleb Marchent added 8 commits January 16, 2019 20:16
setup.py to create folly Cython bindings

Minimum required to get fbthrift to compile in OSS, so only includes
executor

Cython requires that source files (pyx and pxd) are in a directory
matching the extension name, to provide this a tree of symbolic links is
created and the Cython compile happens in that directory.

FIXME: Handle systems that lack required tooling gracefully (don't cause
build failure)
  - Python3 > 3.6 available?
  - Cython installed?

Test Plan:

Dimensions to conder in test plan:
* Distro:
  * Ubuntu 16.04
* Cython?
  * With / without Cython installed
* Python Version
  * Only test with Python3

* Install with alternative DESTDIR
* Configure CMake in source dir
* Configure CMake in _build dir
Avoid unwanted sources being included in the installation when compile
in source tree; by creating a unique directory.
-fPIC is passed to the compiler on generation of objects, to compile
both with and without PIC (Position Independent Code), a second lib is
required.
@calebmarchent calebmarchent force-pushed the build_python_bindings_in_oss branch from ab1fa91 to 30e6f67 Compare January 16, 2019 20:23
Caleb Marchent added 3 commits January 17, 2019 11:42
Was failing on clean machine (without Folly installed) as folly_pic
target lacked explicit include paths.
Also:
  * Pulled folly_pic CMake statements together so that they can be
wrapped in single option
  * Use folly_base sources to create folly_pic, to ensure sources kept
in sync with original folly.
* Allows us to "require" Python and Cython for compilation, which will
ensure that someone trying to compile the extensions has the tools
needed.
Copy link
Contributor

@facebook-github-bot facebook-github-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@calebmarchent has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

sandraiser pushed a commit to sandraiser/folly that referenced this pull request Mar 4, 2019
Summary:
setup.py to create folly Cython bindings

Minimum required to get fbthrift to compile in OSS, so only includes executor

Cython requires that source files (pyx and pxd) are in a directory matching the extension name, to provide this a tree of symbolic links is created and the Cython compile happens in that directory.

  - Python3 > 3.6 available?
  - Cython installed?
Pull Request resolved: facebook#992

Reviewed By: simpkins

Differential Revision: D13716102

Pulled By: calebmarchent

fbshipit-source-id: 5fb285b0b43e8b6d1774fa4b6f2525c327cbcc7e
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants