Skip to content

Comments

Add support for precompiled headers#5298

Open
randombit wants to merge 36 commits intomasterfrom
jack/precompiled-headers
Open

Add support for precompiled headers#5298
randombit wants to merge 36 commits intomasterfrom
jack/precompiled-headers

Conversation

@randombit
Copy link
Owner

@randombit randombit commented Feb 8, 2026

#5164

Stacked on #5297

Tried at MSVC support but it's a quite different model and I got tired of going back and forth with CI. Left to an interested party, hopefully one with a local Windows machine for faster iterations.

On my laptop, building with Clang 21:

They options are still, for the moment at least, defined in the relative
compiler description files, but they aren't used during the build anymore.
@randombit
Copy link
Owner Author

I experimented a bit with including our own headers also into the PCH and the improvement was at best minor and often regressed vs just using standard library headers. I also ran into some situations where a PCH had an old version of something from Botan itself and the resulting error messages were very hard to interpret, so I'm inclined to avoid unless it really helps.

@randombit
Copy link
Owner Author

error: default visibility for functions and variables [-fvisibility] differs in PCH file vs. current file

Seems like older Clang doesn't like this? Clang 21 is fine.

Unfortunate, probably suggests there needs to be 2 PCHs one for the library and the other for tests/cli

@randombit

This comment was marked as outdated.

@randombit

This comment was marked as off-topic.

@randombit

This comment was marked as outdated.

@randombit
Copy link
Owner Author

immintrin.h might not be worth it, only difference between pch_lib.h and pch_exe.h is inclusion of that header and the size difference is crazy:

Clang 21: exe 12 Mb, lib 17 Mb
GCC 15: exe 69 Mb, lib 99 Mb (yikes)

@randombit
Copy link
Owner Author

@copilot Try adding PCH support to the ninja build

Copy link

Copilot AI commented Feb 8, 2026

@randombit I've opened a new pull request, #5299, to work on those changes. Once the pull request is ready, I'll request review from you.

@randombit
Copy link
Owner Author

randombit commented Feb 8, 2026

Weird error right in the middle of a build

  fatal error: file '/home/runner/work/botan/botan/build/obj/pch/pch_exe.h' has been modified since the precompiled header './build/obj/pch/pch_exe.h.pch' was built: mtime changed (was 1770567362, now 1770569364)
  note: please rebuild precompiled header './build/obj/pch/pch_exe.h.pch'
  1 error generated.
  make: *** [Makefile:1864: build/obj/cli/utils.o] Error 1

Not sure what to make of this

Possibly an interaction with ccache. The ccache docs say re PCH: If you use Clang, you must compile with -fno-pch-timestamp.

@coveralls
Copy link

coveralls commented Feb 8, 2026

Coverage Status

coverage: 90.079% (+0.009%) from 90.07%
when pulling ade95ff on jack/precompiled-headers
into f708c36 on master.

@randombit
Copy link
Owner Author

@copilot OK now try to extend to support Microsoft Visual C++ PCH

IIUC you'll have to modify configure to write some little stub cpp files for MSVC to compile to create the PCH

IIUC the relevant options are /Yc, /Yu, and /FI.

Copy link

Copilot AI commented Feb 8, 2026

@randombit I've opened a new pull request, #5301, to work on those changes. Once the pull request is ready, I'll request review from you.

@randombit randombit force-pushed the jack/precompiled-headers branch from 1a51c2c to b86bb92 Compare February 8, 2026 22:05
@randombit randombit requested a review from Copilot February 9, 2026 01:42
@randombit randombit marked this pull request as ready for review February 9, 2026 01:43
@randombit
Copy link
Owner Author

Needs a squash but should otherwise be good to go

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds build-system support for precompiled headers (PCH) to reduce overall compile times, along with a few related header/include cleanups for SIMD and CLMUL code paths.

Changes:

  • Introduce a shared PCH header (src/lib/pch/pch.h) and wire it into Makefile and Ninja build generation (including compiler-specific PCH flags).
  • Extend configuration and cleanup tooling to create/use/remove PCH build artifacts and adjust compiler/build flags to better support PCH sharing.
  • Refine SIMD-related includes/ISA annotations and fix missing intrinsic header inclusion needed for CLMUL usage.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/scripts/cleanup.py Cleans PCH artifacts in the build directory
src/lib/utils/simd/simd_4x64/simd_4x64.h Adds ISA attribute macro to additional members for consistency
src/lib/utils/simd/simd_4x32/simd_4x32.h Switches SSSE3 include to a narrower intrinsic header
src/lib/utils/simd/simd_2x64/simd_2x64.h Adjusts SSSE3 includes and adds ISA attributes to more functions
src/lib/utils/ghash/ghash_cpu/polyval_fn.h Adds wmmintrin.h include for CLMUL intrinsic declarations
src/lib/pch/pch.h New PCH “umbrella” header of common STL headers
src/lib/misc/zfec/zfec_sse2/zfec_sse2.cpp Narrows intrinsic include to SSE2-only header
src/configs/repo_config.env Sets CCACHE_SLOPPINESS to support PCH + ccache together
src/build-data/ninja.in Adds PCH build rules and injects PCH usage into compile rules
src/build-data/makefile.in Adds PCH targets and makes objects depend on generated PCHs
src/build-data/compile_commands.json.in Removes ISA flags from compilation database entries
src/build-data/cc/{clang,gcc,xcode}.txt Defines per-compiler PCH compile/include flags and suffixes
doc/dev_ref/contributing.rst Documents recommended ccache sloppiness settings for PCH
configure.py Adds --disable-pch, generates PCH variables, and adjusts flags to support PCH

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +115 to +118
for f in os.listdir(build_config['pch_dir']):
for suffix in pch_suffixes:
if f.endswith(suffix):
remove_file(os.path.join(build_config['pch_dir'], f))
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

