Compile of "common/kiid.cpp" fails with Boost 1.65.1 due to use of internal "boost::uuids::detail::seed_rng" class
Description
Building KiCad 6.0.7 (f9a2dced) fails on Ubuntu Bionic 18.04 with Boost 1.65.1 with the following error:
[ 13%] Building CXX object common/CMakeFiles/common.dir/kiid.cpp.o
In file included from /usr/include/boost/random/mersenne_twister.hpp:30:0,
from /usr/include/boost/uuid/random_generator.hpp:15,
from /usr/include/boost/uuid/uuid_generators.hpp:17,
from /work/kicad/common/kiid.cpp:28:
/usr/include/boost/random/detail/seed_impl.hpp: In instantiation of 'void boost::random::detail::seed_array_int_impl(SeedSeq&, UIntType (&)[n]) [with int w = 32; long unsigned int n = 624; SeedSeq = boost::uuids::detail::seed_rng; UIntType = unsigned int]':
/usr/include/boost/random/detail/seed_impl.hpp:290:27: required from 'void boost::random::detail::seed_array_int_impl(SeedSeq&, IntType (&)[n], mpl_::false_) [with int w = 32; long unsigned int n = 624; SeedSeq = boost::uuids::detail::seed_rng; IntType = unsigned int; mpl_::false_ = mpl_::bool_<false>]'
/usr/include/boost/random/detail/seed_impl.hpp:296:27: required from 'void boost::random::detail::seed_array_int(SeedSeq&, IntType (&)[n]) [with int w = 32; long unsigned int n = 624; SeedSeq = boost::uuids::detail::seed_rng; IntType = unsigned int]'
/usr/include/boost/random/mersenne_twister.hpp:163:34: required from 'void boost::random::mersenne_twister_engine<UIntType, w, n, m, r, a, u, d, s, b, t, c, l, f>::seed(SeeqSeq&, typename boost::random::detail::disable_seed<SeeqSeq>::type*) [with SeeqSeq = boost::uuids::detail::seed_rng; UIntType = unsigned int; long unsigned int w = 32; long unsigned int n = 624; long unsigned int m = 397; long unsigned int r = 31; UIntType a = 2567483615; long unsigned int u = 11; UIntType d = 4294967295; long unsigned int s = 7; UIntType b = 2636928640; long unsigned int t = 15; UIntType c = 4022730752; long unsigned int l = 18; UIntType f = 1812433253; typename boost::random::detail::disable_seed<SeeqSeq>::type = void]'
/usr/include/boost/random/mersenne_twister.hpp:128:11: required from 'boost::random::mersenne_twister_engine<UIntType, w, n, m, r, a, u, d, s, b, t, c, l, f>::mersenne_twister_engine(SeedSeq&, typename boost::random::detail::disable_constructor<boost::random::mersenne_twister_engine<UIntType, w, n, m, r, a, u, d, s, b, t, c, l, f>, SeedSeq>::type*) [with SeedSeq = boost::uuids::detail::seed_rng; UIntType = unsigned int; long unsigned int w = 32; long unsigned int n = 624; long unsigned int m = 397; long unsigned int r = 31; UIntType a = 2567483615; long unsigned int u = 11; UIntType d = 4294967295; long unsigned int s = 7; UIntType b = 2636928640; long unsigned int t = 15; UIntType c = 4022730752; long unsigned int l = 18; UIntType f = 1812433253; typename boost::random::detail::disable_constructor<boost::random::mersenne_twister_engine<UIntType, w, n, m, r, a, u, d, s, b, t, c, l, f>, SeedSeq>::type = void]'
/work/kicad/common/kiid.cpp:50:73: required from here
/usr/include/boost/random/detail/seed_impl.hpp:269:9: error: 'class boost::uuids::detail::seed_rng' has no member named 'generate'
seq.generate(&storage[0], &storage[0] + ((w+31)/32) * n);
~~~~^~~~~~~~
common/CMakeFiles/common.dir/build.make:4167: recipe for target 'common/CMakeFiles/common.dir/kiid.cpp.o' failed
make[2]: *** [common/CMakeFiles/common.dir/kiid.cpp.o] Error 1
make[2]: Target 'common/CMakeFiles/common.dir/build' not remade because of errors.
CMakeFiles/Makefile2:2262: recipe for target 'common/CMakeFiles/common.dir/all' failed
make[1]: *** [common/CMakeFiles/common.dir/all] Error 2
make[1]: Target 'all' not remade because of errors.
Makefile:162: recipe for target 'all' failed
make: *** [all] Error 2
make: Target 'default_target' not remade because of errors.
However, KiCad 6.0.7 is documented as supporting Boost versions >= 1.59 here: https://gitlab.com/kicad/code/kicad/-/blob/f9a2dced07acac97c62eef0931269fea6bcfb828/INSTALL.txt#L94
Steps to reproduce
# on Ubuntu Bionic 18.04 amd64
git clone https://gitlab.com/kicad/code/kicad.git
pushd kicad
git checkout f9a2dced07acac97c62eef0931269fea6bcfb828
popd
mkdir kicad-build
pushd kicad-build
cmake ../kicad -DKICAD_SPICE=OFF -DKICAD_USE_OCC=OFF
make -j`nproc` -k
Analysis
The relevant code was touched most recently in d440ff7c (FYI @mroszko) and first started using types from one of Boost's "implementation details" detail
namespaces in 2e689901. It probably shouldn't be using anything in a detail
namespace, as such implementation details frequently change between versions.
There is some relevant discussion on the 2e689901 commit. However, the discussion seems to overlook the fact that Boost implementation details (i.e. anything in a ::detail::
namespace) are not part of the documented API and that using detail
members is virtually guaranteed to cause frequent compile breakages and lots of consequent headaches.
Notably, Boost is used in KiCad a lot (2000-ish lines mention Boost), but the kiid.cpp
code has 2 of the 3 total references to a boost::*::detail
member in the entire KiCad codebase:
~/kicad$ grep -ri boost | wc -l
1968
~/kicad$ grep -ri boost | grep ::detail
common/kiid.cpp:static boost::uuids::detail::random_provider seeder; // required to ensure the rng has a random initial seed
common/kiid.cpp:static boost::uuids::detail::seed_rng seeder; // required to ensure the rng has a random initial seed
3d-viewer/3d_cache/3d_cache.cpp: boost::uuids::detail::sha1 dblock;
It would probably be worth eliminating these and having some sort of lint check to prohibit similar detail
usage in the future.
Fix
--- a/common/kiid.cpp
+++ b/common/kiid.cpp
@@ -42,13 +42,8 @@ static std::mutex rng_mutex;
// Static rng and generators are used because the overhead of constant seeding is expensive
// We break out the rng separately from the generator because we want to control seeding in cases like unit tests
-#if BOOST_VERSION >= 106700
-static boost::uuids::detail::random_provider seeder; // required to ensure the rng has a random initial seed
-#else
-static boost::uuids::detail::seed_rng seeder; // required to ensure the rng has a random initial seed
-#endif
-static boost::mt19937 rng( seeder );
-static boost::uuids::basic_random_generator<boost::mt19937> randomGenerator( rng );
+static boost::mt19937 rng;
+static boost::uuids::basic_random_generator<boost::mt19937> randomGenerator;
// These don't have the same performance penalty, but we might as well be consistent
static boost::uuids::string_generator stringGenerator;
@@ -279,6 +274,7 @@ void KIID::CreateNilUuids( bool aNil )
void KIID::SeedGenerator( unsigned int aSeed )
{
rng.seed( aSeed );
+ randomGenerator = boost::uuids::basic_random_generator<boost::mt19937>( rng );
}
The above diff should maintain the same behavior, but doesn't depend on detail
members, and builds on at least Ubuntu 18.04, 20.04, and 22.04.
For @kicad-bot: build-error