|  | 
| 15 | 15 | from .pkgconf_cache import PkgconfCache | 
| 16 | 16 | from .pyproject import PyProject | 
| 17 | 17 | 
 | 
|  | 18 | +import toposort | 
|  | 19 | + | 
| 18 | 20 | 
 | 
| 19 | 21 | @dataclasses.dataclass | 
| 20 | 22 | class Entrypoint: | 
| @@ -150,10 +152,7 @@ def generate(self): | 
| 150 | 152 |         # Generate extension modules | 
| 151 | 153 |         # | 
| 152 | 154 | 
 | 
| 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(): | 
| 157 | 156 |             try: | 
| 158 | 157 |                 yield from self._process_extension_module(package_name, extension) | 
| 159 | 158 |             except Exception as e: | 
| @@ -215,6 +214,32 @@ def _process_export_type_caster(self, name: str, caster_cfg: TypeCasterConfig): | 
| 215 | 214 |         # store it so it can be used elsewhere | 
| 216 | 215 |         self.local_caster_targets[name] = BuildTargetOutput(caster_target, 0) | 
| 217 | 216 | 
 | 
|  | 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 | + | 
| 218 | 243 |     def _process_extension_module( | 
| 219 | 244 |         self, package_name: str, extension: ExtensionModuleConfig | 
| 220 | 245 |     ): | 
|  | 
0 commit comments