os.listdir(build_config['pch_dir']) is unguarded. If the directory was removed manually (or was never created due to an interrupted configure), cleanup.py will raise and make clean/ninja clean will fail. Consider checking os.access(pch_dir, os.X_OK) like other cleanup paths, or catching OSError around os.listdir and treating ENOENT as already-clean.

Suggested change
for f in os.listdir(build_config['pch_dir']):
for suffix in pch_suffixes:
if f.endswith(suffix):
remove_file(os.path.join(build_config['pch_dir'], f))
pch_dir = build_config['pch_dir']
if os.access(pch_dir, os.X_OK):
try:
for f in os.listdir(pch_dir):
for suffix in pch_suffixes:
if f.endswith(suffix):
remove_file(os.path.join(pch_dir, f))
except OSError as e:
if e.errno != errno.ENOENT:
logging.error('Failed accessing PCH directory "%s": %s', pch_dir, e)
else:
logging.debug('PCH directory %s was missing', pch_dir)

Copilot uses AI. Check for mistakes.

link_method = choose_link_method(options)

if options.enable_pch:
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

PCH header copying is guarded by options.enable_pch, but the rest of the build templates are guarded by template_vars['enable_pch'] (which also checks cc.supports_pch()). On unsupported compilers this will still create ${build}/obj/pch and copy pch_*.h, but no build rules will consume them and cleanup.py won't remove them (since pch_dir isn't in build_config). Consider keying this on template_vars['enable_pch'] to keep the filesystem outputs consistent with the generated build rules.

Suggested change
if options.enable_pch:
if template_vars.get('enable_pch'):

Copilot uses AI. Check for mistakes.
Comment on lines 230 to 240
%{for lib_build_info}
build %{obj}: compile_lib %{src}
isa_flags = %{isa_flags}
build %{obj}: compile_lib %{src} | %{pch_target}
%{endfor}

%{for cli_build_info}
build %{obj}: compile_exe %{src}
build %{obj}: compile_exe %{src} | %{pch_target}
%{endfor}

%{for test_build_info}
build %{obj}: compile_exe %{src}
build %{obj}: compile_exe %{src} | %{pch_target}
%{endfor}
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

When precompiled headers are disabled/unsupported, pch_target expands to an empty string, leaving a dangling | in lines like build %{obj}: ... | %{pch_target}. This produces an invalid build.ninja and will break e.g. MSVC/clangcl builds where enable_pch becomes false. Emit the order-only dependency only when enable_pch is true (or include the leading | in the variable so it can be empty safely).

Copilot uses AI. Check for mistakes.
deps = %{ninja_header_deps_style}
%{endif}
command = %{cxx} ${ABI_FLAGS} ${LANG_FLAGS} ${CXXFLAGS} -DBOTAN_IS_BEING_BUILT ${WARN_FLAGS} ${isa_flags} %{public_include_flags} %{internal_include_flags} %{external_include_flags} %{header_deps_flag} %{header_deps_out|concat: $out.d} %{dash_c} $in %{dash_o}$out
command = %{cxx} %{pch_include_for_exe} ${ABI_FLAGS} ${LANG_FLAGS} ${CXXFLAGS} -DBOTAN_IS_BEING_BUILT ${WARN_FLAGS} %{public_include_flags} %{internal_include_flags} %{external_include_flags} %{header_deps_flag} %{header_deps_out|concat: $out.d} %{dash_c} $in %{dash_o}$out
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

compile_exe now injects %{pch_include_for_exe}. However some Ninja build edges using compile_exe (e.g. fuzzers, bogo_shim_object, ct_selftest_object) don't have an order-only dependency on the PCH build. In parallel builds this can lead to nondeterministic PCH usage and, in the worst case, attempting to read a partially-written PCH file. Add the same | pch order-only dependency for all compile_exe invocations when enable_pch is enabled (or ensure these targets don't use the PCH include flag).

Suggested change
command = %{cxx} %{pch_include_for_exe} ${ABI_FLAGS} ${LANG_FLAGS} ${CXXFLAGS} -DBOTAN_IS_BEING_BUILT ${WARN_FLAGS} %{public_include_flags} %{internal_include_flags} %{external_include_flags} %{header_deps_flag} %{header_deps_out|concat: $out.d} %{dash_c} $in %{dash_o}$out
command = %{cxx} ${ABI_FLAGS} ${LANG_FLAGS} ${CXXFLAGS} -DBOTAN_IS_BEING_BUILT ${WARN_FLAGS} %{public_include_flags} %{internal_include_flags} %{external_include_flags} %{header_deps_flag} %{header_deps_out|concat: $out.d} %{dash_c} $in %{dash_o}$out

Copilot uses AI. Check for mistakes.
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