-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Build python with bazel on unix as well #44914
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
Changes from all commits
7c4806a
b03ab75
7844d4a
12dcf2e
5a2a11b
52ecf4c
2c60873
23071cd
b3924ab
758dfaa
698a18b
f1385ca
2e94975
772870d
ead8645
fa114c8
5fa396d
6ee786e
1652c05
62cb026
195b7ab
7c7da49
510b4a6
3fbbc7c
15a2dc4
41fb394
f3823d6
c888e16
4677c0a
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 |
|---|---|---|
| @@ -1,7 +1,10 @@ | ||
| load("@bazel_lib//lib:copy_to_directory.bzl", "copy_to_directory") | ||
| load("@bazel_lib//lib:run_binary.bzl", "run_binary") | ||
| load("@rules_pkg//pkg:install.bzl", "pkg_install") | ||
| load("@rules_pkg//pkg:mappings.bzl", "REMOVE_BASE_DIRECTORY", "pkg_files") | ||
| load("@rules_pkg//pkg:mappings.bzl", "REMOVE_BASE_DIRECTORY", "pkg_files", "pkg_mklink") | ||
| load("@rules_foreign_cc//foreign_cc:defs.bzl", "configure_make") | ||
| load("@rules_pkg//pkg:mappings.bzl", "strip_prefix") | ||
| load("@rules_pkg//pkg:mappings.bzl", "pkg_attributes") | ||
|
|
||
| # Keep in sync with the ones on repos.MODULE.bazel | ||
| python_externals = { | ||
|
|
@@ -14,6 +17,8 @@ python_externals = { | |
| "tcltk": "8.6.15.0", | ||
| } | ||
|
|
||
| VERSION_STR="3.13" | ||
|
|
||
| # These rules will make it easier to get a reference to their folder via $(location) | ||
| # and they add the version in the folder name (as some of the vcxproj stuff relies on that) | ||
| [ | ||
|
|
@@ -86,22 +91,238 @@ run_binary( | |
| visibility = ["//visibility:public"], | ||
| ) | ||
|
|
||
| pkg_files( | ||
| name = "install_files", | ||
| srcs = select({ | ||
| "@platforms//os:windows": [":python_win"], | ||
| filegroup( | ||
| name = "all", | ||
| srcs = glob(["**"], exclude = ["BUILD.bazel"]), | ||
| ) | ||
|
|
||
| UNIX_BINS = [ | ||
| "pip3", | ||
| "python{}".format(VERSION_STR), | ||
| ] | ||
|
|
||
| python_deps = { | ||
| 'libffi': '-lffi', | ||
| 'libsqlite3': '-lsqlite3', | ||
| 'zlib': '-lz', | ||
| 'bzip2': '-lbz2', | ||
| 'liblzma': '-llzma' | ||
| } | ||
|
|
||
| # The list of build tools we want to override in sysconfigdata.py | ||
| # as they will not be available when building custom integrations without bazel | ||
| to_override_build_tools = [ | ||
| 'ar', | ||
| 'gcc', | ||
| 'g++', | ||
| 'ld', | ||
| ] | ||
|
|
||
| to_override_flags = [ | ||
| 'CFLAGS', | ||
| 'CXXFLAGS', | ||
| 'LDFLAGS', | ||
| ] | ||
|
|
||
| configure_make( | ||
| name = "python_unix", | ||
| configure_options = [ | ||
| "--enable-ipv6", | ||
| "--with-ensurepip=yes", | ||
| "--enable-shared", | ||
| "--without-static-libpython", | ||
| "--with-dbmliborder=", | ||
| # Fixes an issue with __DATE__ being set to undefined `redacted` | ||
| # https://github.com/bazelbuild/rules_foreign_cc/issues/239#issuecomment-478167267 | ||
| "CPPFLAGS='-Dredacted=\\\"redacted\\\"'", | ||
| "--with-openssl=$$EXT_BUILD_DEPS/openssl", | ||
| "--with-openssl-rpath=yes", | ||
| ] + select({ | ||
| "@@//:macos_arm64": ["--with-universal-archs=universal2"], | ||
| "@@//:macos_x86_64": ["--with-universal-archs=intel"], | ||
| "//conditions:default": [], | ||
| }), | ||
| copts = [ | ||
| "-O2", | ||
| ], | ||
| env = { | ||
| "OPT": "-DNDEBUG -fwrapv", | ||
| # Ensure we don't use the system provided .pc | ||
| "PKG_CONFIG_LIBDIR": "/does/not/exist", | ||
| } | { | ||
| dep.upper() + '_CFLAGS': "-I$$EXT_BUILD_DEPS/include" for dep in python_deps.keys() | ||
| } | { | ||
| dep.upper() + '_LIBS': lib for dep, lib in python_deps.items() | ||
| } | select({ | ||
| "@platforms//os:macos": { | ||
| # https://github.com/bazelbuild/bazel/issues/5127 | ||
| "AR": "/usr/bin/ar", | ||
| }, | ||
| "//conditions:default": {}, | ||
| }), | ||
| lib_source = ":all", | ||
| # The single dollar sign here isn't a typo, using 2 seems to confuse rules_foreign_cc's substitution | ||
| # This is meant to allow python to find its dependency during its modules import test. | ||
| # We will use the install_dir rpath later on | ||
| linkopts = ["-Wl,-rpath", "$EXT_BUILD_DEPS/lib"], | ||
| out_binaries = UNIX_BINS, | ||
| out_data_dirs = [ | ||
| "lib", | ||
| ], | ||
| out_include_dir = "include", | ||
| visibility = ["//visibility:public"], | ||
| deps = [ | ||
| "@bzip2//:libbz2", | ||
| "@libffi//:libffi", | ||
chouquette marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| "@openssl//:openssl", | ||
| "@sqlite3//:libsqlite3", | ||
| "@xz//:liblzma", | ||
| "@zlib//:zlib", | ||
| ], | ||
| dynamic_deps = [ | ||
| "@bzip2//:bz2", | ||
| "@libffi//:ffi", | ||
| "@sqlite3//:sqlite3", | ||
| "@xz//:lzma", | ||
| "@zlib//:z", | ||
| ], | ||
| targets = [ | ||
| # Build in parallel but install without parallel execution | ||
| # (see https://github.com/python/cpython/issues/109796) | ||
| "-j 16", | ||
| "install" | ||
| ], | ||
| target_compatible_with = select({ | ||
| "@platforms//os:macos": [], | ||
| "@platforms//os:linux": [], | ||
| "//conditions:default": ["@platforms//:incompatible"], | ||
| }), | ||
| # python's build system will output the entire build config to _sysconfigdata_xxx.py | ||
| # This is later used to build extensions with the same tools/compiler/flags/config as the interpreter | ||
| # However, in our case, that means using tools that are stored in the build sandbox, so they aren't | ||
| # usable when building an extension, causing all builds to fail. | ||
| # Ideally we would want to explicitly replace bazel paths with known alternatives, but we don't | ||
| # have an environment variable holding the value we want to replace so we have to resort to | ||
| # a regular expression replacing paths to tools. | ||
| # We also unset the flags listed in to_override_flags. | ||
| # If we start using some specific build flags that need to be propagated, we will need to include | ||
| # them here instead of replacing them by an empty string. | ||
| postfix_script = " && ".join([ | ||
| "perl -i -pe 's/(:?[a-zA-Z0-9_+.\\/-]+)\\/{tool}\\b/{tool}/g' $$INSTALLDIR/lib/python{version}/_sysconfigdata__*.py".format( | ||
|
Contributor
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. LOL... python needs perl to build.
Contributor
Author
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. Comment added, and replied about the |
||
| tool=tool, | ||
| version=VERSION_STR | ||
| ) for tool in to_override_build_tools | ||
| ]) + " && " + | ||
| " && ".join(["perl -i -pe \"s/\'{flag}\': \'.*\',$$/\'{flag}\': \'\',/g\" $$INSTALLDIR/lib/python{version}/_sysconfigdata__*.py".format( | ||
|
Contributor
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. This also could use a comment. I really can't decode what the intent is from the regex. Nit: In general, sed is more well known and widely used for simple search and replace, and requires one less thing installed on the CI machines.
Contributor
Author
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. agreed for sed, the main reason to use perl here is that I want to replace the values in place, and the behavior for that differs between macOS and GNU sed, and I didn't want to have to duplicate the entire line just to adjust |
||
| flag=flag, | ||
| version=VERSION_STR | ||
| ) for flag in to_override_flags | ||
| ]) | ||
| ) | ||
|
|
||
| pkg_files( | ||
| name = "install_files_win", | ||
| srcs = [":python_win"], | ||
| renames = { | ||
| "python_win": REMOVE_BASE_DIRECTORY, | ||
| }, | ||
| ) | ||
|
|
||
| filegroup( | ||
| name = "libs_unix", | ||
| srcs = [":python_unix"], | ||
| output_group = "lib", | ||
| ) | ||
|
|
||
| # Fix symlinks for libpython3.x shared libraries | ||
| # rules_foreign_cc dereferences symlinks during installation since we're using | ||
| # out_data_dir instead of out_shared_libs, so we need to recreate them | ||
| # For context, we use out_data_dir to copy the entire list of python modules which | ||
| # too long to explicitly list in out_shared_libs, and we can't only copy the | ||
| # lib/python3.X folder as it conflicts with the python3.X executables (rules_foreign_cc | ||
| # output groups are named based on the basename) | ||
|
|
||
| # Filter out the dereferenced symlinks - we'll recreate them as proper symlinks | ||
| copy_to_directory( | ||
| name = "libs_unix_no_symlinks", | ||
| srcs = [":libs_unix"], | ||
| # We want to include libpython3.so & libpython3.13.so.1.0, but | ||
| # exclude libpython3.13.so | ||
| exclude_srcs_patterns = [ | ||
| "**/libpython3.*.so", | ||
| "**/python{}/test/**/*".format(VERSION_STR), | ||
| "**/*.exe", | ||
| "**/Makefile", | ||
| ], | ||
| include_external_repositories = ["*"], | ||
| root_paths = ["python_unix"], | ||
| ) | ||
|
|
||
| # Create symlinks for libpython (rules_pkg 1.2+ supports symlinks in pkg_install) | ||
| pkg_mklink( | ||
| name = "libpython_symlink", | ||
| link_name = "lib/libpython{}.so".format(VERSION_STR), | ||
| target = "libpython{}.so.1.0".format(VERSION_STR), | ||
| attributes = pkg_attributes("0644") | ||
| ) | ||
|
|
||
| pkg_mklink( | ||
| name = "python_bin_symlink", | ||
| link_name = "bin/python3", | ||
| target = "python{}".format(VERSION_STR) | ||
| ) | ||
|
|
||
| filegroup( | ||
| name = "headers_unix", | ||
| srcs = [":python_unix"], | ||
| output_group = "include", | ||
| ) | ||
|
|
||
| [ | ||
| filegroup( | ||
| name = "bins_unix_" + bin, | ||
| srcs = [":python_unix"], | ||
| output_group = bin, | ||
| ) | ||
| for bin in UNIX_BINS | ||
| ] | ||
|
|
||
| pkg_files( | ||
| name = "install_libs_unix", | ||
| srcs = [":libs_unix_no_symlinks"], | ||
| renames = { | ||
| "libs_unix_no_symlinks": REMOVE_BASE_DIRECTORY, | ||
| }, | ||
| attributes = pkg_attributes("0644") | ||
| ) | ||
|
|
||
| pkg_files( | ||
| name = "install_headers_unix", | ||
| srcs = [":headers_unix"], | ||
| ) | ||
|
|
||
| pkg_files( | ||
| name = "install_bins_unix", | ||
| srcs = [":bins_unix_" + bin for bin in UNIX_BINS] + [":python_bin_symlink"], | ||
| prefix = "bin", | ||
| attributes = pkg_attributes("0755") | ||
| ) | ||
|
|
||
| pkg_install( | ||
| name = "install", | ||
| srcs = [":install_files"] + select({ | ||
| srcs = select({ | ||
| "@platforms//os:windows": [ | ||
| "@openssl//:openssl_exe_file", | ||
| ":install_files_win" | ||
| ], | ||
| "//conditions:default": [ | ||
| ":install_libs_unix", | ||
| ":install_headers_unix", | ||
| ":install_bins_unix", | ||
| ":python_bin_symlink", | ||
| ], | ||
| }) + select({ | ||
| "@platforms//os:linux": [":libpython_symlink"], | ||
| "//conditions:default": [], | ||
| }), | ||
| ) | ||
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.
Curious. Since the rest of the product is single platform, why do be build some things with universal?
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.
No idea, this is what was done in omnibus so I kept it as-is, but we might want to take a cl$er look