What to do about Boost libraries which use user-defined macros which are not BOOST_ prefixed
Acting on guidance given to my recent supply to this list of unprefixed macros, namespaces etc injected into the global namespace by Boost, I have logged a list of all issues with each library, and linked to all those from a single issue logged at https://github.com/boostorg/boost/issues/352. A problem has arisen which requires input from boost-dev. Some Boost libraries define as part of their public API a non-BOOST_-prefixed macro which changes the definition of their header files e.g. PHOENIX_LIMIT (just to be clear, Phoenix is not the only library doing this) If we change such macros to be like BOOST_PHOENIX_LIMIT instead, all existing code using Boost which sets PHOENIX_LIMIT would potentially *silently* break. What we could decide to do instead is: #if defined(PHOENIX_LIMIT) && !defined(BOOST_PHOENIX_LIMIT) #error In Boost 1.xx PHOENIX_LIMIT was renamed to BOOST_PHOENIX_LIMIT. Please upgrade your code to reflect the new name. #endif Or one could just leave PHOENIX_LIMIT named as is. What would Boost developers prefer we do? Niall
On Monday, December 16, 2019, Niall Douglas via Boost
A problem has arisen which requires input from boost-dev. Some Boost libraries define as part of their public API a non-BOOST_-prefixed macro which changes the definition of their header files e.g.
PHOENIX_LIMIT
(just to be clear, Phoenix is not the only library doing this)
If we change such macros to be like BOOST_PHOENIX_LIMIT instead, all existing code using Boost which sets PHOENIX_LIMIT would potentially *silently* break.
What we could decide to do instead is:
#if defined(PHOENIX_LIMIT) && !defined(BOOST_PHOENIX_LIMIT) #error In Boost 1.xx PHOENIX_LIMIT was renamed to BOOST_PHOENIX_LIMIT. Please upgrade your code to reflect the new name. #endif
Or one could just leave PHOENIX_LIMIT named as is.
What would Boost developers prefer we do?
Niall
I would leave these as-is. Boost isn't defining them. Glen
On 16/12/2019 15:26, Glen Fernandes wrote:
A problem has arisen which requires input from boost-dev. Some Boost libraries define as part of their public API a non-BOOST_-prefixed macro which changes the definition of their header files e.g.
PHOENIX_LIMIT
(just to be clear, Phoenix is not the only library doing this)
If we change such macros to be like BOOST_PHOENIX_LIMIT instead, all existing code using Boost which sets PHOENIX_LIMIT would potentially *silently* break.
What we could decide to do instead is:
#if defined(PHOENIX_LIMIT) && !defined(BOOST_PHOENIX_LIMIT) #error In Boost 1.xx PHOENIX_LIMIT was renamed to BOOST_PHOENIX_LIMIT. Please upgrade your code to reflect the new name. #endif
Or one could just leave PHOENIX_LIMIT named as is.
What would Boost developers prefer we do?
I would leave these as-is. Boost isn't defining them.
Unfortunately multiple Phoenix-using Boost libraries DO define this macro. (And yes, that would cause significant end user surprise as the end user setting would get silently ignored sometimes, but as one of the older Boost libraries, I would guess everybody that cares has adjusted by now) Niall
Niall Douglas wrote:
What we could decide to do instead is:
#if defined(PHOENIX_LIMIT) && !defined(BOOST_PHOENIX_LIMIT) #error In Boost 1.xx PHOENIX_LIMIT was renamed to BOOST_PHOENIX_LIMIT. Please upgrade your code to reflect the new name. #endif
If we do this, instead of #error, we should probably use BOOST_PRAGMA_MESSAGE("...") #define BOOST_PHOENIX_LIMIT PHOENIX_LIMIT This will allow us to fix the uses of PHOENIX_LIMIT within Boost without breaking user code.
On 16/12/2019 15:39, Peter Dimov via Boost wrote:
Niall Douglas wrote:
What we could decide to do instead is:
#if defined(PHOENIX_LIMIT) && !defined(BOOST_PHOENIX_LIMIT) #error In Boost 1.xx PHOENIX_LIMIT was renamed to BOOST_PHOENIX_LIMIT. Please upgrade your code to reflect the new name. #endif
If we do this, instead of #error, we should probably use
BOOST_PRAGMA_MESSAGE("...") #define BOOST_PHOENIX_LIMIT PHOENIX_LIMIT
This will allow us to fix the uses of PHOENIX_LIMIT within Boost without breaking user code.
I've never understood your reluctance Peter to break the build of end users where the change is (a) good for them and (b) find and replace in files solvable within 60 seconds. I don't get the need to be conservative on these sorts of build breaks. The only way that such conservatism makes sense is if there is a unrecompilable binary blob somewhere in this. Then I'd get it. But with anything using Boost, that can't be the case. So I don't get it. Niall
On 12/16/19 08:10, Niall Douglas via Boost wrote:
On 16/12/2019 15:39, Peter Dimov via Boost wrote:
Niall Douglas wrote:
What we could decide to do instead is:
#if defined(PHOENIX_LIMIT) && !defined(BOOST_PHOENIX_LIMIT) #error In Boost 1.xx PHOENIX_LIMIT was renamed to BOOST_PHOENIX_LIMIT. Please upgrade your code to reflect the new name. #endif
If we do this, instead of #error, we should probably use
BOOST_PRAGMA_MESSAGE("...") #define BOOST_PHOENIX_LIMIT PHOENIX_LIMIT
This will allow us to fix the uses of PHOENIX_LIMIT within Boost without breaking user code.
I've never understood your reluctance Peter to break the build of end users where the change is (a) good for them and (b) find and replace in files solvable within 60 seconds. I don't get the need to be conservative on these sorts of build breaks.
The only way that such conservatism makes sense is if there is a unrecompilable binary blob somewhere in this. Then I'd get it. But with anything using Boost, that can't be the case. So I don't get it.
What problem are you wanting to solve here Niall? -- Michael Caisse Ciere Consulting ciere.com
On 12/16/2019 10:22 AM, Niall Douglas via Boost wrote:
Acting on guidance given to my recent supply to this list of unprefixed macros, namespaces etc injected into the global namespace by Boost, I have logged a list of all issues with each library, and linked to all those from a single issue logged at https://github.com/boostorg/boost/issues/352.
A problem has arisen which requires input from boost-dev. Some Boost libraries define as part of their public API a non-BOOST_-prefixed macro which changes the definition of their header files e.g.
PHOENIX_LIMIT
(just to be clear, Phoenix is not the only library doing this)
If we change such macros to be like BOOST_PHOENIX_LIMIT instead, all existing code using Boost which sets PHOENIX_LIMIT would potentially *silently* break.
What we could decide to do instead is:
#if defined(PHOENIX_LIMIT) && !defined(BOOST_PHOENIX_LIMIT) #error In Boost 1.xx PHOENIX_LIMIT was renamed to BOOST_PHOENIX_LIMIT. Please upgrade your code to reflect the new name. #endif
Or one could just leave PHOENIX_LIMIT named as is.
What would Boost developers prefer we do?
I am with Niall in this as I think that all Boost library macros should begin with BOOST_SOMELIBRARY_UPPERCASENAMEOFMACRO_ETC. Maybe we can, in general, deprecate the current macros that do not follow this pattern and then change them to this pattern in some future Boost release. Needless to say it is really important that C++ macro names are as distinct as possible. We all know how ridiculous it is for compiler implementations to name macros with names such as 'max' and 'min' and all the troubles such names have caused for scores of C++ programmers down through the years.
On 16.12.19 17:38, Edward Diener via Boost wrote:
On 12/16/2019 10:22 AM, Niall Douglas via Boost wrote:
#if defined(PHOENIX_LIMIT) && !defined(BOOST_PHOENIX_LIMIT) #error In Boost 1.xx PHOENIX_LIMIT was renamed to BOOST_PHOENIX_LIMIT. Please upgrade your code to reflect the new name. #endif
I am with Niall in this as I think that all Boost library macros should begin with BOOST_SOMELIBRARY_UPPERCASENAMEOFMACRO_ETC. Maybe we can, in general, deprecate the current macros that do not follow this pattern and then change them to this pattern in some future Boost release. Needless to say it is really important that C++ macro names are as distinct as possible. We all know how ridiculous it is for compiler implementations to name macros with names such as 'max' and 'min' and all the troubles such names have caused for scores of C++ programmers down through the years.
I do understand Peter though: This is dangerous! Most of the macros have default values, so when changing the name, users won't notice and applications will continue to work. Until they don't. When using the above code snipped (making the old one an error) how long will you keep it? - Very long: You still block the macro you wanted to free - Short: Users skipping versions won't notice the change until it's to late. We jumped from 1.55 to 1.67 not so long ago... Is the condition `if defined(PHOENIX_LIMIT) && !defined(BOOST_PHOENIX_LIMIT)` even justified? What if someone else defines BOOST_PHOENIX_LIMIT and my library/app defines PHOENIX_LIMIT? Now I don't get an error and stuff breaks when I don't expect it. My proposal: Evaluate each macro carefully. Where changing the macro issue a deprecation message (suppressible per macro) for a couple releases (3? 5? 10?) when the old one is defined. Only change macros where not defining it by the user will lead to compile-time errors. E.g. for BOOST_PHOENIX_LIMIT I think this was the maximum number of arguments supported and not defining it bigger will make code using more args fail to compile. This would be OK. For other macros provide a BOOST_ version and error out if both are defined. So users can start using the "good" ones and docs should only mention them (or hide the old names under a "see there") But the old ones must be kept for those. Mistakes were made, can't really change that now. Alex
When using the above code snipped (making the old one an error) how long will you keep it? - Very long: You still block the macro you wanted to free - Short: Users skipping versions won't notice the change until it's to late. We jumped from 1.55 to 1.67 not so long ago...
We need to stop *defining* non-BOOST_ prefixed macros in Boost. Or injecting anything into the global namespace. Even if we #undef it later. We can however *react* to anything already in the global namespace. It's not us being anti-social, it's us reacting to other code's anti socialness. So, to answer your question, you detect the old setting where the new setting is not applied, and give a useful error (my preference) or warning (Peter's preference).
Is the condition `if defined(PHOENIX_LIMIT) && !defined(BOOST_PHOENIX_LIMIT)` even justified? What if someone else defines BOOST_PHOENIX_LIMIT and my library/app defines PHOENIX_LIMIT? Now I don't get an error and stuff breaks when I don't expect it.
I'd be happy with "#ifdef PHOENIX_LIMIT" then error out personally. Niall
On 12/16/2019 11:58 AM, Alexander Grund via Boost wrote:
On 16.12.19 17:38, Edward Diener via Boost wrote:
On 12/16/2019 10:22 AM, Niall Douglas via Boost wrote:
#if defined(PHOENIX_LIMIT) && !defined(BOOST_PHOENIX_LIMIT) #error In Boost 1.xx PHOENIX_LIMIT was renamed to BOOST_PHOENIX_LIMIT. Please upgrade your code to reflect the new name. #endif
I am with Niall in this as I think that all Boost library macros should begin with BOOST_SOMELIBRARY_UPPERCASENAMEOFMACRO_ETC. Maybe we can, in general, deprecate the current macros that do not follow this pattern and then change them to this pattern in some future Boost release. Needless to say it is really important that C++ macro names are as distinct as possible. We all know how ridiculous it is for compiler implementations to name macros with names such as 'max' and 'min' and all the troubles such names have caused for scores of C++ programmers down through the years.
I do understand Peter though: This is dangerous!
You can eventually put in a common header included by all library XXX headers: #if defined(XXX_SOMEMACRO) #error the correct definition for XXX_SOMEMACRO is now BOOST_XXX_SOMEMACRO. Please make the change in your source code. #endif I understand that this may be annoying, but I think it is eventually worth it. Boost could also provide a Python script to change the name of macros to their Boost equivalent for all source files which may use library XXX etc. I understand that a macro named PHOENIX_SOMETHING is a pretty specific macro name in its own right, and is probably never going to be duplicated at a practical level in non-Phoenix code anywhere, so I am not trying to be doctrinaire about Niall's suggestion. But I think the suggestion is generally right in trying to avoid macro name clashes.
Most of the macros have default values, so when changing the name, users won't notice and applications will continue to work. Until they don't.
When using the above code snipped (making the old one an error) how long will you keep it? - Very long: You still block the macro you wanted to free - Short: Users skipping versions won't notice the change until it's to late. We jumped from 1.55 to 1.67 not so long ago...
Is the condition `if defined(PHOENIX_LIMIT) && !defined(BOOST_PHOENIX_LIMIT)` even justified? What if someone else defines BOOST_PHOENIX_LIMIT and my library/app defines PHOENIX_LIMIT? Now I don't get an error and stuff breaks when I don't expect it.
My proposal: Evaluate each macro carefully. Where changing the macro issue a deprecation message (suppressible per macro) for a couple releases (3? 5? 10?) when the old one is defined. Only change macros where not defining it by the user will lead to compile-time errors. E.g. for BOOST_PHOENIX_LIMIT I think this was the maximum number of arguments supported and not defining it bigger will make code using more args fail to compile. This would be OK. For other macros provide a BOOST_ version and error out if both are defined. So users can start using the "good" ones and docs should only mention them (or hide the old names under a "see there") But the old ones must be kept for those. Mistakes were made, can't really change that now.
You can eventually put in a common header included by all library XXX headers:
#if defined(XXX_SOMEMACRO) #error the correct definition for XXX_SOMEMACRO is now BOOST_XXX_SOMEMACRO. Please make the change in your source code. #endif
I understand that this may be annoying, but I think it is eventually worth it.
So, to answer your question, you detect the old setting where the new setting is not applied, and give a useful error (my preference) or warning (Peter's preference).
So you want to forbid using e.g. PHOENIX_LIMIT for everyone using Boost.Phoenix? What about in 2 releases after that change someone new comes in and uses the new Boost (the first he has ever used) together with some libPhoenix he wrote and (appropriately) uses PHOENIX_LIMIT as the same for his macros? So what is gained?
On 12/17/2019 2:39 AM, Alexander Grund via Boost wrote:
You can eventually put in a common header included by all library XXX headers:
#if defined(XXX_SOMEMACRO) #error the correct definition for XXX_SOMEMACRO is now BOOST_XXX_SOMEMACRO. Please make the change in your source code. #endif
I understand that this may be annoying, but I think it is eventually worth it.
So, to answer your question, you detect the old setting where the new setting is not applied, and give a useful error (my preference) or warning (Peter's preference).
So you want to forbid using e.g. PHOENIX_LIMIT for everyone using Boost.Phoenix? What about in 2 releases after that change someone new comes in and uses the new Boost (the first he has ever used) together with some libPhoenix he wrote and (appropriately) uses PHOENIX_LIMIT as the same for his macros? So what is gained?
It is a macro. Macros do not go into libraries. The libPhoenix he wrote has nothing in it regarding the name PHOENIX_LIMIT. If your hypothetical programmer uses PHOENIX_LIMIT in his code he is told via the preprocessor #error that he must use BOOST_PHOENIX_LIMIT instead.
On 17.12.19 14:50, Edward Diener via Boost wrote:
On 12/17/2019 2:39 AM, Alexander Grund via Boost wrote:
So you want to forbid using e.g. PHOENIX_LIMIT for everyone using Boost.Phoenix? What about in 2 releases after that change someone new comes in and uses the new Boost (the first he has ever used) together with some libPhoenix he wrote and (appropriately) uses PHOENIX_LIMIT as the same for his macros? So what is gained?
It is a macro. Macros do not go into libraries. The libPhoenix he wrote has nothing in it regarding the name PHOENIX_LIMIT. If your hypothetical programmer uses PHOENIX_LIMIT in his code he is told via the preprocessor #error that he must use BOOST_PHOENIX_LIMIT instead.
You misunderstood me. If you (currently) include a header from Boost.Phoenix then PHOENIX_LIMIT will be defined (unless I missed an undef somewhere) So assume the following: - PHOENIX_LIMIT was renamed to BOOST_PHOENIX_LIMIT - An error was added if PHOENIX_LIMIT is defined - A user develops a libPhoenix (unrelated to boost) and uses PHOENIX_LIMIT as per `<libName>_<macro>` naming convention to do something in the headers of his library (e.g. a constant to cap numbers) - A user (the same or another) uses libPhoenix and BoostPhoenix and includes their headers in this order --> libPhoenix headers rightfully define PHOENIX_LIMIT, Boost headers detect the "old" name and error out. Boom, broken some unrelated library for no (apparent) reason
On 2019-12-17 16:59, Alexander Grund via Boost wrote:
On 17.12.19 14:50, Edward Diener via Boost wrote:
On 12/17/2019 2:39 AM, Alexander Grund via Boost wrote:
So you want to forbid using e.g. PHOENIX_LIMIT for everyone using Boost.Phoenix? What about in 2 releases after that change someone new comes in and uses the new Boost (the first he has ever used) together with some libPhoenix he wrote and (appropriately) uses PHOENIX_LIMIT as the same for his macros? So what is gained?
It is a macro. Macros do not go into libraries. The libPhoenix he wrote has nothing in it regarding the name PHOENIX_LIMIT. If your hypothetical programmer uses PHOENIX_LIMIT in his code he is told via the preprocessor #error that he must use BOOST_PHOENIX_LIMIT instead.
You misunderstood me. If you (currently) include a header from Boost.Phoenix then PHOENIX_LIMIT will be defined (unless I missed an undef somewhere)
So assume the following: - PHOENIX_LIMIT was renamed to BOOST_PHOENIX_LIMIT - An error was added if PHOENIX_LIMIT is defined - A user develops a libPhoenix (unrelated to boost) and uses PHOENIX_LIMIT as per `<libName>_<macro>` naming convention to do something in the headers of his library (e.g. a constant to cap numbers) - A user (the same or another) uses libPhoenix and BoostPhoenix and includes their headers in this order
--> libPhoenix headers rightfully define PHOENIX_LIMIT, Boost headers detect the "old" name and error out. Boom, broken some unrelated library for no (apparent) reason
This is not worse than the status quo. Except that currently the two libraries may interpret the macro differently. I think, given that PHOENIX_LIMIT is currently reserved for Boost.Phoenix, keeping it reserved still for the deprecation period is not a problem (IOW, not more of a problem than we currently have). The important part is that we set the transition to BOOST_PHOENIX_LIMIT in motion, starting with PHOENIX_LIMIT deprecation and warning the users.
I think, given that PHOENIX_LIMIT is currently reserved for Boost.Phoenix, keeping it reserved still for the deprecation period is not a problem (IOW, not more of a problem than we currently have). The important part is that we set the transition to BOOST_PHOENIX_LIMIT in motion, starting with PHOENIX_LIMIT deprecation and warning the users.
Firstly I'd like to thank the majority of library maintainers who either went ahead and fixed their non-BOOST_ prefixed libraries immediately, or have agreed to do so when I get a sed script for them. There is resistance however from a minority of library maintainers who insist that this list must formally agree on a policy first. So here is my proposed legacy macro renaming policy: 1. If a Boost library observes the setting of a non-BOOST_ prefixed macro which is defined by other Boost code, it must be renamed. 2. If a Boost library observes the setting of a non-BOOST_ prefixed macro which is never defined by other Boost code, it need not be renamed. 3. If a Boost library defines a non-BOOST_ prefixed macro whose value is observed by code not under Boost control, it is not renamed. 4. For all defining of non-BOOST_ prefixed macros in publicly includable header code, it must be renamed. The end goal of this policy is that future Boost code will never set a non-BOOST_ prefixed macro in public headers, except where third party dependencies require it. Renaming strategy can be anything the library maintainer likes. Good suggestions were made here earlier on how best to give deprecation warnings for the next year or two before insisting, or whether to support multiple observable input macros etc. There is a PR for a library test which determines if your public headers have defined any non-BOOST_ macros at https://github.com/boostorg/boost/pull/356. You can use this to check your own libraries. Some whitelisting in the meta json file may be needed for libraries which have no alternative in the case 2 situation above. If your library is one of those, please comment which library and why in the PR comments. Niall
-----Original Message----- From: Boost
On Behalf Of Niall Douglas via Boost Sent: 16 December 2019 15:22 To: Boost Developers List Cc: Niall Douglas Subject: [boost] What to do about Boost libraries which use user-defined macros which are not BOOST_ prefixed Acting on guidance given to my recent supply to this list of unprefixed macros, namespaces etc injected into the global namespace by Boost, I have logged a
all issues with each library, and linked to all those from a single issue logged at https://github.com/boostorg/boost/issues/352.
A problem has arisen which requires input from boost-dev. Some Boost libraries define as part of their public API a non-BOOST_-prefixed macro which changes
list of the
definition of their header files e.g.
PHOENIX_LIMIT
(just to be clear, Phoenix is not the only library doing this)
If we change such macros to be like BOOST_PHOENIX_LIMIT instead, all existing code using Boost which sets PHOENIX_LIMIT would potentially *silently* break.
What we could decide to do instead is:
#if defined(PHOENIX_LIMIT) && !defined(BOOST_PHOENIX_LIMIT) #error In Boost 1.xx PHOENIX_LIMIT was renamed to BOOST_PHOENIX_LIMIT. Please upgrade your code to reflect the new name. #endif
Or one could just leave PHOENIX_LIMIT named as is.
What would Boost developers prefer we do?
Is it only Boost libraries that define this macro? People have bureaucratic hurdles and hoop to jump over through as well as doing a quick grep-replace. It has been Boost normal practice to give people time to make changes rather than breaking things without warning. Would it be sensible that we combine these two by doing Peter's suggestion now, and Niall's after at least one Boost release? Paul
On 16/12/2019 17:27, Paul A Bristow via Boost wrote:
Is it only Boost libraries that define this macro?
For PHOENIX_LIMIT specifically, both Boost libraries and end user code might define it. Even to different values, and woe betide you if you include an unincluded phoenix header afterwards.
People have bureaucratic hurdles and hoop to jump over through as well as doing a quick grep-replace.
I can't say for anywhere I've never worked, but anywhere I've worked "upgrading our Boost version" is something nobody wants to do, and five or more years typically elapses before it becomes unavoidable. Then whichever poor soul gets assigned is the one who must waste a week of their lives upgrading Boost and validating what has or has not broken. Given the five year upgrade frequency, everybody accepts that the main project will get changed, and that stuff will break. In our case, all our ASIO based code will need to be refactored. That's another week of work in itself. I also suspect we'll need to refactor our Regex based code too. Point is, upgrading Boost is a painful experience which introduces a ton of code churn, and everybody from upper management downwards understands this.
It has been Boost normal practice to give people time to make changes rather than breaking things without warning.
Would it be sensible that we combine these two by doing Peter's suggestion now, and Niall's after at least one Boost release?
One of the big reasons I don't get Peter's caution is that anywhere I've ever worked, nobody has upgraded Boost more frequently than every two or three years, and it's usually a lot more. Maybe I've worked in the wrong places. I will say that 99.9% of the time a Boost upgrade is done because a customer asked for something where the ancient Boost wouldn't cut it. In our case, a customer wants C++ 17 support, and Boost 1.64 is very definitely not C++ 17 clean. So that's two person-weeks at least to upgrade Boost, and possibly a person-month in total after all the churn gets shaken out. Assuming a typical cost to a business for a senior developer, that's 20k of real money per Boost upgrade. Niall
Niall Douglas wrote:
One of the big reasons I don't get Peter's caution is that anywhere I've ever worked, nobody has upgraded Boost more frequently than every two or three years, and it's usually a lot more. Maybe I've worked in the wrong places.
This might well be true in a corporate setting, but downstream packagers such as Linux distros, brew, vcpkg etc "upgrade" Boost more frequently (on each release) and every breaking change in Boost typically affects (many) other packages that then need to be fixed.
On 16/12/2019 18:48, Peter Dimov via Boost wrote:
One of the big reasons I don't get Peter's caution is that anywhere I've ever worked, nobody has upgraded Boost more frequently than every two or three years, and it's usually a lot more. Maybe I've worked in the wrong places.
This might well be true in a corporate setting, but downstream packagers such as Linux distros, brew, vcpkg etc "upgrade" Boost more frequently (on each release) and every breaking change in Boost typically affects (many) other packages that then need to be fixed.
That's a good argument. I guess another reason I feel suspicious of "deprecation warning now, change default sometime later" is that in my experience people always forget to do the second step. Then you get libraries - there are a few popular old C++ ones I won't mention - which implement the deprecated interface forever. That makes compiling with them just a massive noise of deprecation warnings nobody acts upon. It's like all those codebases we've all used which spew warnings, and nobody ever fixes them. I think there's a compromise solution here: Make a new macro: BOOST_MACRO_DEFAULT_CHANGED(PHOENIX_LIMIT, BOOST_PHOENIX_LIMIT, 107200, 107600) This expands into something like: #if BOOST_VERSION >= version && defined(oldmacro) #error oldmacro was replaced with newmacro in Boost vXXX. Please use newmacro to avoid this error. #else #warning oldmacro was replaced with newmacro in Boost vXXX, and use of oldmacro will fail the build from Boost vYYY onwards. Defining newmacro to oldmacro until then. #define newmacro oldmacro #endif I'm not entirely sure how to wrap that into a macro which is portable, but you get the idea. Niall
On 12/17/2019 7:40 AM, Niall Douglas via Boost wrote:
On 16/12/2019 18:48, Peter Dimov via Boost wrote:
One of the big reasons I don't get Peter's caution is that anywhere I've ever worked, nobody has upgraded Boost more frequently than every two or three years, and it's usually a lot more. Maybe I've worked in the wrong places.
This might well be true in a corporate setting, but downstream packagers such as Linux distros, brew, vcpkg etc "upgrade" Boost more frequently (on each release) and every breaking change in Boost typically affects (many) other packages that then need to be fixed.
That's a good argument.
I guess another reason I feel suspicious of "deprecation warning now, change default sometime later" is that in my experience people always forget to do the second step. Then you get libraries - there are a few popular old C++ ones I won't mention - which implement the deprecated interface forever. That makes compiling with them just a massive noise of deprecation warnings nobody acts upon.
It's like all those codebases we've all used which spew warnings, and nobody ever fixes them.
I think there's a compromise solution here:
Make a new macro:
BOOST_MACRO_DEFAULT_CHANGED(PHOENIX_LIMIT, BOOST_PHOENIX_LIMIT, 107200, 107600)
This expands into something like:
#if BOOST_VERSION >= version && defined(oldmacro) #error oldmacro was replaced with newmacro in Boost vXXX. Please use newmacro to avoid this error. #else #warning oldmacro was replaced with newmacro in Boost vXXX, and use of oldmacro will fail the build from Boost vYYY onwards. Defining newmacro to oldmacro until then. #define newmacro oldmacro #endif
A macro can not expand to further preprocessor statements.
I'm not entirely sure how to wrap that into a macro which is portable, but you get the idea.
participants (8)
-
Alexander Grund
-
Andrey Semashev
-
Edward Diener
-
Glen Fernandes
-
Michael Caisse
-
Niall Douglas
-
pbristow@hetp.u-net.com
-
Peter Dimov