Skip to content

Commit 2685b60

Browse files
kostubclaude
andauthored
Fix SPM consumer build: qualify cross-directory header imports (#215) (#217)
Public headers in render/ imported sibling headers from lib/ by bare filename (e.g. `#import "MTMathList.h"`). That only resolves via the target-internal `lib` header search path, which is applied when building iosMath's own sources but NOT when a downstream SPM consumer builds the `iosMath` Clang module from module.modulemap. Consumers therefore failed with "'MTMathList.h' file not found" / "could not build module 'iosMath'", while the bundled demo and in-package tests worked. Qualify the render -> lib imports as `lib/MTMathList.h` so they resolve from the package's public-headers root (exposed to consumers), and add that root to each target's header search paths so internal builds keep resolving the qualified path. Add `iosMathConsumerTests`, a test target that imports iosMath purely as a Clang module with no header search paths, reproducing external SPM consumption. It fails to compile if a bare cross-directory import returns. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent c2ab4af commit 2685b60

5 files changed

Lines changed: 56 additions & 3 deletions

File tree

Package.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ let package = Package(
2222
],
2323
publicHeadersPath: ".",
2424
cSettings: [
25+
.headerSearchPath("."),
2526
.headerSearchPath("lib"),
2627
.headerSearchPath("render"),
2728
.headerSearchPath("render/internal"),
@@ -33,6 +34,7 @@ let package = Package(
3334
path: "iosMathTests",
3435
exclude: ["en.lproj"],
3536
cSettings: [
37+
.headerSearchPath("../iosMath"),
3638
.headerSearchPath("../iosMath/lib"),
3739
.headerSearchPath("../iosMath/render"),
3840
.headerSearchPath("../iosMath/render/internal"),
@@ -43,6 +45,7 @@ let package = Package(
4345
dependencies: ["iosMath"],
4446
path: "iosMathSwiftTests",
4547
cSettings: [
48+
.headerSearchPath("../iosMath"),
4649
.headerSearchPath("../iosMath/lib"),
4750
.headerSearchPath("../iosMath/render"),
4851
.headerSearchPath("../iosMath/render/internal"),
@@ -51,5 +54,14 @@ let package = Package(
5154
.swiftLanguageMode(.v5),
5255
]
5356
),
57+
// Regression guard for issue #215. Imports `iosMath` purely as a Clang
58+
// module with NO header search paths, reproducing how an external SPM
59+
// consumer builds the module. If a public header reintroduces a bare
60+
// cross-directory `#import`, this target fails to compile.
61+
.testTarget(
62+
name: "iosMathConsumerTests",
63+
dependencies: ["iosMath"],
64+
path: "iosMathConsumerTests"
65+
),
5466
]
5567
)

iosMath/render/MTFontManager.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
@import CoreText;
1414

1515
#import "MTFont.h"
16-
#import "MTMathList.h"
16+
#import "lib/MTMathList.h"
1717

1818
NS_ASSUME_NONNULL_BEGIN
1919

iosMath/render/MTMathListDisplay.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
#import "MTConfig.h"
1919

2020
#import "MTFont.h"
21-
#import "MTMathList.h"
21+
#import "lib/MTMathList.h"
2222

2323
NS_ASSUME_NONNULL_BEGIN
2424

iosMath/render/MTMathUILabel.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
#import "MTConfig.h"
1616

1717
#import "MTFont.h"
18-
#import "MTMathList.h"
18+
#import "lib/MTMathList.h"
1919
#import "MTMathListDisplay.h"
2020

2121
/**
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// iosMathModuleConsumerTests.swift
2+
// Regression test for issue #215: "Clang dependency scanning failure,
3+
// fatal error: MTMathList.h not found."
4+
//
5+
// This target deliberately depends on `iosMath` and imports it *purely as a
6+
// Clang module*, with NO header search paths configured in Package.swift. That
7+
// reproduces exactly how a downstream Swift Package Manager consumer builds the
8+
// module: from `module.modulemap` against the package's public-headers root,
9+
// without iosMath's target-internal `lib`/`render` search paths.
10+
//
11+
// The bug was that public headers in `render/` imported sibling headers in
12+
// `lib/` by bare filename (e.g. `#import "MTMathList.h"`), which only resolves
13+
// when the internal `lib` search path is present. External consumers (and this
14+
// target) lack that path, so building the module failed with
15+
// "'MTMathList.h' file not found".
16+
//
17+
// If that regression returns, this target FAILS TO COMPILE — `import iosMath`
18+
// forces the module (all module-map headers) to build. The assertions below are
19+
// secondary; the real guard is that this file compiles at all. Referencing a
20+
// `render/` type (MTMathUILabel) and a `lib/` type (MTMathList) together keeps
21+
// the cross-directory include in the compiled surface.
22+
23+
import XCTest
24+
import iosMath
25+
26+
final class iosMathModuleConsumerTests: XCTestCase {
27+
28+
// Exercises the render -> lib cross-directory include path. MTMathUILabel
29+
// lives in render/ and pulls in MTMathList from lib/.
30+
@MainActor
31+
func testModuleBuildsAndRendersCrossDirectoryTypes() {
32+
let label = MTMathUILabel()
33+
label.latex = #"\frac{1}{2}"#
34+
XCTAssertNotNil(label.mathList)
35+
XCTAssertNil(label.error)
36+
37+
// Use the lib/ type directly as well so it stays in the consumed surface.
38+
let list: MTMathList? = label.mathList
39+
XCTAssertNotNil(list)
40+
}
41+
}

0 commit comments

Comments
 (0)