Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/cmake-win64.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ jobs:
- name: Build and Install tesseract
shell: cmd
run: |
cmake -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_PREFIX_PATH=${{env.ILOC}} -DCMAKE_INSTALL_PREFIX=${{env.ILOC}} -DSW_BUILD=OFF -DBUILD_SHARED_LIBS=ON -DENABLE_LTO=ON -DBUILD_TRAINING_TOOLS=OFF -DFAST_FLOAT=ON -DGRAPHICS_DISABLED=ON -DOPENMP_BUILD=OFF
cmake -Bbuild -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_PREFIX_PATH=${{env.ILOC}} -DCMAKE_INSTALL_PREFIX=${{env.ILOC}} -DSW_BUILD=OFF -DBUILD_SHARED_LIBS=ON -DENABLE_LTO=ON -DBUILD_TRAINING_TOOLS=OFF -DFAST_FLOAT=ON -DGRAPHICS_DISABLED=ON -DOPENMP_BUILD=OFF
cmake --build build --target install

- name: Upload Build Results
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/cmake.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,7 @@ jobs:
brew install leptonica
# brew install libarchive
brew install pango
brew install icu4c && brew link icu4c
brew install cabextract
brew install ninja
ninja --version
cmake --version
clang++ --version
Expand Down Expand Up @@ -96,6 +94,7 @@ jobs:
-G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DOPENMP_BUILD=OFF \
-DENABLE_UNITY_BUILD=ON \
-DCMAKE_CXX_COMPILER=${{ matrix.config.cxx }} \
-DCMAKE_INSTALL_PREFIX:PATH=inst
if: runner.os == 'macOS'
Expand Down
155 changes: 119 additions & 36 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
#
# ##############################################################################

cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
# Require CMake 3.18 for modern features like precompiled headers, unity builds, and better target management
cmake_minimum_required(VERSION 3.18 FATAL_ERROR)

