# ════════════════════════════════════════════════════════════════════════════ # GNU-free CMake build for e2fsprogs 1.47.x (FenrirOS) # # Replaces e2fsprogs' recursive GNU-make / MCONFIG build with a single CMake # project that drives the musl/LLVM toolchain through ninja. It builds the core # ext2/3/4 userspace (mke2fs, e2fsck, tune2fs, dumpe2fs, resize2fs, badblocks, # e2label, e2image, e2undo, blkid, filefrag, logsave, chattr, lsattr, # mklost+found) plus the static support libraries. # # PREREQUISITE: e2fsprogs' own ./configure must have been run ONCE in-tree # (the build function does this with CC=musl-clang). configure is a POSIX-sh # probe that produces the headers CMake cannot: lib/config.h, lib/dirpaths.h, # lib/ext2fs/ext2_types.h, lib/blkid/blkid_types.h, lib/uuid/uuid_types.h and # the lib/et/compile_et script. This file then regenerates the four derived # sources the Makefiles would build (ext2_err, prof_err, crc32c_table.h, # default_profile.c) and compiles everything. # # Recommended configure flags (set by the build function): # --without-libarchive --disable-nls --disable-fuse2fs # ════════════════════════════════════════════════════════════════════════════ cmake_minimum_required(VERSION 3.24) # LINK_GROUP:RESCAN for circular static libs project(e2fsprogs C) set(E2FSPROGS_VERSION "1.47.4" CACHE STRING "e2fsprogs version") set(S "${CMAKE_CURRENT_SOURCE_DIR}") set(B "${CMAKE_CURRENT_BINARY_DIR}") if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release") endif() # config.h carries every feature macro the sources need; every .c does # `#include "config.h"` first, so -DHAVE_CONFIG_H is the only define we add. add_compile_definitions(HAVE_CONFIG_H) # e2fsprogs is warning-clean only on glibc; on musl/clang we keep warnings # non-fatal so a stray -W doesn't abort the build. add_compile_options(-O2 -Wno-error) # ── Sanity: configure must have run ────────────────────────────────────────── if(NOT EXISTS "${S}/lib/config.h") message(FATAL_ERROR "lib/config.h missing -- run e2fsprogs ./configure before cmake") endif() find_program(AWK_EXE NAMES awk gawk mawk REQUIRED) # compile_et(et_file, work_dir) -- reproduce lib/et/compile_et without needing # the substituted wrapper script: it is just two awk passes (et_h.awk / et_c.awk) # over the .et table that emit .h and .c next to it. function(compile_et _et _dir) get_filename_component(_base "${_et}" NAME_WE) execute_process( COMMAND "${AWK_EXE}" -f "${S}/lib/et/et_h.awk" "outfile=${_base}.h" "outfn=${_base}.h" "${_et}" WORKING_DIRECTORY "${_dir}" RESULT_VARIABLE _r) if(_r) message(FATAL_ERROR "et_h.awk on ${_et} failed: ${_r}") endif() execute_process( COMMAND "${AWK_EXE}" -f "${S}/lib/et/et_c.awk" "outfile=${_base}.c" "outfn=${_base}.c" "${_et}" WORKING_DIRECTORY "${_dir}" RESULT_VARIABLE _r) if(_r) message(FATAL_ERROR "et_c.awk on ${_et} failed: ${_r}") endif() endfunction() # Header search: -Ilib resolves "config.h", , "ext2fs/ext2fs.h", # "blkid/blkid.h", "uuid/uuid.h", "support/*.h"; same-dir headers (ext2_err.h, # ext2_types.h, ...) resolve relative to their including file automatically. include_directories("${S}/lib" "${S}") # ════════════════════════════════════════════════════════════════════════════ # Generated sources (mirror the Makefile.in rules) # ════════════════════════════════════════════════════════════════════════════ # 0) lib/dirpaths.h -- the Makefile substitutes @datadir@/@root_sysconfdir@ # from dirpaths.h.in (config.status does NOT create it). Resolve them against # the install prefix so config.h's `#include ` works. if(NOT EXISTS "${S}/lib/dirpaths.h") set(datadir "${CMAKE_INSTALL_PREFIX}/share") set(root_sysconfdir "${CMAKE_INSTALL_PREFIX}/etc") configure_file("${S}/lib/dirpaths.h.in" "${S}/lib/dirpaths.h" @ONLY) endif() # 0b) Public headers uuid/uuid.h and blkid/blkid.h are plain copies of their # .in templates (the Makefile rule is just `cp`); config.status leaves them out. if(NOT EXISTS "${S}/lib/uuid/uuid.h") configure_file("${S}/lib/uuid/uuid.h.in" "${S}/lib/uuid/uuid.h" COPYONLY) endif() if(NOT EXISTS "${S}/lib/blkid/blkid.h") configure_file("${S}/lib/blkid/blkid.h.in" "${S}/lib/blkid/blkid.h" COPYONLY) endif() # 1) lib/ext2fs/ext2_err.{c,h} -- compile_et on the versioned error table. if(NOT EXISTS "${S}/lib/ext2fs/ext2_err.c") configure_file("${S}/lib/ext2fs/ext2_err.et.in" "${S}/lib/ext2fs/ext2_err.et" @ONLY) compile_et("${S}/lib/ext2fs/ext2_err.et" "${S}/lib/ext2fs") endif() # 2) lib/support/prof_err.{c,h} -- compile_et on the profile error table. if(NOT EXISTS "${S}/lib/support/prof_err.c") compile_et("${S}/lib/support/prof_err.et" "${S}/lib/support") endif() # 3) lib/ext2fs/crc32c_table.h -- built natively (host == target x86_64). if(NOT EXISTS "${S}/lib/ext2fs/crc32c_table.h") execute_process( COMMAND "${CMAKE_C_COMPILER}" -I "${S}/lib/ext2fs" -I "${S}/lib" "${S}/lib/ext2fs/gen_crc32ctable.c" -o "${B}/gen_crc32ctable" RESULT_VARIABLE _r) if(_r) message(FATAL_ERROR "compiling gen_crc32ctable failed: ${_r}") endif() execute_process( COMMAND "${B}/gen_crc32ctable" OUTPUT_FILE "${S}/lib/ext2fs/crc32c_table.h" RESULT_VARIABLE _r) if(_r) message(FATAL_ERROR "gen_crc32ctable run failed: ${_r}") endif() endif() # 4) misc/default_profile.c -- awk transform of the stock mke2fs.conf. if(NOT EXISTS "${S}/misc/default_profile.c") execute_process( COMMAND "${AWK_EXE}" -f "${S}/misc/profile-to-c.awk" INPUT_FILE "${S}/misc/mke2fs.conf.in" OUTPUT_FILE "${S}/misc/default_profile.c" RESULT_VARIABLE _r) if(_r) message(FATAL_ERROR "profile-to-c.awk failed: ${_r}") endif() endif() # ════════════════════════════════════════════════════════════════════════════ # Static libraries (object lists transcribed from each lib/*/Makefile.in OBJS) # ════════════════════════════════════════════════════════════════════════════ # libcom_err (lib/et) add_library(com_err STATIC lib/et/error_message.c lib/et/et_name.c lib/et/init_et.c lib/et/com_err.c lib/et/com_right.c) # libe2p (lib/e2p) add_library(e2p STATIC lib/e2p/feature.c lib/e2p/fgetflags.c lib/e2p/fsetflags.c lib/e2p/fgetversion.c lib/e2p/fsetversion.c lib/e2p/getflags.c lib/e2p/getversion.c lib/e2p/hashstr.c lib/e2p/iod.c lib/e2p/ls.c lib/e2p/ljs.c lib/e2p/mntopts.c lib/e2p/parse_num.c lib/e2p/pe.c lib/e2p/pf.c lib/e2p/ps.c lib/e2p/setflags.c lib/e2p/setversion.c lib/e2p/uuid.c lib/e2p/ostype.c lib/e2p/percent.c lib/e2p/crypto_mode.c lib/e2p/fgetproject.c lib/e2p/fsetproject.c lib/e2p/encoding.c lib/e2p/errcode.c) # libuuid (lib/uuid) add_library(uuid STATIC lib/uuid/clear.c lib/uuid/compare.c lib/uuid/copy.c lib/uuid/gen_uuid.c lib/uuid/isnull.c lib/uuid/pack.c lib/uuid/parse.c lib/uuid/unpack.c lib/uuid/unparse.c lib/uuid/uuid_time.c) # libblkid (lib/blkid) add_library(blkid STATIC lib/blkid/cache.c lib/blkid/dev.c lib/blkid/devname.c lib/blkid/devno.c lib/blkid/getsize.c lib/blkid/llseek.c lib/blkid/probe.c lib/blkid/read.c lib/blkid/resolve.c lib/blkid/save.c lib/blkid/tag.c lib/blkid/version.c) target_link_libraries(blkid PUBLIC uuid) # libext2fs (lib/ext2fs) -- includes the *_LIB_OBJS used by resize2fs/e2image # (dupfs, imager) and debugfs helpers, plus tdb, unix_io and the sparse_io stub. add_library(ext2fs STATIC lib/ext2fs/ext2_err.c lib/ext2fs/dupfs.c lib/ext2fs/imager.c lib/ext2fs/bb_compat.c lib/ext2fs/inode_io.c lib/ext2fs/write_bb_file.c lib/ext2fs/test_io.c lib/ext2fs/alloc.c lib/ext2fs/alloc_sb.c lib/ext2fs/alloc_stats.c lib/ext2fs/alloc_tables.c lib/ext2fs/atexit.c lib/ext2fs/badblocks.c lib/ext2fs/bb_inode.c lib/ext2fs/bitmaps.c lib/ext2fs/bitops.c lib/ext2fs/blkmap64_ba.c lib/ext2fs/blkmap64_rb.c lib/ext2fs/blknum.c lib/ext2fs/block.c lib/ext2fs/bmap.c lib/ext2fs/check_desc.c lib/ext2fs/closefs.c lib/ext2fs/crc16.c lib/ext2fs/crc32c.c lib/ext2fs/csum.c lib/ext2fs/dblist.c lib/ext2fs/dblist_dir.c lib/ext2fs/dirblock.c lib/ext2fs/dirhash.c lib/ext2fs/dir_iterate.c lib/ext2fs/expanddir.c lib/ext2fs/ext_attr.c lib/ext2fs/extent.c lib/ext2fs/fallocate.c lib/ext2fs/fileio.c lib/ext2fs/finddev.c lib/ext2fs/flushb.c lib/ext2fs/freefs.c lib/ext2fs/gen_bitmap.c lib/ext2fs/gen_bitmap64.c lib/ext2fs/get_num_dirs.c lib/ext2fs/get_pathname.c lib/ext2fs/getenv.c lib/ext2fs/getsize.c lib/ext2fs/getsectsize.c lib/ext2fs/hashmap.c lib/ext2fs/i_block.c lib/ext2fs/icount.c lib/ext2fs/ind_block.c lib/ext2fs/initialize.c lib/ext2fs/inline.c lib/ext2fs/inline_data.c lib/ext2fs/inode.c lib/ext2fs/io_manager.c lib/ext2fs/ismounted.c lib/ext2fs/link.c lib/ext2fs/llseek.c lib/ext2fs/lookup.c lib/ext2fs/mkdir.c lib/ext2fs/mkjournal.c lib/ext2fs/mmp.c lib/ext2fs/namei.c lib/ext2fs/native.c lib/ext2fs/newdir.c lib/ext2fs/nls_utf8.c lib/ext2fs/openfs.c lib/ext2fs/orphan.c lib/ext2fs/progress.c lib/ext2fs/punch.c lib/ext2fs/qcow2.c lib/ext2fs/read_bb.c lib/ext2fs/read_bb_file.c lib/ext2fs/res_gdt.c lib/ext2fs/rw_bitmaps.c lib/ext2fs/sha512.c lib/ext2fs/swapfs.c lib/ext2fs/symlink.c lib/ext2fs/tdb.c lib/ext2fs/undo_io.c lib/ext2fs/unix_io.c lib/ext2fs/sparse_io.c lib/ext2fs/unlink.c lib/ext2fs/valid_blk.c lib/ext2fs/version.c lib/ext2fs/rbtree.c) target_link_libraries(ext2fs PUBLIC com_err) # libsupport (lib/support) add_library(support STATIC lib/support/cstring.c lib/support/mkquota.c lib/support/plausible.c lib/support/profile.c lib/support/parse_qtype.c lib/support/print_fs_flags.c lib/support/profile_helpers.c lib/support/prof_err.c lib/support/quotaio.c lib/support/quotaio_v2.c lib/support/quotaio_tree.c lib/support/dict.c lib/support/devname.c) target_link_libraries(support PUBLIC ext2fs e2p blkid com_err) # Circular static-archive group: lets the linker rescan until all refs resolve. set(E2FS_LIBS "$") # ════════════════════════════════════════════════════════════════════════════ # Programs (object lists from misc/, e2fsck/, resize/ Makefile.in) # ════════════════════════════════════════════════════════════════════════════ # mke2fs (+ create_inode_libarchive.c is an empty stub without --with-libarchive) add_executable(mke2fs misc/mke2fs.c misc/util.c misc/default_profile.c misc/mk_hugefiles.c misc/create_inode.c misc/create_inode_libarchive.c) target_link_libraries(mke2fs PRIVATE ${E2FS_LIBS}) # e2fsck add_executable(e2fsck e2fsck/unix.c e2fsck/e2fsck.c e2fsck/super.c e2fsck/pass1.c e2fsck/pass1b.c e2fsck/pass2.c e2fsck/pass3.c e2fsck/pass4.c e2fsck/pass5.c e2fsck/journal.c e2fsck/badblocks.c e2fsck/util.c e2fsck/dirinfo.c e2fsck/dx_dirinfo.c e2fsck/ehandler.c e2fsck/problem.c e2fsck/message.c e2fsck/quota.c e2fsck/recovery.c e2fsck/region.c e2fsck/revoke.c e2fsck/ea_refcount.c e2fsck/rehash.c e2fsck/logfile.c e2fsck/sigcatcher.c e2fsck/readahead.c e2fsck/extents.c e2fsck/encrypted_files.c) target_include_directories(e2fsck PRIVATE "${S}/e2fsck") target_link_libraries(e2fsck PRIVATE ${E2FS_LIBS}) # tune2fs -- its journal/recovery/revoke objects come from debugfs/ and e2fsck/ # and must be built with -DDEBUGFS and -I e2fsck (JOURNAL_CFLAGS). Isolate them # in an OBJECT library so the define/include don't leak into tune2fs.c/util.c. add_library(tune2fs_journal OBJECT debugfs/journal.c e2fsck/recovery.c e2fsck/revoke.c) target_compile_definitions(tune2fs_journal PRIVATE DEBUGFS) target_include_directories(tune2fs_journal PRIVATE "${S}/e2fsck" "${S}/misc") add_executable(tune2fs misc/tune2fs.c misc/util.c $) target_include_directories(tune2fs PRIVATE "${S}/e2fsck" "${S}/misc") target_link_libraries(tune2fs PRIVATE ${E2FS_LIBS}) # Small single-source tools sharing the same lib group. foreach(_p dumpe2fs badblocks e2image e2undo filefrag) add_executable(${_p} misc/${_p}.c) target_link_libraries(${_p} PRIVATE ${E2FS_LIBS}) endforeach() # blkid CLI add_executable(blkid_prog misc/blkid.c) set_target_properties(blkid_prog PROPERTIES OUTPUT_NAME blkid) target_link_libraries(blkid_prog PRIVATE ${E2FS_LIBS}) # chattr / lsattr only need e2p (+com_err). add_executable(chattr misc/chattr.c) add_executable(lsattr misc/lsattr.c) target_link_libraries(chattr PRIVATE e2p com_err) target_link_libraries(lsattr PRIVATE e2p com_err) # mklost+found is self-contained. add_executable(mklost_found misc/mklost+found.c) set_target_properties(mklost_found PROPERTIES OUTPUT_NAME "mklost+found") # logsave is self-contained (no libraries). add_executable(logsave misc/logsave.c) # resize2fs add_executable(resize2fs resize/extent.c resize/resize2fs.c resize/main.c resize/online.c resize/resource_track.c resize/sim_progress.c) target_include_directories(resize2fs PRIVATE "${S}/resize") target_link_libraries(resize2fs PRIVATE ${E2FS_LIBS}) # ════════════════════════════════════════════════════════════════════════════ # Install (sbin for fs tools, bin for the attribute utilities) # ════════════════════════════════════════════════════════════════════════════ install(TARGETS mke2fs e2fsck tune2fs dumpe2fs badblocks resize2fs e2image e2undo blkid_prog mklost_found logsave RUNTIME DESTINATION sbin) install(TARGETS filefrag chattr lsattr RUNTIME DESTINATION bin) # Filesystem-variant symlinks (mke2fs/e2fsck dispatch on argv[0]); e2label is a # symlink to tune2fs (it dispatches on argv[0]), not a separate binary. install(CODE " set(_sb \"\${CMAKE_INSTALL_PREFIX}/sbin\") foreach(_v ext2 ext3 ext4) file(CREATE_LINK mke2fs \"\${_sb}/mkfs.\${_v}\" SYMBOLIC) file(CREATE_LINK e2fsck \"\${_sb}/fsck.\${_v}\" SYMBOLIC) endforeach() file(CREATE_LINK tune2fs \"\${_sb}/e2label\" SYMBOLIC) ") # Expose the static UUID library + its header so external GNU-free tools (e.g. # gptfdisk/sgdisk) can link the e2fsprogs libuuid instead of util-linux. Static # only — a .a is never loaded at runtime, so it cannot poison glibc host tools. install(TARGETS uuid ARCHIVE DESTINATION lib) install(FILES "${S}/lib/uuid/uuid.h" DESTINATION include/uuid)