cmake_minimum_required(VERSION 3.20) project(filehasher VERSION 1.0.0 DESCRIPTION "High-performance file hasher 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 file_hasher.c xxhash.c xxh_x86dispatch.c ) # Headers for dependency tracking and IDE set(HEADERS arena.h base.h xxhash.h lf_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 $<$:/O2> ) # Debug: /Zi /Od target_compile_options(${PROJECT_NAME} PRIVATE $<$:/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 $<$:-O3> ) # Debug: -g -O0 target_compile_options(${PROJECT_NAME} PRIVATE $<$:-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 $<$:-O3> ) # Debug: -g -O0 target_compile_options(${PROJECT_NAME} PRIVATE $<$:-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 $<$:-O3> ) # Debug: -g -O0 target_compile_options(${PROJECT_NAME} PRIVATE $<$:-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: $,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 "----------------------------------------")