Skip to content

Commit 17b4d9e

Browse files
authored
Merge pull request #4452 from zdenop/improve_cmake
Cmake optimization with warp2
2 parents 6733a9a + 6d3ef92 commit 17b4d9e

File tree

10 files changed

+867
-46
lines changed

10 files changed

+867
-46
lines changed

.github/workflows/cmake-win64.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ jobs:
112112
- name: Build and Install tesseract
113113
shell: cmd
114114
run: |
115-
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
115+
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
116116
cmake --build build --target install
117117
118118
- name: Upload Build Results

.github/workflows/cmake.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,7 @@ jobs:
5353
brew install leptonica
5454
# brew install libarchive
5555
brew install pango
56-
brew install icu4c && brew link icu4c
5756
brew install cabextract
58-
brew install ninja
5957
ninja --version
6058
cmake --version
6159
clang++ --version
@@ -96,6 +94,7 @@ jobs:
9694
-G Ninja \
9795
-DCMAKE_BUILD_TYPE=Release \
9896
-DOPENMP_BUILD=OFF \
97+
-DENABLE_UNITY_BUILD=ON \
9998
-DCMAKE_CXX_COMPILER=${{ matrix.config.cxx }} \
10099
-DCMAKE_INSTALL_PREFIX:PATH=inst
101100
if: runner.os == 'macOS'

CMakeLists.txt

Lines changed: 119 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
#
99
# ##############################################################################
1010

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

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

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

109111
# ##############################################################################
110112
#
@@ -286,6 +288,8 @@ if(CMAKE_COMPILER_IS_GNUCXX OR MINGW)
286288
elseif(MSVC)
287289
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
288290
add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE) # strdup
291+
add_definitions(-D_USE_MATH_DEFINES) # Enable M_PI and other math constants
292+
add_definitions(-DNOMINMAX) # Prevent min/max macro conflicts
289293
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8")
290294
if(NOT CLANG)
291295
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
@@ -376,6 +380,47 @@ endif()
376380

377381
add_definitions("-DCMAKE_BUILD")
378382

383+
# ##############################################################################
384+
#
385+
# Build optimizations
386+
#
387+
# ##############################################################################
388+
389+
# Setup ccache if available and enabled
390+
if(ENABLE_CCACHE)
391+
find_program(CCACHE_PROGRAM ccache)
392+
if(CCACHE_PROGRAM)
393+
message(STATUS "Found ccache: ${CCACHE_PROGRAM}")
394+
set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
395+
set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
396+
# Configure ccache for better performance
397+
set(ENV{CCACHE_SLOPPINESS} "pch_defines,time_macros")
398+
set(ENV{CCACHE_CPP2} "true")
399+
else()
400+
message(STATUS "ccache not found, disabling ccache support")
401+
set(ENABLE_CCACHE OFF)
402+
endif()
403+
endif()
404+
405+
# Setup Ninja job pools for better resource management
406+
if(ENABLE_NINJA_POOL AND CMAKE_GENERATOR STREQUAL "Ninja")
407+
include(ProcessorCount)
408+
ProcessorCount(N)
409+
if(N GREATER 1)
410+
# Use 75% of available cores for compilation, rest for linking
411+
math(EXPR COMPILE_JOBS "${N} * 3 / 4")
412+
math(EXPR LINK_JOBS "${N} - ${COMPILE_JOBS}")
413+
if(LINK_JOBS LESS 1)
414+
set(LINK_JOBS 1)
415+
endif()
416+
417+
set_property(GLOBAL PROPERTY JOB_POOLS "compile=${COMPILE_JOBS};link=${LINK_JOBS}")
418+
set(CMAKE_JOB_POOL_COMPILE compile)
419+
set(CMAKE_JOB_POOL_LINK link)
420+
message(STATUS "Ninja job pools: compile=${COMPILE_JOBS}, link=${LINK_JOBS}")
421+
endif()
422+
endif()
423+
379424
# ##############################################################################
380425
#
381426
# packages
@@ -569,6 +614,16 @@ message(STATUS "Use system ICU Library [USE_SYSTEM_ICU]: ${USE_SYSTEM_ICU}")
569614
message(
570615
STATUS "Install tesseract configs [INSTALL_CONFIGS]: ${INSTALL_CONFIGS}")
571616
message(STATUS "--------------------------------------------------------")
617+
message(STATUS "Modern build optimizations:")
618+
message(STATUS "Unity build [ENABLE_UNITY_BUILD]: ${ENABLE_UNITY_BUILD}")
619+
message(STATUS "Precompiled headers [ENABLE_PRECOMPILED_HEADERS]: ${ENABLE_PRECOMPILED_HEADERS}")
620+
message(STATUS "ccache [ENABLE_CCACHE]: ${ENABLE_CCACHE}")
621+
if(CMAKE_GENERATOR STREQUAL "Ninja")
622+
message(STATUS "Ninja job pools [ENABLE_NINJA_POOL]: ${ENABLE_NINJA_POOL}")
623+
else()
624+
message(STATUS "Ninja job pools [ENABLE_NINJA_POOL]: Disabled (not using Ninja)")
625+
endif()
626+
message(STATUS "--------------------------------------------------------")
572627
message(STATUS)
573628

574629
# ##############################################################################
@@ -593,19 +648,11 @@ endif()
593648
# LIBRARY tesseract
594649
# ##############################################################################
595650

596-
file(
597-
GLOB
598-
TESSERACT_SRC
599-
src/ccmain/*.cpp
600-
src/ccstruct/*.cpp
601-
src/ccutil/*.cpp
602-
src/classify/*.cpp
603-
src/cutil/*.cpp
604-
src/dict/*.cpp
605-
src/lstm/*.cpp
606-
src/textord/*.cpp
607-
src/viewer/*.cpp
608-
src/wordrec/*.cpp)
651+
# Include source file lists
652+
include(cmake/SourceLists.cmake)
653+
654+
# Build the core source file list
655+
set(TESSERACT_SRC ${TESSERACT_SRC_CORE})
609656

610657
if(DISABLED_LEGACY_ENGINE)
611658
# prepend path to list of source files
@@ -686,8 +733,8 @@ if(DISABLED_LEGACY_ENGINE)
686733
list(REMOVE_ITEM TESSERACT_SRC ${TESSERACT_SRC_LEGACY})
687734
endif(DISABLED_LEGACY_ENGINE)
688735

689-
list(APPEND arch_files src/arch/dotproduct.cpp src/arch/simddetect.cpp
690-
src/arch/intsimdmatrix.cpp)
736+
# Use architecture files from SourceLists.cmake
737+
set(arch_files ${TESSERACT_SRC_ARCH})
691738

692739
if(DOTPRODUCT_FLAGS)
693740
set_source_files_properties(src/arch/dotproduct.cpp
@@ -731,21 +778,8 @@ if(HAVE_NEON)
731778
endif()
732779
endif(HAVE_NEON)
733780

734-
file(
735-
GLOB_RECURSE
736-
TESSERACT_HDR
737-
include/*
738-
src/arch/*.h
739-
src/ccmain/*.h
740-
src/ccstruct/*.h
741-
src/ccutil/*.h
742-
src/classify/*.h
743-
src/cutil/*.h
744-
src/dict/*.h
745-
src/lstm/*.h
746-
src/textord/*.h
747-
src/viewer/*.h
748-
src/wordrec/*.h)
781+
# Use explicit header file lists from SourceLists.cmake
782+
set(TESSERACT_HDR ${TESSERACT_HDR_INCLUDE} ${TESSERACT_HDR_INTERNAL})
749783

750784
set(TESSERACT_SRC
751785
${TESSERACT_SRC}
@@ -799,6 +833,55 @@ set(LIBTESSFILES ${TESSERACT_SRC} ${arch_files} ${arch_files_opt}
799833
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${LIBTESSFILES})
800834

801835
add_library(libtesseract ${LIBTESSFILES})
836+
837+
# Apply modern optimizations to the main library
838+
if(ENABLE_UNITY_BUILD)
839+
set_target_properties(libtesseract PROPERTIES UNITY_BUILD ON)
840+
set_target_properties(libtesseract PROPERTIES UNITY_BUILD_BATCH_SIZE 16)
841+
message(STATUS "Unity build enabled for libtesseract with batch size 16")
842+
endif()
843+
844+
# Apply precompiled headers to reduce compilation time
845+
if(ENABLE_PRECOMPILED_HEADERS)
846+
target_precompile_headers(libtesseract PRIVATE
847+
<vector>
848+
<string>
849+
<memory>
850+
<algorithm>
851+
<iostream>
852+
<cstdlib>
853+
<cstring>
854+
<cmath>
855+
)
856+
857+
# Exclude architecture-specific files from PCH due to custom compiler flags
858+
set(ARCH_FILES_NO_PCH
859+
src/arch/dotproduct.cpp
860+
src/arch/dotproductavx.cpp
861+
src/arch/dotproductavx512.cpp
862+
src/arch/dotproductfma.cpp
863+
src/arch/dotproductsse.cpp
864+
src/arch/dotproductneon.cpp
865+
src/arch/intsimdmatrixavx2.cpp
866+
src/arch/intsimdmatrixsse.cpp
867+
src/arch/intsimdmatrixneon.cpp
868+
)
869+
870+
foreach(file ${ARCH_FILES_NO_PCH})
871+
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${file}")
872+
set_source_files_properties("${file}" PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
873+
endif()
874+
endforeach()
875+
876+
message(STATUS "Precompiled headers enabled for libtesseract (excluding architecture-specific files)")
877+
endif()
878+
879+
# Configure build pools for Ninja
880+
if(ENABLE_NINJA_POOL AND CMAKE_GENERATOR STREQUAL "Ninja")
881+
set_target_properties(libtesseract PROPERTIES JOB_POOL_COMPILE compile)
882+
set_target_properties(libtesseract PROPERTIES JOB_POOL_LINK link)
883+
endif()
884+
802885
target_include_directories(
803886
libtesseract BEFORE
804887
PRIVATE src

cmake/BuildOptimizations.cmake

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License");
2+
# you may not use this file except in compliance with the License.
3+
# You may obtain a copy of the License at
4+
# http://www.apache.org/licenses/LICENSE-2.0
5+
# Unless required by applicable law or agreed to in writing, software
6+
# distributed under the License is distributed on an "AS IS" BASIS,
7+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8+
# See the License for the specific language governing permissions and
9+
# limitations under the License.
10+
11+
################################################################################
12+
#
13+
# Build Optimizations Module
14+
#
15+
# This module provides functions to apply modern CMake build optimizations
16+
# to targets for faster and incremental builds.
17+
#
18+
################################################################################
19+
20+
#
21+
# Function: apply_modern_optimizations
22+
# Apply build optimizations to a target
23+
#
24+
# Parameters:
25+
# target_name - Name of the target to optimize
26+
# PCH_HEADERS - Optional list of headers for precompiled headers
27+
#
28+
function(apply_modern_optimizations target_name)
29+
# Parse arguments
30+
set(oneValueArgs )
31+
set(multiValueArgs PCH_HEADERS)
32+
cmake_parse_arguments(ARG "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
33+
34+
# Apply Unity Build if enabled
35+
if(ENABLE_UNITY_BUILD)
36+
set_target_properties(${target_name} PROPERTIES UNITY_BUILD ON)
37+
# Use smaller batch sizes for libraries with many files
38+
get_target_property(target_type ${target_name} TYPE)
39+
if(target_type STREQUAL "STATIC_LIBRARY" OR target_type STREQUAL "SHARED_LIBRARY")
40+
set_target_properties(${target_name} PROPERTIES UNITY_BUILD_BATCH_SIZE 16)
41+
else()
42+
set_target_properties(${target_name} PROPERTIES UNITY_BUILD_BATCH_SIZE 8)
43+
endif()
44+
message(STATUS "Unity build enabled for ${target_name}")
45+
endif()
46+
47+
# Apply Precompiled Headers if enabled and headers provided
48+
if(ENABLE_PRECOMPILED_HEADERS)
49+
if(ARG_PCH_HEADERS)
50+
target_precompile_headers(${target_name} PRIVATE ${ARG_PCH_HEADERS})
51+
message(STATUS "Precompiled headers enabled for ${target_name}")
52+
else()
53+
# Use common standard library headers as default
54+
target_precompile_headers(${target_name} PRIVATE
55+
<vector>
56+
<string>
57+
<memory>
58+
<algorithm>
59+
<iostream>
60+
<cstdlib>
61+
<cstring>
62+
<cmath>
63+
)
64+
message(STATUS "Default precompiled headers enabled for ${target_name}")
65+
endif()
66+
endif()
67+
68+
# Configure build pools for Ninja
69+
if(ENABLE_NINJA_POOL AND CMAKE_GENERATOR STREQUAL "Ninja")
70+
set_target_properties(${target_name} PROPERTIES JOB_POOL_COMPILE compile)
71+
set_target_properties(${target_name} PROPERTIES JOB_POOL_LINK link)
72+
endif()
73+
74+
# Apply compiler-specific optimizations
75+
if(MSVC)
76+
# Enable parallel compilation for MSVC if not already enabled
77+
get_target_property(target_compile_options ${target_name} COMPILE_OPTIONS)
78+
if(NOT target_compile_options MATCHES "/MP")
79+
target_compile_options(${target_name} PRIVATE "/MP")
80+
endif()
81+
82+
# Enable function-level linking for better optimization
83+
target_compile_options(${target_name} PRIVATE "/Gy")
84+
85+
# Enable intrinsic functions for better performance
86+
target_compile_options(${target_name} PRIVATE "/Oi")
87+
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
88+
# Enable split debug info for faster incremental builds
89+
if(CMAKE_BUILD_TYPE MATCHES Debug)
90+
target_compile_options(${target_name} PRIVATE "-gsplit-dwarf")
91+
endif()
92+
93+
# Enable function sections for better dead code elimination
94+
target_compile_options(${target_name} PRIVATE "-ffunction-sections" "-fdata-sections")
95+
endif()
96+
endfunction()
97+
98+
#
99+
# Function: apply_training_optimizations
100+
# Apply optimizations specific to training tools
101+
#
102+
function(apply_training_optimizations target_name)
103+
apply_modern_optimizations(${target_name}
104+
PCH_HEADERS
105+
<vector>
106+
<string>
107+
<memory>
108+
<iostream>
109+
<fstream>
110+
<cstdlib>
111+
<cstring>
112+
)
113+
114+
# Training tools usually build faster, so smaller unity batches are fine
115+
if(ENABLE_UNITY_BUILD)
116+
set_target_properties(${target_name} PROPERTIES UNITY_BUILD_BATCH_SIZE 4)
117+
endif()
118+
endfunction()
119+
120+
#
121+
# Function: apply_test_optimizations
122+
# Apply optimizations specific to test targets
123+
#
124+
function(apply_test_optimizations target_name)
125+
# Tests often have different compilation patterns
126+
if(ENABLE_PRECOMPILED_HEADERS)
127+
target_precompile_headers(${target_name} PRIVATE
128+
<gtest/gtest.h>
129+
<vector>
130+
<string>
131+
<memory>
132+
<iostream>
133+
)
134+
message(STATUS "Test precompiled headers enabled for ${target_name}")
135+
endif()
136+
137+
# Tests benefit from unity builds but smaller batches
138+
if(ENABLE_UNITY_BUILD)
139+
set_target_properties(${target_name} PROPERTIES UNITY_BUILD ON)
140+
set_target_properties(${target_name} PROPERTIES UNITY_BUILD_BATCH_SIZE 8)
141+
message(STATUS "Unity build enabled for test ${target_name}")
142+
endif()
143+
144+
# Configure Ninja pools
145+
if(ENABLE_NINJA_POOL AND CMAKE_GENERATOR STREQUAL "Ninja")
146+
set_target_properties(${target_name} PROPERTIES JOB_POOL_COMPILE compile)
147+
set_target_properties(${target_name} PROPERTIES JOB_POOL_LINK link)
148+
endif()
149+
endfunction()

0 commit comments

Comments
 (0)