Boost C++ Libraries: Ticket #12712: BOOST_AUTO_TEST_SUITE: Generate unique names by using __COUNTER__ https://svn.boost.org/trac10/ticket/12712 <p> There is a problem with non-unique names of &lt;test_suite_name&gt;_registrar in BOOST_AUTO_TEST_SUITE when joining multiple source files into one file using #include: </p> <p> I have a project with huge number of tests in different files and it takes around 10 minutes to compile. The project structure is like: </p> <p> .../test/data/foo.cpp: <code></code>` #include "stdafx.h" </p> <p> BOOST_AUTO_TEST_SUITE(data) BOOST_AUTO_TEST_SUITE(foo) </p> <p> &lt;my test cases&gt; </p> <p> BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() <code></code>` </p> <p> .../test/data/bar.cpp: <code></code>` #include "stdafx.h" </p> <p> BOOST_AUTO_TEST_SUITE(data) BOOST_AUTO_TEST_SUITE(bar) </p> <p> &lt;my test cases&gt; </p> <p> BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() <code></code>` </p> <p> To reduce the compilation time I included all sources into one file and after that I need to compile only that file (so it works much faster): .../test/_all.cpp: <code></code>` #include "stdafx.h" </p> <p> #include "data/foo.cpp" #include "data/bar.cpp" and so on... </p> <p> <code></code>` </p> <p> But when I'm compiling this file I get a multiple definitions of "data_registrar3" (3 is a substituted <span class="underline">LINE</span>). </p> <p> I think we can use <span class="underline">COUNTER</span> if it's supported (it's not a standard feature but most of compilers support it) so that it will fix the problem. </p> <p> Here is my patch: <code></code>` $ diff unit_test_suite.hpp.original unit_test_suite.hpp -uar --- unit_test_suite.hpp.original 2016-12-26 11:01:33.272912600 +0300 +++ unit_test_suite.hpp 2016-12-26 11:00:37.171138300 +0300 @@ -24,6 +24,11 @@ </p> <blockquote> <p> #include &lt;boost/test/detail/pp_variadic.hpp&gt; </p> </blockquote> <p> +#if defined(<span class="underline">COUNTER</span>) +#define BOOST_TEST_UNIQUE_NUMBER <span class="underline">COUNTER</span> +#else +#define BOOST_TEST_UNIQUE_NUMBER <span class="underline">LINE</span> +#endif </p> <blockquote> <p> <em><span class="underline"></span><span class="underline"></span><span class="underline"></span><span class="underline"></span><span class="underline"></span><span class="underline"></span><span class="underline"></span><span class="underline"></span><span class="underline"></span><span class="underline"></span><span class="underline"></span><span class="underline"></span><span class="underline"></span><span class="underline"></span><span class="underline"></span><span class="underline"></span><span class="underline"></span><span class="underline"></span><span class="underline"></span></em> </p> </blockquote> <p> @@ -120,7 +125,7 @@ </p> <blockquote> <p> <em> <strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong> </strong></em><strong> </strong></p> </blockquote> <blockquote> <p> #define BOOST_AUTO_TEST_SUITE_END() \ </p> </blockquote> <p> -BOOST_AUTO_TU_REGISTRAR( BOOST_JOIN( end_suite, <span class="underline">LINE</span> ) )( 1 ); \ +BOOST_AUTO_TU_REGISTRAR( BOOST_JOIN( end_suite, BOOST_TEST_UNIQUE_NUMBER ) )( 1 ); \ </p> <blockquote> <p> } \ /<strong>/ </strong></p> </blockquote> <p> @@ -298,7 +303,7 @@ </p> <blockquote> <p> #define BOOST_TEST_DECORATOR( D ) \ static boost::unit_test::decorator::collector const&amp; \ </p> </blockquote> <p> -BOOST_JOIN(decorator_collector,<span class="underline">LINE</span>) = D; \ +BOOST_JOIN(decorator_collector,BOOST_TEST_UNIQUE_NUMBER) = D; \ </p> <blockquote> <p> /<strong>/ </strong></p> </blockquote> <blockquote> <p> <em> <strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong></strong><strong> </strong></em><strong> </strong></p> </blockquote> <p> @@ -322,7 +327,7 @@ </p> <blockquote> <p> #define BOOST_AUTO_TU_REGISTRAR( test_name ) \ static boost::unit_test::ut_detail::auto_test_unit_registrar \ </p> </blockquote> <p> -BOOST_JOIN( BOOST_JOIN( test_name, _registrar ), <span class="underline">LINE</span> ) \ +BOOST_JOIN( BOOST_JOIN( test_name, _registrar ), BOOST_TEST_UNIQUE_NUMBER ) \ </p> <blockquote> <p> /<strong>/ #define BOOST_AUTO_TC_INVOKER( test_name ) BOOST_JOIN( test_name, _invoker ) #define BOOST_AUTO_TC_UNIQUE_ID( test_name ) BOOST_JOIN( test_name, _id ) </strong></p> </blockquote> <p> <code></code>` </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/12712 Trac 1.4.3 ki.stfu@… Mon, 26 Dec 2016 08:20:24 GMT <link>https://svn.boost.org/trac10/ticket/12712#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12712#comment:1</guid> <description> <p> Oops. I fixed its style: </p> <hr /> <p> There is a problem with non-unique names of <code>&lt;test_suite_name&gt;_registrar</code> in <code>BOOST_AUTO_TEST_SUITE</code> when joining multiple source files into one file using <code>#include</code>: </p> <p> I have a project with huge number of tests in different files and it takes around 10 minutes to compile. The project structure is like: </p> <p> <code>.../test/data/foo.cpp</code>: </p> <pre class="wiki">#include "stdafx.h" BOOST_AUTO_TEST_SUITE(data) BOOST_AUTO_TEST_SUITE(foo) &lt;my test cases&gt; BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() </pre><p> <code>.../test/data/bar.cpp</code>: </p> <pre class="wiki">#include "stdafx.h" BOOST_AUTO_TEST_SUITE(data) BOOST_AUTO_TEST_SUITE(bar) &lt;my test cases&gt; BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() </pre><p> To reduce the compilation time I included all sources into one file and after that I need to compile only that file (so it works much faster): </p> <p> <code>.../test/_all.cpp</code>: </p> <pre class="wiki">#include "stdafx.h" #include "data/foo.cpp" #include "data/bar.cpp" and so on... </pre><p> But when I'm compiling this file I get a multiple definitions of <code>data_registrar3</code> (<code>3</code> is a substituted <code>__LINE__</code>). </p> <p> I think we can use <code>__COUNTER__</code> if it's supported (it's not a standard feature but most of compilers support it) so that it will fix the problem. </p> <p> Here is my patch: </p> <pre class="wiki">$ diff unit_test_suite.hpp.original unit_test_suite.hpp -uar --- unit_test_suite.hpp.original 2016-12-26 11:01:33.272912600 +0300 +++ unit_test_suite.hpp 2016-12-26 11:00:37.171138300 +0300 @@ -24,6 +24,11 @@ #include &lt;boost/test/detail/pp_variadic.hpp&gt; +#if defined(__COUNTER__) +#define BOOST_TEST_UNIQUE_NUMBER __COUNTER__ +#else +#define BOOST_TEST_UNIQUE_NUMBER __LINE__ +#endif //____________________________________________________________________________// @@ -120,7 +125,7 @@ // ************************************************************************** // #define BOOST_AUTO_TEST_SUITE_END() \ -BOOST_AUTO_TU_REGISTRAR( BOOST_JOIN( end_suite, __LINE__ ) )( 1 ); \ +BOOST_AUTO_TU_REGISTRAR( BOOST_JOIN( end_suite, BOOST_TEST_UNIQUE_NUMBER ) )( 1 ); \ } \ /**/ @@ -298,7 +303,7 @@ #define BOOST_TEST_DECORATOR( D ) \ static boost::unit_test::decorator::collector const&amp; \ -BOOST_JOIN(decorator_collector,__LINE__) = D; \ +BOOST_JOIN(decorator_collector,BOOST_TEST_UNIQUE_NUMBER) = D; \ /**/ // ************************************************************************** // @@ -322,7 +327,7 @@ #define BOOST_AUTO_TU_REGISTRAR( test_name ) \ static boost::unit_test::ut_detail::auto_test_unit_registrar \ -BOOST_JOIN( BOOST_JOIN( test_name, _registrar ), __LINE__ ) \ +BOOST_JOIN( BOOST_JOIN( test_name, _registrar ), BOOST_TEST_UNIQUE_NUMBER ) \ /**/ #define BOOST_AUTO_TC_INVOKER( test_name ) BOOST_JOIN( test_name, _invoker ) #define BOOST_AUTO_TC_UNIQUE_ID( test_name ) BOOST_JOIN( test_name, _id ) </pre> </description> <category>Ticket</category> </item> <item> <author>ki.stfu@…</author> <pubDate>Fri, 30 Dec 2016 04:02:51 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12712#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12712#comment:2</guid> <description> <p> Friendly ping. </p> </description> <category>Ticket</category> </item> <item> <author>ki.stfu@…</author> <pubDate>Mon, 16 Jan 2017 09:24:54 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12712#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12712#comment:3</guid> <description> <p> Friendly ping. </p> </description> <category>Ticket</category> </item> <item> <author>ki.stfu@…</author> <pubDate>Thu, 26 Jan 2017 06:13:48 GMT</pubDate> <title>version changed https://svn.boost.org/trac10/ticket/12712#comment:4 https://svn.boost.org/trac10/ticket/12712#comment:4 <ul> <li><strong>version</strong> <span class="trac-field-old">Boost 1.62.0</span> → <span class="trac-field-new">Boost Development Trunk</span> </li> </ul> Ticket Raffi Enficiaud Mon, 30 Jan 2017 21:21:43 GMT owner changed https://svn.boost.org/trac10/ticket/12712#comment:5 https://svn.boost.org/trac10/ticket/12712#comment:5 <ul> <li><strong>owner</strong> changed from <span class="trac-author">Gennadiy Rozental</span> to <span class="trac-author">Raffi Enficiaud</span> </li> </ul> Ticket Raffi Enficiaud Mon, 30 Jan 2017 21:26:04 GMT <link>https://svn.boost.org/trac10/ticket/12712#comment:6 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12712#comment:6</guid> <description> <p> Hi there, </p> <p> Would you mind checking the current state of boost.test without the <code>#include "stdafx.h"</code> precompiled header? I looks weird to me that those registrar end-up at the same line. </p> </description> <category>Ticket</category> </item> <item> <author>ki.stfu@…</author> <pubDate>Tue, 31 Jan 2017 07:54:11 GMT</pubDate> <title>cc changed https://svn.boost.org/trac10/ticket/12712#comment:7 https://svn.boost.org/trac10/ticket/12712#comment:7 <ul> <li><strong>cc</strong> <span class="trac-author">ki.stfu@…</span> added </li> </ul> <p> <code>stdafx.h</code> doesn't play any special role in this case because I tested it on Linux with clang. So it can be renamed or even removed, it doesn't matter. </p> <p> The fact is that <code>__LINE__</code> is expanded to the current line number and if you have multiple files which define variables on the same line using this naming style then you will get an error. </p> <p> You can reproduce it by following: </p> <pre class="wiki">user@u14:~$ ls _all.cpp bar.cpp foo.cpp user@u14:~$ cat foo.cpp #include &lt;boost/test/unit_test.hpp&gt; BOOST_AUTO_TEST_SUITE(data) BOOST_AUTO_TEST_SUITE(foo) BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() user@u14:~$ cat bar.cpp #include &lt;boost/test/unit_test.hpp&gt; BOOST_AUTO_TEST_SUITE(data) BOOST_AUTO_TEST_SUITE(bar) BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() user@u14:~$ cat _all.cpp #define BOOST_TEST_MAIN #include &lt;boost/test/unit_test.hpp&gt; #include "foo.cpp" #include "bar.cpp" user@u14:~$ clang++ _all.cpp In file included from _all.cpp:5: ./bar.cpp:3:1: error: redefinition of 'data_registrar3' BOOST_AUTO_TEST_SUITE(data) ^ /usr/include/boost/test/unit_test_suite.hpp:45:73: note: expanded from macro 'BOOST_AUTO_TEST_SUITE' namespace suite_name { \ ^ /usr/include/boost/test/unit_test_suite.hpp:209:62: note: expanded from macro '\ BOOST_AUTO_TU_REGISTRAR' static boost::unit_test::ut_detail::auto_test_unit_registrar BOOST_JOIN( BOOST_JOIN( test_name, _registrar ), __LINE__ ) ^ /usr/include/boost/config/suffix.hpp:608:28: note: expanded from macro 'BOOST_JOIN' #define BOOST_JOIN( X, Y ) BOOST_DO_JOIN( X, Y ) ^ /usr/include/boost/config/suffix.hpp:609:31: note: expanded from macro 'BOOST_DO_JOIN' #define BOOST_DO_JOIN( X, Y ) BOOST_DO_JOIN2(X,Y) ^ /usr/include/boost/config/suffix.hpp:610:32: note: expanded from macro 'BOOST_DO_JOIN2' #define BOOST_DO_JOIN2( X, Y ) X##Y ^ &lt;scratch space&gt;:114:1: note: expanded from here data_registrar3 ^ ./foo.cpp:3:1: note: previous definition is here BOOST_AUTO_TEST_SUITE(data) ^ /usr/include/boost/test/unit_test_suite.hpp:45:73: note: expanded from macro 'BOOST_AUTO_TEST_SUITE' namespace suite_name { \ ^ /usr/include/boost/test/unit_test_suite.hpp:209:62: note: expanded from macro '\ BOOST_AUTO_TU_REGISTRAR' static boost::unit_test::ut_detail::auto_test_unit_registrar BOOST_JOIN( BOOST_JOIN( test_name, _registrar ), __LINE__ ) ^ /usr/include/boost/config/suffix.hpp:608:28: note: expanded from macro 'BOOST_JOIN' #define BOOST_JOIN( X, Y ) BOOST_DO_JOIN( X, Y ) ^ /usr/include/boost/config/suffix.hpp:609:31: note: expanded from macro 'BOOST_DO_JOIN' #define BOOST_DO_JOIN( X, Y ) BOOST_DO_JOIN2(X,Y) ^ /usr/include/boost/config/suffix.hpp:610:32: note: expanded from macro 'BOOST_DO_JOIN2' #define BOOST_DO_JOIN2( X, Y ) X##Y ^ &lt;scratch space&gt;:96:1: note: expanded from here data_registrar3 ^ </pre> Ticket Raffi Enficiaud Tue, 31 Jan 2017 16:00:37 GMT <link>https://svn.boost.org/trac10/ticket/12712#comment:8 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12712#comment:8</guid> <description> <p> Thanks for the clarification. The problem with <code>__COUNTER__</code> is that it is not a standard macro, I would rather not include that. Also since those registrar are static, there is no clash in having the exact same declarations (in terms of lines) in 2 different compilation units, if you do not include everything in one place. </p> <p> That is to me a really specific use case, and also has the following drawbacks: </p> <ul><li>each time a .cpp changes, a very big block is recompiled </li><li>you do not benefit from potential accelerations of the build system (<em> builds) </em></li></ul><p> I am not sure the benefits of doing it the way you do outweigh the problems (maybe you have numbers). I would rather suggest a nasty patch: you can specify a line number with the <code>#line</code> preprocessor directive, which may be used in conjunction with <code>__COUNTER__</code> in your case to lower the risks for clashes. </p> </description> <category>Ticket</category> </item> <item> <author>ki.stfu@…</author> <pubDate>Wed, 01 Feb 2017 07:34:47 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12712#comment:9 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12712#comment:9</guid> <description> <p> I don't think I'm doing anything illegal and in my case the game is worth the candle. </p> <p> <code>__COUNTER__</code> is supported by major compilers (MSVC, Clang, GCC) and is already used in Boost library. Moreover, it suits better for generating unique names than <code>__LINE__</code>. </p> <p> So why we can't define <code>BOOST_TEST_UNIQUE_NUMBER</code> macro, which refers to <code>__COUNTER__</code> or (if it's not available to) <code>__LINE__</code>? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Raffi Enficiaud</dc:creator> <pubDate>Wed, 01 Feb 2017 07:56:01 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12712#comment:10 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12712#comment:10</guid> <description> <p> I understand that this is properly handled by major compilers, but not all of them. Maybe there is a way to know if this macro is supported. If so, it would be possible to integrate that, if not then it will be a won't fix. </p> </description> <category>Ticket</category> </item> <item> <author>ki.stfu@…</author> <pubDate>Wed, 01 Feb 2017 07:57:35 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12712#comment:11 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12712#comment:11</guid> <description> <p> How about the way suggested above? </p> <p> <code></code>` #if defined(<span class="underline">COUNTER</span>) #define BOOST_TEST_UNIQUE_NUMBER <span class="underline">COUNTER</span> #else #define BOOST_TEST_UNIQUE_NUMBER <span class="underline">LINE</span> #endif <code></code>` </p> </description> <category>Ticket</category> </item> <item> <author>ki.stfu@…</author> <pubDate>Wed, 01 Feb 2017 07:58:55 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12712#comment:12 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12712#comment:12</guid> <description> <p> Ugh... I meant </p> <pre class="wiki">#if defined(__COUNTER__) #define BOOST_TEST_UNIQUE_NUMBER __COUNTER__ #else #define BOOST_TEST_UNIQUE_NUMBER __LINE__ #endif </pre> </description> <category>Ticket</category> </item> <item> <dc:creator>Raffi Enficiaud</dc:creator> <pubDate>Wed, 01 Feb 2017 08:10:32 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12712#comment:13 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12712#comment:13</guid> <description> <p> Ok, then I'll check with that, I'll keep you updated. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Raffi Enficiaud</dc:creator> <pubDate>Sat, 04 Feb 2017 20:03:58 GMT</pubDate> <title>status, milestone changed https://svn.boost.org/trac10/ticket/12712#comment:14 https://svn.boost.org/trac10/ticket/12712#comment:14 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">assigned</span> </li> <li><strong>milestone</strong> <span class="trac-field-old">To Be Determined</span> → <span class="trac-field-new">Boost 1.64.0</span> </li> </ul> <p> Would you please give a try to the branch <code>topic/12712-several-test-suite-decl-in-same-comp-unit</code> ? </p> <p> Thanks, </p> Ticket ki.stfu@… Mon, 06 Feb 2017 08:00:37 GMT <link>https://svn.boost.org/trac10/ticket/12712#comment:15 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12712#comment:15</guid> <description> <p> Yes, it works! </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Raffi Enficiaud</dc:creator> <pubDate>Wed, 01 Mar 2017 11:33:11 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/12712#comment:16 https://svn.boost.org/trac10/ticket/12712#comment:16 <ul> <li><strong>status</strong> <span class="trac-field-old">assigned</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> </ul> <p> Merged to master, rev a2b73f5d7568e69162dfac213fab87eea0021ec5 </p> Ticket