espidf: never resolve generic platform headers against user libraries
Reported by a user whose every ESP32 build failed with errors from libraries he never installed (SoftwareSerial.h, ArduinoBearSSL.h, Adafruit_GFX.h, AsyncElegantOTA.h) coming out of user_libs_all, in a project whose file list doesn't even show that folder. Traced end to end: ESPAsyncWebServer includes <Hash.h> (an ESP8266-core header, guarded for that platform, so arduino-esp32's tree has no such file). The global scan then resolved it to stemi-hexapod's src/Hash.h -- a hexapod-robot library -- merged the WHOLE library into user_libs_all, and its Serial.cpp / Hash.cpp / Server.cpp / BluetoothLowEnergy.cpp / ExpansionDriver.cpp were compiled, each failing on its own unrelated includes. Log line: 'Merging "stemihexapod" into user_libs_all for <Hash.h>'. Hash.h and friends now join the never-resolve-against-user-libs set. They cannot be discovered by the core-tree scan (the core genuinely lacks them) yet their names are generic enough that some installed library owns a file by that name.
This commit is contained in:
parent
aa273a56e9
commit
7b5d30791c
|
|
@ -693,6 +693,20 @@ class ESPIDFCompiler:
|
|||
'Udp.h', 'IPAddress.h', 'Client.h', 'Server.h', 'Stream.h',
|
||||
'Print.h', 'Printable.h', 'WiFiUdp.h', 'WiFiClient.h',
|
||||
'WiFiServer.h', 'WiFiType.h', 'esp_wifi.h',
|
||||
# Platform headers that do NOT exist in the arduino-esp32 core, so
|
||||
# the core-tree scan can't discover them, yet carry names generic
|
||||
# enough that some random installed library owns a file by that
|
||||
# name. Resolving one drags that whole library into user_libs_all
|
||||
# and its sources then fail on THEIR own missing includes.
|
||||
#
|
||||
# Reported 2026-08-03 (nikas79): ESPAsyncWebServer includes <Hash.h>
|
||||
# (an ESP8266-core header, guarded for that platform) and the global
|
||||
# scan resolved it to `stemihexapod/src/Hash.h` — a hexapod-robot
|
||||
# library — whose Serial.cpp / Hash.cpp / Server.cpp /
|
||||
# BluetoothLowEnergy.cpp / ExpansionDriver.cpp then broke every
|
||||
# ESP32 build with errors naming libraries the user never installed.
|
||||
'Hash.h', 'Serial.h', 'HardwareSerial.h', 'WString.h',
|
||||
'WCharacter.h', 'binary.h', 'pins_arduino.h', 'Esp.h',
|
||||
})
|
||||
|
||||
# arduino-esp32 uses a single library architecture id ("esp32") across
|
||||
|
|
|
|||
|
|
@ -171,3 +171,43 @@ class TestManifestScope(unittest.TestCase):
|
|||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
|
||||
class TestGenericHeaderCollision(unittest.TestCase):
|
||||
"""Issue reported 2026-08-03 (nikas79): ESPAsyncWebServer includes
|
||||
<Hash.h> (an ESP8266-core header) and the global scan resolved it to a
|
||||
hexapod-robot library that happens to ship src/Hash.h. The whole library
|
||||
was merged and its unrelated sources broke every ESP32 build with
|
||||
'fatal error: SoftwareSerial.h' and friends."""
|
||||
|
||||
def setUp(self) -> None:
|
||||
self.tmp = Path(tempfile.mkdtemp())
|
||||
|
||||
def tearDown(self) -> None:
|
||||
shutil.rmtree(self.tmp, ignore_errors=True)
|
||||
|
||||
def test_generic_platform_header_never_resolves_to_a_user_lib(self):
|
||||
ulibs = self.tmp / "Arduino" / "libraries"
|
||||
# A library with a generic Hash.h, exactly like stemi-hexapod.
|
||||
_mk(ulibs / "stemihexapod" / "library.properties",
|
||||
"name=stemi-hexapod\narchitectures=esp32\n")
|
||||
_mk(ulibs / "stemihexapod" / "src" / "Hash.h")
|
||||
_mk(ulibs / "stemihexapod" / "src" / "Serial.cpp",
|
||||
'#include <SoftwareSerial.h>\n')
|
||||
|
||||
c = ESPIDFCompiler()
|
||||
c.arduino_path = ""
|
||||
c._core_headers_cache = None
|
||||
out = self.tmp / "project" / "user_libs"
|
||||
out.mkdir(parents=True)
|
||||
|
||||
_names, hdr2comp = c._resolve_library_components(
|
||||
["Hash.h", "Server.h", "Serial.h"],
|
||||
arduino_libs=ulibs, esp32_libs=None,
|
||||
arduino_comp_name="arduino-esp32", user_libs_dir=out,
|
||||
)
|
||||
for header in ("Hash.h", "Server.h", "Serial.h"):
|
||||
self.assertNotIn(header, hdr2comp, f"{header} must stay core-provided")
|
||||
copied = [p.name for p in out.rglob("*") if p.is_file()]
|
||||
self.assertNotIn("Serial.cpp", copied,
|
||||
"the unrelated library must NOT be merged")
|
||||
|
|
|
|||
Loading…
Reference in New Issue