# In-source builds are disabled.
if("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
Expand Down Expand Up @@ -100,11 +101,12 @@ option(DISABLE_ARCHIVE "Disable build with libarchive (if available)" OFF)
option(DISABLE_CURL "Disable build with libcurl (if available)" OFF)
option(INSTALL_CONFIGS "Install tesseract configs" ON)

if(NOT ${CMAKE_VERSION} VERSION_LESS "3.15.0")
if(WIN32 AND MSVC)
option(WIN32_MT_BUILD "Build with MT flag for MSVC" OFF)
endif()
endif()
# Build optimization options
option(ENABLE_UNITY_BUILD "Enable Unity/Jumbo builds for faster compilation" OFF)
option(ENABLE_PRECOMPILED_HEADERS "Enable precompiled headers for faster compilation" ON)
option(ENABLE_CCACHE "Enable ccache for faster incremental builds" ON)
option(ENABLE_NINJA_POOL "Enable Ninja job pools to manage parallelism" ON)


# ##############################################################################
#
Expand Down Expand Up @@ -286,6 +288,8 @@ if(CMAKE_COMPILER_IS_GNUCXX OR MINGW)
elseif(MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE) # strdup
add_definitions(-D_USE_MATH_DEFINES) # Enable M_PI and other math constants
add_definitions(-DNOMINMAX) # Prevent min/max macro conflicts
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8")
if(NOT CLANG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
Expand Down Expand Up @@ -376,6 +380,47 @@ endif()

add_definitions("-DCMAKE_BUILD")

# ##############################################################################
#
# Build optimizations
#
# ##############################################################################

# Setup ccache if available and enabled
if(ENABLE_CCACHE)
find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
message(STATUS "Found ccache: ${CCACHE_PROGRAM}")
set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
# Configure ccache for better performance
set(ENV{CCACHE_SLOPPINESS} "pch_defines,time_macros")
set(ENV{CCACHE_CPP2} "true")
else()
message(STATUS "ccache not found, disabling ccache support")
set(ENABLE_CCACHE OFF)
endif()
endif()

# Setup Ninja job pools for better resource management
if(ENABLE_NINJA_POOL AND CMAKE_GENERATOR STREQUAL "Ninja")
include(ProcessorCount)
ProcessorCount(N)
if(N GREATER 1)
# Use 75% of available cores for compilation, rest for linking
math(EXPR COMPILE_JOBS "${N} * 3 / 4")
math(EXPR LINK_JOBS "${N} - ${COMPILE_JOBS}")
if(LINK_JOBS LESS 1)
set(LINK_JOBS 1)
endif()

set_property(GLOBAL PROPERTY JOB_POOLS "compile=${COMPILE_JOBS};link=${LINK_JOBS}")
set(CMAKE_JOB_POOL_COMPILE compile)
set(CMAKE_JOB_POOL_LINK link)
message(STATUS "Ninja job pools: compile=${COMPILE_JOBS}, link=${LINK_JOBS}")
endif()
endif()

# ##############################################################################
#
# packages
Expand Down Expand Up @@ -569,6 +614,16 @@ message(STATUS "Use system ICU Library [USE_SYSTEM_ICU]: ${USE_SYSTEM_ICU}")
message(
STATUS "Install tesseract configs [INSTALL_CONFIGS]: ${INSTALL_CONFIGS}")
message(STATUS "--------------------------------------------------------")
message(STATUS "Modern build optimizations:")
message(STATUS "Unity build [ENABLE_UNITY_BUILD]: ${ENABLE_UNITY_BUILD}")
message(STATUS "Precompiled headers [ENABLE_PRECOMPILED_HEADERS]: ${ENABLE_PRECOMPILED_HEADERS}")
message(STATUS "ccache [ENABLE_CCACHE]: ${ENABLE_CCACHE}")
if(CMAKE_GENERATOR STREQUAL "Ninja")
message(STATUS "Ninja job pools [ENABLE_NINJA_POOL]: ${ENABLE_NINJA_POOL}")
else()
message(STATUS "Ninja job pools [ENABLE_NINJA_POOL]: Disabled (not using Ninja)")
endif()
message(STATUS "--------------------------------------------------------")
message(STATUS)

# ##############################################################################
Expand All @@ -593,19 +648,11 @@ endif()
# LIBRARY tesseract
# ##############################################################################

file(
GLOB
TESSERACT_SRC
src/ccmain/*.cpp
src/ccstruct/*.cpp
src/ccutil/*.cpp
src/classify/*.cpp
src/cutil/*.cpp
src/dict/*.cpp
src/lstm/*.cpp
src/textord/*.cpp
src/viewer/*.cpp
src/wordrec/*.cpp)
# Include source file lists
include(cmake/SourceLists.cmake)

# Build the core source file list
set(TESSERACT_SRC ${TESSERACT_SRC_CORE})

if(DISABLED_LEGACY_ENGINE)
# prepend path to list of source files
Expand Down Expand Up @@ -686,8 +733,8 @@ if(DISABLED_LEGACY_ENGINE)
list(REMOVE_ITEM TESSERACT_SRC ${TESSERACT_SRC_LEGACY})
endif(DISABLED_LEGACY_ENGINE)

list(APPEND arch_files src/arch/dotproduct.cpp src/arch/simddetect.cpp
src/arch/intsimdmatrix.cpp)
# Use architecture files from SourceLists.cmake
set(arch_files ${TESSERACT_SRC_ARCH})

if(DOTPRODUCT_FLAGS)
set_source_files_properties(src/arch/dotproduct.cpp
Expand Down Expand Up @@ -731,21 +778,8 @@ if(HAVE_NEON)
endif()
endif(HAVE_NEON)

file(
GLOB_RECURSE
TESSERACT_HDR
include/*
src/arch/*.h
src/ccmain/*.h
src/ccstruct/*.h
src/ccutil/*.h
src/classify/*.h
src/cutil/*.h
src/dict/*.h
src/lstm/*.h
src/textord/*.h
src/viewer/*.h
src/wordrec/*.h)
# Use explicit header file lists from SourceLists.cmake
set(TESSERACT_HDR ${TESSERACT_HDR_INCLUDE} ${TESSERACT_HDR_INTERNAL})

set(TESSERACT_SRC
${TESSERACT_SRC}
Expand Down Expand Up @@ -799,6 +833,55 @@ set(LIBTESSFILES ${TESSERACT_SRC} ${arch_files} ${arch_files_opt}
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${LIBTESSFILES})

add_library(libtesseract ${LIBTESSFILES})

# Apply modern optimizations to the main library
if(ENABLE_UNITY_BUILD)
set_target_properties(libtesseract PROPERTIES UNITY_BUILD ON)
set_target_properties(libtesseract PROPERTIES UNITY_BUILD_BATCH_SIZE 16)
message(STATUS "Unity build enabled for libtesseract with batch size 16")
endif()

# Apply precompiled headers to reduce compilation time
if(ENABLE_PRECOMPILED_HEADERS)
target_precompile_headers(libtesseract PRIVATE
<vector>
<string>
<memory>
<algorithm>
<iostream>
<cstdlib>
<cstring>
<cmath>
)

# Exclude architecture-specific files from PCH due to custom compiler flags
set(ARCH_FILES_NO_PCH
src/arch/dotproduct.cpp
src/arch/dotproductavx.cpp
src/arch/dotproductavx512.cpp
src/arch/dotproductfma.cpp
src/arch/dotproductsse.cpp
src/arch/dotproductneon.cpp
src/arch/intsimdmatrixavx2.cpp
src/arch/intsimdmatrixsse.cpp
src/arch/intsimdmatrixneon.cpp
)

foreach(file ${ARCH_FILES_NO_PCH})
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${file}")
set_source_files_properties("${file}" PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
endif()
endforeach()

message(STATUS "Precompiled headers enabled for libtesseract (excluding architecture-specific files)")
endif()

# Configure build pools for Ninja
if(ENABLE_NINJA_POOL AND CMAKE_GENERATOR STREQUAL "Ninja")
set_target_properties(libtesseract PROPERTIES JOB_POOL_COMPILE compile)
set_target_properties(libtesseract PROPERTIES JOB_POOL_LINK link)
endif()

target_include_directories(
libtesseract BEFORE
PRIVATE src
Expand Down
149 changes: 149 additions & 0 deletions cmake/BuildOptimizations.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

################################################################################
#
# Build Optimizations Module
#
# This module provides functions to apply modern CMake build optimizations
# to targets for faster and incremental builds.
#
################################################################################

#
# Function: apply_modern_optimizations
# Apply build optimizations to a target
#
# Parameters:
# target_name - Name of the target to optimize
# PCH_HEADERS - Optional list of headers for precompiled headers
#
function(apply_modern_optimizations target_name)
# Parse arguments
set(oneValueArgs )
set(multiValueArgs PCH_HEADERS)
cmake_parse_arguments(ARG "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

# Apply Unity Build if enabled
if(ENABLE_UNITY_BUILD)
set_target_properties(${target_name} PROPERTIES UNITY_BUILD ON)
# Use smaller batch sizes for libraries with many files
get_target_property(target_type ${target_name} TYPE)
if(target_type STREQUAL "STATIC_LIBRARY" OR target_type STREQUAL "SHARED_LIBRARY")
set_target_properties(${target_name} PROPERTIES UNITY_BUILD_BATCH_SIZE 16)
else()
set_target_properties(${target_name} PROPERTIES UNITY_BUILD_BATCH_SIZE 8)
endif()
message(STATUS "Unity build enabled for ${target_name}")
endif()

# Apply Precompiled Headers if enabled and headers provided
if(ENABLE_PRECOMPILED_HEADERS)
if(ARG_PCH_HEADERS)
target_precompile_headers(${target_name} PRIVATE ${ARG_PCH_HEADERS})
message(STATUS "Precompiled headers enabled for ${target_name}")
else()
# Use common standard library headers as default
target_precompile_headers(${target_name} PRIVATE
<vector>
<string>
<memory>
<algorithm>
<iostream>
<cstdlib>
<cstring>
<cmath>
)
message(STATUS "Default precompiled headers enabled for ${target_name}")
endif()
endif()

# Configure build pools for Ninja
if(ENABLE_NINJA_POOL AND CMAKE_GENERATOR STREQUAL "Ninja")
set_target_properties(${target_name} PROPERTIES JOB_POOL_COMPILE compile)
set_target_properties(${target_name} PROPERTIES JOB_POOL_LINK link)
endif()

# Apply compiler-specific optimizations
if(MSVC)
# Enable parallel compilation for MSVC if not already enabled
get_target_property(target_compile_options ${target_name} COMPILE_OPTIONS)
if(NOT target_compile_options MATCHES "/MP")
target_compile_options(${target_name} PRIVATE "/MP")
endif()

# Enable function-level linking for better optimization
target_compile_options(${target_name} PRIVATE "/Gy")

# Enable intrinsic functions for better performance
target_compile_options(${target_name} PRIVATE "/Oi")
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
# Enable split debug info for faster incremental builds
if(CMAKE_BUILD_TYPE MATCHES Debug)
target_compile_options(${target_name} PRIVATE "-gsplit-dwarf")
endif()

# Enable function sections for better dead code elimination
target_compile_options(${target_name} PRIVATE "-ffunction-sections" "-fdata-sections")
endif()
endfunction()

#
# Function: apply_training_optimizations
# Apply optimizations specific to training tools
#
function(apply_training_optimizations target_name)
apply_modern_optimizations(${target_name}
PCH_HEADERS
<vector>
<string>
<memory>
<iostream>
<fstream>
<cstdlib>
<cstring>
)

# Training tools usually build faster, so smaller unity batches are fine
if(ENABLE_UNITY_BUILD)
set_target_properties(${target_name} PROPERTIES UNITY_BUILD_BATCH_SIZE 4)
endif()
endfunction()

#
# Function: apply_test_optimizations
# Apply optimizations specific to test targets
#
function(apply_test_optimizations target_name)
# Tests often have different compilation patterns
if(ENABLE_PRECOMPILED_HEADERS)
target_precompile_headers(${target_name} PRIVATE
<gtest/gtest.h>
<vector>
<string>
<memory>
<iostream>
)
message(STATUS "Test precompiled headers enabled for ${target_name}")
endif()

# Tests benefit from unity builds but smaller batches
if(ENABLE_UNITY_BUILD)
set_target_properties(${target_name} PROPERTIES UNITY_BUILD ON)
set_target_properties(${target_name} PROPERTIES UNITY_BUILD_BATCH_SIZE 8)
message(STATUS "Unity build enabled for test ${target_name}")
endif()

# Configure Ninja pools
if(ENABLE_NINJA_POOL AND CMAKE_GENERATOR STREQUAL "Ninja")
set_target_properties(${target_name} PROPERTIES JOB_POOL_COMPILE compile)
set_target_properties(${target_name} PROPERTIES JOB_POOL_LINK link)
endif()
endfunction()
Loading
Loading