Linux下__attribute__((visibility (default)))的使用
在Linux下動態庫(.so)中,通過GCC的C++ visibility屬性可以控制共享文件導出符號。在GCC 4.0及以上版本中,有個visibility屬性,可見屬性可以應用到函數、變量、模板以及C++類。
限制符號可見性的原因:從動態庫中盡可能少地輸出符號是一個好的實踐經驗。輸出一個受限制的符號會提高程序的模塊性,并隱藏實現的細節。動態庫裝載和識別的符號越少,程序啟動和運行的速度就越快。導出所有符號會減慢程序速度,并耗用大量內存。
“default”:用它定義的符號將被導出,動態庫中的函數默認是可見的。”hidden”:用它定義的符號將不被導出,并且不能從其它對象進行使用,動態庫中的函數是被隱藏的。default意味著該方法對其它模塊是可見的。而hidden表示該方法符號不會被放到動態符號表里,所以其它模塊(可執行文件或者動態庫)不可以通過符號表訪問該方法。
要定義GNU屬性,需要包含__attribute__和用括號括住的內容。可以將符號的可見性指定為visibility(“hidden”),這將不允許它們在庫中被導出,但是可以在源文件之間共享。實際上,隱藏的符號將不會出現在動態符號表中,但是還被留在符號表中用于靜態鏈接。
導出列表由編譯器在創建共享庫的時候自動生成,也可以由開發人員手工編寫。導出列表的原理是顯式地告訴編譯器可以通過外部文件從對象文件導出的符號是哪些。GNU用戶將此類外部文件稱作為”導出映射”。
以下是測試代碼,各個文件的內容如下:
Dynamic_Library/library.hpp:
#ifndef FBC_LIBRARY_LIBRARY_HPP_
#define FBC_LIBRARY_LIBRARY_HPP_// reference: https://gcc.gnu.org/wiki/Visibility
//            https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/CppRuntimeEnv/Articles/SymbolVisibility.html#ifdef __GNUC__ >= 4 // it means the compiler is GCC version 4.0 or later#ifdef FBC_EXPORT#warning "===== dynamic library ====="#define FBC_API_PUBLIC __attribute__((visibility ("default")))#define FBC_API_LOCAL __attribute__((visibility("hidden")))#else#warning "===== static library ====="#define FBC_API_PUBLIC#define FBC_API_LOCAL#endif
#else#error "##### requires gcc version >= 4.0 #####"
#endif#ifdef __cplusplus
extern "C" {
#endifFBC_API_PUBLIC int library_add(int a, int b);
FBC_API_LOCAL void print_log();#ifdef FBC_EXPORT
FBC_API_PUBLIC int value;
#endif#ifdef __cplusplus
}
#endiftemplate<typename T>
class FBC_API_PUBLIC Simple {
public:Simple() = default;void Init(T a, T b);T Add() const;private:T a, b;
};#endif // FBC_LIBRARY_LIBRARY_HPP_ 
Dynamic_Library/library.cpp:
#include "library.hpp"
#include <iostream>
#include <string>FBC_API_PUBLIC int library_add(int a, int b)
{
#ifdef FBC_EXPORTvalue = 11;
#endiffprintf(stdout, "File: %s, Function: %s, Line: %d\n", __FILE__, __FUNCTION__, __LINE__);return (a+b);
}FBC_API_LOCAL void print_log()
{fprintf(stderr, "print_log function is hidden, in dynamic library: %s, %d\n", __FUNCTION__, __LINE__);
}template<typename T>
void Simple<T>::Init(T a, T b)
{this->a = a;this->b = b;
}template<typename T>
T Simple<T>::Add() const
{fprintf(stdout, "File: %s, Function: %s, Line: %d\n", __FILE__, __FUNCTION__, __LINE__);return (a + b);
}template class Simple<int>;
template class Simple<std::string>; 
Test_Dynamic_Library/test_library.hpp:
#ifndef FBC_CPPBASE_TEST_TEST_LIBRARY_HPP_
#define FBC_CPPBASE_TEST_TEST_LIBRARY_HPP_namespace test_library_ {#ifdef __cplusplusextern "C" {
#endifint test_library_1();
int test_library_2();
int test_library_3();#ifdef __cplusplus}
#endif} // namespace test_library_#endif // FBC_CPPBASE_TEST_TEST_LIBRARY_HPP_ 
Test_Dynamic_Library/test_library.cpp:
#include "test_library.hpp"
#include <iostream>
#include <string>#include <library.hpp>namespace test_library_ {int test_library_1()
{int a{ 4 }, b{ 5 }, c{ 0 };c = library_add(a, b);fprintf(stdout, "%d + %d = %d\n", a, b, c);#ifdef FBC_EXPORTfprintf(stdout, "dynamic library: value: %d\n", value);
#endifreturn 0;
}int test_library_2()
{Simple<int> simple1;int a{ 4 }, b{ 5 }, c{ 0 };simple1.Init(a, b);c = simple1.Add();fprintf(stdout, "%d + %d = %d\n", a, b, c);Simple<std::string> simple2;std::string str1{ "csdn blog: " }, str2{ "http://blog.csdn.net/fengbingchun" }, str3;simple2.Init(str1, str2);str3 = simple2.Add();fprintf(stdout, "contents: %s\n", str3.c_str());return 0;
}int test_library_3()
{
#ifdef FBC_EXPORTfprintf(stdout, "dynamic library cann't run print_log function\n");
#elseprint_log();
#endifreturn 0;
}} // namespace test_library_ 
Test_Dynamic_Library/main.cpp:
#include <iostream>
#include "test_library.hpp"int main()
{test_library_::test_library_1();test_library_::test_library_2();test_library_::test_library_3();return 0;
} 
CMakeLists.txt:
# CMake file for Samples_Dynamic_Library# 設定依賴的CMake版本
CMAKE_MINIMUM_REQUIRED(VERSION 3.2)# 指定項目名稱
PROJECT(Test_Dynamic_Library)# 打印相關信息, CMAKE_CURRENT_SOURCE_DIR指的是當前處理的CMakeLists.txt所在的路徑
MESSAGE(STATUS "current path: ${CMAKE_CURRENT_SOURCE_DIR}")# 使CMake支持C++11特性
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu++0x")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x")# 定義用戶自定義變量  
SET(PATH_DYNAMIC_LIBRARY_CPP_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Dynamic_Library)
SET(PATH_TEST_DYNAMIC_LIBRARY_CPP_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Test_Dynamic_Library)
SET(PATH_DYNAMIC_LIBRARY_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Dynamic_Library)
#MESSAGE(STATUS "Dynamic Library cpp files path: ${PATH_DYNAMIC_LIBRARY_CPP_FILES}")
#MESSAGE(STATUS "Test Dynamic Library cpp files path: ${PATH_TEST_DYNAMIC_LIBRARY_CPP_FILES}")# 遞歸查詢所有匹配的文件:*.cpp
FILE(GLOB_RECURSE DYNAMIC_LIBRARY_CPP_LIST ${PATH_DYNAMIC_LIBRARY_CPP_FILES}/*.cpp)
FILE(GLOB_RECURSE TEST_DYNAMIC_LIBRARY_CPP_LIST ${PATH_TEST_DYNAMIC_LIBRARY_CPP_FILES}/*.cpp)
#MESSAGE(STATUS "Dynamic Library cpp list: ${DYNAMIC_LIBRARY_CPP_LIST}")
#MESSAGE(STATUS "Test Dynamic Library cpp list: ${TEST_DYNAMIC_LIBRARY_CPP_LIST}")IF (BUILD_DYNAMIC_LIBRARY)# 添加編譯參數,添加-D預編譯宏定義,可以一次添加多個ADD_DEFINITIONS(-DFBC_EXPORT)# 生成動態庫ADD_LIBRARY(Dynamic_Library SHARED ${DYNAMIC_LIBRARY_CPP_LIST})
ELSE()ADD_LIBRARY(Static_Library STATIC ${DYNAMIC_LIBRARY_CPP_LIST})
ENDIF()# 指定需要包含的頭文件
INCLUDE_DIRECTORIES(${PATH_DYNAMIC_LIBRARY_INCLUDE_DIR})# 生成可執行文件Test_Dynamic_Library
ADD_EXECUTABLE(Test_Dynamic_Library ${TEST_DYNAMIC_LIBRARY_CPP_LIST})
IF (BUILD_DYNAMIC_LIBRARY)# 用來為target添加需要鏈接的共享庫,指定工程所用的依賴庫,包括動態庫和靜態庫TARGET_LINK_LIBRARIES(Test_Dynamic_Library Dynamic_Library)
ELSE()TARGET_LINK_LIBRARIES(Test_Dynamic_Library Static_Library)
ENDIF() 
編譯方法(ReadMe.txt):
在Linux下通過CMake編譯Samples_Dynamic_Library中的測試代碼步驟:
將終端定位到Linux_Code_Test/Samples_Dynamic_Library,依次執行如下命令:
$ mkdir build
$ cd build
// Note:-DBUILD_DYNAMIC_LIBRARY=1,編譯生成動態庫; -DBUILD_DYNAMIC_LIBRARY=0, 編譯生成靜態庫
$ cmake -DBUILD_DYNAMIC_LIBRARY=1 ..
$ make (生成動態庫和執行文件)
$ ./Test_Dynamic_Library 
 ? ? ? ? GitHub:https://github.com/fengbingchun/Linux_Code_Test
總結
以上是生活随笔為你收集整理的Linux下__attribute__((visibility (default)))的使用的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: OpenCV3.3中决策树(Decisi
 - 下一篇: C++中extern的使用