Snippets
Pieter PCMake
Compilation timing
Stripping debug information
# Strip and install debug information
function(myproject_install_debug_syms target component dest_lib dest_bin)
if (MSVC)
install(FILES "$<TARGET_PDB_FILE:${target}>"
DESTINATION ${dest_bin}
CONFIGURATIONS Debug RelWithDebInfo
COMPONENT ${component}
OPTIONAL EXCLUDE_FROM_ALL)
elseif (CMAKE_STRIP AND CMAKE_OBJCOPY)
set(DEBUG_FILE "$<TARGET_FILE_NAME:${target}>.debug")
add_custom_command(TARGET ${target} POST_BUILD
COMMAND "${CMAKE_STRIP}" "--only-keep-debug" "$<TARGET_FILE:${target}>" "-o" "${DEBUG_FILE}"
COMMAND "${CMAKE_STRIP}" "--strip-debug" "$<TARGET_FILE:${target}>"
COMMAND "${CMAKE_OBJCOPY}" "--add-gnu-debuglink=${DEBUG_FILE}" "$<TARGET_FILE:${target}>"
COMMAND "${CMAKE_COMMAND}" "-E" "echo" "Stripped into ${DEBUG_FILE}"
WORKING_DIRECTORY $<TARGET_FILE_DIR:${target}>)
install(FILES "$<TARGET_FILE_DIR:${target}>/${DEBUG_FILE}"
DESTINATION ${dest_lib}
CONFIGURATIONS Debug RelWithDebInfo
COMPONENT ${component}
EXCLUDE_FROM_ALL)
endif()
endfunction()
# Usage
include(GNUInstallDirs)
foreach(target IN LISTS MYPROJECT_INSTALL_TARGETS)
get_target_property(target_TYPE ${target} TYPE)
if (${target_TYPE} STREQUAL "SHARED_LIBRARY")
myproject_install_debug_syms(${target} debug
${CMAKE_INSTALL_LIBDIR}
${CMAKE_INSTALL_BINDIR})
endif()
endforeach()
Hiding symbols with default visibility in shared library
function(configure_visibility target)
set_target_properties(${target} PROPERTIES CXX_VISIBILITY_PRESET "hidden"
VISIBILITY_INLINES_HIDDEN true)
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
target_link_options(${target} PRIVATE "LINKER:--exclude-libs,ALL")
endif()
endfunction()
The target properties ensure that the source files comprising the given target are compiled with the visibility set to hidden, which means that unless a symbol is explicitly marked “export”, it won't be exported in the shared library.
The linker option ensures that symbols with default visibility in any static
libraries the target depends on are not exported in the shared library either.
From man ld(1)
:
--exclude-libs lib,lib,...
Specifies a list of archive libraries from which symbols should not
be automatically exported. The library names may be delimited by
commas or colons. Specifying "--exclude-libs ALL" excludes symbols
in all archive libraries from automatic export.
For explicitly exporting symbols that are part of the public API, see GenerateExportHeader.
Linux compilation and development
Inspecting binaries
# Dependencies and dynamic section of a shared library
readelf -d libfile.so
# List of symbols in shared library (1)
nm -CD --defined-only --size-sort libfile.so
# List of symbols in shared library (2)
readelf --wide --symbols --demangle libfile.so
# Filter symbols and prevent line wrapping
readelf --wide --symbols --demangle libfile.so | grep name | bat --wrap=never
Checking a debug link
# Dependencies and dynamic section of a shared library
objcopy -O binary --dump-section .gnu_debuglink=>(cut -d '' -f 1 -) libfile.so
Check the GLIBC version requirements of an ELF file
C++
Reversing a linked list
#include <utility> // std::exchange
struct Node {
Node *next = nullptr;
};
Node *reverse_linked_list(Node *fwd) {
Node *rev = nullptr;
while (fwd)
rev = std::exchange(fwd, std::exchange(fwd->next, rev));
return rev;
}