Skip to content

toolchains: board up broeken window, stub libxml2 to silence ld.lld warning#9809

Closed
oharboe wants to merge 9 commits intoThe-OpenROAD-Project:masterfrom
Pinata-Consulting:libxml-warning-fix
Closed

toolchains: board up broeken window, stub libxml2 to silence ld.lld warning#9809
oharboe wants to merge 9 commits intoThe-OpenROAD-Project:masterfrom
Pinata-Consulting:libxml-warning-fix

Conversation

@oharboe
Copy link
Collaborator

@oharboe oharboe commented Mar 18, 2026

avoids sudo ln hacks on Ubuntu, for instance.

ld.lld dynamically links libxml2 but only uses it for Windows manifest merging. Build a versioned stub into @llvm_prebuilt lib/ via patch_cmds so the RUNPATH picks it up instead of the system library, eliminating the "no version information available" warning and the libxml2-dev dependency.

@oharboe oharboe requested a review from maliberty March 18, 2026 15:36
@oharboe
Copy link
Collaborator Author

oharboe commented Mar 18, 2026

@hzeller 😿 What else can we do?

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request addresses the issue of ld.lld dynamically linking libxml2 by introducing a stub library. This eliminates the need for the libxml2-dev dependency and resolves the "no version information available" warning. The changes involve modifying the MODULE.bazel file to include the stub and adding new files for the stub's source and documentation. I have identified one area for improvement related to the patch command in MODULE.bazel.

Comment on lines +200 to +241
"""\
cat > _stub.c << 'STUB'
#include <stdlib.h>
void *xmlFree = 0;
void *xmlAddChild(void *p, void *c) { abort(); }
void *xmlCopyNamespace(void *n) { abort(); }
void xmlDocDumpFormatMemoryEnc(void *d,void *b,void *s,
const char *e, int f) { abort(); }
void *xmlDocGetRootElement(void *d) { abort(); }
void *xmlDocSetRootElement(void *d, void *r) { abort(); }
void xmlFreeDoc(void *d) { abort(); }
void xmlFreeNode(void *n) { abort(); }
void xmlFreeNs(void *n) { abort(); }
void *xmlNewDoc(const void *v) { abort(); }
void *xmlNewNs(void *n, const void *h, const void *p) { abort(); }
void *xmlNewProp(void *n, const void *a, const void *v) { abort(); }
void *xmlReadMemory(const char *b, int sz, const char *u,
const char *e, int o) { abort(); }
void xmlSetGenericErrorFunc(void *c, void *h) { abort(); }
void *xmlStrdup(const void *s) { abort(); }
void xmlUnlinkNode(void *n) { abort(); }
STUB

cat > _stub.ver << 'VER'
LIBXML2_2.4.30 {
global: xmlAddChild; xmlCopyNamespace; xmlDocDumpFormatMemoryEnc;
xmlDocGetRootElement; xmlDocSetRootElement; xmlFree;
xmlFreeDoc; xmlFreeNode; xmlFreeNs; xmlNewDoc; xmlNewNs;
xmlNewProp; xmlSetGenericErrorFunc; xmlStrdup; xmlUnlinkNode;
local: *;
};
LIBXML2_2.6.0 {
global: xmlReadMemory;
} LIBXML2_2.4.30;
VER

cc -shared -o lib/libxml2.so.2 \
-Wl,--version-script=_stub.ver \
-Wl,-soname,libxml2.so.2 \
_stub.c \
&& rm _stub.c _stub.ver
""",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The patch_cmds script in MODULE.bazel compiles the stub inline. While functional, this approach tightly couples the stub's compilation details to the MODULE.bazel file. For better maintainability and separation of concerns, consider moving the compilation logic to a separate Bazel rule (e.g., a genrule in bazel/libxml2_stub/BUILD.bazel) and referencing the output of that rule in MODULE.bazel. This would make the stub more modular and easier to update or modify in the future.

Also, the patch_cmds attribute is executed during the repository fetching phase. Any errors in these commands can be difficult to debug, as they occur before the main build process. Moving the compilation to a standard Bazel rule would allow for better error reporting and debugging.

Finally, the canonical source is in bazel/libxml2_stub/, but the actual compilation happens in MODULE.bazel. This is inconsistent and could lead to confusion. Centralizing the logic in bazel/libxml2_stub/ would improve clarity.

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions


#include <stdlib.h>

void *xmlFree = NULL;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: inclusion of deprecated C++ header 'stdlib.h'; consider using 'cstdlib' instead [modernize-deprecated-headers]

Suggested change
void *xmlFree = NULL;
><cstdlib>


#include <stdlib.h>

void *xmlFree = NULL;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: variable 'xmlFree' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
void *xmlFree = NULL;
static

