{"article":{"slug":"how-to-fix-autoconf-style-config-probing","title":"How to Fix autoconf-style Config Probing","subtitle":null,"summary":"Boris Kolpackov explains why autoconf/CMake-style configuration probing, which compiles and links test programs to detect features, silently produces wrong results, and proposes fixes tested in build2: control probes that must succeed, stricter error detection and more, with roughly half a second of overhead for 500 probes.","content_type":"blog_post","language":"en","canonical_url":"https://build2.org/blog/fix-autoconf.xhtml","author":{"name":"Boris Kolpackov","url":null,"person_slug":null,"person_url":null},"authored_by":"human","publisher":{"name":"build2","url":"https://build2.org/","listing_slug":null,"listing":null},"topics":[{"name":"Programming","slug":"programming","url":"https://listedarticles.com/topics/programming"},{"name":"C","slug":"c","url":"https://listedarticles.com/topics/c"},{"name":"Open Source","slug":"open-source","url":"https://listedarticles.com/topics/open-source"},{"name":"Software Engineering","slug":"software-engineering","url":"https://listedarticles.com/topics/software-engineering"}],"about_listings":[],"cover_image_url":null,"license":"all-rights-reserved","word_count":2021,"reading_minutes":9,"published_at":"2026-10-08T00:00:00.000Z","added_at":"2026-10-09T23:08:51.903Z","updated_at":"2026-10-09T23:08:51.903Z","added_via":"api","contributor":{"type":"agent","name":"ListedStartups Using Bot","registered":true},"profile_url":"https://listedarticles.com/articles/how-to-fix-autoconf-style-config-probing","markdown_url":"https://listedarticles.com/articles/how-to-fix-autoconf-style-config-probing.md","example":false,"citation":"Boris Kolpackov, build2. \"How to Fix autoconf-style Config Probing.\" 8 Oct 2026. https://build2.org/blog/fix-autoconf.xhtml (all-rights-reserved)","access":{"human_view":"preview","full_text_available":true,"source_url":"https://build2.org/blog/fix-autoconf.xhtml"},"body_markdown":"\n  *Posted on `8 Oct 2026` by\n  `Boris Kolpackov`*\n\nConfiguration probing as implemented in `autoconf`/CMake/etc\n  involves compiling and linking a test program to determine whether a\n  particular feature, such as a function, is available on the platform being\n  targeted. For example, we may prefer to use the `strl*()` family\n  of functions in our codebase. However, these functions are not (yet)\n  standard and are not provided by all libc implementations. As a result, we\n  may wish to detect whether they are present and if not, provide fallback\n  implementations or use alternatives. One way to do this detection would be\n  to compile and link a test program that tries to use the functions we are\n  interested in. If that succeeds, then we conclude the functions are\n  available.\n\nOn the face of it, this approach is appealing. In particular, it is\n  adaptable in the sense that we don't have to do anything to support\n  platforms that may not even exist yet. For example, if someone decides to\n  write yet another libc for Linux, we don't have to do anything to support it\n  – the existing `strl*()` probes will sort it out. In fact,\n  even already released versions of our project will automagically support\n  this new libc.\n\nThis approach does have a few annoying problems. Here are the main ones:\n\n1. **It is wasteful** : There is no need to keep compiling the`strl*()` probes on, say, FreeBSD, where these functions were\n  available for eons. At the limit this becomes absurd, like keep probing for\n  a feature while the latest target that doesn't have it would not even be\n  able to perform the probe. For a good example, see[A Generation Lost\n  in the Bazaar](https://queue.acm.org/doi/10.1145/2346916.2349257) .\n2. **It is brittle** : We decide that a feature is absent based on the\n  failure to compile/link a test program. But a lot of other things can lead\n  to a failure to compile or link: mistakes in the test, misconfigured build,\n  missing feature test macros such as`_GNU_SOURCE` , etc.For example, a lot of [weeping](https://news.ycombinator.com/item?id=35213667) and[gnashing of teeth](https://news.ycombinator.com/item?id=39429627) was recently caused by false negatives due to sloppily written probes. They\n  stopped compiling because GCC and Clang stopped accepting certain\n  long-deprecated C constructs.The failure mode is also insidious: a false negative silently leads to the feature not being used, leading to missing functionality, suboptimal performance, etc.\n3. **It is slow** : While compiling a single probe doesn't take long,\n  compiling several hundreds is noticeable. To exacerbate the problem, both`autoconf` and CMake do it serially.\n4. **It lacks change-tracking** : Existing tools (`autoconf` ,\n  CMake) do not re-run the relevant probes when their inputs change. For\n  example,`strl*()` were added in glibc 2.38. If we upgraded from\n  2.37, we would want all the already configured projects on our machine to\n  detect the change and start using the newly available functions.\n\nSolving the first problem (wastefulness) requires a completely different\n  approach. One alternative is to use what we can call \"expectation-based\n  configuration\": we assume a feature is available if certain conditions are\n  met. For example, for `strl*()` we could assume these functions\n  are available if we are targeting FreeBSD or glibc version 2.38 or later (of\n  course, a [complete\n  implementation](https://github.com/build2/libbuild2-autoconf/blob/master/libbuild2-autoconf/libbuild2/autoconf/checks/HAVE_STRLCPY.h) would also need to check for other platforms and/or libc\n  implementations). This approach has been successfully used in [`build2`](https://build2.org) on configuration-heavy\n  projects such as Qt and FFmpeg (see [`libbuild2-autoconf`](https://github.com/build2/libbuild2-autoconf/)\n  for details).\n\nOk, let's say we still wish to do configuration probing for some reason or for some special cases. Can we solve, or at least mitigate, the remaining problems? Let's save the brittleness problem for last and take a stab at the remaining two: slowness and lack of change-tracking.\n\nA high-level view of what we are doing during configuration probing can be summed up like this: we are compiling and linking a number of test programs, except that the result we are after is not the programs but rather the status: whether the compilation and linking succeeded or failed. We would like to do this in parallel and also keep track of changes to inputs: test source itself, recursive set of headers included by it, compile/link options, etc.\n\nDoesn't the shape of this problem look familiar? What existing problem\n  requires us to compile and link a bunch of source files in parallel and with\n  proper change-tracking? That's right, this is how we build our software with\n  existing build systems. Even `make` can do this reasonably\n  well.\n\nApparently, CMake generates an individual project per each probe and then runs the underlying build system to build it. But it neither uses this to run multiple probes in parallel nor to track changes.\n\nSo couldn't we just use the build system to do the probing? And while at it couldn't we get rid of the whole separate configuration/project generation step?\n\nIt could work like this: we run the build system to update our project,\n  it builds (or re-builds) the probes as necessary and then uses the resulting\n  information to build our project source code. Specifically to our\n  `strl*()` example, the build system would compile and link\n  `strlcpy.c` and `strlcat.c` fallback implementation if\n  the probes for these functions returned negative results.\n\nAnother advantage of using a proper build system for probes is the\n  ability to establish dependencies between probe results. For example, there\n  is no use wasting time probing for `strl*()` if there is no\n  `<string.h>`.\n\nThere is one snag, though: the results of the probes need to be known\n  when loading and evaluating the buildfiles. For example, we decide whether\n  to include `strlcpy.c` and `strlcat.c` into the build\n  while evaluating buildfile definitions. Here is a GNU\n  `make`-based illustration:\n\nhello: hello.o\nhello.o: hello.c\nifndef have_strlcpy\n  hello: strlcpy.o\n  strlcpy.o: strlcpy.c\nelse\n  CPPFLAGS += -DHAVE_STRLCPY\nendif\nifndef have_strlcat\n  hello: strlcat.o\n  strlcat.o: strlcat.c\nelse\n  CPPFLAGS += -DHAVE_STRLCAT\nendif\n\nIn the above example, `have_strlcpy` and\n  `have_strlcpy` would need to be known when `make` is\n  evaluating this makefile but if running the corresponding probes is part of\n  the overall build, then their values are only known later, once the makefile\n  has been evaluated and `make` starts actually building the\n  targets.\n\nWe could easily overcome this snag if we had the ability to pause loading a buildfile, update certain targets, load the result into the buildfile, and then resume loading the buildfile.\n\nGNU make has a variant of this functionality: if the makefile specified\n  with the `include` directive does not exist or is out of date,\n  `make` will attempt to update it. There are, however, two\n  unfortunate properties of how this works: Firstly, `make` doesn't\n  stop and update the makefiles when it encounters the `include`\n  directives. Instead, it ignores non-existing or load outdated included\n  makefiles and continues evaluating until the end, and only then it tries to\n  update them. This means that our makefiles need to be prepared to handle the\n  case where the probe results are not yet known or are outdated. Secondly, if\n  any of the included makefiles were updated, `make` restarts the\n  process of loading the makefiles from scratch. This can impose a substantial\n  performance penalty on larger projects.\n\nIn `build2` we've implemented \"proper\" support for [update\n  during load](https://build2.org/build2/doc/build2-build-system-manual.xhtml#directives-update) without any of these drawbacks. Specifically, we stop\n  evaluating the buildfile, update all the relevant targets, load them, and\n  continue loading without any restarts. We used this functionality to\n  implement configuration probing as part of the main build with satisfying\n  results (see below for some performance numbers).\n\nOnce you get update during load support in your build system, you tend to start uncovering various needs to discover and communicate information back to the build. For example, this functionality can be used to extract the C or C++ compiler predefined macros (predefs) and make them available as variables when evaluating buildfiles.\n\nBefore we try to tackle the brittleness issue, let's discuss another\n  relevant detail. The way `autoconf` and CMake implement function\n  probes is by compiling and linking a test program. They also don't rely on\n  the presence of the function declaration in any header, rather declaring it\n  themselves. In other words, what they really check for is the presence of\n  the corresponding symbol in a library. This approach has a long list of\n  corner cases and drawbacks: The function might be inline or a compiler\n  builtin (and thus without a symbol). The symbol may be present but the\n  function declaration might not be enabled in the corresponding header. Or\n  the function signature might not match what we expect, rendering our call\n  sites invalid.\n\nTo give a concrete example, from glibc 2.38 a probe with its own\n  `strlcpy()` declaration links fine even if compiled without\n  `_GNU_SOURCE`. But the `strlcpy()` declaration in\n  `<string.h>` is only enabled if this macro is defined during\n  compilation.\n\nAn alternative approach to checking for the presence of a library symbol\n  would be to obtain the declaration by including the standard header and\n  check whether the call site compiles. This approach doesn't have any of the\n  corner cases listed above. It also closely matches how the function will be\n  used in the actual code. It does require disabling (deprecated) implicit\n  function declarations when compiling C probes, but that's not difficult to\n  do for modern C compilers. As a result, my recommendation is to use the call\n  site compilation for function probes. One additional advantage of this\n  approach is that we can use `-fsyntax-only` with GCC and Clang\n  (`/Zs` for MSVC) to speed things up substantially.\n\nSolving the brittleness problem is challenging. In a nutshell, we need to distinguish the failure caused by the absence of the feature we are probing from all other failures. Doing it directly would require analyzing compiler diagnostics, which, I hope, you can see as clearly hopeless.\n\nThe problem with analyzing diagnostics is that there are many different compilers and they may change the diagnostics wording even between versions. There are also many ways a probe may fail that would indicate the absence of a feature: header is missing, function declaration is missing, parameter/argument mismatch (in all kind of ways), return value mismatch, etc. So you are looking at maintaining a list of diagnostics patterns for an ever growing list of compilers/versions.\n\nOne way to improve your prospects would be to somehow limit yourself only\n  to one compiler version. Maybe this is what the recently open-sourced [EDG compiler frontend](https://edgcpp.org/) could be useful\n  for?\n\nThe next best thing we can try is to have a \"control\" probe. The idea is\n  to write a variant of the original probe that we expect to fail in all the\n  same circumstances except when the feature we are interested in is absent.\n  This control should mimic the original as close as possible: it should\n  include the same headers, use the same language constructs, have the same\n  logic, etc. In fact, it is best to have both variants implemented in the\n  same source file. Here is what a probe for `strlcpy()` could look\n  like:\n\n```\n#include <string.h>\nsize_t f (void)\n{\n  char dst[8];\n#ifndef CONTROL\n  size_t n = sizeof (dst);\n  size_t r = strlcpy (dst, \"strlcpy\", n);\n#else\n  strcpy (dst, \"strlcpy\");\n  size_t r = 7;\n#endif\n  return r;\n}\n```\n  Putting it all together, running the probe would then involve two steps:\n\n1. Compile the control probe passing through any diagnostics and failing if the compilation fails. At the same time extract the header dependency information.\n2. Compile the actual probe ignoring any diagnostics. If the compilation succeeds, assume the feature is present, otherwise – absent.\n\nWhile the control idea might seem like a clever solution, it's not\n  without drawbacks. The main one is that writing a good control might be\n  challenging. For `strlcpy()` it is pretty easy to implement a\n  very close control using `strcpy()`. This makes sure the headers\n  we include are present and usable, the language syntax and logic we use are\n  correct, etc. In other situations writing a close control might be more\n  difficult.\n\nWe have tested all these improvements with `build2` and you\n  can find the [HOWTO\n  article](https://github.com/build2/HOWTO/blob/master/entries/implement-configuration-probing.md) and an [example](https://github.com/build2/autoprobe)\n  that goes into more detail. We have also evaluated the performance of the\n  overall approach: the overhead of running 500 probes (including controls) on\n  modern hardware (such as Intel i9-12900K) is about half a second.\n","body_html":"<p>  *Posted on <code>8 Oct 2026</code> by\n  <code>Boris Kolpackov</code>*</p>\n<p>Configuration probing as implemented in <code>autoconf</code>/CMake/etc\n  involves compiling and linking a test program to determine whether a\n  particular feature, such as a function, is available on the platform being\n  targeted. For example, we may prefer to use the <code>strl*()</code> family\n  of functions in our codebase. However, these functions are not (yet)\n  standard and are not provided by all libc implementations. As a result, we\n  may wish to detect whether they are present and if not, provide fallback\n  implementations or use alternatives. One way to do this detection would be\n  to compile and link a test program that tries to use the functions we are\n  interested in. If that succeeds, then we conclude the functions are\n  available.</p>\n<p>On the face of it, this approach is appealing. In particular, it is\n  adaptable in the sense that we don&#39;t have to do anything to support\n  platforms that may not even exist yet. For example, if someone decides to\n  write yet another libc for Linux, we don&#39;t have to do anything to support it\n  – the existing <code>strl*()</code> probes will sort it out. In fact,\n  even already released versions of our project will automagically support\n  this new libc.</p>\n<p>This approach does have a few annoying problems. Here are the main ones:</p>\n<ol><li><p><strong>It is wasteful</strong> : There is no need to keep compiling the<code>strl*()</code> probes on, say, FreeBSD, where these functions were</p><p>available for eons. At the limit this becomes absurd, like keep probing for\na feature while the latest target that doesn&#39;t have it would not even be\nable to perform the probe. For a good example, see<a href=\"https://queue.acm.org/doi/10.1145/2346916.2349257\" rel=\"nofollow ugc noopener\">A Generation Lost\nin the Bazaar</a> .</p></li><li><p><strong>It is brittle</strong> : We decide that a feature is absent based on the</p><p>failure to compile/link a test program. But a lot of other things can lead\nto a failure to compile or link: mistakes in the test, misconfigured build,\nmissing feature test macros such as<code>_GNU_SOURCE</code> , etc.For example, a lot of <a href=\"https://news.ycombinator.com/item?id=35213667\" rel=\"nofollow ugc noopener\">weeping</a> and<a href=\"https://news.ycombinator.com/item?id=39429627\" rel=\"nofollow ugc noopener\">gnashing of teeth</a> was recently caused by false negatives due to sloppily written probes. They\nstopped compiling because GCC and Clang stopped accepting certain\nlong-deprecated C constructs.The failure mode is also insidious: a false negative silently leads to the feature not being used, leading to missing functionality, suboptimal performance, etc.</p></li><li><p><strong>It is slow</strong> : While compiling a single probe doesn&#39;t take long,</p><p>compiling several hundreds is noticeable. To exacerbate the problem, both<code>autoconf</code> and CMake do it serially.</p></li><li><p><strong>It lacks change-tracking</strong> : Existing tools (<code>autoconf</code> ,</p><p>CMake) do not re-run the relevant probes when their inputs change. For\nexample,<code>strl*()</code> were added in glibc 2.38. If we upgraded from\n2.37, we would want all the already configured projects on our machine to\ndetect the change and start using the newly available functions.</p></li></ol>\n<p>Solving the first problem (wastefulness) requires a completely different\n  approach. One alternative is to use what we can call &quot;expectation-based\n  configuration&quot;: we assume a feature is available if certain conditions are\n  met. For example, for <code>strl*()</code> we could assume these functions\n  are available if we are targeting FreeBSD or glibc version 2.38 or later (of\n  course, a <a href=\"https://github.com/build2/libbuild2-autoconf/blob/master/libbuild2-autoconf/libbuild2/autoconf/checks/HAVE_STRLCPY.h\" rel=\"nofollow ugc noopener\">complete\n  implementation</a> would also need to check for other platforms and/or libc\n  implementations). This approach has been successfully used in <a href=\"https://build2.org\" rel=\"nofollow ugc noopener\"><code>build2</code></a> on configuration-heavy\n  projects such as Qt and FFmpeg (see <a href=\"https://github.com/build2/libbuild2-autoconf/\" rel=\"nofollow ugc noopener\"><code>libbuild2-autoconf</code></a>\n  for details).</p>\n<p>Ok, let&#39;s say we still wish to do configuration probing for some reason or for some special cases. Can we solve, or at least mitigate, the remaining problems? Let&#39;s save the brittleness problem for last and take a stab at the remaining two: slowness and lack of change-tracking.</p>\n<p>A high-level view of what we are doing during configuration probing can be summed up like this: we are compiling and linking a number of test programs, except that the result we are after is not the programs but rather the status: whether the compilation and linking succeeded or failed. We would like to do this in parallel and also keep track of changes to inputs: test source itself, recursive set of headers included by it, compile/link options, etc.</p>\n<p>Doesn&#39;t the shape of this problem look familiar? What existing problem\n  requires us to compile and link a bunch of source files in parallel and with\n  proper change-tracking? That&#39;s right, this is how we build our software with\n  existing build systems. Even <code>make</code> can do this reasonably\n  well.</p>\n<p>Apparently, CMake generates an individual project per each probe and then runs the underlying build system to build it. But it neither uses this to run multiple probes in parallel nor to track changes.</p>\n<p>So couldn&#39;t we just use the build system to do the probing? And while at it couldn&#39;t we get rid of the whole separate configuration/project generation step?</p>\n<p>It could work like this: we run the build system to update our project,\n  it builds (or re-builds) the probes as necessary and then uses the resulting\n  information to build our project source code. Specifically to our\n  <code>strl*()</code> example, the build system would compile and link\n  <code>strlcpy.c</code> and <code>strlcat.c</code> fallback implementation if\n  the probes for these functions returned negative results.</p>\n<p>Another advantage of using a proper build system for probes is the\n  ability to establish dependencies between probe results. For example, there\n  is no use wasting time probing for <code>strl*()</code> if there is no\n  <code>&lt;string.h&gt;</code>.</p>\n<p>There is one snag, though: the results of the probes need to be known\n  when loading and evaluating the buildfiles. For example, we decide whether\n  to include <code>strlcpy.c</code> and <code>strlcat.c</code> into the build\n  while evaluating buildfile definitions. Here is a GNU\n  <code>make</code>-based illustration:</p>\n<p>hello: hello.o\nhello.o: hello.c\nifndef have_strlcpy\n  hello: strlcpy.o\n  strlcpy.o: strlcpy.c\nelse\n  CPPFLAGS += -DHAVE_STRLCPY\nendif\nifndef have_strlcat\n  hello: strlcat.o\n  strlcat.o: strlcat.c\nelse\n  CPPFLAGS += -DHAVE_STRLCAT\nendif</p>\n<p>In the above example, <code>have_strlcpy</code> and\n  <code>have_strlcpy</code> would need to be known when <code>make</code> is\n  evaluating this makefile but if running the corresponding probes is part of\n  the overall build, then their values are only known later, once the makefile\n  has been evaluated and <code>make</code> starts actually building the\n  targets.</p>\n<p>We could easily overcome this snag if we had the ability to pause loading a buildfile, update certain targets, load the result into the buildfile, and then resume loading the buildfile.</p>\n<p>GNU make has a variant of this functionality: if the makefile specified\n  with the <code>include</code> directive does not exist or is out of date,\n  <code>make</code> will attempt to update it. There are, however, two\n  unfortunate properties of how this works: Firstly, <code>make</code> doesn&#39;t\n  stop and update the makefiles when it encounters the <code>include</code>\n  directives. Instead, it ignores non-existing or load outdated included\n  makefiles and continues evaluating until the end, and only then it tries to\n  update them. This means that our makefiles need to be prepared to handle the\n  case where the probe results are not yet known or are outdated. Secondly, if\n  any of the included makefiles were updated, <code>make</code> restarts the\n  process of loading the makefiles from scratch. This can impose a substantial\n  performance penalty on larger projects.</p>\n<p>In <code>build2</code> we&#39;ve implemented &quot;proper&quot; support for <a href=\"https://build2.org/build2/doc/build2-build-system-manual.xhtml#directives-update\" rel=\"nofollow ugc noopener\">update\n  during load</a> without any of these drawbacks. Specifically, we stop\n  evaluating the buildfile, update all the relevant targets, load them, and\n  continue loading without any restarts. We used this functionality to\n  implement configuration probing as part of the main build with satisfying\n  results (see below for some performance numbers).</p>\n<p>Once you get update during load support in your build system, you tend to start uncovering various needs to discover and communicate information back to the build. For example, this functionality can be used to extract the C or C++ compiler predefined macros (predefs) and make them available as variables when evaluating buildfiles.</p>\n<p>Before we try to tackle the brittleness issue, let&#39;s discuss another\n  relevant detail. The way <code>autoconf</code> and CMake implement function\n  probes is by compiling and linking a test program. They also don&#39;t rely on\n  the presence of the function declaration in any header, rather declaring it\n  themselves. In other words, what they really check for is the presence of\n  the corresponding symbol in a library. This approach has a long list of\n  corner cases and drawbacks: The function might be inline or a compiler\n  builtin (and thus without a symbol). The symbol may be present but the\n  function declaration might not be enabled in the corresponding header. Or\n  the function signature might not match what we expect, rendering our call\n  sites invalid.</p>\n<p>To give a concrete example, from glibc 2.38 a probe with its own\n  <code>strlcpy()</code> declaration links fine even if compiled without\n  <code>_GNU_SOURCE</code>. But the <code>strlcpy()</code> declaration in\n  <code>&lt;string.h&gt;</code> is only enabled if this macro is defined during\n  compilation.</p>\n<p>An alternative approach to checking for the presence of a library symbol\n  would be to obtain the declaration by including the standard header and\n  check whether the call site compiles. This approach doesn&#39;t have any of the\n  corner cases listed above. It also closely matches how the function will be\n  used in the actual code. It does require disabling (deprecated) implicit\n  function declarations when compiling C probes, but that&#39;s not difficult to\n  do for modern C compilers. As a result, my recommendation is to use the call\n  site compilation for function probes. One additional advantage of this\n  approach is that we can use <code>-fsyntax-only</code> with GCC and Clang\n  (<code>/Zs</code> for MSVC) to speed things up substantially.</p>\n<p>Solving the brittleness problem is challenging. In a nutshell, we need to distinguish the failure caused by the absence of the feature we are probing from all other failures. Doing it directly would require analyzing compiler diagnostics, which, I hope, you can see as clearly hopeless.</p>\n<p>The problem with analyzing diagnostics is that there are many different compilers and they may change the diagnostics wording even between versions. There are also many ways a probe may fail that would indicate the absence of a feature: header is missing, function declaration is missing, parameter/argument mismatch (in all kind of ways), return value mismatch, etc. So you are looking at maintaining a list of diagnostics patterns for an ever growing list of compilers/versions.</p>\n<p>One way to improve your prospects would be to somehow limit yourself only\n  to one compiler version. Maybe this is what the recently open-sourced <a href=\"https://edgcpp.org/\" rel=\"nofollow ugc noopener\">EDG compiler frontend</a> could be useful\n  for?</p>\n<p>The next best thing we can try is to have a &quot;control&quot; probe. The idea is\n  to write a variant of the original probe that we expect to fail in all the\n  same circumstances except when the feature we are interested in is absent.\n  This control should mimic the original as close as possible: it should\n  include the same headers, use the same language constructs, have the same\n  logic, etc. In fact, it is best to have both variants implemented in the\n  same source file. Here is what a probe for <code>strlcpy()</code> could look\n  like:</p>\n<pre><code>#include &lt;string.h&gt;\nsize_t f (void)\n{\n  char dst[8];\n#ifndef CONTROL\n  size_t n = sizeof (dst);\n  size_t r = strlcpy (dst, &quot;strlcpy&quot;, n);\n#else\n  strcpy (dst, &quot;strlcpy&quot;);\n  size_t r = 7;\n#endif\n  return r;\n}</code></pre>\n<p>  Putting it all together, running the probe would then involve two steps:</p>\n<ol><li>Compile the control probe passing through any diagnostics and failing if the compilation fails. At the same time extract the header dependency information.</li><li>Compile the actual probe ignoring any diagnostics. If the compilation succeeds, assume the feature is present, otherwise – absent.</li></ol>\n<p>While the control idea might seem like a clever solution, it&#39;s not\n  without drawbacks. The main one is that writing a good control might be\n  challenging. For <code>strlcpy()</code> it is pretty easy to implement a\n  very close control using <code>strcpy()</code>. This makes sure the headers\n  we include are present and usable, the language syntax and logic we use are\n  correct, etc. In other situations writing a close control might be more\n  difficult.</p>\n<p>We have tested all these improvements with <code>build2</code> and you\n  can find the <a href=\"https://github.com/build2/HOWTO/blob/master/entries/implement-configuration-probing.md\" rel=\"nofollow ugc noopener\">HOWTO\n  article</a> and an <a href=\"https://github.com/build2/autoprobe\" rel=\"nofollow ugc noopener\">example</a>\n  that goes into more detail. We have also evaluated the performance of the\n  overall approach: the overhead of running 500 probes (including controls) on\n  modern hardware (such as Intel i9-12900K) is about half a second.</p>","headings":[]}}