diff mbox

[1/1] core: add option to force compiling C++ as C++11

Message ID 1448549404-11670-1-git-send-email-agalakhov@gmail.com
State Superseded
Headers show

Commit Message

Alexey Galakhov Nov. 26, 2015, 2:50 p.m. UTC
Many C++ libraries like boost and log4cplus use defines to be compatible with
both C++03 and C++11 standards. This causes ABI incompatibilities between
a library built with C++03 and an application built with C++11. To avoid this,
one has to built libraries as C++11 as well.

This patch introduces the BR2_ENABLE_CPP11 configuration option that forces
passing --std=c++11 to the compiler while building C++ target libraries.

Signed-off-by: Alexey Galakhov <agalakhov@gmail.com>
---
 Config.in           | 16 ++++++++++++++++
 package/Makefile.in | 12 +++++++++++-
 2 files changed, 27 insertions(+), 1 deletion(-)

Comments

Thomas Petazzoni Nov. 26, 2015, 4:51 p.m. UTC | #1
Dear Alexey Galakhov,

On Thu, 26 Nov 2015 15:50:04 +0100, Alexey Galakhov wrote:
> Many C++ libraries like boost and log4cplus use defines to be compatible with
> both C++03 and C++11 standards. This causes ABI incompatibilities between
> a library built with C++03 and an application built with C++11. To avoid this,
> one has to built libraries as C++11 as well.

I am not familiar with C++ issues, can you give some more details and
specific examples here ?

> +config BR2_ENABLE_CPP11
> +	bool "force C++11 when building libraries"
> +	default n
> +	depends on BR2_INSTALL_LIBSTDCPP
> +	depends on BR2_TOOLCHAIN_GCC_AT_LEAST_4_3
> +	help
> +	  Force building of C++ libraries in C++11 mode.
> +
> +	  Some C++ libraries (i.e. boost) behave differently if compiled with
> +	  and without --std=c++11 flag. They define classes differently. This
> +	  causes linker errors while trying to use such a library in a C++11
> +	  project.
> +
> +	  This option forces building of all such libraries in C++11 mode.
> +	  Enable it if you encounter C++11-related linker errors.

I don't think it is appropriate for Buildroot to have an option to be
enabled "if you encounter <foo> errors". If there is a problem, it
should be fixed properly, without having to rely on the user enabling
(or not enabling) a given option.

Thomas
Alexey Galakhov Nov. 26, 2015, 8:43 p.m. UTC | #2
Dear Thomas,

> I am not familiar with C++ issues, can you give some more details and
> specific examples here ?

This is more or less a toolchain issue. Consider we're building a C++
library with a class declaration in *.h and its implementation in
*.cpp. Compilation with a C++03 compiler results in the generation of
several functions corresponding to class methods. Compilation with a
C++11 compiler gives two additional functions, corresponding to the
move constructor and the move assignment operator (new features of
C++11).

If a C++ library is compiled with an C++03 compiler (that is the
default when using g++), its object files won't contain the
implementations of these new methods. The library is then unusable for
C++11 compiler. In the worst case we have to recompile all the
libraries in the system with a C++11 compiler.

Example linker error is:

In function log4cplus::detail::macros_get_logger(log4cplus::Logger&&)':
/usr/include/log4cplus/loggingmacros.h:106: undefined reference
tolog4cplus::Logger::Logger(log4cplus::Logger&&)'

This function is only generated when compiling in C++11 mode. It does
not exist in C++03 mode.

To clarify: This is NOT an error inside buildroot! This only happens if
compiling some 3rd-party or proprietary code against previously
compiled buildroot system. If I want to compile my program with
--std=c++11, I have to compile buildroot with --std=c++11 as well.


> I don't think it is appropriate for Buildroot to have an option to be
> enabled "if you encounter <foo> errors". If there is a problem, it
> should be fixed properly, without having to rely on the user enabling
> (or not enabling) a given option.

Unfortunately, there is no "proper" solution. An alternative solution
could be compiling most of the C++ libraries twice and thus providing
two versions of each *.so file, one for C++03 and C++11. We could also
try to make this option on per-package basis, but this should be then
done in every library package using C++ and would be confusing.

The proper help text would probably be something like this:
"""
  Enable this option if you need the move-semantics implementation in  
  the shared C++ libraries of buildroot. I.e., if you want to link your
  own C++11 applications against them and the linker complains about
  non-existing move constructor.
"""

