Ship linkable libraries in the macOS wheel - #21771
Open
shoumikhin wants to merge 15 commits into
Open
Conversation
Contributor
Author
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/21771
Note: Links to docs will display an error until the docs builds have been completed. This comment was automatically generated by Dr. CI and updates every 15 minutes. |
This was referenced Aug 12, 2026
shoumikhin
pushed a commit
that referenced
this pull request
Aug 12, 2026
The macOS wheel shipped one fused Python extension and no linkable libraries, so a
C++ application got nothing from it: the headers and the CMake package were there, but
every component a consumer asked for resolved to nothing. On Linux the same wheel
ships the runtime, the kernels, the delegates, the thread pool and the profiler as
separate libraries, and a C++ application links them directly.
The three mechanisms that made this Linux only now have Mach-O equivalents:
runtime search path $ORIGIN loader_path
keeping a registration
only library linked --no-as-needed -force_load, already present
library identity ELF soname install name relative to rpath
Windows is still refused, because there the runtime carries no export annotations for
a DLL, which is a missing capability rather than a different spelling of one.
The packaging entries and the package config asked for a .so by name, so they would
have looked for a file the build never emits. Both now derive the suffix from the
platform, and the config also accounts for Mach-O putting the version before the
suffix, libfoo.1.dylib, where ELF puts it after, libfoo.so.1.
The two wheel test suites now run on macOS as well, which is what makes the split
verified rather than claimed: the Python extension links these libraries itself, so it
passes whether or not the package config names them or the shipped headers are
complete. Porting them needed a suffix helper, the Mach-O spelling of the symbol
queries, since nm -D asks for a dynamic symbol table that Mach-O does not have, and
otool in place of readelf. One check keeps a documented skip on macOS: ldd resolves
dependencies transitively and reports undefined symbols, and otool -L only lists
recorded names, so claiming equivalence there would weaken the check while appearing
to strengthen coverage.
Test Plan: exercised both platform branches of every changed helper.
The CMake helpers, driven with real CMake and the Apple branch forced, so the macOS
answers are checked rather than assumed:
shipped runtime path Linux $ORIGIN macOS loader_path
two entry path Linux $ORIGIN/../../lib:... macOS loader_path/../../lib;...
library identity Linux version only macOS install name rpath
The Python helpers, loaded under each platform:
suffix .so .dylib
defined symbols nm -DC nm -gU -C
undefined symbols nm -DC --undefined-only nm -gu -C
library file name libexecutorch.so libexecutorch.dylib
The symbol queries and the load command reader were then run against a real Mach-O
library on macOS: 137 defined and 133 undefined symbols listed, and the load commands
read, including the dependency and search path entries and the torch dependency the
libtorch check looks for.
Linux is unaffected, verified by building a wheel from this change and confirming it
still ships the same six libraries.
ghstack-source-id: fecf306
ghstack-comment-id: 5263018041
Pull-Request: #21771
shoumikhin
pushed a commit
that referenced
this pull request
Aug 12, 2026
The macOS wheel shipped one fused Python extension and no linkable libraries, so a
C++ application got nothing from it: the headers and the CMake package were there, but
every component a consumer asked for resolved to nothing. On Linux the same wheel
ships the runtime, the kernels, the delegates, the thread pool and the profiler as
separate libraries, and a C++ application links them directly.
The three mechanisms that made this Linux only now have Mach-O equivalents:
runtime search path $ORIGIN loader_path
keeping a registration
only library linked --no-as-needed -force_load, already present
library identity ELF soname install name relative to rpath
Windows is still refused, because there the runtime carries no export annotations for
a DLL, which is a missing capability rather than a different spelling of one.
The packaging entries and the package config asked for a .so by name, so they would
have looked for a file the build never emits. Both now derive the suffix from the
platform, and the config also accounts for Mach-O putting the version before the
suffix, libfoo.1.dylib, where ELF puts it after, libfoo.so.1.
The two wheel test suites now run on macOS as well, which is what makes the split
verified rather than claimed: the Python extension links these libraries itself, so it
passes whether or not the package config names them or the shipped headers are
complete. Porting them needed a suffix helper, the Mach-O spelling of the symbol
queries, since nm -D asks for a dynamic symbol table that Mach-O does not have, and
otool in place of readelf. One check keeps a documented skip on macOS: ldd resolves
dependencies transitively and reports undefined symbols, and otool -L only lists
recorded names, so claiming equivalence there would weaken the check while appearing
to strengthen coverage.
Test Plan: exercised both platform branches of every changed helper.
The CMake helpers, driven with real CMake and the Apple branch forced, so the macOS
answers are checked rather than assumed:
shipped runtime path Linux $ORIGIN macOS loader_path
two entry path Linux $ORIGIN/../../lib:... macOS loader_path/../../lib;...
library identity Linux version only macOS install name rpath
The Python helpers, loaded under each platform:
suffix .so .dylib
defined symbols nm -DC nm -gU -C
undefined symbols nm -DC --undefined-only nm -gu -C
library file name libexecutorch.so libexecutorch.dylib
The symbol queries and the load command reader were then run against a real Mach-O
library on macOS: 137 defined and 133 undefined symbols listed, and the load commands
read, including the dependency and search path entries and the torch dependency the
libtorch check looks for.
Linux is unaffected, verified by building a wheel from this change and confirming it
still ships the same six libraries.
ghstack-source-id: 8a272c5
ghstack-comment-id: 5263018041
Pull-Request: #21771
shoumikhin
pushed a commit
that referenced
this pull request
Aug 12, 2026
The macOS wheel shipped one fused Python extension and no linkable libraries, so a
C++ application got nothing from it: the headers and the CMake package were there, but
every component a consumer asked for resolved to nothing. On Linux the same wheel
ships the runtime, the kernels, the delegates, the thread pool and the profiler as
separate libraries, and a C++ application links them directly.
The three mechanisms that made this Linux only now have Mach-O equivalents:
runtime search path $ORIGIN loader_path
keeping a registration
only library linked --no-as-needed -force_load, already present
library identity ELF soname install name relative to rpath
Windows is still refused, because there the runtime carries no export annotations for
a DLL, which is a missing capability rather than a different spelling of one.
The packaging entries and the package config asked for a .so by name, so they would
have looked for a file the build never emits. Both now derive the suffix from the
platform, and the config also accounts for Mach-O putting the version before the
suffix, libfoo.1.dylib, where ELF puts it after, libfoo.so.1.
The two wheel test suites now run on macOS as well, which is what makes the split
verified rather than claimed: the Python extension links these libraries itself, so it
passes whether or not the package config names them or the shipped headers are
complete. Porting them needed a suffix helper, the Mach-O spelling of the symbol
queries, since nm -D asks for a dynamic symbol table that Mach-O does not have, and
otool in place of readelf. One check keeps a documented skip on macOS: ldd resolves
dependencies transitively and reports undefined symbols, and otool -L only lists
recorded names, so claiming equivalence there would weaken the check while appearing
to strengthen coverage.
Test Plan: exercised both platform branches of every changed helper.
The CMake helpers, driven with real CMake and the Apple branch forced, so the macOS
answers are checked rather than assumed:
shipped runtime path Linux $ORIGIN macOS loader_path
two entry path Linux $ORIGIN/../../lib:... macOS loader_path/../../lib;...
library identity Linux version only macOS install name rpath
The Python helpers, loaded under each platform:
suffix .so .dylib
defined symbols nm -DC nm -gU -C
undefined symbols nm -DC --undefined-only nm -gu -C
library file name libexecutorch.so libexecutorch.dylib
The symbol queries and the load command reader were then run against a real Mach-O
library on macOS: 137 defined and 133 undefined symbols listed, and the load commands
read, including the dependency and search path entries and the torch dependency the
libtorch check looks for.
Linux is unaffected, verified by building a wheel from this change and confirming it
still ships the same six libraries.
ghstack-source-id: 2600dd7
ghstack-comment-id: 5263018041
Pull-Request: #21771
shoumikhin
pushed a commit
that referenced
this pull request
Aug 12, 2026
The macOS wheel shipped one fused Python extension and no linkable libraries, so a
C++ application got nothing from it: the headers and the CMake package were there, but
every component a consumer asked for resolved to nothing. On Linux the same wheel
ships the runtime, the kernels, the delegates, the thread pool and the profiler as
separate libraries, and a C++ application links them directly.
The three mechanisms that made this Linux only now have Mach-O equivalents:
runtime search path $ORIGIN loader_path
keeping a registration
only library linked --no-as-needed -force_load, already present
library identity ELF soname install name relative to rpath
Windows is still refused, because there the runtime carries no export annotations for
a DLL, which is a missing capability rather than a different spelling of one.
The packaging entries and the package config asked for a .so by name, so they would
have looked for a file the build never emits. Both now derive the suffix from the
platform, and the config also accounts for Mach-O putting the version before the
suffix, libfoo.1.dylib, where ELF puts it after, libfoo.so.1.
The two wheel test suites now run on macOS as well, which is what makes the split
verified rather than claimed: the Python extension links these libraries itself, so it
passes whether or not the package config names them or the shipped headers are
complete. Porting them needed a suffix helper, the Mach-O spelling of the symbol
queries, since nm -D asks for a dynamic symbol table that Mach-O does not have, and
otool in place of readelf. One check keeps a documented skip on macOS: ldd resolves
dependencies transitively and reports undefined symbols, and otool -L only lists
recorded names, so claiming equivalence there would weaken the check while appearing
to strengthen coverage.
Test Plan: exercised both platform branches of every changed helper.
The CMake helpers, driven with real CMake and the Apple branch forced, so the macOS
answers are checked rather than assumed:
shipped runtime path Linux $ORIGIN macOS loader_path
two entry path Linux $ORIGIN/../../lib:... macOS loader_path/../../lib;...
library identity Linux version only macOS install name rpath
The Python helpers, loaded under each platform:
suffix .so .dylib
defined symbols nm -DC nm -gU -C
undefined symbols nm -DC --undefined-only nm -gu -C
library file name libexecutorch.so libexecutorch.dylib
The symbol queries and the load command reader were then run against a real Mach-O
library on macOS: 137 defined and 133 undefined symbols listed, and the load commands
read, including the dependency and search path entries and the torch dependency the
libtorch check looks for.
Linux is unaffected, verified by building a wheel from this change and confirming it
still ships the same six libraries.
ghstack-source-id: 5a6301e
ghstack-comment-id: 5263018041
Pull-Request: #21771
shoumikhin
pushed a commit
that referenced
this pull request
Aug 12, 2026
The macOS wheel shipped one fused Python extension and no linkable libraries, so a
C++ application got nothing from it: the headers and the CMake package were there, but
every component a consumer asked for resolved to nothing. On Linux the same wheel
ships the runtime, the kernels, the delegates, the thread pool and the profiler as
separate libraries, and a C++ application links them directly.
The three mechanisms that made this Linux only now have Mach-O equivalents:
runtime search path $ORIGIN loader_path
keeping a registration
only library linked --no-as-needed -force_load, already present
library identity ELF soname install name relative to rpath
Windows is still refused, because there the runtime carries no export annotations for
a DLL, which is a missing capability rather than a different spelling of one.
The packaging entries and the package config asked for a .so by name, so they would
have looked for a file the build never emits. Both now derive the suffix from the
platform, and the config also accounts for Mach-O putting the version before the
suffix, libfoo.1.dylib, where ELF puts it after, libfoo.so.1.
The two wheel test suites now run on macOS as well, which is what makes the split
verified rather than claimed: the Python extension links these libraries itself, so it
passes whether or not the package config names them or the shipped headers are
complete. Porting them needed a suffix helper, the Mach-O spelling of the symbol
queries, since nm -D asks for a dynamic symbol table that Mach-O does not have, and
otool in place of readelf. One check keeps a documented skip on macOS: ldd resolves
dependencies transitively and reports undefined symbols, and otool -L only lists
recorded names, so claiming equivalence there would weaken the check while appearing
to strengthen coverage.
Test Plan: exercised both platform branches of every changed helper.
The CMake helpers, driven with real CMake and the Apple branch forced, so the macOS
answers are checked rather than assumed:
shipped runtime path Linux $ORIGIN macOS loader_path
two entry path Linux $ORIGIN/../../lib:... macOS loader_path/../../lib;...
library identity Linux version only macOS install name rpath
The Python helpers, loaded under each platform:
suffix .so .dylib
defined symbols nm -DC nm -gU -C
undefined symbols nm -DC --undefined-only nm -gu -C
library file name libexecutorch.so libexecutorch.dylib
The symbol queries and the load command reader were then run against a real Mach-O
library on macOS: 137 defined and 133 undefined symbols listed, and the load commands
read, including the dependency and search path entries and the torch dependency the
libtorch check looks for.
Linux is unaffected, verified by building a wheel from this change and confirming it
still ships the same six libraries.
ghstack-source-id: 2f0e969
ghstack-comment-id: 5263018041
Pull-Request: #21771
shoumikhin
pushed a commit
that referenced
this pull request
Aug 12, 2026
The macOS wheel shipped one fused Python extension and no linkable libraries, so a
C++ application got nothing from it: the headers and the CMake package were there, but
every component a consumer asked for resolved to nothing. On Linux the same wheel
ships the runtime, the kernels, the delegates, the thread pool and the profiler as
separate libraries, and a C++ application links them directly.
The three mechanisms that made this Linux only now have Mach-O equivalents:
runtime search path $ORIGIN loader_path
keeping a registration
only library linked --no-as-needed -force_load, already present
library identity ELF soname install name relative to rpath
Windows is still refused, because there the runtime carries no export annotations for
a DLL, which is a missing capability rather than a different spelling of one.
The packaging entries and the package config asked for a .so by name, so they would
have looked for a file the build never emits. Both now derive the suffix from the
platform, and the config also accounts for Mach-O putting the version before the
suffix, libfoo.1.dylib, where ELF puts it after, libfoo.so.1.
The two wheel test suites now run on macOS as well, which is what makes the split
verified rather than claimed: the Python extension links these libraries itself, so it
passes whether or not the package config names them or the shipped headers are
complete. Porting them needed a suffix helper, the Mach-O spelling of the symbol
queries, since nm -D asks for a dynamic symbol table that Mach-O does not have, and
otool in place of readelf. One check keeps a documented skip on macOS: ldd resolves
dependencies transitively and reports undefined symbols, and otool -L only lists
recorded names, so claiming equivalence there would weaken the check while appearing
to strengthen coverage.
Test Plan: exercised both platform branches of every changed helper.
The CMake helpers, driven with real CMake and the Apple branch forced, so the macOS
answers are checked rather than assumed:
shipped runtime path Linux $ORIGIN macOS loader_path
two entry path Linux $ORIGIN/../../lib:... macOS loader_path/../../lib;...
library identity Linux version only macOS install name rpath
The Python helpers, loaded under each platform:
suffix .so .dylib
defined symbols nm -DC nm -gU -C
undefined symbols nm -DC --undefined-only nm -gu -C
library file name libexecutorch.so libexecutorch.dylib
The symbol queries and the load command reader were then run against a real Mach-O
library on macOS: 137 defined and 133 undefined symbols listed, and the load commands
read, including the dependency and search path entries and the torch dependency the
libtorch check looks for.
Linux is unaffected, verified by building a wheel from this change and confirming it
still ships the same six libraries.
ghstack-source-id: 4e4f552
ghstack-comment-id: 5263018041
Pull-Request: #21771
shoumikhin
pushed a commit
that referenced
this pull request
Aug 12, 2026
The macOS wheel shipped one fused Python extension and no linkable libraries, so a
C++ application got nothing from it: the headers and the CMake package were there, but
every component a consumer asked for resolved to nothing. On Linux the same wheel
ships the runtime, the kernels, the delegates, the thread pool and the profiler as
separate libraries, and a C++ application links them directly.
The three mechanisms that made this Linux only now have Mach-O equivalents:
runtime search path $ORIGIN loader_path
keeping a registration
only library linked --no-as-needed -force_load, already present
library identity ELF soname install name relative to rpath
Windows is still refused, because there the runtime carries no export annotations for
a DLL, which is a missing capability rather than a different spelling of one.
The packaging entries and the package config asked for a .so by name, so they would
have looked for a file the build never emits. Both now derive the suffix from the
platform, and the config also accounts for Mach-O putting the version before the
suffix, libfoo.1.dylib, where ELF puts it after, libfoo.so.1.
The two wheel test suites now run on macOS as well, which is what makes the split
verified rather than claimed: the Python extension links these libraries itself, so it
passes whether or not the package config names them or the shipped headers are
complete. Porting them needed a suffix helper, the Mach-O spelling of the symbol
queries, since nm -D asks for a dynamic symbol table that Mach-O does not have, and
otool in place of readelf. One check keeps a documented skip on macOS: ldd resolves
dependencies transitively and reports undefined symbols, and otool -L only lists
recorded names, so claiming equivalence there would weaken the check while appearing
to strengthen coverage.
Test Plan: exercised both platform branches of every changed helper.
The CMake helpers, driven with real CMake and the Apple branch forced, so the macOS
answers are checked rather than assumed:
shipped runtime path Linux $ORIGIN macOS loader_path
two entry path Linux $ORIGIN/../../lib:... macOS loader_path/../../lib;...
library identity Linux version only macOS install name rpath
The Python helpers, loaded under each platform:
suffix .so .dylib
defined symbols nm -DC nm -gU -C
undefined symbols nm -DC --undefined-only nm -gu -C
library file name libexecutorch.so libexecutorch.dylib
The symbol queries and the load command reader were then run against a real Mach-O
library on macOS: 137 defined and 133 undefined symbols listed, and the load commands
read, including the dependency and search path entries and the torch dependency the
libtorch check looks for.
Linux is unaffected, verified by building a wheel from this change and confirming it
still ships the same six libraries.
ghstack-source-id: 03b7de8
ghstack-comment-id: 5263018041
Pull-Request: #21771
shoumikhin
pushed a commit
that referenced
this pull request
Aug 12, 2026
The macOS wheel shipped one fused Python extension and no linkable libraries, so a
C++ application got nothing from it: the headers and the CMake package were there, but
every component a consumer asked for resolved to nothing. On Linux the same wheel
ships the runtime, the kernels, the delegates, the thread pool and the profiler as
separate libraries, and a C++ application links them directly.
The three mechanisms that made this Linux only now have Mach-O equivalents:
runtime search path $ORIGIN loader_path
keeping a registration
only library linked --no-as-needed -force_load, already present
library identity ELF soname install name relative to rpath
Windows is still refused, because there the runtime carries no export annotations for
a DLL, which is a missing capability rather than a different spelling of one.
The packaging entries and the package config asked for a .so by name, so they would
have looked for a file the build never emits. Both now derive the suffix from the
platform, and the config also accounts for Mach-O putting the version before the
suffix, libfoo.1.dylib, where ELF puts it after, libfoo.so.1.
The two wheel test suites now run on macOS as well, which is what makes the split
verified rather than claimed: the Python extension links these libraries itself, so it
passes whether or not the package config names them or the shipped headers are
complete. Porting them needed a suffix helper, the Mach-O spelling of the symbol
queries, since nm -D asks for a dynamic symbol table that Mach-O does not have, and
otool in place of readelf. One check keeps a documented skip on macOS: ldd resolves
dependencies transitively and reports undefined symbols, and otool -L only lists
recorded names, so claiming equivalence there would weaken the check while appearing
to strengthen coverage.
Test Plan: exercised both platform branches of every changed helper.
The CMake helpers, driven with real CMake and the Apple branch forced, so the macOS
answers are checked rather than assumed:
shipped runtime path Linux $ORIGIN macOS loader_path
two entry path Linux $ORIGIN/../../lib:... macOS loader_path/../../lib;...
library identity Linux version only macOS install name rpath
The Python helpers, loaded under each platform:
suffix .so .dylib
defined symbols nm -DC nm -gU -C
undefined symbols nm -DC --undefined-only nm -gu -C
library file name libexecutorch.so libexecutorch.dylib
The symbol queries and the load command reader were then run against a real Mach-O
library on macOS: 137 defined and 133 undefined symbols listed, and the load commands
read, including the dependency and search path entries and the torch dependency the
libtorch check looks for.
Linux is unaffected, verified by building a wheel from this change and confirming it
still ships the same six libraries.
ghstack-source-id: dcff297
ghstack-comment-id: 5263018041
Pull-Request: #21771
shoumikhin
pushed a commit
that referenced
this pull request
Aug 12, 2026
The macOS wheel shipped one fused Python extension and no linkable libraries, so a
C++ application got nothing from it: the headers and the CMake package were there, but
every component a consumer asked for resolved to nothing. On Linux the same wheel
ships the runtime, the kernels, the delegates, the thread pool and the profiler as
separate libraries, and a C++ application links them directly.
The three mechanisms that made this Linux only now have Mach-O equivalents:
runtime search path $ORIGIN loader_path
keeping a registration
only library linked --no-as-needed -force_load, already present
library identity ELF soname install name relative to rpath
Windows is still refused, because there the runtime carries no export annotations for
a DLL, which is a missing capability rather than a different spelling of one.
The packaging entries and the package config asked for a .so by name, so they would
have looked for a file the build never emits. Both now derive the suffix from the
platform, and the config also accounts for Mach-O putting the version before the
suffix, libfoo.1.dylib, where ELF puts it after, libfoo.so.1.
The two wheel test suites now run on macOS as well, which is what makes the split
verified rather than claimed: the Python extension links these libraries itself, so it
passes whether or not the package config names them or the shipped headers are
complete. Porting them needed a suffix helper, the Mach-O spelling of the symbol
queries, since nm -D asks for a dynamic symbol table that Mach-O does not have, and
otool in place of readelf. One check keeps a documented skip on macOS: ldd resolves
dependencies transitively and reports undefined symbols, and otool -L only lists
recorded names, so claiming equivalence there would weaken the check while appearing
to strengthen coverage.
Test Plan: exercised both platform branches of every changed helper.
The CMake helpers, driven with real CMake and the Apple branch forced, so the macOS
answers are checked rather than assumed:
shipped runtime path Linux $ORIGIN macOS loader_path
two entry path Linux $ORIGIN/../../lib:... macOS loader_path/../../lib;...
library identity Linux version only macOS install name rpath
The Python helpers, loaded under each platform:
suffix .so .dylib
defined symbols nm -DC nm -gU -C
undefined symbols nm -DC --undefined-only nm -gu -C
library file name libexecutorch.so libexecutorch.dylib
The symbol queries and the load command reader were then run against a real Mach-O
library on macOS: 137 defined and 133 undefined symbols listed, and the load commands
read, including the dependency and search path entries and the torch dependency the
libtorch check looks for.
Linux is unaffected, verified by building a wheel from this change and confirming it
still ships the same six libraries.
ghstack-source-id: c1ba013
ghstack-comment-id: 5263018041
Pull-Request: #21771
shoumikhin
requested a deployment
to
cadence
August 12, 2026 13:13 — with
GitHub Actions
In progress
shoumikhin
pushed a commit
that referenced
this pull request
Aug 12, 2026
The macOS wheel shipped one fused Python extension and no linkable libraries, so a
C++ application got nothing from it: the headers and the CMake package were there, but
every component a consumer asked for resolved to nothing. On Linux the same wheel
ships the runtime, the kernels, the delegates, the thread pool and the profiler as
separate libraries, and a C++ application links them directly.
The three mechanisms that made this Linux only now have Mach-O equivalents:
runtime search path $ORIGIN loader_path
keeping a registration
only library linked --no-as-needed -force_load, already present
library identity ELF soname install name relative to rpath
Windows is still refused, because there the runtime carries no export annotations for
a DLL, which is a missing capability rather than a different spelling of one.
The packaging entries and the package config asked for a .so by name, so they would
have looked for a file the build never emits. Both now derive the suffix from the
platform, and the config also accounts for Mach-O putting the version before the
suffix, libfoo.1.dylib, where ELF puts it after, libfoo.so.1.
The two wheel test suites now run on macOS as well, which is what makes the split
verified rather than claimed: the Python extension links these libraries itself, so it
passes whether or not the package config names them or the shipped headers are
complete. Porting them needed a suffix helper, the Mach-O spelling of the symbol
queries, since nm -D asks for a dynamic symbol table that Mach-O does not have, and
otool in place of readelf. One check keeps a documented skip on macOS: ldd resolves
dependencies transitively and reports undefined symbols, and otool -L only lists
recorded names, so claiming equivalence there would weaken the check while appearing
to strengthen coverage.
Test Plan: exercised both platform branches of every changed helper.
The CMake helpers, driven with real CMake and the Apple branch forced, so the macOS
answers are checked rather than assumed:
shipped runtime path Linux $ORIGIN macOS loader_path
two entry path Linux $ORIGIN/../../lib:... macOS loader_path/../../lib;...
library identity Linux version only macOS install name rpath
The Python helpers, loaded under each platform:
suffix .so .dylib
defined symbols nm -DC nm -gU -C
undefined symbols nm -DC --undefined-only nm -gu -C
library file name libexecutorch.so libexecutorch.dylib
The symbol queries and the load command reader were then run against a real Mach-O
library on macOS: 137 defined and 133 undefined symbols listed, and the load commands
read, including the dependency and search path entries and the torch dependency the
libtorch check looks for.
Linux is unaffected, verified by building a wheel from this change and confirming it
still ships the same six libraries.
ghstack-source-id: 4176fdc
ghstack-comment-id: 5263018041
Pull-Request: #21771
shoumikhin
requested a deployment
to
cadence
August 12, 2026 13:13 — with
GitHub Actions
In progress
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The macOS wheel shipped one fused Python extension and no linkable libraries, so a
C++ application got nothing from it: the headers and the CMake package were there, but
every component a consumer asked for resolved to nothing. On Linux the same wheel
ships the runtime, the kernels, the delegates, the thread pool and the profiler as
separate libraries, and a C++ application links them directly.
The three mechanisms that made this Linux only now have Mach-O equivalents:
Windows is still refused, because there the runtime carries no export annotations for
a DLL, which is a missing capability rather than a different spelling of one.
The packaging entries and the package config asked for a .so by name, so they would
have looked for a file the build never emits. Both now derive the suffix from the
platform, and the config also accounts for Mach-O putting the version before the
suffix, libfoo.1.dylib, where ELF puts it after, libfoo.so.1.
The two wheel test suites now run on macOS as well, which is what makes the split
verified rather than claimed: the Python extension links these libraries itself, so it
passes whether or not the package config names them or the shipped headers are
complete. Porting them needed a suffix helper, the Mach-O spelling of the symbol
queries, since nm -D asks for a dynamic symbol table that Mach-O does not have, and
otool in place of readelf. One check keeps a documented skip on macOS: ldd resolves
dependencies transitively and reports undefined symbols, and otool -L only lists
recorded names, so claiming equivalence there would weaken the check while appearing
to strengthen coverage.
Test Plan: exercised both platform branches of every changed helper.
The CMake helpers, driven with real CMake and the Apple branch forced, so the macOS
answers are checked rather than assumed:
The Python helpers, loaded under each platform:
The symbol queries and the load command reader were then run against a real Mach-O
library on macOS: 137 defined and 133 undefined symbols listed, and the load commands
read, including the dependency and search path entries and the torch dependency the
libtorch check looks for.
Linux is unaffected, verified by building a wheel from this change and confirming it
still ships the same six libraries.