Skip to content

Commit 2378f0a

Browse files
committed
toposort extension modules so that ordering doesn't matter
1 parent f9faea7 commit 2378f0a

File tree

5 files changed

+44
-6
lines changed

5 files changed

+44
-6
lines changed

src/semiwrap/cmd_gen_modinit_hpp.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ def main():
101101
module_name = sys.argv[1]
102102
output_hpp = sys.argv[2]
103103
inputs = sys.argv[3:]
104-
assert len(inputs) > 0
105104
except Exception as e:
106105
print(__doc__, file=sys.stderr)
107106
sys.exit(1)

src/semiwrap/makeplan.py

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
from .pkgconf_cache import PkgconfCache
1616
from .pyproject import PyProject
1717

18+
import toposort
19+
1820

1921
@dataclasses.dataclass
2022
class Entrypoint:
@@ -150,10 +152,7 @@ def generate(self):
150152
# Generate extension modules
151153
#
152154

153-
for package_name, extension in projectcfg.extension_modules.items():
154-
if extension.ignore:
155-
continue
156-
155+
for package_name, extension in self._sorted_extension_modules():
157156
try:
158157
yield from self._process_extension_module(package_name, extension)
159158
except Exception as e:
@@ -215,6 +214,32 @@ def _process_export_type_caster(self, name: str, caster_cfg: TypeCasterConfig):
215214
# store it so it can be used elsewhere
216215
self.local_caster_targets[name] = BuildTargetOutput(caster_target, 0)
217216

217+
def _sorted_extension_modules(
218+
self,
219+
) -> T.Generator[T.Tuple[str, ExtensionModuleConfig], None, None]:
220+
# sort extension modules by dependencies, that way modules can depend on other modules
221+
# also declared in pyproject.toml without needing to worry about ordering in the file
222+
by_name = {}
223+
to_sort: T.Dict[str, T.Set[str]] = {}
224+
225+
for package_name, extension in self.pyproject.project.extension_modules.items():
226+
if extension.ignore:
227+
continue
228+
229+
name = extension.name or package_name.replace(".", "_")
230+
by_name[name] = (package_name, extension)
231+
232+
deps = to_sort.setdefault(name, set())
233+
for dep in extension.wraps:
234+
deps.add(dep)
235+
for dep in extension.depends:
236+
deps.add(dep)
237+
238+
for name in toposort.toposort_flatten(to_sort, sort=True):
239+
data = by_name.get(name)
240+
if data:
241+
yield data
242+
218243
def _process_extension_module(
219244
self, package_name: str, extension: ExtensionModuleConfig
220245
):

tests/cpp/sw-test-base/meson.build

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,8 @@ swtest_base__module2_sources += files(
1212
'src/swtest_base/cpp/main2.cpp',
1313
)
1414

15+
swtest_base__module3_sources += files(
16+
'src/swtest_base/cpp/main3.cpp',
17+
)
18+
1519
subdir('wrapcfg/modules')

tests/cpp/sw-test-base/pyproject.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,16 @@ base_class = "cpp/baseclass.h"
2929

3030

3131
[tool.semiwrap.extension_modules."swtest_base._module2"]
32-
depends = ["swtest_base__module"]
32+
depends = ["swtest_base__module", "swtest_base__module3"]
3333

3434
[tool.semiwrap.extension_modules."swtest_base._module2".headers]
3535
fn2 = "cpp/fn2.h"
3636

37+
38+
[tool.semiwrap.extension_modules."swtest_base._module3"]
39+
# empty module to test dependency on module declared after a module
40+
41+
3742
[tool.semiwrap.export_type_casters.sw-test-base-casters]
3843
pypackage = "swtest_base"
3944
includedir = ["src/swtest_base/cpp/type_casters"]
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#include <semiwrap_init.swtest_base._module3.hpp>
2+
3+
SEMIWRAP_PYBIND11_MODULE(m) {
4+
initWrapper(m);
5+
}

0 commit comments

Comments
 (0)