Regards,
Alexey
Arnout Vandecappelle Nov. 28, 2015, 12:24 a.m. UTC | #3
On 26-11-15 21:43, Alexey Galakhov wrote:
> Dear Thomas,
> 
>> I am not familiar with C++ issues, can you give some more details and
>> specific examples here ?
> 
> This is more or less a toolchain issue. Consider we're building a C++
> library with a class declaration in *.h and its implementation in
> *.cpp. Compilation with a C++03 compiler results in the generation of
> several functions corresponding to class methods. Compilation with a
> C++11 compiler gives two additional functions, corresponding to the
> move constructor and the move assignment operator (new features of
> C++11).
> 
> If a C++ library is compiled with an C++03 compiler (that is the
> default when using g++), its object files won't contain the
> implementations of these new methods. The library is then unusable for
> C++11 compiler. In the worst case we have to recompile all the
> libraries in the system with a C++11 compiler.
> 
> Example linker error is:
> 
> In function log4cplus::detail::macros_get_logger(log4cplus::Logger&&)':
> /usr/include/log4cplus/loggingmacros.h:106: undefined reference
> tolog4cplus::Logger::Logger(log4cplus::Logger&&)'
> 
> This function is only generated when compiling in C++11 mode. It does
> not exist in C++03 mode.
> 
> To clarify: This is NOT an error inside buildroot! This only happens if
> compiling some 3rd-party or proprietary code against previously
> compiled buildroot system. If I want to compile my program with
> --std=c++11, I have to compile buildroot with --std=c++11 as well.

 Well, we _have_ packages that build with --std=c++11 or similar, and that use
boost. For example pulseview. So I would think we would see build failures there
as well.

 Point is: if this is a problem for external code, it will also be a problem for
buildroot packages. So we have to find a way to solve it fundamentally.

> 
> 
>> I don't think it is appropriate for Buildroot to have an option to be
>> enabled "if you encounter <foo> errors". If there is a problem, it
>> should be fixed properly, without having to rely on the user enabling
>> (or not enabling) a given option.
> 
> Unfortunately, there is no "proper" solution. An alternative solution
> could be compiling most of the C++ libraries twice and thus providing
> two versions of each *.so file, one for C++03 and C++11. We could also
> try to make this option on per-package basis, but this should be then
> done in every library package using C++ and would be confusing.

 We're definitely not going to build everything twice. We might make packages
like glibmm that add the --std=c++11 option select the BR2_ENABLE_CPP11 option,
for example.


 Regards,
 Arnout

> 
> The proper help text would probably be something like this:
> """
>   Enable this option if you need the move-semantics implementation in  
>   the shared C++ libraries of buildroot. I.e., if you want to link your
>   own C++11 applications against them and the linker complains about
>   non-existing move constructor.
> """
> 
> Regards,
> Alexey
> 
> _______________________________________________
> buildroot mailing list
> buildroot@busybox.net
> http://lists.busybox.net/mailman/listinfo/buildroot
>
Arnout Vandecappelle Nov. 28, 2015, 12:33 a.m. UTC | #4
On 26-11-15 15:50, Alexey Galakhov wrote:
> Many C++ libraries like boost and log4cplus use defines to be compatible with
> both C++03 and C++11 standards. This causes ABI incompatibilities between
> a library built with C++03 and an application built with C++11. To avoid this,
> one has to built libraries as C++11 as well.
> 
> This patch introduces the BR2_ENABLE_CPP11 configuration option that forces
> passing --std=c++11 to the compiler while building C++ target libraries.
> 
> Signed-off-by: Alexey Galakhov <agalakhov@gmail.com>
> ---
>  Config.in           | 16 ++++++++++++++++
>  package/Makefile.in | 12 +++++++++++-
>  2 files changed, 27 insertions(+), 1 deletion(-)
> 
> diff --git a/Config.in b/Config.in
> index d795361..79e4d31 100644
> --- a/Config.in
> +++ b/Config.in
> @@ -533,6 +533,22 @@ config BR2_ENABLE_SSP
>  comment "enabling Stack Smashing Protection requires support in the toolchain"
>  	depends on !BR2_TOOLCHAIN_HAS_SSP
>  
> +config BR2_ENABLE_CPP11
> +	bool "force C++11 when building libraries"
> +	default n
> +	depends on BR2_INSTALL_LIBSTDCPP
> +	depends on BR2_TOOLCHAIN_GCC_AT_LEAST_4_3

 As I understand it, the move constructor was only introduced in gcc 4.6 so we
should take that as the base, no? And actually, in practice, any package that
relies on C++11 will probably need gcc 4.7 anyway since that's the first one to
support a reasonable subset of the standard. So I'd propose to take that as the
minimum version. This also simplifies the selection of the --std= option.

> +	help
> +	  Force building of C++ libraries in C++11 mode.
> +
> +	  Some C++ libraries (i.e. boost) behave differently if compiled with
> +	  and without --std=c++11 flag. They define classes differently. This
> +	  causes linker errors while trying to use such a library in a C++11
> +	  project.
> +
> +	  This option forces building of all such libraries in C++11 mode.
> +	  Enable it if you encounter C++11-related linker errors.
> +
>  choice
>  	bool "libraries"
>  	default BR2_SHARED_LIBS if BR2_BINFMT_SUPPORTS_SHARED
> diff --git a/package/Makefile.in b/package/Makefile.in
> index 85008bb..0bb911e 100644
> --- a/package/Makefile.in
> +++ b/package/Makefile.in
> @@ -135,9 +135,19 @@ ifeq ($(BR2_DEBUG_3),y)
>  TARGET_DEBUGGING = -g3
>  endif
>  
> +ifeq ($(BR2_ENABLE_CPP11),y)
> +ifeq ($(BR2_TOOLCHAIN_GCC_AT_LEAST_4_7),y)
> +TARGET_CXXLANGUAGE = --std=c++11
> +else
> +TARGET_CXXLANGUAGE = --std=c++0x
> +endif
> +else
> +TARGET_CXXLANGUAGE =

 There's no need to define it empty, just remove the else branch.

> +endif
> +
>  TARGET_CPPFLAGS += -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
>  TARGET_CFLAGS = $(TARGET_CPPFLAGS) $(TARGET_ABI) $(TARGET_OPTIMIZATION) $(TARGET_DEBUGGING)
> -TARGET_CXXFLAGS = $(TARGET_CFLAGS)
> +TARGET_CXXFLAGS = $(TARGET_CFLAGS) $(TARGET_CXXLANGUAGE)

 I was thinking if it wouldn't be better to add this to the toolchain wrapper,
but in fact it is a good idea to let the package's build system know explicitly
that we're going to enable C++11 support. So this is fine.


 Regards,
 Arnout

>  TARGET_LDFLAGS = $(call qstrip,$(BR2_TARGET_LDFLAGS))
>  
>  ifeq ($(BR2_BINFMT_FLAT),y)
>
Alexey Galakhov Nov. 28, 2015, 11:06 a.m. UTC | #5
On Sat, 28 Nov 2015 01:24:30 +0100
Arnout Vandecappelle <arnout@mind.be> wrote:

>  Well, we _have_ packages that build with --std=c++11 or similar, and
> that use boost. For example pulseview. So I would think we would see
> build failures there as well.

Most of the boost acts as a header-only library and thus does work even
in this situation. Linking with -lboost_filesystem is a notable
exception.

Regards,
Alexey
diff mbox

Patch

diff --git a/Config.in b/Config.in
index d795361..79e4d31 100644
--- a/Config.in
+++ b/Config.in
@@ -533,6 +533,22 @@  config BR2_ENABLE_SSP
 comment "enabling Stack Smashing Protection requires support in the toolchain"
 	depends on !BR2_TOOLCHAIN_HAS_SSP
 
+config BR2_ENABLE_CPP11
+	bool "force C++11 when building libraries"
+	default n
+	depends on BR2_INSTALL_LIBSTDCPP
+	depends on BR2_TOOLCHAIN_GCC_AT_LEAST_4_3
+	help
+	  Force building of C++ libraries in C++11 mode.
+
+	  Some C++ libraries (i.e. boost) behave differently if compiled with
+	  and without --std=c++11 flag. They define classes differently. This
+	  causes linker errors while trying to use such a library in a C++11
+	  project.
+
+	  This option forces building of all such libraries in C++11 mode.
+	  Enable it if you encounter C++11-related linker errors.
+
 choice
 	bool "libraries"
 	default BR2_SHARED_LIBS if BR2_BINFMT_SUPPORTS_SHARED
diff --git a/package/Makefile.in b/package/Makefile.in
index 85008bb..0bb911e 100644
--- a/package/Makefile.in
+++ b/package/Makefile.in
@@ -135,9 +135,19 @@  ifeq ($(BR2_DEBUG_3),y)
 TARGET_DEBUGGING = -g3
 endif
 
+ifeq ($(BR2_ENABLE_CPP11),y)
+ifeq ($(BR2_TOOLCHAIN_GCC_AT_LEAST_4_7),y)
+TARGET_CXXLANGUAGE = --std=c++11
+else
+TARGET_CXXLANGUAGE = --std=c++0x
+endif
+else
+TARGET_CXXLANGUAGE =
+endif
+
 TARGET_CPPFLAGS += -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
 TARGET_CFLAGS = $(TARGET_CPPFLAGS) $(TARGET_ABI) $(TARGET_OPTIMIZATION) $(TARGET_DEBUGGING)
-TARGET_CXXFLAGS = $(TARGET_CFLAGS)
+TARGET_CXXFLAGS = $(TARGET_CFLAGS) $(TARGET_CXXLANGUAGE)
 TARGET_LDFLAGS = $(call qstrip,$(BR2_TARGET_LDFLAGS))
 
 ifeq ($(BR2_BINFMT_FLAT),y)