@@ -622,7 +622,13 @@ def copy_link_to_lib(p: pathlib.Path):
622
622
"""
623
623
624
624
625
- def hack_props (td : pathlib .Path , pcbuild_path : pathlib .Path , arch : str , static : bool ):
625
+ def hack_props (
626
+ td : pathlib .Path ,
627
+ pcbuild_path : pathlib .Path ,
628
+ arch : str ,
629
+ static : bool ,
630
+ building_libffi : bool ,
631
+ ):
626
632
# TODO can we pass props into msbuild.exe?
627
633
628
634
# Our dependencies are in different directories from what CPython's
@@ -724,18 +730,37 @@ def hack_props(td: pathlib.Path, pcbuild_path: pathlib.Path, arch: str, static:
724
730
b"<_DLLSuffix>-1_1-%s</_DLLSuffix>" % suffix ,
725
731
)
726
732
733
+ libffi_props = pcbuild_path / "libffi.props"
734
+
735
+ if static and building_libffi :
736
+ # For some reason the built .lib doesn't have the -7 suffix in
737
+ # static build mode. This is possibly a side-effect of CPython's
738
+ # libffi build script not officially supporting static-only builds.
739
+ static_replace_in_file (
740
+ libffi_props ,
741
+ b"<AdditionalDependencies>libffi-7.lib;%(AdditionalDependencies)</AdditionalDependencies>" ,
742
+ b"<AdditionalDependencies>libffi.lib;%(AdditionalDependencies)</AdditionalDependencies>" ,
743
+ )
744
+
727
745
728
746
def hack_project_files (
729
747
td : pathlib .Path ,
730
748
cpython_source_path : pathlib .Path ,
731
749
build_directory : str ,
732
750
static : bool ,
751
+ building_libffi : bool ,
733
752
):
734
753
"""Hacks Visual Studio project files to work with our build."""
735
754
736
755
pcbuild_path = cpython_source_path / "PCbuild"
737
756
738
- hack_props (td , pcbuild_path , build_directory , static = static )
757
+ hack_props (
758
+ td ,
759
+ pcbuild_path ,
760
+ build_directory ,
761
+ static = static ,
762
+ building_libffi = building_libffi ,
763
+ )
739
764
740
765
# Our SQLite directory is named weirdly. This throws off version detection
741
766
# in the project file. Replace the parsing logic with a static string.
@@ -797,6 +822,24 @@ def hack_project_files(
797
822
br'<ClCompile Include="$(opensslIncludeDir)\openssl\applink.c">' ,
798
823
)
799
824
825
+ pythoncore_proj = pcbuild_path / "pythoncore.vcxproj"
826
+
827
+ # normally the _ctypes extension/project pulls in libffi via
828
+ # <Link><AdditionalDependencies>. However, as part of converting this
829
+ # extension to static, we lose the transitive dependency. Here, we
830
+ # hack pythoncore as a one-off to add the dependency. Ideally we would
831
+ # handle this when hacking the extension's project. But it is easier to
832
+ # do here.
833
+ if static and building_libffi :
834
+ libffi_path = td / "libffi" / "libffi.lib"
835
+ static_replace_in_file (
836
+ pythoncore_proj ,
837
+ b"<AdditionalDependencies>version.lib;shlwapi.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>" ,
838
+ b"<AdditionalDependencies>version.lib;shlwapi.lib;ws2_32.lib;"
839
+ + bytes (libffi_path )
840
+ + b";%(AdditionalDependencies)</AdditionalDependencies>" ,
841
+ )
842
+
800
843
if static :
801
844
for extension , entry in sorted (CONVERT_TO_BUILTIN_EXTENSIONS .items ()):
802
845
if entry .get ("ignore_static" ):
@@ -810,7 +853,6 @@ def hack_project_files(
810
853
811
854
# pythoncore.vcxproj produces libpython. Typically pythonXY.dll. We change
812
855
# it to produce a static library.
813
- pythoncore_proj = pcbuild_path / "pythoncore.vcxproj"
814
856
pyproject_props = pcbuild_path / "pyproject.props"
815
857
816
858
# Need to replace Py_ENABLE_SHARED with Py_NO_ENABLE_SHARED so symbol
@@ -1314,7 +1356,11 @@ def build_openssl(
1314
1356
1315
1357
1316
1358
def build_libffi (
1317
- python : str , arch : str , sh_exe : pathlib .Path , dest_archive : pathlib .Path
1359
+ python : str ,
1360
+ arch : str ,
1361
+ sh_exe : pathlib .Path ,
1362
+ dest_archive : pathlib .Path ,
1363
+ static : bool ,
1318
1364
):
1319
1365
with tempfile .TemporaryDirectory (prefix = "libffi-build-" ) as td :
1320
1366
td = pathlib .Path (td )
@@ -1355,6 +1401,23 @@ def build_libffi(
1355
1401
/ "prepare_libffi.bat"
1356
1402
)
1357
1403
1404
+ if static :
1405
+ # We replace FFI_BUILDING_DLL with FFI_BUILDING so
1406
+ # declspec(dllexport) isn't used.
1407
+ # We add USE_STATIC_RTL to force static linking of the crt.
1408
+ static_replace_in_file (
1409
+ prepare_libffi ,
1410
+ b"CPPFLAGS='-DFFI_BUILDING_DLL'" ,
1411
+ b"CPPFLAGS='-DFFI_BUILDING -DUSE_STATIC_RTL'" ,
1412
+ )
1413
+
1414
+ # We also need to tell configure to only build a static library.
1415
+ static_replace_in_file (
1416
+ prepare_libffi ,
1417
+ b"--build=$BUILD --host=$HOST;" ,
1418
+ b"--build=$BUILD --host=$HOST --disable-shared;" ,
1419
+ )
1420
+
1358
1421
env = dict (os .environ )
1359
1422
env ["LIBFFI_SOURCE" ] = str (ffi_source_path )
1360
1423
env ["VCVARSALL" ] = str (find_vcvarsall_path ())
@@ -1776,7 +1839,13 @@ def build_cpython(
1776
1839
1777
1840
builtin_extensions = parse_config_c (config_c )
1778
1841
1779
- hack_project_files (td , cpython_source_path , build_directory , static = static )
1842
+ hack_project_files (
1843
+ td ,
1844
+ cpython_source_path ,
1845
+ build_directory ,
1846
+ static = static ,
1847
+ building_libffi = libffi_archive is not None ,
1848
+ )
1780
1849
hack_source_files (cpython_source_path , static = static )
1781
1850
1782
1851
if pgo :
@@ -2114,7 +2183,13 @@ def main():
2114
2183
"libffi-%s-%s.tar" % (target_triple , args .profile )
2115
2184
)
2116
2185
if not libffi_archive .exists ():
2117
- build_libffi (args .python , arch , pathlib .Path (args .sh ), libffi_archive )
2186
+ build_libffi (
2187
+ args .python ,
2188
+ arch ,
2189
+ pathlib .Path (args .sh ),
2190
+ libffi_archive ,
2191
+ "static" in args .profile ,
2192
+ )
2118
2193
else :
2119
2194
libffi_archive = None
2120
2195
0 commit comments