#include <stdlib.h>

void *xmlFree = NULL;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: use nullptr [modernize-use-nullptr]

Suggested change
;nullptr


void *xmlFree = NULL;

void *xmlAddChild(void *p, void *c) { abort(); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: function 'xmlAddChild' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
void *xmlAddChild(void *p, void *c) { abort(); }
static

void *xmlFree = NULL;

void *xmlAddChild(void *p, void *c) { abort(); }
void *xmlCopyNamespace(void *n) { abort(); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: function 'xmlCopyNamespace' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
void *xmlCopyNamespace(void *n) { abort(); }
}static

void xmlFreeNs(void *n) { abort(); }
void *xmlNewDoc(const void *v) { abort(); }
void *xmlNewNs(void *n, const void *h, const void *p) { abort(); }
void *xmlNewProp(void *n, const void *name, const void *v){ abort(); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: function 'xmlNewProp' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
void *xmlNewProp(void *n, const void *name, const void *v){ abort(); }
}static

void *xmlNewDoc(const void *v) { abort(); }
void *xmlNewNs(void *n, const void *h, const void *p) { abort(); }
void *xmlNewProp(void *n, const void *name, const void *v){ abort(); }
void *xmlReadMemory(const char *b, int sz, const char *u,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: function 'xmlReadMemory' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
void *xmlReadMemory(const char *b, int sz, const char *u,
}static

void *xmlNewProp(void *n, const void *name, const void *v){ abort(); }
void *xmlReadMemory(const char *b, int sz, const char *u,
const char *e, int o) { abort(); }
void xmlSetGenericErrorFunc(void *c, void *h) { abort(); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: function 'xmlSetGenericErrorFunc' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
void xmlSetGenericErrorFunc(void *c, void *h) { abort(); }
}static

void *xmlReadMemory(const char *b, int sz, const char *u,
const char *e, int o) { abort(); }
void xmlSetGenericErrorFunc(void *c, void *h) { abort(); }
void *xmlStrdup(const void *s) { abort(); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: function 'xmlStrdup' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
void *xmlStrdup(const void *s) { abort(); }
}static

const char *e, int o) { abort(); }
void xmlSetGenericErrorFunc(void *c, void *h) { abort(); }
void *xmlStrdup(const void *s) { abort(); }
void xmlUnlinkNode(void *n) { abort(); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: function 'xmlUnlinkNode' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
void xmlUnlinkNode(void *n) { abort(); }
}static

@oharboe oharboe force-pushed the libxml-warning-fix branch 2 times, most recently from 36c072d to 96f485a Compare March 18, 2026 15:45
…arning

avoids sudo ln hacks on Ubuntu, for instance.

ld.lld dynamically links libxml2 but only uses it for Windows manifest
merging.  Build a versioned stub into @llvm_prebuilt lib/ via patch_cmds
so the RUNPATH picks it up instead of the system library, eliminating
the "no version information available" warning and the libxml2-dev
dependency.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
@oharboe oharboe force-pushed the libxml-warning-fix branch from 96f485a to 32ec425 Compare March 18, 2026 15:45
Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

{
abort();
}
void* xmlCopyNamespace(void* n)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: function 'xmlCopyNamespace' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
void* xmlCopyNamespace(void* n)
}static

{
abort();
}
void xmlDocDumpFormatMemoryEnc(void* d, void* b, void* s, const char* e, int f)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: function 'xmlDocDumpFormatMemoryEnc' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
void xmlDocDumpFormatMemoryEnc(void* d, void* b, void* s, const char* e, int f)
}static

{
abort();
}
void* xmlDocGetRootElement(void* d)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: function 'xmlDocGetRootElement' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
void* xmlDocGetRootElement(void* d)
}static

{
abort();
}
void* xmlDocSetRootElement(void* d, void* r)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: function 'xmlDocSetRootElement' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
void* xmlDocSetRootElement(void* d, void* r)
}static

{
abort();
}
void xmlFreeDoc(void* d)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: function 'xmlFreeDoc' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
void xmlFreeDoc(void* d)
}static

{
abort();
}
void* xmlNewProp(void* n, const void* name, const void* v)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: function 'xmlNewProp' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
void* xmlNewProp(void* n, const void* name, const void* v)
}static

{
abort();
}
void* xmlReadMemory(const char* b, int sz, const char* u, const char* e, int o)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: function 'xmlReadMemory' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
void* xmlReadMemory(const char* b, int sz, const char* u, const char* e, int o)
}static

{
abort();
}
void xmlSetGenericErrorFunc(void* c, void* h)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: function 'xmlSetGenericErrorFunc' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
void xmlSetGenericErrorFunc(void* c, void* h)
}static

