Skip to content

[BUILD] Install an explicit list of ext headers instead of the whole tree - #4327

Merged
marcalff merged 12 commits into
open-telemetry:mainfrom
thc1006:build/ext-header-install-manifest-1980
Aug 4, 2026
Merged

[BUILD] Install an explicit list of ext headers instead of the whole tree#4327
marcalff merged 12 commits into
open-telemetry:mainfrom
thc1006:build/ext-header-install-manifest-1980

Conversation

@thc1006

@thc1006 thc1006 commented Aug 1, 2026

Copy link
Copy Markdown
Member

Step 2 of the plan in #4315, and a contribution to #1980.

ext_common installed include/opentelemetry/ext with a *.h glob, so every header under that tree shipped whether or not it was meant to. This replaces the glob with a list of the headers the component installs. A header now reaches the package only when it is named, which is the signal you asked for when one is renamed or removed, and it makes each later decision about the installed surface a one line diff.

No longer installed

  • client/detail/default_factory.h, an internal helper included by exporter sources rather than by any public header.
  • client/curl/http_client_curl.h and client/curl/http_operation_curl.h, the curl implementation. These two go together, since the first includes the second. A consumer creates a curl client through http_client_factory_curl.h, which includes only the abstract http_client_factory.h.
  • server/http_server.h and server/socket_tools.h, the embedded HTTP server.

The server and client/detail directories go with them. install(DIRECTORY)
creates a destination directory for every source directory it walks and applies
FILES_MATCHING to the files it finds there, so naming files alone still
installed both, empty. Excluding the two directories drops them from the walk:

with the directory excludes     ext/http/{client/curl, common}
                                empty directories: none

without them                    ext/http/{client/curl, client/detail,
                                          common, server}
                                empty directories: client/detail, server

All five headers are a breaking change for anyone who included them from an installed package, which is why the CHANGELOG names them. The embedded server in particular has shipped for a long time, so out of tree users of it lose it here rather than when it moves.

The embedded server, and what it took to drop it

examples/http/server.h includes http_server.h, and examples_test turned WITH_EXAMPLES_HTTP on whenever ext_http_curl was installed, so examples/http was built against the install prefix. The example is now disabled there unconditionally, per review.

That variable gates exactly one thing, add_subdirectory(http) in examples/CMakeLists.txt, so the coverage this gives up is the http example building against the install prefix, and nothing else. The ext headers that example uses are still exercised by install/test/src/test_ext_http.cc and test_ext_http_curl.cc.

Dropping the headers also made the ws2_32 link on the opentelemetry_ext interface wrong: the target no longer carries a header that calls Winsock, so a package consumer would inherit a link it has no use for. It now goes on the seven targets that compile the server, which is the full transitive closure of the two headers over the include graph on main:

curl_http_test, socket_tools_test, w3c_tracecontext_http_test_server, otlp_http_exporter_test, otlp_http_log_record_exporter_test, zipkin_exporter_test, and the http_server example. The http_client example is not among them; it uses the curl client only.

Two notes on that link. socket_tools.h carries #pragma comment(lib, "ws2_32.lib") under _WIN32, which MSVC and clang-cl honor and MinGW's GCC does not, so every Windows job in CI resolves Winsock through the pragma and none of them can tell the difference either way. And Bazel's //ext:headers still globs the whole include tree, so it still exposes the server and its -DEFAULTLIB:Ws2_32.lib linkopt is still load bearing. It stays.

The file move itself is #4332.

Guarding it

Every other case in the install tests compiles against headers that are present, so putting the glob back over include/opentelemetry/ext would leave all of them passing while the package quietly grew five headers again. install/test/cmake/CMakeLists.txt now fails when any of the five is found under the include directory the installed opentelemetry-cpp::api target points at, and separately when either pruned directory is present.

Checked both ways, for both guards. With the manifest it reports Checking <prefix>/include for headers that must not ship and configures. With the glob restored it stops at

CMake Error at CMakeLists.txt:90 (message):
  The ext_common component installed headers it is meant to leave out:

and with the manifest kept but the two directory excludes removed, at

CMake Error at CMakeLists.txt:109 (message):
  The ext_common component left directories behind in the install tree:

Verification

Installed from main and from this branch into separate clean prefixes and compared the whole trees, not just the headers:

