cmake:gperftools效能分析工具find libprofiler 指令碼暨profiler的靜態連線問題
阿新 • • 發佈:2018-12-01
gperftools是一個很好用的效能分析工具,但沒有提供官方的用於查詢profiler庫的cmake指令碼,所以在基於cmake管理的專案中如果要在系統查詢libprofiler庫就就要自己寫FindPROFILER.cmake指令碼。
將指令碼所在的資料夾加入CMAKE_MODULE_PATH
,呼叫find_package(PROFILER)
,就會找到系統中安裝的gperftools的libprofiler庫,
指令碼不僅按傳統方式輸出LIBPROFILER_xxx
系列變數,還會建立gperftools::profiler
INTERFACE target.方便在專案中引用。
FindPROFILER.cmake
# - Find libprofiler # - This module determines the libprofiler library of the system # the vairable can be set # LIBPROFILER_STATIC_LINK set true for static link library 為TRUE是要求靜態連線 # The following variables are set if the library found: # LIBPROFILER_FOUND - If false do nnt try to use libprofiler. # LIBPROFILER_INCLUDE_DIRS - where to find the headfile of library.include資料夾位置 # LIBPROFILER_LIBRARY_DIRS - where to find the libprofiler library.profiler庫所在位置 # LIBPROFILER_LIBRARIES, the library file name needed to use libprofiler.profiler庫及所有依賴庫列表 # LIBPROFILER_LIBRARY - the library needed to use libprofiler. profiler庫全路徑 # imported target # gperftools::profiler if(LIBPROFILER_FOUND) return() endif() include (depcommon) # linux系統下呼叫pkg-config查詢profiler if (NOT WIN32) include(FindPkgConfig) unset(_verexp) if(LIBPROFILER_FIND_VERSION) if(LIBPROFILER_FIND_VERSION_EXACT) set(_verexp "=${LIBPROFILER_FIND_VERSION}") else() set(_verexp ">=${LIBPROFILER_FIND_VERSION}") endif() endif() pkg_check_modules (LIBPROFILER libprofiler${_verexp}) endif() if (NOT LIBPROFILER_FOUND) # windows系統下通過查詢標頭檔案 gperftools/profiler.h和find_library 查詢profiler來實現 # find the headfile of library set (PROFILER_HEADS gperftools/profiler.h) find_path (LIBPROFILER_INCLUDE_DIRS ${PROFILER_HEADS}) set (PROFILER_NAMES ${PROFILER_NAMES} profiler) find_library (LIBPROFILER_LIBRARY NAMES ${PROFILER_NAMES}) # just find one of dependency, guess other one. if (NOT LIBPROFILER_LIBRARY AND LIBPROFILER_INCLUDE_DIRS) message ("We just find the headfile, try to guess the library location.") set (LIBPROFILER_LIBRARY_DIRS "${LIBPROFILER_INCLUDE_DIRS}/../lib") find_library (LIBPROFILER_LIBRARY NAMES ${PROFILER_NAMES} PATHS ${LIBPROFILER_LIBRARY_DIRS}) elseif (NOT LIBPROFILER_INCLUDE_DIRS AND LIBPROFILER_LIBRARY) message ("We just find the lib file, try to guess the include location.") get_filename_component(LIBPROFILER_LIBRARY_DIRS ${LIBPROFILER_LIBRARY} DIRECTORY) find_path (LIBPROFILER_INCLUDE_DIRS ${PROFILER_HEADS} "${LIBPROFILER_LIBRARY_DIRS}../included") endif() # find the library. if (LIBPROFILER_INCLUDE_DIRS AND LIBPROFILER_LIBRARY) if (NOT LIBPROFILER_LIBRARY_DIRS) get_filename_component(LIBPROFILER_LIBRARY_DIRS ${LIBPROFILER_LIBRARY} DIRECTORY) endif () list(APPEND profiler pthread) endif() else () list(GET MGNCS_LIBRARIES 0 _name) find_library (LIBPROFILER_LIBRARY NAMES ${LIBPROFILER_LIBRARIES} PATHS ${LIBPROFILER_LIBRARY_DIRS}) endif() # handle the QUIETLY and REQUIRED arguments and set LIBPROFILER_FOUND to TRUE if # all listed variables are TRUE include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBPROFILER DEFAULT_MSG LIBPROFILER_LIBRARIES LIBPROFILER_INCLUDE_DIRS) if(LIBPROFILER_FOUND) set(_static_libname libtcmalloc_and_profiler.a) find_library (LIBPROFILER_STATIC_LIBRARY NAMES ${_static_libname} PATHS ${LIBPROFILER_LIBRARY_DIRS}) if(NOT LIBPROFILER_FIND_QUIETLY) message(STATUS " -I: ${LIBPROFILER_INCLUDE_DIRS}") message(STATUS " -L: ${LIBPROFILER_LIBRARY_DIRS}") message(STATUS " -l: ${LIBPROFILER_LIBRARIES}") endif() find_library (LIBPROFILER_LIBRARY NAMES ${LIBPROFILER_LIBRARIES} PATHS ${LIBPROFILER_LIBRARY_DIRS}) # create imported target if (NOT TARGET gperftools::profiler) add_library(gperftools::profiler INTERFACE IMPORTED) if(LIBPROFILER_STATIC_LINK) # for linking static profiler,must use libtcmalloc_and_profiler.a,see also README gperftools set(_link_libs ${LIBPROFILER_STATIC_LDFLAGS}) if(NOT LIBPROFILER_STATIC_LIBRARY) message(FATAL_ERROR "NOT FOUND static library for profiler:${_static_libname} ") endif() # 替換 profiler 為 :libtcmalloc_and_profiler.a string(REPLACE profiler :${_static_libname} _link_libs "${_link_libs}") else() set(_link_libs ${LIBPROFILER_LDFLAGS}) endif() set_target_properties(gperftools::profiler PROPERTIES INTERFACE_COMPILE_OPTIONS "${LIBPROFILER_CFLAGS_OTHER}" INTERFACE_INCLUDE_DIRECTORIES "${LIBPROFILER_INCLUDE_DIRS}" INTERFACE_LINK_LIBRARIES "${_link_libs}" ) if(NOT LIBPROFILER_FIND_QUIETLY) message(STATUS "IMPORTED TARGET: gperftools::profiler,link libraies ${_link_libs}") endif() endif () endif(LIBPROFILER_FOUND)
靜態連線profiler
關於靜態連線profiler,之前看過不少部落格文章,都指出gperftools不支援靜態連線profiler庫。但我查看了gperftools(2.7)的官方說明,提供了靜態連線profiler庫的方法:
下面的英文說明來自gperftools的官方說明(https://github.com/gperftools/gperftools/blob/master/README)
EVERYTHING IN ONE ----------------- If you want the CPU profiler, heap profiler, and heap leak-checker to all be available for your application, you can do: gcc -o myapp ... -lprofiler -ltcmalloc However, if you have a reason to use the static versions of the library, this two-library linking won't work: gcc -o myapp ... /usr/lib/libprofiler.a /usr/lib/libtcmalloc.a # errors! Instead, use the special libtcmalloc_and_profiler library, which we make for just this purpose: gcc -o myapp ... /usr/lib/libtcmalloc_and_profiler.a
確實直接靜態連線libprofiler.a是不行的,但這裡也明確給出了靜態連線profiler的方式:用libtcmalloc_and_profiler.a
替代libprofiler.a
。
所以在上面的cmake指令碼中當LIBPROFILER_STATIC_LINK
為TRUE時,會替換 profiler
為 :libtcmalloc_and_profiler.a