Combining the [[deprecated]]
and the __attribute__ ((visibility ("default")))
attributes with -std=c++14
generate errors (different depending on the order used expected identifier before ‘__attribute__’
or expected identifier before ‘[’ token
).
Using them separately does not generate the errors.
The c++11 style attribute [[gnu::visibility("default")]]
works for classes, but not for functions (the code compiles, but produces a -Wattributes
warning and the symbol is left out when built with -fvisibility=hidden
).
Is this a bug in the compiler (I used GCC 6.2 for these tests) or something specified by c++ standard? The same code ([[deprecated]] __attribute__ ((visibility ("default")))
) works as expected using clang).
This is the code I used for my tests to combine all the possibilities, the only cases that produce the wanted result (deprecated + default visibility) are 3 and 7, i.e. the ones using the old style attributes.
foo.h
#if defined(X_VERSION)
# if (X_VERSION % 4) == 0 // 0 4 8 12
# define DEPRECATED [[deprecated]]
# define VISIBILITY [[gnu::visibility("default")]]
# elif (X_VERSION % 4) == 1 // 1 5 9 13
# define DEPRECATED [[deprecated]]
# define VISIBILITY __attribute__ ((visibility ("default")))
# elif (X_VERSION % 4) == 2 // 2 6 10 14
# define DEPRECATED __attribute__((__deprecated__))
# define VISIBILITY [[gnu::visibility("default")]]
# elif (X_VERSION % 4) == 3 // 3 7 11 15
# define DEPRECATED __attribute__((__deprecated__))
# define VISIBILITY __attribute__ ((visibility ("default")))
# else
# error "Invalid X_VERSION"
# endif
# if (X_VERSION / 4) == 0 // 0 1 2 3
# define DEPRECATED_API DEPRECATED VISIBILITY
# elif (X_VERSION / 4) == 1 // 4 5 6 7
# define DEPRECATED_API VISIBILITY DEPRECATED
# elif (X_VERSION / 4) == 2 // 8 9 10 11
# define DEPRECATED_API DEPRECATED
# elif (X_VERSION / 4) == 3 // 12 13 14 15
# define DEPRECATED_API VISIBILITY
# else
# error "Invalid X_VERSION"
# endif
#else
# error "X_VERSION not defined"
#endif
#if defined(DEPRECATED_API)
# define XSTR(x) STR(x)
# define STR(x) #x
# pragma message "DEPRECATED_API = " XSTR(DEPRECATED_API)
#endif
class DEPRECATED_API foo
{
public:
foo();
virtual ~foo();
void test();
int a;
};
void DEPRECATED_API a_function();
foo.cpp
#include <foo.h>
foo::foo() {}
foo::~foo() {}
void foo::test() {}
void a_function() {}
CMakeLists.txt
cmake_minimum_required(VERSION 3.6)
project(test_lib)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
set(CMAKE_INCLUDE_CURRENT_DIR ON)
foreach(i RANGE 0 15)
if(i LESS 10)
set(target_name foo_v0${i})
else()
set(target_name foo_v${i})
endif()
add_library(${target_name} SHARED foo.cpp foo.h)
target_compile_definitions(${target_name} PRIVATE X_VERSION=${i})
endforeach()
Usually __attribute__((visibility("default"))) is used in combination with -fvisibility=hidden linker flag. The latter would make "hidden" the default visibility for all symbols of a shared library. Back to the original example from folly, class FOLLY_EXPORT OptionalEmptyException : public std::runtime_error { ... 12.
With the visibility type attributes, you can control whether and how a structure/union/class or an enumeration that is defined in one module can be referenced or used in other modules. Visibility attributes affect only types with external linkage.
After a lot of time, I found that:
void [[deprecated]] [[gnu::visibility("default")]] a_function();
should have been:
[[deprecated]] [[gnu::visibility("default")]] void a_function();
In this case, both version 0 and 4 work as expected.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With