Only in inst-main/include/opentelemetry/ext/http/client/curl: http_client_curl.h
Only in inst-main/include/opentelemetry/ext/http/client/curl: http_operation_curl.h
Only in inst-main/include/opentelemetry/ext/http/client/detail: default_factory.h
Only in inst-main/include/opentelemetry/ext/http/server: http_server.h
Only in inst-main/include/opentelemetry/ext/http/server: socket_tools.h

files only in main: 5    files only in pr: 0
differing content: 13    total files in pr: 631

The five are the intended removals, nothing is added, and the thirteen that differ are all static archives, which are not byte reproducible across builds. Every installed header and every CMake config file is identical.

The install tests then pass against that prefix, 100% tests passed, 0 tests failed out of 37, over api, sdk, ext_common, ext_http, ext_http_curl, the ostream and in memory exporters and zipkin.

As a control, flipping WITH_EXAMPLES_HTTP back on against the same prefix fails, which is the reason the line is there:

95% tests passed, 2 tests failed out of 37

The following tests FAILED:
	 36 - examples-build-test (Failed)
	 37 - examples-run-test (Failed)

examples/http/server.h:6:10: fatal error:
    opentelemetry/ext/http/server/http_server.h: No such file or directory

That run is a Linux subset of what CI covers, nine components rather than twenty one, and it cannot exercise the ws2_32 change at all, since the pragma covers every Windows configuration CI builds. The exhaustive enumeration above is what that part rests on.

Not in scope

Manifests for the other components, the FILE_SET and VERIFY_INTERFACE_HEADER_SETS work that needs CMake 3.24, and moving the embedded server out of ext, which is #4332.

@thc1006
thc1006 requested a review from a team as a code owner August 1, 2026 11:20
…tree

ext_common installed include/opentelemetry/ext with a *.h glob, so every header
under that tree shipped whether or not it was meant to. Naming the headers makes
the installed surface deliberate: one reaches the package only when it is listed,
which is a signal when a public header is renamed or removed.

Three headers the glob installed are dropped. client/detail/default_factory.h is
an internal helper included by exporter sources rather than by any public header.
client/curl/http_client_curl.h and client/curl/http_operation_curl.h are the curl
implementation, and the first includes the second. A consumer creates a curl
client through http_client_factory_curl.h, which includes only the abstract
http_client_factory.h, so neither is needed to use the package.

http_server.h and socket_tools.h stay. examples/http/server.h includes the first,
and examples_test builds examples/http against the install prefix whenever
ext_http_curl is installed, so removing it breaks examples-build-test.
@thc1006
thc1006 force-pushed the build/ext-header-install-manifest-1980 branch from 5da5792 to cb6c264 Compare August 1, 2026 11:20
@codecov

codecov Bot commented Aug 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 80.86%. Comparing base (e79ab1f) to head (b4cac29).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #4327      +/-   ##
==========================================
+ Coverage   80.85%   80.86%   +0.02%     
==========================================
  Files         450      450              
  Lines       19215    19215              
==========================================
+ Hits        15535    15537       +2     
+ Misses       3680     3678       -2     

see 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@dbarker dbarker left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for the PR and clear description! Please see feedback and requested changes below.

Comment thread ext/CMakeLists.txt Outdated
Comment thread ext/CMakeLists.txt Outdated
…all-manifest-1980

# Conflicts:
#	CHANGELOG.md
thc1006 added a commit to thc1006/opentelemetry-cpp that referenced this pull request Aug 2, 2026
Review feedback on open-telemetry#4327.

http_server.h and socket_tools.h are an embedded HTTP server for tests and
the http example, so drop them from the ext_common manifest rather than
keeping the glob's behaviour for them.

The http example includes them, so it cannot build against the install
prefix once they stop shipping. Disable it in the install test.

That also makes the ws2_32 link on the opentelemetry_ext interface wrong:
the target no longer carries a header that calls Winsock, so a package
consumer inherits a link it has no use for. Move it to the seven targets
that compile the server, which is the full transitive closure of the two
headers over the include graph. MSVC autolinks through the pragma in
socket_tools.h, so this only shows up on MinGW and GCC for Windows.

Bazel's //ext:headers still globs the whole include tree and so still
exposes the server, and its linkopt stays for that reason.

The file move itself is tracked in open-telemetry#4332.
thc1006 added a commit to thc1006/opentelemetry-cpp that referenced this pull request Aug 2, 2026
Review feedback on open-telemetry#4327.