{
abort();
}
void* xmlStrdup(const void* s)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: function 'xmlStrdup' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
void* xmlStrdup(const void* s)
}static

{
abort();
}
void xmlUnlinkNode(void* n)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: function 'xmlUnlinkNode' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
void xmlUnlinkNode(void* n)
}static

oharboe and others added 5 commits March 18, 2026 22:23
These functions are exported .so entry points — external linkage is
intentional and required for the shared library stub to satisfy ld.lld's
dynamic dependency on libxml2.so.2.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
This is a C file — stdlib.h is the correct header, not cstdlib.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
This is a C file — NULL is correct, nullptr is C++ only.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
Address review concern about coupling compilation to MODULE.bazel:
patch_cmds runs inside the downloaded archive and cannot reference
workspace files, so the stub must be compiled inline.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
@github-actions
Copy link
Contributor

clang-tidy review says "All clean, LGTM! 👍"

@maliberty
Copy link
Member

Yuck. Where does this warning happen?

The stub shared library uses Linux-specific linker flags
(--version-script, -soname) that do not exist on macOS ld,
causing the Mac CI build to fail.  Guard the compilation
with a uname check so patch_cmds is a no-op on non-Linux.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
@github-actions
Copy link
Contributor

clang-tidy review says "All clean, LGTM! 👍"

@oharboe
Copy link
Collaborator Author

oharboe commented Mar 18, 2026

Yuck. Where does this warning happen?

Ubuntu 25.10 and who knows where else... this will become better, but for now we don't need Windows xml manifest parsing, so just board up the broken window. It is easier to have Claude board up this broken window than to document it. We never saw it again. 😌

Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
@github-actions
Copy link
Contributor

clang-tidy review says "All clean, LGTM! 👍"

toolchains_llvm skips auto-download when any toolchain_root is set.
Add a separate llvm_prebuilt_macos http_archive for macOS ARM64 and a
second toolchain_root entry so macOS CI gets a valid toolchain root.
The libxml2 stub is Linux-only, so the macOS archive needs no patching.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
@github-actions
Copy link
Contributor

clang-tidy review says "All clean, LGTM! 👍"

@maliberty
Copy link
Member

I still have no idea what the actual problem is. All this to solve a warning?

@oharboe
Copy link
Collaborator Author

oharboe commented Mar 20, 2026

I still have no idea what the actual problem is. All this to solve a warning?

Yes: users have to fix mysterious errors on Ubuntu when building with bazel without this. I think this is a shortcoming in the upstream bazel bcr llvm toolchain that will go away as bazel progresses. I'm thinking we should board up the broken window and forget all about it, surely they know upstream and they have a plan to fix it, it just takes time.

As the title says: I'm boarding up a broken window.

Important and useful warnings are drowned out by noise warnings and at some point nobody cares about warnings.

Bad.

@hzeller Thoughts?

@oharboe
Copy link
Collaborator Author

oharboe commented Mar 20, 2026

I get a ton of these:

INFO: From Linking external/googletest+/libgtest_main.so:
external/toolchains_llvm++llvm+llvm_toolchain/bin/../../toolchains_llvm++llvm+llvm_toolchain_llvm/bin/ld.lld: /lib/x86_64-linux-gnu/libxml2.so.2: no version information available (required by external/toolchains_llvm++llvm+llvm_toolchain/bin/../../toolchains_llvm++llvm+llvm_toolchain_llvm/bin/ld.lld)
external/toolchains_llvm++llvm+llvm_toolchain/bin/../../toolchains_llvm++llvm+llvm_toolchain_llvm/bin/ld.lld: /lib/x86_64-linux-gnu/libxml2.so.2: no version information available (required by external/toolchains_llvm++llvm+llvm_toolchain/bin/../../toolchains_llvm++llvm+llvm_toolchain_llvm/bin/ld.lld)

@hzeller
Copy link
Collaborator

hzeller commented Mar 20, 2026

I think the amount of changes to work around this temporary glitch is not useful. It creates immediate technical debt with a lot of head-scratching of someone trying to understand what is going on.

Not everything that can be hacked around with a massive hack that can be done by Claude ... is something one should be done :)

What I found is, that the builds of llvm are different and sometimes link in libxml, sometimes not, also tinfo is another library that is sometimes linked sometimes not. So I'd try to check a slightly compiler version (not 20.1.8 but something different), also with the newest 1.6.0 toolchains_llvm available on BCR.

If that doesn't work, I think for now it is ok to document that it won't work for certain versions of Ubuntu, and just recommend to comment out the @llvm_toolchain//:all part in register_toolchains to use the local compiler in that case.

@oharboe oharboe closed this Mar 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants