mirror of
https://github.com/RapidAI/RapidOCR.git
synced 2026-11-11 21:40:52 +08:00
Expose the PP-OCRv6 engine through a stable C ABI and installable shared and static libraries, plus a ctypes Python package that follows the RapidOCR call shape. Keep AVX-512 out of the AVX2 object file and speed up GEMM accumulate and the AArch64 GEMM tile. Co-authored-by: Daniel <znsoft@163.com>
270 lines
13 KiB
CMake
270 lines
13 KiB
CMake
cmake_minimum_required(VERSION 3.20)
|
|
project(ppocr_cpp VERSION 5.0.0 LANGUAGES C CXX)
|
|
|
|
include(GNUInstallDirs)
|
|
include(CMakePackageConfigHelpers)
|
|
|
|
option(PPOCR_BUILD_SHARED "Build the shared library" ON)
|
|
option(PPOCR_BUILD_STATIC "Build the static library" ON)
|
|
option(PPOCR_BUILD_EXAMPLES "Build examples and smoke tools" ON)
|
|
option(PPOCR_BUILD_TESTS "Build the C API smoke test" ON)
|
|
|
|
if(NOT PPOCR_BUILD_SHARED AND NOT PPOCR_BUILD_STATIC)
|
|
message(FATAL_ERROR "Enable PPOCR_BUILD_SHARED and/or PPOCR_BUILD_STATIC")
|
|
endif()
|
|
|
|
set(PPOCR_SOURCES
|
|
src/kernels.cpp
|
|
src/onnx_lite.cpp
|
|
src/ppocr.cpp
|
|
src/vulkan_backend.cpp
|
|
src/ppocr_c_api.cpp
|
|
)
|
|
|
|
add_library(ppocr_objects OBJECT ${PPOCR_SOURCES})
|
|
set_target_properties(ppocr_objects PROPERTIES
|
|
POSITION_INDEPENDENT_CODE ON
|
|
CXX_VISIBILITY_PRESET hidden
|
|
VISIBILITY_INLINES_HIDDEN ON)
|
|
target_compile_definitions(ppocr_objects PRIVATE PPOCR_BUILDING_SHARED)
|
|
target_include_directories(ppocr_objects PUBLIC
|
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
|
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
|
|
target_compile_features(ppocr_objects PUBLIC cxx_std_20)
|
|
|
|
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/third_party/Vulkan-Headers/include/vulkan/vulkan.h")
|
|
target_include_directories(ppocr_objects PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/Vulkan-Headers/include)
|
|
target_compile_definitions(ppocr_objects PRIVATE PPOCR_HAS_VULKAN_HEADERS=1)
|
|
endif()
|
|
# The vendored glslang.exe is a Windows compiler. On Linux/ARM use a host
|
|
# glslangValidator so the build does not try to execute a PE binary.
|
|
if(WIN32 AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/third_party/glslang/bin/glslang.exe")
|
|
set(PPOCR_GLSLANG "${CMAKE_CURRENT_SOURCE_DIR}/third_party/glslang/bin/glslang.exe")
|
|
else()
|
|
find_program(PPOCR_GLSLANG NAMES glslangValidator glslang)
|
|
endif()
|
|
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/third_party/Vulkan-Headers/include/vulkan/vulkan.h" AND PPOCR_GLSLANG)
|
|
set(PPOCR_VULKAN_GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")
|
|
set(PPOCR_VULKAN_SPV "${PPOCR_VULKAN_GENERATED_DIR}/vulkan_binary.spv")
|
|
set(PPOCR_VULKAN_SPV_HEADER "${PPOCR_VULKAN_GENERATED_DIR}/vulkan_binary_spv.hpp")
|
|
set(PPOCR_VULKAN_TAIL_SPV "${PPOCR_VULKAN_GENERATED_DIR}/vulkan_depthwise_tail.spv")
|
|
set(PPOCR_VULKAN_TAIL_SPV_HEADER "${PPOCR_VULKAN_GENERATED_DIR}/vulkan_depthwise_tail_spv.hpp")
|
|
set(PPOCR_VULKAN_POINTWISE_TAIL_SPV "${PPOCR_VULKAN_GENERATED_DIR}/vulkan_pointwise_tail.spv")
|
|
set(PPOCR_VULKAN_POINTWISE_TAIL_SPV_HEADER "${PPOCR_VULKAN_GENERATED_DIR}/vulkan_pointwise_tail_spv.hpp")
|
|
add_custom_command(
|
|
OUTPUT "${PPOCR_VULKAN_SPV}" "${PPOCR_VULKAN_SPV_HEADER}" "${PPOCR_VULKAN_TAIL_SPV}" "${PPOCR_VULKAN_TAIL_SPV_HEADER}" "${PPOCR_VULKAN_POINTWISE_TAIL_SPV}" "${PPOCR_VULKAN_POINTWISE_TAIL_SPV_HEADER}"
|
|
COMMAND ${CMAKE_COMMAND} -E make_directory "${PPOCR_VULKAN_GENERATED_DIR}"
|
|
COMMAND "${PPOCR_GLSLANG}" -V -S comp -o "${PPOCR_VULKAN_SPV}" "${CMAKE_CURRENT_SOURCE_DIR}/src/vulkan_binary.comp"
|
|
COMMAND "${PPOCR_GLSLANG}" -V -S comp -o "${PPOCR_VULKAN_TAIL_SPV}" "${CMAKE_CURRENT_SOURCE_DIR}/src/vulkan_depthwise_tail.comp"
|
|
COMMAND "${PPOCR_GLSLANG}" -V -S comp -o "${PPOCR_VULKAN_POINTWISE_TAIL_SPV}" "${CMAKE_CURRENT_SOURCE_DIR}/src/vulkan_pointwise_tail.comp"
|
|
COMMAND ${CMAKE_COMMAND} -DINPUT=${PPOCR_VULKAN_SPV} -DOUTPUT=${PPOCR_VULKAN_SPV_HEADER} -DNAME=kVulkanBinarySpv -P "${CMAKE_CURRENT_SOURCE_DIR}/src/embed_spirv.cmake"
|
|
COMMAND ${CMAKE_COMMAND} -DINPUT=${PPOCR_VULKAN_TAIL_SPV} -DOUTPUT=${PPOCR_VULKAN_TAIL_SPV_HEADER} -DNAME=kVulkanDepthwiseTailSpv -P "${CMAKE_CURRENT_SOURCE_DIR}/src/embed_spirv.cmake"
|
|
COMMAND ${CMAKE_COMMAND} -DINPUT=${PPOCR_VULKAN_POINTWISE_TAIL_SPV} -DOUTPUT=${PPOCR_VULKAN_POINTWISE_TAIL_SPV_HEADER} -DNAME=kVulkanPointwiseTailSpv -P "${CMAKE_CURRENT_SOURCE_DIR}/src/embed_spirv.cmake"
|
|
COMMAND ${CMAKE_COMMAND} -E touch "${PPOCR_VULKAN_SPV_HEADER}"
|
|
COMMAND ${CMAKE_COMMAND} -E touch "${PPOCR_VULKAN_TAIL_SPV_HEADER}"
|
|
COMMAND ${CMAKE_COMMAND} -E touch "${PPOCR_VULKAN_POINTWISE_TAIL_SPV_HEADER}"
|
|
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/vulkan_binary.comp" "${CMAKE_CURRENT_SOURCE_DIR}/src/vulkan_depthwise_tail.comp" "${CMAKE_CURRENT_SOURCE_DIR}/src/vulkan_pointwise_tail.comp" "${CMAKE_CURRENT_SOURCE_DIR}/src/embed_spirv.cmake" "${PPOCR_GLSLANG}"
|
|
VERBATIM)
|
|
add_custom_target(ppocr_vulkan_shader DEPENDS "${PPOCR_VULKAN_SPV_HEADER}" "${PPOCR_VULKAN_TAIL_SPV_HEADER}" "${PPOCR_VULKAN_POINTWISE_TAIL_SPV_HEADER}")
|
|
add_dependencies(ppocr_objects ppocr_vulkan_shader)
|
|
target_include_directories(ppocr_objects PRIVATE "${PPOCR_VULKAN_GENERATED_DIR}")
|
|
target_compile_definitions(ppocr_objects PRIVATE PPOCR_HAS_VULKAN_KERNELS=1)
|
|
endif()
|
|
|
|
if(MSVC)
|
|
target_compile_options(ppocr_objects PRIVATE /W4 /permissive- /O2 /fp:fast)
|
|
else()
|
|
target_compile_options(ppocr_objects PRIVATE -Wall -Wextra -Wpedantic -O3 -ffast-math -funroll-loops)
|
|
endif()
|
|
|
|
string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR};${CMAKE_GENERATOR_PLATFORM}" PPOCR_CPU)
|
|
if(NOT MSVC AND PPOCR_CPU MATCHES "x86_64|amd64|x64|i[3-6]86")
|
|
# Baseline translation units stay SSE2. Auto-vectorization must not emit
|
|
# AVX or AVX-512, or an AVX2-only machine will SIGILL inside the fallback.
|
|
set_source_files_properties(
|
|
src/kernels.cpp src/onnx_lite.cpp src/ppocr.cpp src/vulkan_backend.cpp src/ppocr_c_api.cpp
|
|
PROPERTIES COMPILE_OPTIONS "-mno-avx;-mno-avx2;-mno-avx512f")
|
|
endif()
|
|
|
|
# AVX2 is isolated in its own object file. kernels.cpp remains baseline x86,
|
|
# so CPUs without AVX/AVX2 can safely take its scalar fallback at runtime.
|
|
if(PPOCR_CPU MATCHES "x86_64|amd64|x64|i[3-6]86")
|
|
target_sources(ppocr_objects PRIVATE src/kernels_avx2.cpp)
|
|
target_compile_definitions(ppocr_objects PRIVATE PPOCR_HAS_AVX2_KERNELS=1)
|
|
if(MSVC)
|
|
set_source_files_properties(src/kernels_avx2.cpp PROPERTIES COMPILE_OPTIONS "/arch:AVX2;/fp:fast")
|
|
else()
|
|
# -mno-avx512* is last-wins together with -mavx2 and forbids the compiler
|
|
# from rewriting this file with EVEX/zmm encodings.
|
|
set_source_files_properties(src/kernels_avx2.cpp PROPERTIES COMPILE_OPTIONS
|
|
"-mavx2;-mfma;-mno-avx512f;-mno-avx512bw;-mno-avx512vl;-mno-avx512dq")
|
|
endif()
|
|
target_sources(ppocr_objects PRIVATE src/kernels_avx512.cpp)
|
|
target_compile_definitions(ppocr_objects PRIVATE PPOCR_HAS_AVX512_KERNELS=1)
|
|
if(MSVC)
|
|
set_source_files_properties(src/kernels_avx512.cpp PROPERTIES COMPILE_OPTIONS "/arch:AVX512;/fp:fast")
|
|
else()
|
|
# This TU uses AVX-512F/DQ/BW/VL plus BMI tzcnt. None of those encodings
|
|
# are enabled in kernels.cpp or kernels_avx2.cpp. HasAvx512() requires
|
|
# the same feature bits before the TU is entered.
|
|
set_source_files_properties(src/kernels_avx512.cpp PROPERTIES COMPILE_OPTIONS
|
|
"-mavx512f;-mavx512dq;-mavx512bw;-mavx512vl;-mbmi;-mbmi2;-mfma")
|
|
endif()
|
|
endif()
|
|
|
|
set(PPOCR_INSTALL_TARGETS "")
|
|
|
|
if(PPOCR_BUILD_STATIC)
|
|
add_library(ppocr STATIC $<TARGET_OBJECTS:ppocr_objects>)
|
|
target_include_directories(ppocr PUBLIC
|
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
|
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
|
|
target_compile_features(ppocr PUBLIC cxx_std_20)
|
|
if(UNIX AND NOT APPLE)
|
|
target_link_libraries(ppocr PUBLIC ${CMAKE_DL_LIBS})
|
|
endif()
|
|
set_target_properties(ppocr PROPERTIES OUTPUT_NAME ppocr EXPORT_NAME static)
|
|
if(WIN32)
|
|
set_target_properties(ppocr PROPERTIES OUTPUT_NAME ppocr_static)
|
|
endif()
|
|
add_library(ppocr::static ALIAS ppocr)
|
|
list(APPEND PPOCR_INSTALL_TARGETS ppocr)
|
|
endif()
|
|
|
|
if(PPOCR_BUILD_SHARED)
|
|
add_library(ppocr_shared SHARED $<TARGET_OBJECTS:ppocr_objects>)
|
|
target_include_directories(ppocr_shared PUBLIC
|
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
|
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
|
|
target_compile_features(ppocr_shared PUBLIC cxx_std_20)
|
|
target_compile_definitions(ppocr_shared PUBLIC PPOCR_SHARED)
|
|
if(UNIX AND NOT APPLE)
|
|
target_link_libraries(ppocr_shared PRIVATE ${CMAKE_DL_LIBS})
|
|
endif()
|
|
set_target_properties(ppocr_shared PROPERTIES
|
|
OUTPUT_NAME ppocr
|
|
EXPORT_NAME ppocr
|
|
VERSION ${PROJECT_VERSION}
|
|
SOVERSION ${PROJECT_VERSION_MAJOR})
|
|
add_library(ppocr::ppocr ALIAS ppocr_shared)
|
|
list(APPEND PPOCR_INSTALL_TARGETS ppocr_shared)
|
|
endif()
|
|
|
|
function(ppocr_link_runtime target)
|
|
if(PPOCR_BUILD_STATIC)
|
|
target_link_libraries(${target} PRIVATE ppocr)
|
|
else()
|
|
target_link_libraries(${target} PRIVATE ppocr_shared)
|
|
endif()
|
|
endfunction()
|
|
|
|
if(PPOCR_BUILD_EXAMPLES)
|
|
add_executable(ppocr_demo examples/ppocr_demo.cpp)
|
|
ppocr_link_runtime(ppocr_demo)
|
|
|
|
add_executable(ppocr_cpp_api_demo examples/cpp_api_demo.cpp)
|
|
target_link_libraries(ppocr_cpp_api_demo PRIVATE $<IF:$<BOOL:${PPOCR_BUILD_SHARED}>,ppocr_shared,ppocr>)
|
|
if(PPOCR_BUILD_SHARED)
|
|
set_target_properties(ppocr_cpp_api_demo PROPERTIES BUILD_RPATH "$<TARGET_FILE_DIR:ppocr_shared>")
|
|
endif()
|
|
|
|
add_executable(ppocr_c_api_demo examples/c_api_demo.c)
|
|
target_link_libraries(ppocr_c_api_demo PRIVATE $<IF:$<BOOL:${PPOCR_BUILD_SHARED}>,ppocr_shared,ppocr>)
|
|
if(PPOCR_BUILD_SHARED)
|
|
set_target_properties(ppocr_c_api_demo PROPERTIES BUILD_RPATH "$<TARGET_FILE_DIR:ppocr_shared>")
|
|
endif()
|
|
|
|
add_executable(ppocr_isa_bench examples/ppocr_isa_bench.cpp)
|
|
ppocr_link_runtime(ppocr_isa_bench)
|
|
target_include_directories(ppocr_isa_bench PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
|
|
|
add_executable(ppocr_bench examples/ppocr_bench.cpp)
|
|
ppocr_link_runtime(ppocr_bench)
|
|
|
|
add_executable(ppocr_mem_soak examples/ppocr_mem_soak.cpp)
|
|
ppocr_link_runtime(ppocr_mem_soak)
|
|
if(WIN32)
|
|
target_link_libraries(ppocr_mem_soak PRIVATE psapi)
|
|
endif()
|
|
|
|
add_executable(ppocr_vulkan_smoke examples/ppocr_vulkan_smoke.cpp)
|
|
ppocr_link_runtime(ppocr_vulkan_smoke)
|
|
target_include_directories(ppocr_vulkan_smoke PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
|
|
|
add_executable(ppocr_batch_smoke examples/ppocr_batch_smoke.cpp)
|
|
ppocr_link_runtime(ppocr_batch_smoke)
|
|
|
|
add_executable(ppocr_kernel_smoke examples/ppocr_kernel_smoke.cpp)
|
|
ppocr_link_runtime(ppocr_kernel_smoke)
|
|
target_include_directories(ppocr_kernel_smoke PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
|
|
|
add_executable(ppocr_gpu_graph_smoke examples/ppocr_gpu_graph_smoke.cpp)
|
|
ppocr_link_runtime(ppocr_gpu_graph_smoke)
|
|
target_include_directories(ppocr_gpu_graph_smoke PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
|
|
|
add_executable(ppocr_gpu_frontend_smoke examples/ppocr_gpu_frontend_smoke.cpp)
|
|
ppocr_link_runtime(ppocr_gpu_frontend_smoke)
|
|
target_include_directories(ppocr_gpu_frontend_smoke PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
|
|
|
add_executable(ppocr_gpu_pipeline_smoke examples/ppocr_gpu_pipeline_smoke.cpp)
|
|
ppocr_link_runtime(ppocr_gpu_pipeline_smoke)
|
|
target_include_directories(ppocr_gpu_pipeline_smoke PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
|
|
|
add_executable(ppocr_gpu_ocr_smoke examples/ppocr_gpu_ocr_smoke.cpp)
|
|
ppocr_link_runtime(ppocr_gpu_ocr_smoke)
|
|
|
|
add_executable(ppocr_gpu_graph_mem_soak examples/ppocr_gpu_graph_mem_soak.cpp)
|
|
ppocr_link_runtime(ppocr_gpu_graph_mem_soak)
|
|
target_include_directories(ppocr_gpu_graph_mem_soak PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
|
endif()
|
|
|
|
if(PPOCR_BUILD_TESTS)
|
|
add_executable(ppocr_c_api_smoke tests/c_api_smoke.c)
|
|
target_link_libraries(ppocr_c_api_smoke PRIVATE $<IF:$<BOOL:${PPOCR_BUILD_SHARED}>,ppocr_shared,ppocr>)
|
|
if(PPOCR_BUILD_SHARED)
|
|
set_target_properties(ppocr_c_api_smoke PROPERTIES BUILD_RPATH "$<TARGET_FILE_DIR:ppocr_shared>")
|
|
endif()
|
|
enable_testing()
|
|
add_test(NAME c_api_smoke COMMAND ppocr_c_api_smoke)
|
|
if(NOT MSVC AND PPOCR_CPU MATCHES "x86_64|amd64|x64|i[3-6]86")
|
|
add_test(NAME isa_encoding
|
|
COMMAND sh ${CMAKE_CURRENT_SOURCE_DIR}/tests/check_isa_encoding.sh
|
|
${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/ppocr_objects.dir/src/kernels.cpp.o
|
|
${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/ppocr_objects.dir/src/kernels_avx2.cpp.o
|
|
${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/ppocr_objects.dir/src/kernels_avx512.cpp.o)
|
|
endif()
|
|
endif()
|
|
|
|
if(NOT SKBUILD)
|
|
install(TARGETS ${PPOCR_INSTALL_TARGETS}
|
|
EXPORT ppocrTargets
|
|
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
|
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
|
install(DIRECTORY include/ppocr DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
|
install(EXPORT ppocrTargets
|
|
NAMESPACE ppocr::
|
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ppocr)
|
|
configure_package_config_file(
|
|
cmake/ppocrConfig.cmake.in
|
|
${CMAKE_CURRENT_BINARY_DIR}/ppocrConfig.cmake
|
|
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ppocr)
|
|
write_basic_package_version_file(
|
|
${CMAKE_CURRENT_BINARY_DIR}/ppocrConfigVersion.cmake
|
|
COMPATIBILITY SameMajorVersion)
|
|
install(FILES
|
|
${CMAKE_CURRENT_BINARY_DIR}/ppocrConfig.cmake
|
|
${CMAKE_CURRENT_BINARY_DIR}/ppocrConfigVersion.cmake
|
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ppocr)
|
|
else()
|
|
# scikit-build-core stages the shared library next to the Python package.
|
|
if(NOT PPOCR_BUILD_SHARED)
|
|
message(FATAL_ERROR "The Python wheel needs PPOCR_BUILD_SHARED=ON")
|
|
endif()
|
|
install(TARGETS ppocr_shared
|
|
LIBRARY DESTINATION "${SKBUILD_PLATLIB_DIR}/rapidocr"
|
|
RUNTIME DESTINATION "${SKBUILD_PLATLIB_DIR}/rapidocr"
|
|
ARCHIVE DESTINATION "${SKBUILD_PLATLIB_DIR}/rapidocr")
|
|
endif()
|