http_server.h and socket_tools.h are an embedded HTTP server for tests and
the http example, so drop them from the ext_common manifest rather than
keeping the glob's behaviour for them.

The http example includes them, so it cannot build against the install
prefix once they stop shipping. Disable it in the install test.

That also makes the ws2_32 link on the opentelemetry_ext interface wrong:
the target no longer carries a header that calls Winsock, so a package
consumer inherits a link it has no use for. Move it to the seven targets
that compile the server, which is the full transitive closure of the two
headers over the include graph. MSVC autolinks through the pragma in
socket_tools.h, so this only shows up on MinGW and GCC for Windows.

Bazel's //ext:headers still globs the whole include tree and so still
exposes the server, and its linkopt stays for that reason.

The file move itself is tracked in open-telemetry#4332.
@thc1006
thc1006 force-pushed the build/ext-header-install-manifest-1980 branch from 0b9e1ce to 25283a9 Compare August 2, 2026 18:06
Review feedback on open-telemetry#4327.

http_server.h and socket_tools.h are an embedded HTTP server for tests and
the http example, so drop them from the ext_common manifest rather than
keeping the glob's behaviour for them.

The http example includes them, so it cannot build against the install
prefix once they stop shipping. Disable it in the install test.

That also makes the ws2_32 link on the opentelemetry_ext interface wrong:
the target no longer carries a header that calls Winsock, so a package
consumer inherits a link it has no use for. Move it to the seven targets
that compile the server, which is the full transitive closure of the two
headers over the include graph. MSVC autolinks through the pragma in
socket_tools.h, so this only shows up on MinGW and GCC for Windows.

Bazel's //ext:headers still globs the whole include tree and so still
exposes the server, and its linkopt stays for that reason.

The file move itself is tracked in open-telemetry#4332.
@thc1006
thc1006 force-pushed the build/ext-header-install-manifest-1980 branch from 25283a9 to b54f80f Compare August 2, 2026 18:14
@thc1006

thc1006 commented Aug 2, 2026

Copy link
Copy Markdown
Member Author

All six done, thanks for the clear list.

  1. set(WITH_EXAMPLES_HTTP OFF) unconditionally in examples_test.
  2. Both server patterns out of the manifest.
  3. ws2_32 off the opentelemetry_ext interface and onto the seven targets that compile the server. That set is the transitive closure of the two headers over the include graph, so it covers the two OTLP HTTP tests and the zipkin test as well as the ext tests and the example. http_client is not in it.
  4. First paragraph gone.
  5. TODO added above the call.
  6. Move the embedded HTTP server headers out of ext/include #4332.

One thing I deliberately did not change, in case it reads as an oversight: Bazel's //ext:headers keeps its -DEFAULTLIB:Ws2_32.lib. That target still globs the whole include tree, so it still exposes the server and the linkopt is still load bearing there. #4332 is where the two build systems line up again.

Worth knowing about the ws2_32 move: socket_tools.h has #pragma comment(lib, "ws2_32.lib") under _WIN32, which MSVC and clang-cl honor, and every Windows job in CI is one of those. So CI cannot fail either way, and the enumeration is what this rests on rather than a green run.

Verified by installing main and this branch into clean prefixes: five headers gone, none added, and the only files that differ are the thirteen static archives. Install tests are 37/37 against the manifest prefix, and forcing WITH_EXAMPLES_HTTP back on against that same prefix fails examples-build-test and examples-run-test on the missing http_server.h, which is the control for that one line. Numbers are in the description.

Last thing: #4283 and #4294 both touch ext/test/http/CMakeLists.txt, so whichever lands second needs a rebase. Neither needs the link, both new targets are if(NOT WIN32).

@dbarker dbarker left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for the changes. Looks good to me. Minor request below to the changelog entry.

Comment thread CHANGELOG.md Outdated
thc1006 added 2 commits August 3, 2026 05:31
Per review: the entry described the removals in prose and named only two of
the five headers. It now sits under Breaking changes with every path listed,
and says what a consumer that included one of them should do instead.
Every other case here compiles against headers that are present, so putting
the glob back over include/opentelemetry/ext would leave all of them
passing while the package quietly grew five headers again.

