Files
duplicatefinder/CMakeLists.txt
amir f37e915489 Minor optimisations and bug fixes
Fix bug in mt_mpmc.c, in Linux mutexes are not recursive.
Add arena_trim_string() to the arena API
Removing arena->path, now paths are pushed to arena->metadata
Replacing fe->owner[128] with char *owner; the owner is not pushed as a
string to arena->metadata and trimed with arena_trim_string()
Improving cache locality in arena->metadata, the memory layout is not
fe; fe->path; fe->owner.
Cache aligning all arenas except HasherContext->arena to sizeof(void *).
Pushing elements one by one instead of snprintf() in finalize_file() and
hash_worker().
Getting the full path of current directory instead of "."
Fixing bug in path formating, this allow us to remove normalize_path()
from the hot loop.
2026-05-08 20:06:48 +01:00

285 lines
9.6 KiB
CMake

cmake_minimum_required(VERSION 3.20)
project(dfin
VERSION 1.0.0
DESCRIPTION "High-performance duplicate finder with I/O Ring/io_uring support"
LANGUAGES C
)
# ---------------------------------------------------------------------------
# Force compiler search order
# ---------------------------------------------------------------------------
# On Windows, prefer clang-cl, then GCC, then Clang
if(WIN32)
# Try to force compiler order if not already set
if(NOT CMAKE_C_COMPILER)
# Search in preferred order
find_program(CLANG_CL_COMPILER NAMES clang-cl)
find_program(GCC_COMPILER NAMES gcc)
find_program(CLANG_COMPILER NAMES clang)
if(CLANG_CL_COMPILER)
message(STATUS "Found clang-cl as preferred compiler: ${CLANG_CL_COMPILER}")
set(CMAKE_C_COMPILER "${CLANG_CL_COMPILER}" CACHE STRING "" FORCE)
elseif(GCC_COMPILER)
message(STATUS "Found GCC as fallback compiler: ${GCC_COMPILER}")
set(CMAKE_C_COMPILER "${GCC_COMPILER}" CACHE STRING "" FORCE)
elseif(CLANG_COMPILER)
message(STATUS "Found Clang as last-resort compiler: ${CLANG_COMPILER}")
set(CMAKE_C_COMPILER "${CLANG_COMPILER}" CACHE STRING "" FORCE)
endif()
endif()
else()
# On Linux, prefer GCC, then Clang
if(NOT CMAKE_C_COMPILER)
find_program(GCC_COMPILER NAMES gcc)
find_program(CLANG_COMPILER NAMES clang)
if(GCC_COMPILER)
message(STATUS "Found GCC as preferred compiler: ${GCC_COMPILER}")
set(CMAKE_C_COMPILER "${GCC_COMPILER}" CACHE STRING "" FORCE)
elseif(CLANG_COMPILER)
message(STATUS "Found Clang as fallback compiler: ${CLANG_COMPILER}")
set(CMAKE_C_COMPILER "${CLANG_COMPILER}" CACHE STRING "" FORCE)
endif()
endif()
endif()
# Now project() will use the compiler we found
# However, since we needed project() first to get C support,
# we check what we actually got
message(STATUS "Using compiler: ${CMAKE_C_COMPILER} (${CMAKE_C_COMPILER_ID})")
# ---------------------------------------------------------------------------
# Platform and Compiler Detection
# ---------------------------------------------------------------------------
if(WIN32)
set(PLATFORM_WINDOWS TRUE)
set(PLATFORM_NAME "Windows")
else()
set(PLATFORM_LINUX TRUE)
set(PLATFORM_NAME "Linux")
endif()
# Compiler type
if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
# Check if it's clang-cl
if(CMAKE_C_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
set(COMPILER_CLANG_CL TRUE)
message(STATUS "Detected clang-cl (MSVC-compatible frontend)")
else()
set(COMPILER_CLANG_GNU TRUE)
message(STATUS "Detected Clang (GNU-compatible frontend)")
endif()
elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU")
set(COMPILER_GCC TRUE)
message(STATUS "Detected GCC")
elseif(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
# We don't want MSVC, but if it's found, warn user
message(FATAL_ERROR
"MSVC (cl.exe) detected!\n"
"This project requires clang-cl, GCC, or Clang.\n"
"Please install one of these compilers or specify manually:\n"
" cmake .. -DCMAKE_C_COMPILER=clang-cl\n"
" cmake .. -DCMAKE_C_COMPILER=gcc\n"
" cmake .. -DCMAKE_C_COMPILER=clang\n"
)
endif()
# ---------------------------------------------------------------------------
# Build System Selection
# ---------------------------------------------------------------------------
if(NOT CMAKE_GENERATOR OR CMAKE_GENERATOR STREQUAL "")
find_program(NINJA_EXECUTABLE NAMES ninja)
if(NINJA_EXECUTABLE)
message(STATUS "Using Ninja build system")
set(CMAKE_GENERATOR "Ninja")
else()
message(STATUS "Ninja not found, using default generator: ${CMAKE_GENERATOR}")
endif()
endif()
# ---------------------------------------------------------------------------
# Source Files
# ---------------------------------------------------------------------------
set(SOURCES
duplicate_finder.c
xxhash.c
xxh_x86dispatch.c
)
# Headers for dependency tracking and IDE
set(HEADERS
arena.h
base.h
xxhash.h
mt_mpmc.h
)
# ---------------------------------------------------------------------------
# Create Executable
# ---------------------------------------------------------------------------
add_executable(${PROJECT_NAME}
${SOURCES}
${HEADERS}
)
# Include directories
target_include_directories(${PROJECT_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
)
# ---------------------------------------------------------------------------
# Compiler Flags - Exact match to your commands
# ---------------------------------------------------------------------------
if(PLATFORM_WINDOWS)
if(COMPILER_CLANG_CL)
# === clang-cl flags ===
# Release: /O2
target_compile_options(${PROJECT_NAME} PRIVATE
$<$<CONFIG:Release>:/O2>
)
# Debug: /Zi /Od
target_compile_options(${PROJECT_NAME} PRIVATE
$<$<CONFIG:Debug>:/Zi /Od>
)
# Common warnings
target_compile_options(${PROJECT_NAME} PRIVATE /W4)
elseif(COMPILER_GCC)
# === GCC flags (Windows/MinGW) ===
# Release: -O3
target_compile_options(${PROJECT_NAME} PRIVATE
$<$<CONFIG:Release>:-O3>
)
# Debug: -g -O0
target_compile_options(${PROJECT_NAME} PRIVATE
$<$<CONFIG:Debug>:-g -O0>
)
# Common warnings
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra)
elseif(COMPILER_CLANG_GNU)
# === Clang flags (Windows, GNU frontend) ===
# Release: -O3
target_compile_options(${PROJECT_NAME} PRIVATE
$<$<CONFIG:Release>:-O3>
)
# Debug: -g -O0
target_compile_options(${PROJECT_NAME} PRIVATE
$<$<CONFIG:Debug>:-g -O0>
)
# Common warnings
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra)
endif()
# Windows-specific libraries
target_link_libraries(${PROJECT_NAME} PRIVATE
kernel32
)
# Windows-specific defines
target_compile_definitions(${PROJECT_NAME} PRIVATE
WIN32_LEAN_AND_MEAN
_WIN32_WINNT=0x0A00 # Windows 10+
)
# Set output name with .exe
set_target_properties(${PROJECT_NAME} PROPERTIES
SUFFIX ".exe"
)
elseif(PLATFORM_LINUX)
# === Linux GCC/Clang flags ===
if(COMPILER_GCC OR COMPILER_CLANG_GNU)
# Release: -O3
target_compile_options(${PROJECT_NAME} PRIVATE
$<$<CONFIG:Release>:-O3>
)
# Debug: -g -O0
target_compile_options(${PROJECT_NAME} PRIVATE
$<$<CONFIG:Debug>:-g -O0>
)
# Common warnings
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra)
endif()
# Linux-specific libraries
find_package(Threads REQUIRED)
find_library(LIBURING_LIBRARY NAMES uring)
if(LIBURING_LIBRARY)
message(STATUS "Found liburing: ${LIBURING_LIBRARY}")
target_link_libraries(${PROJECT_NAME} PRIVATE
Threads::Threads
${LIBURING_LIBRARY}
)
else()
message(FATAL_ERROR "liburing not found! Install liburing-dev or equivalent")
endif()
# Linux-specific defines
target_compile_definitions(${PROJECT_NAME} PRIVATE
_GNU_SOURCE
)
endif()
# ---------------------------------------------------------------------------
# C Standard
# ---------------------------------------------------------------------------
set_target_properties(${PROJECT_NAME} PROPERTIES
C_STANDARD 11
C_STANDARD_REQUIRED ON
C_EXTENSIONS OFF
)
# ---------------------------------------------------------------------------
# Build Configurations
# ---------------------------------------------------------------------------
# Set default build type if not specified (matching your Release command)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING
"Choose the type of build: Release or Debug" FORCE)
message(STATUS "No build type specified, defaulting to Release")
endif()
# ---------------------------------------------------------------------------
# IDE Support
# ---------------------------------------------------------------------------
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# ---------------------------------------------------------------------------
# Info Target
# ---------------------------------------------------------------------------
add_custom_target(info
COMMAND ${CMAKE_COMMAND} -E echo "=== Build Configuration ==="
COMMAND ${CMAKE_COMMAND} -E echo "Project: ${PROJECT_NAME}"
COMMAND ${CMAKE_COMMAND} -E echo "Compiler: ${CMAKE_C_COMPILER} (${CMAKE_C_COMPILER_ID})"
COMMAND ${CMAKE_COMMAND} -E echo "Frontend: $<IF:$<BOOL:${COMPILER_CLANG_CL}>,clang-cl,GNU>"
COMMAND ${CMAKE_COMMAND} -E echo "Generator: ${CMAKE_GENERATOR}"
COMMAND ${CMAKE_COMMAND} -E echo "Build Type: ${CMAKE_BUILD_TYPE}"
COMMAND ${CMAKE_COMMAND} -E echo "Platform: ${PLATFORM_NAME}"
COMMAND ${CMAKE_COMMAND} -E echo "============================"
)
# ---------------------------------------------------------------------------
# Print final configuration
# ---------------------------------------------------------------------------
message(STATUS "----------------------------------------")
message(STATUS "Configuration Summary:")
message(STATUS " Compiler: ${CMAKE_C_COMPILER}")
message(STATUS " Build Type: ${CMAKE_BUILD_TYPE}")
message(STATUS " Generator: ${CMAKE_GENERATOR}")
message(STATUS " Platform: ${PLATFORM_NAME}")
message(STATUS "----------------------------------------")