Compare commits

..

2 Commits

Author SHA1 Message Date
4779a38911 patch 2026-01-29 19:44:35 +03:00
f273c2fc7e added shit 2026-01-29 19:44:35 +03:00
25 changed files with 1323 additions and 1458 deletions

View File

@@ -1,25 +0,0 @@
format:
line_width: 100
tab_size: 4
use_tabchars: false
max_subgroups_hwrap: 3
max_pargs_hwrap: 5
separate_ctrl_name_with_space: false
separate_fn_name_with_space: false
dangle_parens: false
dangle_align: child
line_ending: unix
command_case: canonical
keyword_case: upper
enable_sort: true
autosort: true
markup:
bullet_char: "*"
enum_char: .
enable_markup: false
additional_commands:
target_link_libraries:
kwargs:
PUBLIC: "*"
SHARED: "*"
PRIVATE: "*"

2
.gitattributes vendored
View File

@@ -1,2 +0,0 @@
# SCM syntax highlighting & preventing 3-way merges
pixi.lock merge=binary linguist-language=YAML linguist-generated=true -diff

8
.gitignore vendored
View File

@@ -5,10 +5,4 @@
.idea/workspace.xml .idea/workspace.xml
/build/ /build/
/clang-coverage/ /clang-coverage/
*.gcov *.gcov
*.bin
# pixi lock
pixi.lock
# pixi environments
.pixi/*
!.pixi/config.toml

3
.idea/editor.xml generated
View File

@@ -17,7 +17,7 @@
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatTooManyArgs/@EntryIndexedValue" value="WARNING" type="string" /> <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatTooManyArgs/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCStyleCast/@EntryIndexedValue" value="SUGGESTION" type="string" /> <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCStyleCast/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCVQualifierCanNotBeAppliedToReference/@EntryIndexedValue" value="WARNING" type="string" /> <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCVQualifierCanNotBeAppliedToReference/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassCanBeFinal/@EntryIndexedValue" value="HINT" type="string" /> <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassCanBeFinal/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassIsIncomplete/@EntryIndexedValue" value="WARNING" type="string" /> <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassIsIncomplete/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassNeedsConstructorBecauseOfUninitializedMember/@EntryIndexedValue" value="WARNING" type="string" /> <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassNeedsConstructorBecauseOfUninitializedMember/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassNeverUsed/@EntryIndexedValue" value="WARNING" type="string" /> <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
@@ -56,6 +56,7 @@
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultInitializationWithNoUserConstructor/@EntryIndexedValue" value="WARNING" type="string" /> <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultInitializationWithNoUserConstructor/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultIsUsedAsIdentifier/@EntryIndexedValue" value="WARNING" type="string" /> <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultIsUsedAsIdentifier/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultedSpecialMemberFunctionIsImplicitlyDeleted/@EntryIndexedValue" value="WARNING" type="string" /> <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultedSpecialMemberFunctionIsImplicitlyDeleted/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefinitionsOrder/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeletingVoidPointer/@EntryIndexedValue" value="WARNING" type="string" /> <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeletingVoidPointer/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDependentTemplateWithoutTemplateKeyword/@EntryIndexedValue" value="WARNING" type="string" /> <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDependentTemplateWithoutTemplateKeyword/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDependentTypeWithoutTypenameKeyword/@EntryIndexedValue" value="WARNING" type="string" /> <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDependentTypeWithoutTypenameKeyword/@EntryIndexedValue" value="WARNING" type="string" />

View File

@@ -9,56 +9,49 @@ include(CheckCXXCompilerFlag)
include(cmake/Coverage.cmake) include(cmake/Coverage.cmake)
include(cmake/Valgrind.cmake) include(cmake/Valgrind.cmake)
if(MSVC) if (MSVC)
check_cxx_compiler_flag("/arch:AVX2" COMPILER_SUPPORTS_AVX2) check_cxx_compiler_flag("/arch:AVX2" COMPILER_SUPPORTS_AVX2)
else() else ()
check_cxx_compiler_flag("-mavx2" COMPILER_SUPPORTS_AVX2) check_cxx_compiler_flag("-mavx2" COMPILER_SUPPORTS_AVX2)
endif() endif ()
option(OMATH_BUILD_TESTS "Build unit tests" OFF) option(OMATH_BUILD_TESTS "Build unit tests" OFF)
option(OMATH_BUILD_BENCHMARK "Build benchmarks" OFF) option(OMATH_BUILD_BENCHMARK "Build benchmarks" OFF)
option(OMATH_THREAT_WARNING_AS_ERROR option(OMATH_THREAT_WARNING_AS_ERROR "Set highest level of warnings and force compiler to treat them as errors" ON)
"Set highest level of warnings and force compiler to treat them as errors" ON)
option(OMATH_BUILD_AS_SHARED_LIBRARY "Build Omath as .so or .dll" OFF) option(OMATH_BUILD_AS_SHARED_LIBRARY "Build Omath as .so or .dll" OFF)
option(OMATH_USE_AVX2 "Omath will use AVX2 to boost performance" ${COMPILER_SUPPORTS_AVX2}) option(OMATH_USE_AVX2 "Omath will use AVX2 to boost performance" ${COMPILER_SUPPORTS_AVX2})
option(OMATH_IMGUI_INTEGRATION "Omath will define method to convert omath types to imgui types" OFF) option(OMATH_IMGUI_INTEGRATION "Omath will define method to convert omath types to imgui types" OFF)
option(OMATH_BUILD_EXAMPLES "Build example projects with you can learn & play" OFF) option(OMATH_BUILD_EXAMPLES "Build example projects with you can learn & play" OFF)
option(OMATH_STATIC_MSVC_RUNTIME_LIBRARY "Force Omath to link static runtime" OFF) option(OMATH_STATIC_MSVC_RUNTIME_LIBRARY "Force Omath to link static runtime" OFF)
option(OMATH_ENABLE_LEGACY option(OMATH_SUPRESS_SAFETY_CHECKS "Supress some safety checks in release build to improve general performance" ON)
"Will enable legacy classes that MUST be used ONLY for backward compatibility" ON) option(OMATH_USE_UNITY_BUILD "Will enable unity build to speed up compilation" OFF)
option(OMATH_SUPRESS_SAFETY_CHECKS option(OMATH_ENABLE_LEGACY "Will enable legacy classes that MUST be used ONLY for backward compatibility" ON)
"Supress some safety checks in release build to improve general performance" ON)
option(OMATH_ENABLE_COVERAGE "Enable coverage" OFF) option(OMATH_ENABLE_COVERAGE "Enable coverage" OFF)
option(OMATH_ENABLE_FORCE_INLINE option(OMATH_ENABLE_FORCE_INLINE "Will for compiler to make some functions to be force inlined no matter what" ON)
"Will for compiler to make some functions to be force inlined no matter what" ON) if (VCPKG_MANIFEST_FEATURES)
if(VCPKG_MANIFEST_FEATURES) foreach (omath_feature IN LISTS VCPKG_MANIFEST_FEATURES)
foreach(omath_feature IN LISTS VCPKG_MANIFEST_FEATURES) if (omath_feature STREQUAL "imgui")
if(omath_feature STREQUAL "imgui")
set(OMATH_IMGUI_INTEGRATION ON) set(OMATH_IMGUI_INTEGRATION ON)
elseif(omath_feature STREQUAL "avx2") elseif (omath_feature STREQUAL "avx2")
set(OMATH_USE_AVX2 ${COMPILER_SUPPORTS_AVX2}) set(OMATH_USE_AVX2 ${COMPILER_SUPPORTS_AVX2})
elseif(omath_feature STREQUAL "tests") elseif (omath_feature STREQUAL "tests")
set(OMATH_BUILD_TESTS ON) set(OMATH_BUILD_TESTS ON)
elseif(omath_feature STREQUAL "benchmark") elseif (omath_feature STREQUAL "benchmark")
set(OMATH_BUILD_BENCHMARK ON) set(OMATH_BUILD_BENCHMARK ON)
elseif(omath_feature STREQUAL "examples") elseif (omath_feature STREQUAL "examples")
set(OMATH_BUILD_EXAMPLES ON) set(OMATH_BUILD_EXAMPLES ON)
endif() endif ()
endforeach() endforeach ()
endif() endif ()
if(OMATH_USE_AVX2 AND NOT COMPILER_SUPPORTS_AVX2) if (OMATH_USE_AVX2 AND NOT COMPILER_SUPPORTS_AVX2)
message( message(WARNING "OMATH_USE_AVX2 requested, but compiler/target does not support AVX2. Disabling.")
WARNING "OMATH_USE_AVX2 requested, but compiler/target does not support AVX2. Disabling.")
set(OMATH_USE_AVX2 OFF CACHE BOOL "Omath will use AVX2 to boost performance" FORCE) set(OMATH_USE_AVX2 OFF CACHE BOOL "Omath will use AVX2 to boost performance" FORCE)
endif() endif ()
if(${PROJECT_IS_TOP_LEVEL}) if (${PROJECT_IS_TOP_LEVEL})
message( message(STATUS "[${PROJECT_NAME}]: Building on ${CMAKE_HOST_SYSTEM_NAME}, compiler ${CMAKE_CXX_COMPILER_ID}")
STATUS
"[${PROJECT_NAME}]: Building on ${CMAKE_HOST_SYSTEM_NAME}, compiler ${CMAKE_CXX_COMPILER_ID}"
)
message(STATUS "[${PROJECT_NAME}]: Warnings as errors ${OMATH_THREAT_WARNING_AS_ERROR}") message(STATUS "[${PROJECT_NAME}]: Warnings as errors ${OMATH_THREAT_WARNING_AS_ERROR}")
message(STATUS "[${PROJECT_NAME}]: Build unit tests ${OMATH_BUILD_TESTS}") message(STATUS "[${PROJECT_NAME}]: Build unit tests ${OMATH_BUILD_TESTS}")
message(STATUS "[${PROJECT_NAME}]: Build benchmark ${OMATH_BUILD_BENCHMARK}") message(STATUS "[${PROJECT_NAME}]: Build benchmark ${OMATH_BUILD_BENCHMARK}")
@@ -72,63 +65,68 @@ if(${PROJECT_IS_TOP_LEVEL})
message(STATUS "[${PROJECT_NAME}]: Building using vcpkg ${OMATH_BUILD_VIA_VCPKG}") message(STATUS "[${PROJECT_NAME}]: Building using vcpkg ${OMATH_BUILD_VIA_VCPKG}")
message(STATUS "[${PROJECT_NAME}]: Coverage feature status ${OMATH_ENABLE_COVERAGE}") message(STATUS "[${PROJECT_NAME}]: Coverage feature status ${OMATH_ENABLE_COVERAGE}")
message(STATUS "[${PROJECT_NAME}]: Valgrind feature status ${OMATH_ENABLE_VALGRIND}") message(STATUS "[${PROJECT_NAME}]: Valgrind feature status ${OMATH_ENABLE_VALGRIND}")
endif() endif ()
file(GLOB_RECURSE OMATH_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp") file(GLOB_RECURSE OMATH_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp")
file(GLOB_RECURSE OMATH_HEADERS CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp") file(GLOB_RECURSE OMATH_HEADERS CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp")
if(OMATH_BUILD_AS_SHARED_LIBRARY) if (OMATH_BUILD_AS_SHARED_LIBRARY)
add_library(${PROJECT_NAME} SHARED ${OMATH_SOURCES} ${OMATH_HEADERS}) add_library(${PROJECT_NAME} SHARED ${OMATH_SOURCES} ${OMATH_HEADERS})
else() else ()
add_library(${PROJECT_NAME} STATIC ${OMATH_SOURCES} ${OMATH_HEADERS}) add_library(${PROJECT_NAME} STATIC ${OMATH_SOURCES} ${OMATH_HEADERS})
endif() endif ()
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_VERSION="${PROJECT_VERSION}") target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_VERSION="${PROJECT_VERSION}")
if(OMATH_IMGUI_INTEGRATION) if (OMATH_IMGUI_INTEGRATION)
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_IMGUI_INTEGRATION) target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_IMGUI_INTEGRATION)
# IMGUI is being linked as submodule # IMGUI is being linked as submodule
if(TARGET imgui) if (TARGET imgui)
target_link_libraries(${PROJECT_NAME} PUBLIC imgui) target_link_libraries(${PROJECT_NAME} PUBLIC imgui)
install( install(TARGETS imgui
TARGETS imgui EXPORT omathTargets
EXPORT omathTargets ARCHIVE DESTINATION lib
ARCHIVE DESTINATION lib LIBRARY DESTINATION lib
LIBRARY DESTINATION lib RUNTIME DESTINATION bin)
RUNTIME DESTINATION bin) else ()
else()
# Assume that IMGUI linked via VCPKG. # Assume that IMGUI linked via VCPKG.
find_package(imgui CONFIG REQUIRED) find_package(imgui CONFIG REQUIRED)
target_link_libraries(${PROJECT_NAME} PUBLIC imgui::imgui) target_link_libraries(${PROJECT_NAME} PUBLIC imgui::imgui)
endif() endif ()
endif() endif ()
if(OMATH_USE_AVX2) if (OMATH_USE_AVX2)
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_USE_AVX2) target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_USE_AVX2)
endif() endif ()
if(OMATH_SUPRESS_SAFETY_CHECKS) if (OMATH_SUPRESS_SAFETY_CHECKS)
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_SUPRESS_SAFETY_CHECKS) target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_SUPRESS_SAFETY_CHECKS)
endif() endif ()
if(OMATH_ENABLE_LEGACY) if (OMATH_ENABLE_LEGACY)
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_ENABLE_LEGACY) target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_ENABLE_LEGACY)
endif() endif ()
if(OMATH_ENABLE_FORCE_INLINE) if (OMATH_ENABLE_FORCE_INLINE)
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_ENABLE_FORCE_INLINE) target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_ENABLE_FORCE_INLINE)
endif() endif ()
set_target_properties( set_target_properties(${PROJECT_NAME} PROPERTIES
${PROJECT_NAME} ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}" CXX_STANDARD 23
CXX_STANDARD 23 CXX_STANDARD_REQUIRED ON)
CXX_STANDARD_REQUIRED ON)
if (OMATH_USE_UNITY_BUILD)
set_target_properties(${PROJECT_NAME} PROPERTIES
UNITY_BUILD ON
UNITY_BUILD_BATCH_SIZE 20)
endif ()
if (OMATH_STATIC_MSVC_RUNTIME_LIBRARY) if (OMATH_STATIC_MSVC_RUNTIME_LIBRARY)
set_target_properties(${PROJECT_NAME} PROPERTIES set_target_properties(${PROJECT_NAME} PROPERTIES
@@ -136,15 +134,15 @@ if (OMATH_STATIC_MSVC_RUNTIME_LIBRARY)
) )
endif () endif ()
if(OMATH_USE_AVX2) if (OMATH_USE_AVX2)
if(MSVC) if (MSVC)
target_compile_options(${PROJECT_NAME} PUBLIC /arch:AVX2) target_compile_options(${PROJECT_NAME} PUBLIC /arch:AVX2)
elseif(EMSCRIPTEN) elseif (EMSCRIPTEN)
target_compile_options(${PROJECT_NAME} PUBLIC -msimd128 -mavx2) target_compile_options(${PROJECT_NAME} PUBLIC -msimd128 -mavx2)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang") elseif (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
target_compile_options(${PROJECT_NAME} PUBLIC -mfma -mavx2) target_compile_options(${PROJECT_NAME} PUBLIC -mfma -mavx2)
endif() endif ()
endif() endif ()
if(EMSCRIPTEN) if(EMSCRIPTEN)
target_compile_options(${PROJECT_NAME} PUBLIC -fexceptions) target_compile_options(${PROJECT_NAME} PUBLIC -fexceptions)
@@ -153,79 +151,79 @@ endif()
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_23) target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_23)
if(OMATH_BUILD_TESTS)
if (OMATH_BUILD_TESTS)
add_subdirectory(tests) add_subdirectory(tests)
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_BUILD_TESTS) target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_BUILD_TESTS)
if(OMATH_ENABLE_COVERAGE) if(OMATH_ENABLE_COVERAGE)
omath_setup_coverage(${PROJECT_NAME}) omath_setup_coverage(${PROJECT_NAME})
endif() endif()
endif() endif ()
if(OMATH_BUILD_BENCHMARK) if (OMATH_BUILD_BENCHMARK)
add_subdirectory(benchmark) add_subdirectory(benchmark)
endif() endif ()
if(OMATH_BUILD_EXAMPLES) if (OMATH_BUILD_EXAMPLES)
add_subdirectory(examples) add_subdirectory(examples)
endif() endif ()
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND OMATH_THREAT_WARNING_AS_ERROR)
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND OMATH_THREAT_WARNING_AS_ERROR)
target_compile_options(${PROJECT_NAME} PRIVATE /W4 /WX) target_compile_options(${PROJECT_NAME} PRIVATE /W4 /WX)
elseif(OMATH_THREAT_WARNING_AS_ERROR) elseif (OMATH_THREAT_WARNING_AS_ERROR)
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic -Werror) target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic -Werror)
endif() endif ()
# Windows SDK redefine min/max via preprocessor and break std::min and std::max # Windows SDK redefine min/max via preprocessor and break std::min and std::max
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
target_compile_definitions(${PROJECT_NAME} INTERFACE NOMINMAX) target_compile_definitions(${PROJECT_NAME} INTERFACE NOMINMAX)
endif() endif ()
target_include_directories(${PROJECT_NAME}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> # Use this path when building the project
$<INSTALL_INTERFACE:include> # Use this path when the project is installed
)
target_include_directories(
${PROJECT_NAME}
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> # Use this path
# when building
# the project
$<INSTALL_INTERFACE:include> # Use this path when the project is
# installed
)
# Installation rules # Installation rules
# Install the library # Install the library
install( install(TARGETS ${PROJECT_NAME}
TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}Targets
EXPORT ${PROJECT_NAME}Targets ARCHIVE DESTINATION lib COMPONENT ${PROJECT_NAME} # For static libraries
ARCHIVE DESTINATION lib COMPONENT ${PROJECT_NAME} # For static libraries LIBRARY DESTINATION lib COMPONENT ${PROJECT_NAME} # For shared libraries
LIBRARY DESTINATION lib COMPONENT ${PROJECT_NAME} # For shared libraries RUNTIME DESTINATION bin COMPONENT ${PROJECT_NAME} # For executables (on Windows)
RUNTIME DESTINATION bin COMPONENT ${PROJECT_NAME} # For executables (on )
# Windows)
)
# Install headers as part of omath_component # Install headers as part of omath_component
install(DIRECTORY include/ DESTINATION include COMPONENT ${PROJECT_NAME}) install(DIRECTORY include/ DESTINATION include COMPONENT ${PROJECT_NAME})
# Export omath target for CMake find_package support, also under omath_component # Export omath target for CMake find_package support, also under omath_component
install( install(EXPORT ${PROJECT_NAME}Targets
EXPORT ${PROJECT_NAME}Targets FILE ${PROJECT_NAME}Targets.cmake
FILE ${PROJECT_NAME}Targets.cmake NAMESPACE ${PROJECT_NAME}::
NAMESPACE ${PROJECT_NAME}:: DESTINATION lib/cmake/${PROJECT_NAME} COMPONENT ${PROJECT_NAME}
DESTINATION lib/cmake/${PROJECT_NAME} )
COMPONENT ${PROJECT_NAME})
# Generate the omathConfigVersion.cmake file # Generate the omathConfigVersion.cmake file
write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/omathConfigVersion.cmake" write_basic_package_version_file(
VERSION ${PROJECT_VERSION} COMPATIBILITY AnyNewerVersion) "${CMAKE_CURRENT_BINARY_DIR}/omathConfigVersion.cmake"
VERSION ${PROJECT_VERSION}
COMPATIBILITY AnyNewerVersion
)
# Generate the omathConfig.cmake file from the template (which is in the cmake/ # Generate the omathConfig.cmake file from the template (which is in the cmake/ folder)
# folder)
configure_package_config_file( configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/omathConfig.cmake.in" # Path to the .in "${CMAKE_CURRENT_SOURCE_DIR}/cmake/omathConfig.cmake.in" # Path to the .in file
# file "${CMAKE_CURRENT_BINARY_DIR}/omathConfig.cmake" # Output path for the generated file
"${CMAKE_CURRENT_BINARY_DIR}/omathConfig.cmake" # Output path for the INSTALL_DESTINATION lib/cmake/${PROJECT_NAME}
# generated file )
INSTALL_DESTINATION lib/cmake/${PROJECT_NAME})
# Install the generated config files # Install the generated config files
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/omathConfig.cmake" install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/omathConfigVersion.cmake" "${CMAKE_CURRENT_BINARY_DIR}/omathConfig.cmake"
DESTINATION lib/cmake/${PROJECT_NAME}) "${CMAKE_CURRENT_BINARY_DIR}/omathConfigVersion.cmake"
DESTINATION lib/cmake/${PROJECT_NAME}
)

View File

@@ -1 +1 @@
4.7.1 4.6.0

View File

@@ -1,23 +1,22 @@
project(omath_benchmark) project(omath_benchmark)
file(GLOB_RECURSE OMATH_BENCHMARK_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") file(GLOB_RECURSE OMATH_BENCHMARK_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
add_executable(${PROJECT_NAME} ${OMATH_BENCHMARK_SOURCES}) add_executable(${PROJECT_NAME} ${OMATH_BENCHMARK_SOURCES})
set_target_properties( set_target_properties(${PROJECT_NAME} PROPERTIES
${PROJECT_NAME} ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}" CXX_STANDARD 23
CXX_STANDARD 23 CXX_STANDARD_REQUIRED ON)
CXX_STANDARD_REQUIRED ON)
if(TARGET benchmark::benchmark) # Benchmark is being linked as submodule if (TARGET benchmark::benchmark) # Benchmark is being linked as submodule
target_link_libraries(${PROJECT_NAME} PRIVATE benchmark::benchmark omath) target_link_libraries(${PROJECT_NAME} PRIVATE benchmark::benchmark omath)
else() else()
find_package(benchmark CONFIG REQUIRED) # Benchmark is being linked as vcpkg find_package(benchmark CONFIG REQUIRED) # Benchmark is being linked as vcpkg package
# package
target_link_libraries(${PROJECT_NAME} PRIVATE benchmark::benchmark omath) target_link_libraries(${PROJECT_NAME} PRIVATE benchmark::benchmark omath)
endif() endif ()
if(OMATH_ENABLE_VALGRIND) if(OMATH_ENABLE_VALGRIND)
omath_setup_valgrind(${PROJECT_NAME}) omath_setup_valgrind(${PROJECT_NAME})

View File

@@ -7,23 +7,38 @@ function(omath_setup_coverage TARGET_NAME)
endif() endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND MSVC) if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND MSVC)
target_compile_options(${TARGET_NAME} PRIVATE -fprofile-instr-generate -fcoverage-mapping target_compile_options(${TARGET_NAME} PRIVATE
/Zi) -fprofile-instr-generate
target_link_options( -fcoverage-mapping
${TARGET_NAME} /Zi
PRIVATE )
target_link_options(${TARGET_NAME} PRIVATE
-fprofile-instr-generate -fprofile-instr-generate
-fcoverage-mapping -fcoverage-mapping
/DEBUG:FULL /DEBUG:FULL
/INCREMENTAL:NO /INCREMENTAL:NO
/PROFILE) /PROFILE
)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang") elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang")
target_compile_options(${TARGET_NAME} PRIVATE -fprofile-instr-generate -fcoverage-mapping target_compile_options(${TARGET_NAME} PRIVATE
-g -O0) -fprofile-instr-generate
target_link_options(${TARGET_NAME} PRIVATE -fprofile-instr-generate -fcoverage-mapping) -fcoverage-mapping
-g
-O0
)
target_link_options(${TARGET_NAME} PRIVATE
-fprofile-instr-generate
-fcoverage-mapping
)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
target_compile_options(${TARGET_NAME} PRIVATE --coverage -g -O0) target_compile_options(${TARGET_NAME} PRIVATE
target_link_options(${TARGET_NAME} PRIVATE --coverage) --coverage
-g
-O0
)
target_link_options(${TARGET_NAME} PRIVATE
--coverage
)
endif() endif()
if(TARGET coverage) if(TARGET coverage)
@@ -32,36 +47,40 @@ function(omath_setup_coverage TARGET_NAME)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND MSVC) if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND MSVC)
message(STATUS "MSVC detected: Use VS Code Coverage from CI workflow") message(STATUS "MSVC detected: Use VS Code Coverage from CI workflow")
add_custom_target( add_custom_target(coverage
coverage
DEPENDS unit_tests DEPENDS unit_tests
COMMAND $<TARGET_FILE:unit_tests> COMMAND $<TARGET_FILE:unit_tests>
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMENT "Running tests for coverage (use VS Code Coverage from CI)") COMMENT "Running tests for coverage (use VS Code Coverage from CI)"
)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang") elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang")
add_custom_target( add_custom_target(coverage
coverage
DEPENDS unit_tests DEPENDS unit_tests
COMMAND bash "${CMAKE_SOURCE_DIR}/scripts/coverage-llvm.sh" "${CMAKE_SOURCE_DIR}" COMMAND bash "${CMAKE_SOURCE_DIR}/scripts/coverage-llvm.sh"
"${CMAKE_BINARY_DIR}" "$<TARGET_FILE:unit_tests>" "${CMAKE_BINARY_DIR}/coverage" "${CMAKE_SOURCE_DIR}"
"${CMAKE_BINARY_DIR}"
"$<TARGET_FILE:unit_tests>"
"${CMAKE_BINARY_DIR}/coverage"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMENT "Running LLVM coverage") COMMENT "Running LLVM coverage"
)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
add_custom_target( add_custom_target(coverage
coverage
DEPENDS unit_tests DEPENDS unit_tests
COMMAND $<TARGET_FILE:unit_tests> || true COMMAND $<TARGET_FILE:unit_tests> || true
COMMAND lcov --capture --directory "${CMAKE_BINARY_DIR}" --output-file COMMAND lcov --capture --directory "${CMAKE_BINARY_DIR}"
"${CMAKE_BINARY_DIR}/coverage.info" --ignore-errors mismatch,gcov --output-file "${CMAKE_BINARY_DIR}/coverage.info"
COMMAND --ignore-errors mismatch,gcov
lcov --remove "${CMAKE_BINARY_DIR}/coverage.info" "*/tests/*" "*/gtest/*" COMMAND lcov --remove "${CMAKE_BINARY_DIR}/coverage.info"
"*/googletest/*" "*/_deps/*" "/usr/*" --output-file "*/tests/*" "*/gtest/*" "*/googletest/*" "*/_deps/*" "/usr/*"
"${CMAKE_BINARY_DIR}/coverage.info" --ignore-errors unused --output-file "${CMAKE_BINARY_DIR}/coverage.info"
COMMAND genhtml "${CMAKE_BINARY_DIR}/coverage.info" --output-directory --ignore-errors unused
"${CMAKE_BINARY_DIR}/coverage" COMMAND genhtml "${CMAKE_BINARY_DIR}/coverage.info"
--output-directory "${CMAKE_BINARY_DIR}/coverage"
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
COMMENT "Running lcov/genhtml") COMMENT "Running lcov/genhtml"
)
endif() endif()
endfunction() endfunction()

View File

@@ -22,19 +22,23 @@ function(omath_setup_valgrind TARGET_NAME)
return() return()
endif() endif()
set(VALGRIND_FLAGS --leak-check=full --show-leak-kinds=all --track-origins=yes set(VALGRIND_FLAGS
--error-exitcode=99) --leak-check=full
--show-leak-kinds=all
--track-origins=yes
--error-exitcode=99
)
set(VALGRIND_TARGET "valgrind_${TARGET_NAME}") set(VALGRIND_TARGET "valgrind_${TARGET_NAME}")
if(NOT TARGET ${VALGRIND_TARGET}) if(NOT TARGET ${VALGRIND_TARGET})
add_custom_target( add_custom_target(${VALGRIND_TARGET}
${VALGRIND_TARGET}
DEPENDS ${TARGET_NAME} DEPENDS ${TARGET_NAME}
COMMAND ${VALGRIND_EXECUTABLE} ${VALGRIND_FLAGS} $<TARGET_FILE:${TARGET_NAME}> COMMAND ${VALGRIND_EXECUTABLE} ${VALGRIND_FLAGS} $<TARGET_FILE:${TARGET_NAME}>
WORKING_DIRECTORY $<TARGET_FILE_DIR:${TARGET_NAME}> WORKING_DIRECTORY $<TARGET_FILE_DIR:${TARGET_NAME}>
COMMENT "Running Valgrind memory check on ${TARGET_NAME}..." COMMENT "Running Valgrind memory check on ${TARGET_NAME}..."
USES_TERMINAL) USES_TERMINAL
)
add_dependencies(valgrind_all ${VALGRIND_TARGET}) add_dependencies(valgrind_all ${VALGRIND_TARGET})
endif() endif()

View File

@@ -1,38 +1,40 @@
project(examples) project(examples)
add_executable(example_projection_matrix_builder example_proj_mat_builder.cpp) add_executable(example_projection_matrix_builder example_proj_mat_builder.cpp)
set_target_properties( set_target_properties(example_projection_matrix_builder PROPERTIES
example_projection_matrix_builder CXX_STANDARD 26
PROPERTIES CXX_STANDARD 23 ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}") )
target_link_libraries(example_projection_matrix_builder PRIVATE omath::omath) target_link_libraries(example_projection_matrix_builder PRIVATE omath::omath)
add_executable(example_signature_scan example_signature_scan.cpp) add_executable(example_signature_scan example_signature_scan.cpp)
set_target_properties( set_target_properties(example_signature_scan PROPERTIES
example_signature_scan CXX_STANDARD 26
PROPERTIES CXX_STANDARD 23 ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}") )
target_link_libraries(example_signature_scan PRIVATE omath::omath) target_link_libraries(example_signature_scan PRIVATE omath::omath)
add_executable(example_glfw3 example_glfw3.cpp)
set_target_properties(
example_glfw3
PROPERTIES CXX_STANDARD 23
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}")
find_package(OpenGL) add_executable(example_glfw3 example_glfw3.cpp)
set_target_properties(example_glfw3 PROPERTIES CXX_STANDARD 26
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
)
find_package(GLEW REQUIRED) find_package(GLEW REQUIRED)
find_package(glfw3 CONFIG REQUIRED) find_package(glfw3 CONFIG REQUIRED)
target_link_libraries(example_glfw3 PRIVATE omath::omath GLEW::GLEW glfw OpenGL::OpenGL) target_link_libraries(example_glfw3 PRIVATE omath::omath GLEW::GLEW glfw)
find_path(TINYGLTF_INCLUDE_DIRS "tiny_gltf.h")
target_include_directories(example_glfw3 PRIVATE ${TINYGLTF_INCLUDE_DIRS})
if(OMATH_ENABLE_VALGRIND) if(OMATH_ENABLE_VALGRIND)
omath_setup_valgrind(example_projection_matrix_builder) omath_setup_valgrind(example_projection_matrix_builder)
omath_setup_valgrind(example_signature_scan) omath_setup_valgrind(example_signature_scan)
omath_setup_valgrind(example_glfw3) omath_setup_valgrind(example_glfw3)
endif() endif()

File diff suppressed because it is too large Load Diff

View File

@@ -63,7 +63,7 @@ namespace omath::primitives
m_to_world_matrix = std::nullopt; m_to_world_matrix = std::nullopt;
} }
void set_rotation(const RotationAnglesType& new_rotation_angles) void set_rotation(const RotationAngles& new_rotation_angles)
{ {
m_rotation_angles = new_rotation_angles; m_rotation_angles = new_rotation_angles;
m_to_world_matrix = std::nullopt; m_to_world_matrix = std::nullopt;
@@ -82,7 +82,7 @@ namespace omath::primitives
} }
[[nodiscard]] [[nodiscard]]
const RotationAnglesType& get_rotation_angles() const const RotationAngles& get_rotation_angles() const
{ {
return m_rotation_angles; return m_rotation_angles;
} }
@@ -127,7 +127,7 @@ namespace omath::primitives
VectorType m_origin; VectorType m_origin;
VectorType m_scale; VectorType m_scale;
RotationAnglesType m_rotation_angles; RotationAngles m_rotation_angles;
mutable std::optional<Mat4X4> m_to_world_matrix; mutable std::optional<Mat4X4> m_to_world_matrix;
}; };

View File

@@ -7,6 +7,7 @@
#include <limits> #include <limits>
#include <memory> #include <memory>
#include <memory_resource> #include <memory_resource>
#include <ostream>
#include <queue> #include <queue>
#include <utility> #include <utility>
#include <vector> #include <vector>
@@ -86,6 +87,7 @@ namespace omath::collision
// Converged if we cant push the face closer than tolerance // Converged if we cant push the face closer than tolerance
if (p_dist - face.d <= params.tolerance) if (p_dist - face.d <= params.tolerance)
{ {
std::println("Vectex size {}, Faces size {}",vertexes.size(), faces.size());
out.normal = face.n; out.normal = face.n;
out.depth = face.d; // along unit normal out.depth = face.d; // along unit normal
out.iterations = it + 1; out.iterations = it + 1;
@@ -118,7 +120,6 @@ namespace omath::collision
if (faces.empty()) if (faces.empty())
return std::nullopt; return std::nullopt;
const auto best = *std::ranges::min_element(faces, [](const auto& first, const auto& second) const auto best = *std::ranges::min_element(faces, [](const auto& first, const auto& second)
{ return first.d < second.d; }); { return first.d < second.d; });
out.normal = best.n; out.normal = best.n;

View File

@@ -1,15 +0,0 @@
//
// Created by Vladislav on 26.01.2026.
//
#pragma once
namespace omath::trigonometry
{
template<class RotationAxisX, class RotationAxisY, class RotationAxisZ>
struct RotationAngles final
{
RotationAxisX rotation_axis_x;
RotationAxisY rotation_axis_y;
RotationAxisZ rotation_axis_z;
};
}

View File

@@ -1,25 +0,0 @@
//
// Created by Copilot on 04.02.2026.
//
#pragma once
#include <cstdint>
#include <filesystem>
#include <optional>
#include <string_view>
#include "section_scan_result.hpp"
namespace omath
{
class MachOPatternScanner final
{
public:
[[nodiscard]]
static std::optional<std::uintptr_t>
scan_for_pattern_in_loaded_module(const void* module_base_address, const std::string_view& pattern,
const std::string_view& target_section_name = "__text");
[[nodiscard]]
static std::optional<SectionScanResult>
scan_for_pattern_in_file(const std::filesystem::path& path_to_file, const std::string_view& pattern,
const std::string_view& target_section_name = "__text");
};
} // namespace omath

View File

@@ -1,69 +0,0 @@
[workspace]
name = "omath"
version = "5.7.0"
description = "Cross-platform modern general purpose math library written in C++23 that suitable for cheat/game development."
authors = [
"orange-cpp <orange_github@proton.me>"
]
license = "Zlib"
license-file = "LICENSE"
readme = "README.md"
documentation = "http://libomath.org"
repository = "https://github.com/orange-cpp/omath"
channels = ["conda-forge"]
platforms = ["win-64", "linux-64", "linux-aarch64", "osx-64", "osx-arm64"]
[tasks]
format = { cwd = "pixi", cmd = "cmake -P fmt.cmake" }
configure = { cmd = "cmake -G Ninja -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DOMATH_USE_AVX2=OFF -DOMATH_IMGUI_INTEGRATION=ON -DOMATH_BUILD_TESTS=ON -DOMATH_BUILD_BENCHMARK=ON -DOMATH_BUILD_EXAMPLES=ON .", depends-on = ["format"] }
build = { cmd = "cmake --build build --config Debug -j", depends-on = ["configure"] }
examples = { cwd = "pixi", cmd = "cmake -DCMAKE_BUILD_TYPE=Debug -P run.examples.cmake", depends-on = ["build"] }
tests = { cwd = "pixi", cmd = "cmake -DCMAKE_BUILD_TYPE=Debug -P run.unit.tests.cmake", depends-on = ["build"] }
benchmark = { cwd = "pixi", cmd = "cmake -DCMAKE_BUILD_TYPE=Debug -P run.benchmark.cmake", depends-on = ["build"] }
[dependencies]
benchmark = ">=1.9.5,<2"
ccache = ">=4.12.2,<5"
cmake = ">=4.2.3,<5"
cmake-format = ">=0.6.13,<0.7"
cxx-compiler = ">=1.11.0,<2"
imgui = ">=1.92.3,<2"
gtest = ">=1.17.0,<2"
glew = ">=2.3.0,<3"
glfw = ">=3.4,<4"
ninja = ">=1.13.2,<2"
[target.linux-64.dependencies]
mesa-libgl-devel-cos7-x86_64 = ">=18.3.4,<19"
xorg-x11-server-xvfb-cos7-x86_64 = ">=1.20.4,<2"
[target.linux-64.activation.env]
__GLX_VENDOR_LIBRARY_NAME = "mesa"
EGL_PLATFORM = "x11"
GLFW_PLATFORM = "x11"
[target.linux-64.tasks]
examples = { cwd = "pixi", cmd = "xvfb-run -a -s '-screen 0 1024x768x24 +extension GLX +render' cmake -DCMAKE_BUILD_TYPE=Debug -P run.examples.cmake", depends-on = ["build"] }
[target.win-64.dependencies]
mesa-libgl-devel-cos7-x86_64 = ">=18.3.4,<19"
[target.osx-64.dependencies]
mesa-libgl-devel-cos7-x86_64 = ">=18.3.4,<19"
[target.osx-arm64.dependencies]
mesa-libgl-devel-cos7-aarch64 = ">=18.3.4,<19"
[target.linux-aarch64.dependencies]
mesa-libgl-devel-cos7-aarch64 = ">=18.3.4,<19"
xorg-x11-server-xvfb-cos7-aarch64 = ">=1.20.4,<2"
[target.linux-aarch64.activation.env]
__GLX_VENDOR_LIBRARY_NAME = "mesa"
EGL_PLATFORM = "x11"
GLFW_PLATFORM = "x11"
[target.linux-aarch64.tasks]
examples = { cwd = "pixi", cmd = "xvfb-run -a -s '-screen 0 1024x768x24 +extension GLX +render' cmake -DCMAKE_BUILD_TYPE=Debug -P run.examples.cmake", depends-on = ["build"] }

View File

@@ -1,36 +0,0 @@
# cmake/Format.cmake
# Find cmake-format executable
find_program(CMAKE_FORMAT_EXECUTABLE NAMES cmake-format)
if(NOT CMAKE_FORMAT_EXECUTABLE)
message(FATAL_ERROR "cmake-format not found. Please install it first.")
endif()
# Get the project root directory (assuming this script is in cmake/
# subdirectory)
get_filename_component(PROJECT_ROOT "../${CMAKE_CURRENT_LIST_DIR}" ABSOLUTE)
# Iterate over all files in the project root
file(GLOB_RECURSE ALL_FILES "${PROJECT_ROOT}/*")
foreach(FILE ${ALL_FILES})
# Basic ignores for common directories to avoid formatting external/build
# files Note: We check for substrings in the full path
if("${FILE}" MATCHES "/\\.git/"
OR "${FILE}" MATCHES "/build/"
OR "${FILE}" MATCHES "/cmake-build/"
OR "${FILE}" MATCHES "/\\.pixi/"
OR "${FILE}" MATCHES "/vcpkg_installed/")
continue()
endif()
get_filename_component(FILENAME "${FILE}" NAME)
# Check if file ends with .cmake or matches exactly to CMakeLists.txt
if("${FILENAME}" STREQUAL "CMakeLists.txt" OR "${FILENAME}" MATCHES "\\.cmake$")
message(STATUS "Formatting ${FILE}")
execute_process(COMMAND ${CMAKE_FORMAT_EXECUTABLE} --config-files
"${PROJECT_ROOT}/.cmake-format" -i "${FILE}")
endif()
endforeach()

View File

@@ -1,63 +0,0 @@
# cmake/run.examples.cmake
# Get the project root directory (assuming this script is in cmake/ subdirectory)
get_filename_component(PROJECT_ROOT "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE)
# Default to Debug if CMAKE_BUILD_TYPE is not specified
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug")
else()
message(STATUS "CMAKE_BUILD_TYPE is set to: ${CMAKE_BUILD_TYPE}")
endif()
# Define the directory where executables are located
# Based on CMakeLists.txt: "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
set(EXAMPLES_BIN_DIR "${PROJECT_ROOT}/out/${CMAKE_BUILD_TYPE}")
if(NOT EXISTS "${EXAMPLES_BIN_DIR}")
message(FATAL_ERROR "Examples binary directory not found: ${EXAMPLES_BIN_DIR}. Please build the project first.")
endif()
message(STATUS "Looking for benchmark executables in: ${EXAMPLES_BIN_DIR}")
# Find all files starting with "omath_benchmark"
file(GLOB EXAMPLE_FILES "${EXAMPLES_BIN_DIR}/omath_benchmark*")
foreach(EXAMPLE_PATH ${EXAMPLE_FILES})
# Skip directories
if(IS_DIRECTORY "${EXAMPLE_PATH}")
continue()
endif()
get_filename_component(FILENAME "${EXAMPLE_PATH}" NAME)
get_filename_component(EXTENSION "${EXAMPLE_PATH}" EXT)
# Filter out potential debug symbols or non-executable artifacts
if(EXTENSION STREQUAL ".pdb" OR EXTENSION STREQUAL ".ilk" OR EXTENSION STREQUAL ".obj")
continue()
endif()
# On Windows, we expect .exe
if(MSVC AND NOT EXTENSION STREQUAL ".exe")
continue()
endif()
# On Linux/macOS, check permissions or just try to run it.
message(STATUS "-------------------------------------------------")
message(STATUS "Running benchmark: ${FILENAME}")
message(STATUS "-------------------------------------------------")
execute_process(
COMMAND "${EXAMPLE_PATH}"
WORKING_DIRECTORY "${PROJECT_ROOT}"
RESULT_VARIABLE EXIT_CODE
)
if(NOT EXIT_CODE EQUAL 0)
message(WARNING "Benchmark ${FILENAME} exited with error code: ${EXIT_CODE}")
else()
message(STATUS "Benchmark ${FILENAME} completed successfully.")
endif()
endforeach()

View File

@@ -1,63 +0,0 @@
# cmake/run.examples.cmake
# Get the project root directory (assuming this script is in cmake/ subdirectory)
get_filename_component(PROJECT_ROOT "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE)
# Default to Debug if CMAKE_BUILD_TYPE is not specified
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug")
else()
message(STATUS "CMAKE_BUILD_TYPE is set to: ${CMAKE_BUILD_TYPE}")
endif()
# Define the directory where executables are located
# Based on CMakeLists.txt: "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
set(EXAMPLES_BIN_DIR "${PROJECT_ROOT}/out/${CMAKE_BUILD_TYPE}")
if(NOT EXISTS "${EXAMPLES_BIN_DIR}")
message(FATAL_ERROR "Examples binary directory not found: ${EXAMPLES_BIN_DIR}. Please build the project first.")
endif()
message(STATUS "Looking for example executables in: ${EXAMPLES_BIN_DIR}")
# Find all files starting with "example_"
file(GLOB EXAMPLE_FILES "${EXAMPLES_BIN_DIR}/example_*")
foreach(EXAMPLE_PATH ${EXAMPLE_FILES})
# Skip directories
if(IS_DIRECTORY "${EXAMPLE_PATH}")
continue()
endif()
get_filename_component(FILENAME "${EXAMPLE_PATH}" NAME)
get_filename_component(EXTENSION "${EXAMPLE_PATH}" EXT)
# Filter out potential debug symbols or non-executable artifacts
if(EXTENSION STREQUAL ".pdb" OR EXTENSION STREQUAL ".ilk" OR EXTENSION STREQUAL ".obj")
continue()
endif()
# On Windows, we expect .exe
if(MSVC AND NOT EXTENSION STREQUAL ".exe")
continue()
endif()
# On Linux/macOS, check permissions or just try to run it.
message(STATUS "-------------------------------------------------")
message(STATUS "Running example: ${FILENAME}")
message(STATUS "-------------------------------------------------")
execute_process(
COMMAND "${EXAMPLE_PATH}"
WORKING_DIRECTORY "${PROJECT_ROOT}"
RESULT_VARIABLE EXIT_CODE
)
if(NOT EXIT_CODE EQUAL 0)
message(WARNING "Example ${FILENAME} exited with error code: ${EXIT_CODE}")
else()
message(STATUS "Example ${FILENAME} completed successfully.")
endif()
endforeach()

View File

@@ -1,63 +0,0 @@
# cmake/run.examples.cmake
# Get the project root directory (assuming this script is in cmake/ subdirectory)
get_filename_component(PROJECT_ROOT "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE)
# Default to Debug if CMAKE_BUILD_TYPE is not specified
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug")
else()
message(STATUS "CMAKE_BUILD_TYPE is set to: ${CMAKE_BUILD_TYPE}")
endif()
# Define the directory where executables are located
# Based on CMakeLists.txt: "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
set(EXAMPLES_BIN_DIR "${PROJECT_ROOT}/out/${CMAKE_BUILD_TYPE}")
if(NOT EXISTS "${EXAMPLES_BIN_DIR}")
message(FATAL_ERROR "Examples binary directory not found: ${EXAMPLES_BIN_DIR}. Please build the project first.")
endif()
message(STATUS "Looking for unit test executables in: ${EXAMPLES_BIN_DIR}")
# Find all files starting with "unit_tests"
file(GLOB EXAMPLE_FILES "${EXAMPLES_BIN_DIR}/unit_tests*")
foreach(EXAMPLE_PATH ${EXAMPLE_FILES})
# Skip directories
if(IS_DIRECTORY "${EXAMPLE_PATH}")
continue()
endif()
get_filename_component(FILENAME "${EXAMPLE_PATH}" NAME)
get_filename_component(EXTENSION "${EXAMPLE_PATH}" EXT)
# Filter out potential debug symbols or non-executable artifacts
if(EXTENSION STREQUAL ".pdb" OR EXTENSION STREQUAL ".ilk" OR EXTENSION STREQUAL ".obj")
continue()
endif()
# On Windows, we expect .exe
if(MSVC AND NOT EXTENSION STREQUAL ".exe")
continue()
endif()
# On Linux/macOS, check permissions or just try to run it.
message(STATUS "-------------------------------------------------")
message(STATUS "Running unit_tests: ${FILENAME}")
message(STATUS "-------------------------------------------------")
execute_process(
COMMAND "${EXAMPLE_PATH}"
WORKING_DIRECTORY "${PROJECT_ROOT}"
RESULT_VARIABLE EXIT_CODE
)
if(NOT EXIT_CODE EQUAL 0)
message(WARNING "Example ${FILENAME} exited with error code: ${EXIT_CODE}")
else()
message(STATUS "Example ${FILENAME} completed successfully.")
endif()
endforeach()

View File

@@ -1,349 +0,0 @@
//
// Created by Copilot on 04.02.2026.
//
#include "omath/utility/macho_pattern_scan.hpp"
#include "omath/utility/pattern_scan.hpp"
#include <cstring>
#include <fstream>
#include <variant>
#include <vector>
#pragma pack(push, 1)
namespace
{
// Mach-O magic numbers
constexpr std::uint32_t mh_magic_32 = 0xFEEDFACE;
constexpr std::uint32_t mh_magic_64 = 0xFEEDFACF;
constexpr std::uint32_t mh_cigam_32 = 0xCEFAEDFE; // Byte-swapped 32-bit
constexpr std::uint32_t mh_cigam_64 = 0xCFFAEDFE; // Byte-swapped 64-bit
// Load command types
constexpr std::uint32_t lc_segment = 0x1;
constexpr std::uint32_t lc_segment_64 = 0x19;
// ReSharper disable CppDeclaratorNeverUsed
// Mach-O header for 32-bit
struct MachHeader32 final
{
std::uint32_t magic;
std::uint32_t cputype;
std::uint32_t cpusubtype;
std::uint32_t filetype;
std::uint32_t ncmds;
std::uint32_t sizeofcmds;
std::uint32_t flags;
};
// Mach-O header for 64-bit
struct MachHeader64 final
{
std::uint32_t magic;
std::uint32_t cputype;
std::uint32_t cpusubtype;
std::uint32_t filetype;
std::uint32_t ncmds;
std::uint32_t sizeofcmds;
std::uint32_t flags;
std::uint32_t reserved;
};
// Load command header
struct LoadCommand final
{
std::uint32_t cmd;
std::uint32_t cmdsize;
};
// Segment command for 32-bit
struct SegmentCommand32 final
{
std::uint32_t cmd;
std::uint32_t cmdsize;
char segname[16];
std::uint32_t vmaddr;
std::uint32_t vmsize;
std::uint32_t fileoff;
std::uint32_t filesize;
std::uint32_t maxprot;
std::uint32_t initprot;
std::uint32_t nsects;
std::uint32_t flags;
};
// Segment command for 64-bit
struct SegmentCommand64 final
{
std::uint32_t cmd;
std::uint32_t cmdsize;
char segname[16];
std::uint64_t vmaddr;
std::uint64_t vmsize;
std::uint64_t fileoff;
std::uint64_t filesize;
std::uint32_t maxprot;
std::uint32_t initprot;
std::uint32_t nsects;
std::uint32_t flags;
};
// Section for 32-bit
struct Section32 final
{
char sectname[16];
char segname[16];
std::uint32_t addr;
std::uint32_t size;
std::uint32_t offset;
std::uint32_t align;
std::uint32_t reloff;
std::uint32_t nreloc;
std::uint32_t flags;
std::uint32_t reserved1;
std::uint32_t reserved2;
};
// Section for 64-bit
struct Section64 final
{
char sectname[16];
char segname[16];
std::uint64_t addr;
std::uint64_t size;
std::uint32_t offset;
std::uint32_t align;
std::uint32_t reloff;
std::uint32_t nreloc;
std::uint32_t flags;
std::uint32_t reserved1;
std::uint32_t reserved2;
std::uint32_t reserved3;
};
// ReSharper enable CppDeclaratorNeverUsed
#pragma pack(pop)
enum class MachOArch : std::int8_t
{
x32,
x64,
};
struct ExtractedSection final
{
std::uintptr_t virtual_base_addr{};
std::uintptr_t raw_base_addr{};
std::vector<std::byte> data;
};
[[nodiscard]]
std::optional<MachOArch> get_macho_arch(std::fstream& file)
{
std::uint32_t magic{};
const std::streampos backup_pos = file.tellg();
file.seekg(0, std::ios_base::beg);
file.read(reinterpret_cast<char*>(&magic), sizeof(magic));
file.seekg(backup_pos, std::ios_base::beg);
if (magic == mh_magic_64 || magic == mh_cigam_64)
return MachOArch::x64;
if (magic == mh_magic_32 || magic == mh_cigam_32)
return MachOArch::x32;
return std::nullopt;
}
[[nodiscard]]
bool is_macho_file(std::fstream& file)
{
return get_macho_arch(file).has_value();
}
[[nodiscard]]
std::string_view get_section_name(const char* sectname)
{
// Mach-O section names are fixed 16-byte arrays, not necessarily null-terminated
return std::string_view(sectname, std::min(std::strlen(sectname), std::size_t{16}));
}
template<typename HeaderType, typename SegmentType, typename SectionType, std::uint32_t segment_cmd>
std::optional<ExtractedSection> extract_section_impl(std::fstream& file, const std::string_view& section_name)
{
HeaderType header{};
file.seekg(0, std::ios_base::beg);
if (!file.read(reinterpret_cast<char*>(&header), sizeof(header))) [[unlikely]]
return std::nullopt;
std::streamoff cmd_offset = sizeof(header);
for (std::uint32_t i = 0; i < header.ncmds; ++i)
{
LoadCommand lc{};
file.seekg(cmd_offset, std::ios_base::beg);
if (!file.read(reinterpret_cast<char*>(&lc), sizeof(lc))) [[unlikely]]
return std::nullopt;
if (lc.cmd != segment_cmd)
{
cmd_offset += static_cast<std::streamoff>(lc.cmdsize);
continue;
}
SegmentType segment{};
file.seekg(cmd_offset, std::ios_base::beg);
if (!file.read(reinterpret_cast<char*>(&segment), sizeof(segment))) [[unlikely]]
return std::nullopt;
if (!segment.nsects)
{
cmd_offset += static_cast<std::streamoff>(lc.cmdsize);
continue;
}
std::streamoff sect_offset = cmd_offset + static_cast<std::streamoff>(sizeof(segment));
for (std::uint32_t j = 0; j < segment.nsects; ++j)
{
SectionType section{};
file.seekg(sect_offset, std::ios_base::beg);
if (!file.read(reinterpret_cast<char*>(&section), sizeof(section))) [[unlikely]]
return std::nullopt;
if (get_section_name(section.sectname) != section_name)
{
sect_offset += static_cast<std::streamoff>(sizeof(section));
continue;
}
ExtractedSection out;
out.virtual_base_addr = static_cast<std::uintptr_t>(section.addr);
out.raw_base_addr = static_cast<std::uintptr_t>(section.offset);
out.data.resize(static_cast<std::size_t>(section.size));
file.seekg(static_cast<std::streamoff>(section.offset), std::ios_base::beg);
if (!file.read(reinterpret_cast<char*>(out.data.data()), static_cast<std::streamsize>(out.data.size())))
[[unlikely]]
return std::nullopt;
return out;
}
}
return std::nullopt;
}
[[nodiscard]]
std::optional<ExtractedSection> get_macho_section_by_name(const std::filesystem::path& path,
const std::string_view& section_name)
{
std::fstream file(path, std::ios::binary | std::ios::in);
if (!file.is_open()) [[unlikely]]
return std::nullopt;
if (!is_macho_file(file)) [[unlikely]]
return std::nullopt;
const auto arch = get_macho_arch(file);
if (!arch.has_value()) [[unlikely]]
return std::nullopt;
if (arch.value() == MachOArch::x64)
return extract_section_impl<MachHeader64, SegmentCommand64, Section64, lc_segment_64>(file, section_name);
return extract_section_impl<MachHeader32, SegmentCommand32, Section32, lc_segment>(file, section_name);
}
template<typename HeaderType, typename SegmentType, typename SectionType, std::uint32_t segment_cmd>
std::optional<std::uintptr_t> scan_in_module_impl(const std::byte* base, const std::string_view pattern,
const std::string_view target_section_name)
{
const auto* header = reinterpret_cast<const HeaderType*>(base);
std::size_t cmd_offset = sizeof(HeaderType);
for (std::uint32_t i = 0; i < header->ncmds; ++i)
{
const auto* lc = reinterpret_cast<const LoadCommand*>(base + cmd_offset);
if (lc->cmd != segment_cmd)
{
cmd_offset += lc->cmdsize;
continue;
}
const auto* segment = reinterpret_cast<const SegmentType*>(base + cmd_offset);
std::size_t sect_offset = cmd_offset + sizeof(SegmentType);
for (std::uint32_t j = 0; j < segment->nsects; ++j)
{
const auto* section = reinterpret_cast<const SectionType*>(base + sect_offset);
if (get_section_name(section->sectname) != target_section_name && section->size > 0)
{
sect_offset += sizeof(SectionType);
continue;
}
const auto* section_begin = base + static_cast<std::size_t>(section->addr);
const auto* section_end = section_begin + static_cast<std::size_t>(section->size);
const auto scan_result = omath::PatternScanner::scan_for_pattern(section_begin, section_end, pattern);
if (scan_result != section_end)
return reinterpret_cast<std::uintptr_t>(scan_result);
}
}
return std::nullopt;
}
} // namespace
namespace omath
{
std::optional<std::uintptr_t>
MachOPatternScanner::scan_for_pattern_in_loaded_module(const void* module_base_address,
const std::string_view& pattern,
const std::string_view& target_section_name)
{
if (module_base_address == nullptr) [[unlikely]]
return std::nullopt;
const auto* base = static_cast<const std::byte*>(module_base_address);
// Read magic to determine architecture
std::uint32_t magic{};
std::memcpy(&magic, base, sizeof(magic));
if (magic == mh_magic_64 || magic == mh_cigam_64)
return scan_in_module_impl<MachHeader64, SegmentCommand64, Section64, lc_segment_64>(base, pattern,
target_section_name);
if (magic == mh_magic_32 || magic == mh_cigam_32)
return scan_in_module_impl<MachHeader32, SegmentCommand32, Section32, lc_segment>(base, pattern,
target_section_name);
return std::nullopt;
}
std::optional<SectionScanResult>
MachOPatternScanner::scan_for_pattern_in_file(const std::filesystem::path& path_to_file,
const std::string_view& pattern,
const std::string_view& target_section_name)
{
const auto macho_section = get_macho_section_by_name(path_to_file, target_section_name);
if (!macho_section.has_value()) [[unlikely]]
return std::nullopt;
const auto scan_result =
PatternScanner::scan_for_pattern(macho_section->data.cbegin(), macho_section->data.cend(), pattern);
if (scan_result == macho_section->data.cend())
return std::nullopt;
const auto offset = std::distance(macho_section->data.begin(), scan_result);
return SectionScanResult{.virtual_base_addr = macho_section->virtual_base_addr,
.raw_base_addr = macho_section->raw_base_addr,
.target_offset = offset};
}
} // namespace omath

View File

@@ -237,7 +237,7 @@ namespace
variant); variant);
} }
struct ExtractedSection final struct ExtractedSection
{ {
std::uintptr_t virtual_base_addr; std::uintptr_t virtual_base_addr;
std::uintptr_t raw_base_addr; std::uintptr_t raw_base_addr;

View File

@@ -7,15 +7,14 @@ include(GoogleTest)
file(GLOB_RECURSE UNIT_TESTS_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") file(GLOB_RECURSE UNIT_TESTS_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
add_executable(${PROJECT_NAME} ${UNIT_TESTS_SOURCES}) add_executable(${PROJECT_NAME} ${UNIT_TESTS_SOURCES})
set_target_properties( set_target_properties(${PROJECT_NAME} PROPERTIES
${PROJECT_NAME} ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}" CXX_STANDARD 23
CXX_STANDARD 23 CXX_STANDARD_REQUIRED ON)
CXX_STANDARD_REQUIRED ON)
if(TARGET gtest) # GTest is being linked as submodule if (TARGET gtest) # GTest is being linked as submodule
target_link_libraries(${PROJECT_NAME} PRIVATE gtest gtest_main omath::omath) target_link_libraries(${PROJECT_NAME} PRIVATE gtest gtest_main omath::omath)
else() # GTest is being linked as vcpkg package else() # GTest is being linked as vcpkg package
find_package(GTest CONFIG REQUIRED) find_package(GTest CONFIG REQUIRED)
@@ -31,8 +30,7 @@ if(OMATH_ENABLE_VALGRIND)
omath_setup_valgrind(${PROJECT_NAME}) omath_setup_valgrind(${PROJECT_NAME})
endif() endif()
# Skip test discovery for Android/iOS builds or when cross-compiling - binaries # Skip test discovery for Android/iOS builds or when cross-compiling - binaries cannot run on host
# cannot run on host if (NOT (ANDROID OR IOS OR EMSCRIPTEN))
if(NOT (ANDROID OR IOS OR EMSCRIPTEN))
gtest_discover_tests(${PROJECT_NAME}) gtest_discover_tests(${PROJECT_NAME})
endif() endif()

View File

@@ -1,357 +0,0 @@
//
// Created by Copilot on 04.02.2026.
//
// Unit tests for MachOPatternScanner
#include <gtest/gtest.h>
#include <omath/utility/macho_pattern_scan.hpp>
#include <cstdint>
#include <cstring>
#include <fstream>
#include <vector>
using namespace omath;
namespace
{
// Mach-O magic numbers
constexpr std::uint32_t mh_magic_64 = 0xFEEDFACF;
constexpr std::uint32_t mh_magic_32 = 0xFEEDFACE;
constexpr std::uint32_t lc_segment = 0x1;
constexpr std::uint32_t lc_segment_64 = 0x19;
#pragma pack(push, 1)
struct MachHeader64
{
std::uint32_t magic;
std::uint32_t cputype;
std::uint32_t cpusubtype;
std::uint32_t filetype;
std::uint32_t ncmds;
std::uint32_t sizeofcmds;
std::uint32_t flags;
std::uint32_t reserved;
};
struct MachHeader32
{
std::uint32_t magic;
std::uint32_t cputype;
std::uint32_t cpusubtype;
std::uint32_t filetype;
std::uint32_t ncmds;
std::uint32_t sizeofcmds;
std::uint32_t flags;
};
struct SegmentCommand64
{
std::uint32_t cmd;
std::uint32_t cmdsize;
char segname[16];
std::uint64_t vmaddr;
std::uint64_t vmsize;
std::uint64_t fileoff;
std::uint64_t filesize;
std::uint32_t maxprot;
std::uint32_t initprot;
std::uint32_t nsects;
std::uint32_t flags;
};
struct SegmentCommand32
{
std::uint32_t cmd;
std::uint32_t cmdsize;
char segname[16];
std::uint32_t vmaddr;
std::uint32_t vmsize;
std::uint32_t fileoff;
std::uint32_t filesize;
std::uint32_t maxprot;
std::uint32_t initprot;
std::uint32_t nsects;
std::uint32_t flags;
};
struct Section64
{
char sectname[16];
char segname[16];
std::uint64_t addr;
std::uint64_t size;
std::uint32_t offset;
std::uint32_t align;
std::uint32_t reloff;
std::uint32_t nreloc;
std::uint32_t flags;
std::uint32_t reserved1;
std::uint32_t reserved2;
std::uint32_t reserved3;
};
struct Section32
{
char sectname[16];
char segname[16];
std::uint32_t addr;
std::uint32_t size;
std::uint32_t offset;
std::uint32_t align;
std::uint32_t reloff;
std::uint32_t nreloc;
std::uint32_t flags;
std::uint32_t reserved1;
std::uint32_t reserved2;
};
#pragma pack(pop)
// Helper function to create a minimal 64-bit Mach-O file with a __text section
bool write_minimal_macho64_file(const std::string& path, const std::vector<std::uint8_t>& section_bytes)
{
std::ofstream f(path, std::ios::binary);
if (!f.is_open())
return false;
// Calculate sizes
constexpr std::size_t header_size = sizeof(MachHeader64);
constexpr std::size_t segment_size = sizeof(SegmentCommand64);
constexpr std::size_t section_size = sizeof(Section64);
constexpr std::size_t load_cmd_size = segment_size + section_size;
// Section data will start after headers
const std::size_t section_offset = header_size + load_cmd_size;
// Create Mach-O header
MachHeader64 header{};
header.magic = mh_magic_64;
header.cputype = 0x01000007; // CPU_TYPE_X86_64
header.cpusubtype = 0x3; // CPU_SUBTYPE_X86_64_ALL
header.filetype = 0x2; // MH_EXECUTE
header.ncmds = 1;
header.sizeofcmds = static_cast<std::uint32_t>(load_cmd_size);
header.flags = 0;
header.reserved = 0;
f.write(reinterpret_cast<const char*>(&header), sizeof(header));
// Create segment command
SegmentCommand64 segment{};
segment.cmd = lc_segment_64;
segment.cmdsize = static_cast<std::uint32_t>(load_cmd_size);
std::strncpy(segment.segname, "__TEXT", 16);
segment.vmaddr = 0x100000000;
segment.vmsize = section_bytes.size();
segment.fileoff = section_offset;
segment.filesize = section_bytes.size();
segment.maxprot = 7; // VM_PROT_ALL
segment.initprot = 5; // VM_PROT_READ | VM_PROT_EXECUTE
segment.nsects = 1;
segment.flags = 0;
f.write(reinterpret_cast<const char*>(&segment), sizeof(segment));
// Create section
Section64 section{};
std::strncpy(section.sectname, "__text", 16);
std::strncpy(section.segname, "__TEXT", 16);
section.addr = 0x100000000;
section.size = section_bytes.size();
section.offset = static_cast<std::uint32_t>(section_offset);
section.align = 0;
section.reloff = 0;
section.nreloc = 0;
section.flags = 0;
section.reserved1 = 0;
section.reserved2 = 0;
section.reserved3 = 0;
f.write(reinterpret_cast<const char*>(&section), sizeof(section));
// Write section data
f.write(reinterpret_cast<const char*>(section_bytes.data()), static_cast<std::streamsize>(section_bytes.size()));
f.close();
return true;
}
// Helper function to create a minimal 32-bit Mach-O file with a __text section
bool write_minimal_macho32_file(const std::string& path, const std::vector<std::uint8_t>& section_bytes)
{
std::ofstream f(path, std::ios::binary);
if (!f.is_open())
return false;
// Calculate sizes
constexpr std::size_t header_size = sizeof(MachHeader32);
constexpr std::size_t segment_size = sizeof(SegmentCommand32);
constexpr std::size_t section_size = sizeof(Section32);
constexpr std::size_t load_cmd_size = segment_size + section_size;
// Section data will start after headers
const std::size_t section_offset = header_size + load_cmd_size;
// Create Mach-O header
MachHeader32 header{};
header.magic = mh_magic_32;
header.cputype = 0x7; // CPU_TYPE_X86
header.cpusubtype = 0x3; // CPU_SUBTYPE_X86_ALL
header.filetype = 0x2; // MH_EXECUTE
header.ncmds = 1;
header.sizeofcmds = static_cast<std::uint32_t>(load_cmd_size);
header.flags = 0;
f.write(reinterpret_cast<const char*>(&header), sizeof(header));
// Create segment command
SegmentCommand32 segment{};
segment.cmd = lc_segment;
segment.cmdsize = static_cast<std::uint32_t>(load_cmd_size);
std::strncpy(segment.segname, "__TEXT", 16);
segment.vmaddr = 0x1000;
segment.vmsize = static_cast<std::uint32_t>(section_bytes.size());
segment.fileoff = static_cast<std::uint32_t>(section_offset);
segment.filesize = static_cast<std::uint32_t>(section_bytes.size());
segment.maxprot = 7; // VM_PROT_ALL
segment.initprot = 5; // VM_PROT_READ | VM_PROT_EXECUTE
segment.nsects = 1;
segment.flags = 0;
f.write(reinterpret_cast<const char*>(&segment), sizeof(segment));
// Create section
Section32 section{};
std::strncpy(section.sectname, "__text", 16);
std::strncpy(section.segname, "__TEXT", 16);
section.addr = 0x1000;
section.size = static_cast<std::uint32_t>(section_bytes.size());
section.offset = static_cast<std::uint32_t>(section_offset);
section.align = 0;
section.reloff = 0;
section.nreloc = 0;
section.flags = 0;
section.reserved1 = 0;
section.reserved2 = 0;
f.write(reinterpret_cast<const char*>(&section), sizeof(section));
// Write section data
f.write(reinterpret_cast<const char*>(section_bytes.data()), static_cast<std::streamsize>(section_bytes.size()));
f.close();
return true;
}
} // namespace
// Test scanning for a pattern that exists in a 64-bit Mach-O file
TEST(unit_test_macho_pattern_scan_file, ScanFindsPattern64)
{
constexpr std::string_view path = "./test_minimal_macho64.bin";
const std::vector<std::uint8_t> bytes = {0x55, 0x48, 0x89, 0xE5, 0x90, 0x90}; // push rbp; mov rbp, rsp; nop; nop
ASSERT_TRUE(write_minimal_macho64_file(path.data(), bytes));
const auto res = MachOPatternScanner::scan_for_pattern_in_file(path, "55 48 89 E5", "__text");
EXPECT_TRUE(res.has_value());
if (res.has_value())
{
EXPECT_EQ(res->target_offset, 0);
}
}
// Test scanning for a pattern that exists in a 32-bit Mach-O file
TEST(unit_test_macho_pattern_scan_file, ScanFindsPattern32)
{
constexpr std::string_view path = "./test_minimal_macho32.bin";
const std::vector<std::uint8_t> bytes = {0x55, 0x89, 0xE5, 0x90, 0x90}; // push ebp; mov ebp, esp; nop; nop
ASSERT_TRUE(write_minimal_macho32_file(path.data(), bytes));
const auto res = MachOPatternScanner::scan_for_pattern_in_file(path, "55 89 E5", "__text");
EXPECT_TRUE(res.has_value());
if (res.has_value())
{
EXPECT_EQ(res->target_offset, 0);
}
}
// Test scanning for a pattern that does not exist
TEST(unit_test_macho_pattern_scan_file, ScanMissingPattern)
{
constexpr std::string_view path = "./test_minimal_macho_missing.bin";
const std::vector<std::uint8_t> bytes = {0x00, 0x01, 0x02, 0x03};
ASSERT_TRUE(write_minimal_macho64_file(path.data(), bytes));
const auto res = MachOPatternScanner::scan_for_pattern_in_file(path, "FF EE DD", "__text");
EXPECT_FALSE(res.has_value());
}
// Test scanning for a pattern at a non-zero offset
TEST(unit_test_macho_pattern_scan_file, ScanPatternAtOffset)
{
constexpr std::string_view path = "./test_minimal_macho_offset.bin";
const std::vector<std::uint8_t> bytes = {0x90, 0x90, 0x90, 0x55, 0x48, 0x89, 0xE5}; // nops then pattern
ASSERT_TRUE(write_minimal_macho64_file(path.data(), bytes));
const auto res = MachOPatternScanner::scan_for_pattern_in_file(path, "55 48 89 E5", "__text");
EXPECT_TRUE(res.has_value());
if (res.has_value())
{
EXPECT_EQ(res->target_offset, 3);
}
}
// Test scanning with wildcards
TEST(unit_test_macho_pattern_scan_file, ScanWithWildcard)
{
constexpr std::string_view path = "./test_minimal_macho_wildcard.bin";
const std::vector<std::uint8_t> bytes = {0x55, 0x48, 0x89, 0xE5, 0x90};
ASSERT_TRUE(write_minimal_macho64_file(path.data(), bytes));
const auto res = MachOPatternScanner::scan_for_pattern_in_file(path, "55 ? 89 E5", "__text");
EXPECT_TRUE(res.has_value());
}
// Test scanning a non-existent file
TEST(unit_test_macho_pattern_scan_file, ScanNonExistentFile)
{
const auto res = MachOPatternScanner::scan_for_pattern_in_file("/non/existent/file.bin", "55 48", "__text");
EXPECT_FALSE(res.has_value());
}
// Test scanning an invalid (non-Mach-O) file
TEST(unit_test_macho_pattern_scan_file, ScanInvalidFile)
{
constexpr std::string_view path = "./test_invalid_macho.bin";
std::ofstream f(path.data(), std::ios::binary);
const std::vector<std::uint8_t> garbage = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
f.write(reinterpret_cast<const char*>(garbage.data()), static_cast<std::streamsize>(garbage.size()));
f.close();
const auto res = MachOPatternScanner::scan_for_pattern_in_file(path, "55 48", "__text");
EXPECT_FALSE(res.has_value());
}
// Test scanning for a non-existent section
TEST(unit_test_macho_pattern_scan_file, ScanNonExistentSection)
{
constexpr std::string_view path = "./test_minimal_macho_nosect.bin";
const std::vector<std::uint8_t> bytes = {0x55, 0x48, 0x89, 0xE5};
ASSERT_TRUE(write_minimal_macho64_file(path.data(), bytes));
const auto res = MachOPatternScanner::scan_for_pattern_in_file(path, "55 48", "__nonexistent");
EXPECT_FALSE(res.has_value());
}
// Test scanning with null module base address
TEST(unit_test_macho_pattern_scan_loaded, ScanNullModule)
{
const auto res = MachOPatternScanner::scan_for_pattern_in_loaded_module(nullptr, "55 48", "__text");
EXPECT_FALSE(res.has_value());
}
// Test scanning in loaded module with invalid magic
TEST(unit_test_macho_pattern_scan_loaded, ScanInvalidMagic)
{
std::vector<std::uint8_t> invalid_data(256, 0x00);
const auto res = MachOPatternScanner::scan_for_pattern_in_loaded_module(invalid_data.data(), "55 48", "__text");
EXPECT_FALSE(res.has_value());
}

View File

@@ -30,7 +30,8 @@
"description": "Build benchmarks", "description": "Build benchmarks",
"dependencies": [ "dependencies": [
"glfw3", "glfw3",
"glew" "glew",
"tinygltf"
] ]
}, },
"imgui": { "imgui": {