The check runs against the include directory the installed api target
points at, not the test project's own prefix.
@thc1006
thc1006 force-pushed the build/ext-header-install-manifest-1980 branch from 1677154 to ed6f6d7 Compare August 2, 2026 21:53
thc1006 added 2 commits August 3, 2026 06:36
get_target_property returns <VAR>-NOTFOUND when the property is unset, and
list(GET) returns that string without complaint, so every EXISTS below would
answer false and the check would pass having examined nothing. It now
insists on a real directory first.

Also drop the WITH_HTTP_CLIENT_CURL block from examples_test: the only thing
under examples/ that reads it is examples/http, which this PR no longer
builds there.
install(DIRECTORY) creates a destination directory for every source
directory it walks and applies FILES_MATCHING to the files it finds
there, so listing only file names left include/opentelemetry/ext/http/
server and .../client/detail installed with nothing in them. Excluding
the two directories drops them from the walk, and the install test now
asserts they are absent rather than relying on the file check alone.
@thc1006

thc1006 commented Aug 2, 2026

Copy link
Copy Markdown
Member Author

Your approval is recorded against f4573881 and four commits have landed since, so rather than let them ride on it:

  • 6ade65d0 is the CHANGELOG breaking change call out you asked for.
  • ed6f6d77 adds the negative case to the install test. Every existing case compiles against headers that are present, so putting the glob back would leave all of them passing while the package quietly grew five headers again.
  • 9e187675 hardens that check. It reads INTERFACE_INCLUDE_DIRECTORIES off the imported api target, and an unset property yields <VAR>-NOTFOUND, which list(GET) returns without complaint, so a check whose only job is to fail loudly could have passed having looked at nothing.
  • a75c0e53 closes something the file manifest alone did not. install(DIRECTORY) creates a destination directory for every source directory it walks and applies FILES_MATCHING to what it finds there, so naming only file names still installed include/opentelemetry/ext/http/server/ and .../client/detail/, empty. Two directory excludes drop them from the walk.

Installed into a clean prefix both ways:

with the directory excludes     ext/http/{client/curl, common}
                                empty directories: none

without them                    ext/http/{client/curl, client/detail,
                                          common, server}
                                empty directories: client/detail, server

Both guards were checked in the failing direction too. With the glob restored the install test stops at The ext_common component installed headers it is meant to leave out:, and with the manifest kept but only the two directory excludes removed, at The ext_common component left directories behind in the install tree:.

The last commit is the one furthest from what you reviewed. Say the word and I will drop it and open it separately, or squash it in, whichever you prefer.

Issue for the file move is #4332.

@dbarker dbarker left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please see the requested change below to revert the latest install test change.

Comment thread install/test/cmake/CMakeLists.txt Outdated
thc1006 and others added 2 commits August 3, 2026 23:55
A list of files that should not exist has no natural end, and every entry is
one more thing to keep in step with the install rules. The removal these five
headers needed is already shown by the install test compiling against the
package without them, and by this PR's CI run.

Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com>

@dbarker dbarker left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you for the updates!

thc1006 added a commit to thc1006/opentelemetry-cpp that referenced this pull request Aug 3, 2026
The local include-what-you-use and clang-tidy runs built the exporter library,
which does not compile the test file, so three findings reached CI instead. The
test drops an include the log handler header already provides, takes a
reference where it was copying a shared_ptr, and the scope guard declares the
four special members that a user-declared destructor calls for.

The guard holds a pointer to the completion now rather than a shared_ptr, so
the .cc no longer names one and the include goes with it. The two async include
guards were the same condition twice and are one block.

Checked by building the test target against all three cmake option presets the
workflows use, and against main for a baseline: include-what-you-use reports
the same two blocks and no include changes on either, and clang-tidy reports
the same eighteen warnings on either, with nothing on the branch that is not
also on main.

Comments in the completion cases now say what the code does rather than what it
used to do, which is the review note on open-telemetry#4327 applied here as well.

Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com>
thc1006 added a commit to thc1006/opentelemetry-cpp that referenced this pull request Aug 3, 2026
Two comments described a check this branch removes, which is the kind of
rationale @dbarker asked to keep in the pull request and the git history rather
than in the code, on open-telemetry#4327. They now describe the bodies themselves: two
successes that differ only in whitespace, and a rejected item whose shard
counter still reads as a success to anything reading the body as text.

Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com>
@marcalff
marcalff merged commit 1967428 into open-telemetry:main Aug 4, 2026
72 checks passed
@thc1006
thc1006 deleted the build/ext-header-install-manifest-1980 branch August 4, 2026 05:57
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