cmake_minimum_required(VERSION 3.10) project(libelf C) # ────────────────────────────────────────────────────────────────────────── # GNU-free CMake build for elfutils' libelf. # # This replaces the ancient (2009) Michael Riepe libelf 0.8.x with the modern, # actively-maintained elfutils libelf — the implementation the Linux kernel # (objtool) detects via `pkg-config libelf`. elfutils ships only an # autoconf/automake + GNU make build; this CMakeLists builds *just* the libelf # component (plus the three lib/ helpers it links) against the musl/LLVM # toolchain, with no GNU autotools or GNU make involved. # # Expected source layout: the elfutils source tree, i.e. this file is dropped # at the top level next to libelf/ and lib/. # # Build with the musl/LLVM toolchain file, e.g.: # cmake -S . -B build \ # -DCMAKE_TOOLCHAIN_FILE=/usr/local/musl/share/musl-llvm-toolchain.cmake \ # -DCMAKE_INSTALL_PREFIX=/usr/local # cmake --build build # cmake --install build # ────────────────────────────────────────────────────────────────────────── set(CMAKE_C_STANDARD 99) set(CMAKE_POSITION_INDEPENDENT_CODE ON) # Version (elfutils). Override with -DLIBELF_VERSION=... if(NOT DEFINED LIBELF_VERSION) set(LIBELF_VERSION "0.193") endif() # zlib is a hard dependency of elf_compress.c (compressed ELF sections). It is # built GNU-free from source into the same prefix before libelf. find_library(ZLIB_LIB z PATHS "${CMAKE_INSTALL_PREFIX}/lib" /usr/local/lib /usr/local/musl/lib) find_path(ZLIB_INC zlib.h PATHS "${CMAKE_INSTALL_PREFIX}/include" /usr/local/include /usr/local/musl/include) if(NOT ZLIB_LIB) message(FATAL_ERROR "libelf: zlib (libz) not found — build zlib first.") endif() # ── Generated config.h ──────────────────────────────────────────────────── # Feature macros for a Linux/x86_64 + musl/LLVM host. Mirrors what elfutils' # ./configure would emit for this target. Functions musl lacks a *declaration* # for are set to 0 so lib/system.h provides a fallback; rawmemchr (no fallback) # is supplied by musl-compat.h. file(WRITE "${CMAKE_BINARY_DIR}/config.h" "#ifndef _LIBELF_CONFIG_H #define _LIBELF_CONFIG_H 1 #define PACKAGE \"elfutils\" #define PACKAGE_NAME \"elfutils\" #define PACKAGE_VERSION \"${LIBELF_VERSION}\" #define VERSION \"${LIBELF_VERSION}\" /* x86_64 permits unaligned accesses. */ #define ALLOW_UNALIGNED 1 /* GNU libc extensions: musl declares these under _GNU_SOURCE. */ #define HAVE_DECL_MEMPCPY 1 #define HAVE_DECL_MEMRCHR 1 #define HAVE_DECL_REALLOCARRAY 1 /* musl lacks these declarations -> use elfutils fallbacks / musl-compat.h. */ #define HAVE_DECL_POWEROF2 0 #define HAVE_DECL_RAWMEMCHR 0 /* musl has (verr/vwarn) but not glibc's ; lib/error.c synthesises error() from err.h when HAVE_ERROR_H is undefined. */ #define HAVE_ERR_H 1 /* Toolchain (clang) feature support. */ #define HAVE_FALLTHROUGH 1 #define HAVE_GCC_STRUCT 1 #define HAVE_VISIBILITY 1 /* Linux mremap(2). */ #define HAVE_MREMAP 1 /* SYMBOL_VERSIONING and USE_LOCKS intentionally left undefined: libelf uses no symbol-version macros, and objtool/modpost use libelf single-threaded, so locks expand to no-ops. */ /* elfutils expects its configure-generated config.h to pull in eu-config.h (compiler attribute macros: attribute_hidden, internal_function, ...). */ #include #endif ") # ── Sources ─────────────────────────────────────────────────────────────── set(ELF_DIR "${CMAKE_SOURCE_DIR}/libelf") set(LIB_DIR "${CMAKE_SOURCE_DIR}/lib") if(NOT EXISTS "${ELF_DIR}/libelfP.h") message(FATAL_ERROR "libelf: expected elfutils source tree at ${CMAKE_SOURCE_DIR} (missing libelf/).") endif() # All libelf/*.c belong to the library (verified against libelf_a_SOURCES). file(GLOB libelfSrcs "${ELF_DIR}/*.c") # Helpers libelf links from lib/: tsearch wrappers, xmalloc, and the err.h # based error() fallback. list(APPEND libelfSrcs "${LIB_DIR}/eu-search.c" "${LIB_DIR}/xmalloc.c" "${LIB_DIR}/error.c" ) set(libelfCFLAGS -D_GNU_SOURCE -DHAVE_CONFIG_H -std=gnu99 -include "${CMAKE_SOURCE_DIR}/musl-compat.h" -Wno-macro-redefined ) include_directories( "${CMAKE_BINARY_DIR}" # config.h "${ELF_DIR}" "${LIB_DIR}" "${ZLIB_INC}" ) # ── Shared + static library ─────────────────────────────────────────────── add_library(elf SHARED ${libelfSrcs}) target_compile_options(elf PRIVATE ${libelfCFLAGS} -DPIC -DSHARED) target_link_libraries(elf PRIVATE ${ZLIB_LIB}) set_target_properties(elf PROPERTIES OUTPUT_NAME elf VERSION "1.${LIBELF_VERSION}" SOVERSION "1" ) add_library(elf-static STATIC ${libelfSrcs}) target_compile_options(elf-static PRIVATE ${libelfCFLAGS}) set_target_properties(elf-static PROPERTIES OUTPUT_NAME elf) # ── Install ─────────────────────────────────────────────────────────────── install(TARGETS elf elf-static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin ) # Public headers (elfutils ships its own richer superset that objtool # expects, plus libelf.h/gelf.h/nlist.h). install(FILES "${ELF_DIR}/libelf.h" "${ELF_DIR}/gelf.h" "${ELF_DIR}/nlist.h" "${ELF_DIR}/elf.h" DESTINATION include ) # pkg-config file so the kernel's `HOSTPKG_CONFIG libelf` resolves. file(WRITE "${CMAKE_BINARY_DIR}/libelf.pc" "prefix=${CMAKE_INSTALL_PREFIX} exec_prefix=\${prefix} libdir=\${prefix}/lib includedir=\${prefix}/include Name: libelf Description: elfutils libelf library to read and write ELF files Version: ${LIBELF_VERSION} URL: http://elfutils.org/ Libs: -L\${libdir} -lelf Libs.private: -lz Cflags: -I\${includedir} ") install(FILES "${CMAKE_BINARY_DIR}/libelf.pc" DESTINATION lib/pkgconfig)